From 44d81d1baba8095eb5830d750399f0cd220ebd29 Mon Sep 17 00:00:00 2001 From: Raz Date: Mon, 18 Dec 2023 21:28:19 +0700 Subject: [PATCH] Bring in ExSecp256k1 (#36) * Bring support for ex_secp256k1 --- .github/workflows/ci.yml | 68 ++++++++++++++++++++++++++++++ CHANGELOG.md | 9 ++++ README.md | 41 ++++++------------ config/config.exs | 4 +- lib/block_keys/base58/encoder.ex | 2 +- lib/block_keys/crypto.ex | 13 +++--- lib/block_keys/ethereum/address.ex | 2 +- mix.exs | 8 ++-- mix.lock | 30 ++++++------- 9 files changed, 115 insertions(+), 62 deletions(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..accd9c8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,68 @@ +name: CI + +on: + pull_request: + push: + branches: + - main + +jobs: + mix_test: + runs-on: ubuntu-20.04 + env: + MIX_ENV: test + RUSTLER_BUILD: "0" + + name: Elixir ${{ matrix.pair.elixir }} / OTP ${{ matrix.pair.otp }} + + strategy: + fail-fast: false + matrix: + include: + - pair: + elixir: 1.12.1 + otp: 24.0.2 + - pair: + elixir: 1.11.4 + otp: 23.3.1 + - pair: + elixir: 1.11.4 + otp: 24.0.2 + - pair: + elixir: 1.10.4 + otp: 23.3.1 + - pair: + elixir: 1.10.4 + otp: 22.2.8 + - pair: + elixir: 1.12.1 + otp: 23.3.1 + - pair: + elixir: 1.14.3 + otp: 25.2.1 + - pair: + elixir: 1.15 + otp: 26.0 + lint: lint + steps: + - uses: actions/checkout@v3 + + - uses: erlef/setup-beam@v1 + with: + otp-version: ${{ matrix.pair.otp }} + elixir-version: ${{ matrix.pair.elixir }} + + - name: Install Dependencies + run: mix deps.get + + - run: mix format --check-formatted + if: ${{ matrix.lint }} + + - run: mix deps.unlock --check-unused + if: ${{ matrix.lint }} + + - run: mix deps.compile + + - run: mix compile --warnings-as-errors + + - run: mix test diff --git a/CHANGELOG.md b/CHANGELOG.md index 04f36d1..c789589 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## v1.0.0 + + **Breaking Changes** + + * Removes support for libsecp256k1 Nif library in favour of the + better maitained ex_secp256k1. The Rust based ex_secp256k1 also comes with + precompiled binaries, making compilation much faster. + + ## v0.1.10 * Adds support for OTP 24 diff --git a/README.md b/README.md index 055f411..92a662b 100644 --- a/README.md +++ b/README.md @@ -14,38 +14,11 @@ Add the dependency to your `mix.exs`: ``` def deps do [ - {:block_keys, "~> 0.1.10"} + {:block_keys, "~> 1.0.0"} ] end ``` -### Using a different libsecp256k1 library - -By default, this package depends on the [ExThereum's fork of libsecp256k1 C Nif](https://github.com/exthereum/libsecp256k1). - -If you prefer, you can either roll your own Crypto module or use another experimental and probably incomplete Rust based Nif -based on [Parity's pure Rust implementation](https://crates.io/crates/libsecp256k1). - -Add this additional dependency to your `mix.exs`: - -``` -def deps do - [ - ... - {:rusty_secp256k1, "~> 0.1.6"} - ... - ] -end -``` - -And configure the package to use it in your `config.exs` or the appropriate env configuration: - -``` -config :block_keys, :ec_module, RustySecp256k1 -``` - -Note that you will need to have Rust installed and configured in order to build the `rusty_secp256k1` dependency. - ## What is this good for ? The purpose of HD wallets is to increase anonymity by generating different addresses each time you transact. For Bitcoin this means generating @@ -164,3 +137,15 @@ Is equivalent to ``` M/60'/0'/0'/0/0 ``` + +## Contributing + +1. [Fork it!](https://github.com/zyield/block_keys) +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Commit your changes (`git commit -am 'Add some feature'`) +4. Push to the branch (`git push origin my-new-feature`) +5. Create new Pull Request + +## License + +ExKeccak is released under the Apache-2.0 License. diff --git a/config/config.exs b/config/config.exs index d17c097..c56af5e 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,6 +1,6 @@ # This file is responsible for configuring your application # and its dependencies with the aid of the Mix.Config module. -use Mix.Config +import Config # This configuration is loaded before any dependency and is restricted # to this project. If another project depends on this project, this @@ -21,8 +21,6 @@ use Mix.Config # config :logger, level: :info # -config :block_keys, :ec_module, :libsecp256k1 - # It is also possible to import configuration files, relative to this # directory. For example, you can emulate configuration per environment # by uncommenting the line below and defining dev.exs, test.exs and such. diff --git a/lib/block_keys/base58/encoder.ex b/lib/block_keys/base58/encoder.ex index c19b559..6e9812d 100644 --- a/lib/block_keys/base58/encoder.ex +++ b/lib/block_keys/base58/encoder.ex @@ -1,5 +1,5 @@ defmodule BlockKeys.Base58.Encoder do - @btc_alphabet '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' + @btc_alphabet ~c"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" def alphabet, do: @btc_alphabet diff --git a/lib/block_keys/crypto.ex b/lib/block_keys/crypto.ex index 57e4a90..4d9b063 100644 --- a/lib/block_keys/crypto.ex +++ b/lib/block_keys/crypto.ex @@ -19,19 +19,18 @@ defmodule BlockKeys.Crypto do # tweak the child key by adding the parent key to it def ec_point_addition(parent_key, child_key) do - ec_module().ec_pubkey_tweak_add(parent_key, child_key) + with {:ok, decompressed_parent_key} <- ExSecp256k1.public_key_decompress(parent_key), + {:ok, key} <- ExSecp256k1.public_key_tweak_add(decompressed_parent_key, child_key) do + ExSecp256k1.public_key_compress(key) + end end def public_key(private_key) do - {:ok, public_key} = ec_module().ec_pubkey_create(private_key, :uncompressed) + {:ok, public_key} = ExSecp256k1.create_public_key(private_key) public_key end def public_key_decompress(public_key) do - ec_module().ec_pubkey_decompress(public_key) - end - - defp ec_module do - Application.fetch_env!(:block_keys, :ec_module) + ExSecp256k1.public_key_decompress(public_key) end end diff --git a/lib/block_keys/ethereum/address.ex b/lib/block_keys/ethereum/address.ex index 5d3d0ec..889c360 100644 --- a/lib/block_keys/ethereum/address.ex +++ b/lib/block_keys/ethereum/address.ex @@ -35,5 +35,5 @@ defmodule BlockKeys.Ethereum.Address do |> Kernel.<>(address |> Base.encode16(case: :lower)) end - defp keccak256(data), do: :keccakf1600.hash(:sha3_256, data) + defp keccak256(data), do: ExKeccak.hash_256(data) end diff --git a/mix.exs b/mix.exs index 534af8d..a73a645 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule BlockKeys.MixProject do def project do [ app: :block_keys, - version: "0.1.10", + version: "1.0.0", elixir: "~> 1.7", description: description(), start_permanent: Mix.env() == :prod, @@ -41,9 +41,9 @@ defmodule BlockKeys.MixProject do defp deps do [ {:ex_doc, "~> 0.19", only: :dev, runtime: false}, - {:keccakf1600, "~> 2.0", hex: :keccakf1600_otp23}, - {:excoveralls, "~> 0.10", only: :test}, - {:libsecp256k1, "~> 0.1.9"} + {:ex_keccak, "~> 0.7.3"}, + {:ex_secp256k1, "~> 0.7.2"}, + {:excoveralls, "~> 0.10", only: :test} ] end end diff --git a/mix.lock b/mix.lock index 18238eb..a739b24 100644 --- a/mix.lock +++ b/mix.lock @@ -1,20 +1,14 @@ %{ - "certifi": {:hex, :certifi, "2.4.2", "75424ff0f3baaccfd34b1214184b6ef616d89e420b258bb0a5ea7d7bc628f7f0", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "01d479edba0569a7b7a2c8bf923feeb6dc6a358edc2965ef69aea9ba288bb243"}, - "earmark": {:hex, :earmark, "1.3.1", "73812f447f7a42358d3ba79283cfa3075a7580a3a2ed457616d6517ac3738cb9", [:mix], [], "hexpm", "000aaeff08919e95e7aea13e4af7b2b9734577b3e6a7c50ee31ee88cab6ec4fb"}, - "ex_doc": {:hex, :ex_doc, "0.19.3", "3c7b0f02851f5fc13b040e8e925051452e41248f685e40250d7e40b07b9f8c10", [:mix], [{:earmark, "~> 1.2", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.10", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "0e11d67e662142fc3945b0ee410c73c8c956717fbeae4ad954b418747c734973"}, - "excoveralls": {:hex, :excoveralls, "0.10.5", "7c912c4ec0715a6013647d835c87cde8154855b9b84e256bc7a63858d5f284e3", [:mix], [{:hackney, "~> 1.13", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "176052589b681f44de12fb85182ccf0296030f619b6939926bc647dabedf9320"}, - "hackney": {:hex, :hackney, "1.15.0", "287a5d2304d516f63e56c469511c42b016423bcb167e61b611f6bad47e3ca60e", [:rebar3], [{:certifi, "2.4.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "b69d97134f1876ba8e4e2f405e9da8cba7cf4f2da0b7cc24a5ccef8dcf1b46b2"}, - "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "4bdd305eb64e18b0273864920695cb18d7a2021f31a11b9c5fbcd9a253f936e2"}, - "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fdf843bca858203ae1de16da2ee206f53416bbda5dc8c9e78f43243de4bc3afe"}, - "keccakf1600": {:hex, :keccakf1600_otp23, "2.0.0", "77f7a1002b9f2972d991cfddb771fb71f600b6f0c125e82f01dff619a9292cb3", [:rebar3], [], "hexpm", "627691e1049eeccec3a12f3fa5d9df33f06dd5a7b81b5f7ebcb152c96d5c87c9"}, - "libsecp256k1": {:hex, :libsecp256k1, "0.1.10", "d27495e2b9851c7765129b76c53b60f5e275bd6ff68292c50536bf6b8d091a4d", [:make, :mix], [{:mix_erlang_tasks, "0.1.0", [hex: :mix_erlang_tasks, repo: "hexpm", optional: false]}], "hexpm", "09ea06239938571124f7f5a27bc9ac45dfb1cfc2df40d46ee9b59c3d51366652"}, - "makeup": {:hex, :makeup, "0.8.0", "9cf32aea71c7fe0a4b2e9246c2c4978f9070257e5c9ce6d4a28ec450a839b55f", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5fbc8e549aa9afeea2847c0769e3970537ed302f93a23ac612602e805d9d1e7f"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.13.0", "be7a477997dcac2e48a9d695ec730b2d22418292675c75aa2d34ba0909dcdeda", [:mix], [{:makeup, "~> 0.8", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "adf0218695e22caeda2820eaba703fa46c91820d53813a2223413da3ef4ba515"}, - "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, - "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "hexpm", "7a4c8e1115a2732a67d7624e28cf6c9f30c66711a9e92928e745c255887ba465"}, - "mix_erlang_tasks": {:hex, :mix_erlang_tasks, "0.1.0", "36819fec60b80689eb1380938675af215565a89320a9e29c72c70d97512e4649", [:mix], [], "hexpm", "95d2839c422c482a70c08a8702da8242f86b773f8ab6e8602a4eb72da8da04ed"}, - "nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm", "5c040b8469c1ff1b10093d3186e2e10dbe483cd73d79ec017993fb3985b8a9b3"}, - "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"}, - "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm", "603561dc0fd62f4f2ea9b890f4e20e1a0d388746d6e20557cafb1b16950de88c"}, - "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm", "1d1848c40487cdb0b30e8ed975e34e025860c02e419cb615d255849f3427439d"}, + "castore": {:hex, :castore, "1.0.5", "9eeebb394cc9a0f3ae56b813459f990abb0a3dedee1be6b27fdb50301930502f", [:mix], [], "hexpm", "8d7c597c3e4a64c395980882d4bca3cebb8d74197c590dc272cfd3b6a6310578"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, + "ex_doc": {:hex, :ex_doc, "0.31.0", "06eb1dfd787445d9cab9a45088405593dd3bb7fe99e097eaa71f37ba80c7a676", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "5350cafa6b7f77bdd107aa2199fe277acf29d739aba5aee7e865fc680c62a110"}, + "ex_keccak": {:hex, :ex_keccak, "0.7.3", "33298f97159f6b0acd28f6e96ce5ea975a0f4a19f85fe615b4f4579b88b24d06", [:mix], [{:rustler, ">= 0.0.0", [hex: :rustler, repo: "hexpm", optional: true]}, {:rustler_precompiled, "~> 0.6.1", [hex: :rustler_precompiled, repo: "hexpm", optional: false]}], "hexpm", "4c5e6d9d5f77b64ab48769a0166a9814180d40ced68ed74ce60a5174ab55b3fc"}, + "ex_secp256k1": {:hex, :ex_secp256k1, "0.7.2", "33398c172813b90fab9ab75c12b98d16cfab472c6dcbde832b13c45ce1c01947", [:mix], [{:rustler, ">= 0.0.0", [hex: :rustler, repo: "hexpm", optional: true]}, {:rustler_precompiled, "~> 0.6", [hex: :rustler_precompiled, repo: "hexpm", optional: false]}], "hexpm", "f3b1bf56e6992e28b9d86e3bf741a4aca3e641052eb47d13ae4f5f4d4944bdaf"}, + "excoveralls": {:hex, :excoveralls, "0.18.0", "b92497e69465dc51bc37a6422226ee690ab437e4c06877e836f1c18daeb35da9", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "1109bb911f3cb583401760be49c02cbbd16aed66ea9509fc5479335d284da60b"}, + "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, + "makeup": {:hex, :makeup, "1.1.1", "fa0bc768698053b2b3869fa8a62616501ff9d11a562f3ce39580d60860c3a55e", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5dc62fbdd0de44de194898b6710692490be74baa02d9d108bc29f007783b0b48"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"}, + "makeup_erlang": {:hex, :makeup_erlang, "0.1.3", "d684f4bac8690e70b06eb52dad65d26de2eefa44cd19d64a8095e1417df7c8fd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "b78dc853d2e670ff6390b605d807263bf606da3c82be37f9d7f68635bd886fc9"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, + "rustler_precompiled": {:hex, :rustler_precompiled, "0.6.3", "f838d94bc35e1844973ee7266127b156fdc962e9e8b7ff666c8fb4fed7964d23", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, "~> 0.23", [hex: :rustler, repo: "hexpm", optional: true]}], "hexpm", "e18ecca3669a7454b3a2be75ae6c3ef01d550bc9a8cf5fbddcfff843b881d7c6"}, }