From 79862ffda5bc41a89dc7bc149144687d8c43f868 Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Mon, 5 Apr 2021 13:14:58 +0530 Subject: [PATCH] feat: mnemonic phrase support for wallet (#256) * feat: mnemonic phrase support for wallet * refactor: better error handling and clippy linting * fix: derive from path and tests * chore: renamed package coins-bip39 * refactor: convenient builder API to setup mnemonic wallet * refactor: re-export coins-bip39 for convenience * clippy: fix warnings for multiple complex types in provider * feat: randomly generated mnemonic phrase can be written to storage --- Cargo.lock | 724 +++++++++++++++-------- ethers-core/src/types/mod.rs | 3 + ethers-core/src/types/path_or_string.rs | 37 ++ ethers-providers/src/lib.rs | 1 + ethers-signers/Cargo.toml | 3 +- ethers-signers/src/lib.rs | 5 +- ethers-signers/src/wallet/mnemonic.rs | 279 +++++++++ ethers-signers/src/wallet/mod.rs | 7 + ethers-signers/src/wallet/private_key.rs | 51 +- ethers-signers/src/wallet/util.rs | 14 + 10 files changed, 846 insertions(+), 278 deletions(-) create mode 100644 ethers-core/src/types/path_or_string.rs create mode 100644 ethers-signers/src/wallet/mnemonic.rs create mode 100644 ethers-signers/src/wallet/util.rs diff --git a/Cargo.lock b/Cargo.lock index 92f155e5..6466ad2b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,7 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - [[package]] name = "Inflector" version = "0.11.4" @@ -23,9 +21,9 @@ dependencies = [ [[package]] name = "adler" -version = "0.2.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aead" @@ -33,7 +31,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" dependencies = [ - "generic-array", + "generic-array 0.14.4", ] [[package]] @@ -54,7 +52,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" dependencies = [ "cipher", - "opaque-debug", + "opaque-debug 0.3.0", ] [[package]] @@ -64,7 +62,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" dependencies = [ "cipher", - "opaque-debug", + "opaque-debug 0.3.0", ] [[package]] @@ -87,9 +85,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cddc5f91628367664cc7c69714ff08deee8a3efc54623011c772544d7b2767" +checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" [[package]] name = "arrayref" @@ -105,9 +103,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "async-trait" -version = "0.1.42" +version = "0.1.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3a45e77e34375a7923b1e8febb049bb011f064714a8e17a1a616fef01da13d" +checksum = "36ea56748e10732c49404c153638a15ec3d6211ec5ff35d9bb20e13b93576adf" dependencies = [ "proc-macro2", "quote", @@ -134,9 +132,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "backtrace" -version = "0.3.55" +version = "0.3.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef5140344c85b01f9bbb4d4b7288a8aa4b3287ccef913a14bcc78a1063623598" +checksum = "9d117600f438b1707d4e4ae15d3595657288f8235a0eb593e80ecc98ab34e1bc" dependencies = [ "addr2line", "cfg-if 1.0.0", @@ -146,6 +144,28 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base58" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" + +[[package]] +name = "base58check" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee2fe4c9a0c84515f136aaae2466744a721af6d63339c18689d9e995d74d99b" +dependencies = [ + "base58", + "sha2 0.8.2", +] + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + [[package]] name = "base64" version = "0.13.0" @@ -154,9 +174,15 @@ checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "base64ct" -version = "0.2.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22fb38fd6e62e4ceec8543db40ceb714454ff173451a0f2a6c8952fdf39a2d6c" +checksum = "d0d27fb6b6f1e43147af148af49d49329413ba781aa0d5e10979831c210173b5" + +[[package]] +name = "bech32" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dabbe35f96fb9507f7330793dc490461b2962659ac5d427181e451a623751d1" [[package]] name = "bincode" @@ -176,12 +202,22 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "bitvec" -version = "0.18.4" +version = "0.17.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2838fdd79e8776dbe07a106c784b0f8dda571a21b2750a092cc4cbaa653c8e" +checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" +dependencies = [ + "either", + "radium 0.3.0", +] + +[[package]] +name = "bitvec" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98fcd36dda4e17b7d7abc64cb549bf0201f4ab71e00700c798ca7e62ed3761fa" dependencies = [ "funty", - "radium 0.4.1", + "radium 0.3.0", "wyz", ] @@ -197,6 +233,17 @@ dependencies = [ "wyz", ] +[[package]] +name = "blake2" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a5720225ef5daecf08657f23791354e1685a8c91a4c60c7f3d3b2892f978f4" +dependencies = [ + "crypto-mac 0.8.0", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + [[package]] name = "blake2b_simd" version = "0.5.11" @@ -208,14 +255,26 @@ dependencies = [ "constant_time_eq", ] +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding 0.1.5", + "byte-tools", + "byteorder", + "generic-array 0.12.4", +] + [[package]] name = "block-buffer" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "block-padding", - "generic-array", + "block-padding 0.2.1", + "generic-array 0.14.4", ] [[package]] @@ -224,10 +283,19 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57a0e8073e8baa88212fb5823574c02ebccb395136ba9a164ab89379ec6072f0" dependencies = [ - "block-padding", + "block-padding 0.2.1", "cipher", ] +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", +] + [[package]] name = "block-padding" version = "0.2.1" @@ -235,10 +303,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" [[package]] -name = "bumpalo" -version = "3.4.0" +name = "bs58" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" +checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb" + +[[package]] +name = "bumpalo" +version = "3.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" [[package]] name = "byte-slice-cast" @@ -246,6 +320,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65c1bf4a04a88c54f589125563643d773f3254b5c38571395e2b591c693bbc81" +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + [[package]] name = "byteorder" version = "1.3.4" @@ -263,9 +343,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.66" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" [[package]] name = "ccm" @@ -275,7 +355,7 @@ checksum = "5aca1a8fbc20b50ac9673ff014abfb2b5f4085ee1a850d408f14a159c5853ac7" dependencies = [ "aead", "cipher", - "subtle", + "subtle 2.4.0", ] [[package]] @@ -310,7 +390,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" dependencies = [ - "generic-array", + "generic-array 0.14.4", ] [[package]] @@ -319,10 +399,63 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73d4de4f7724e5fe70addfb2bd37c2abd2f95084a429d7773b0b9645499b4272" dependencies = [ - "crypto-mac", + "crypto-mac 0.10.0", "dbl", ] +[[package]] +name = "coins-bip32" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7293fc13f56d24998ad405f2402145b27c28940e2bf0f739a1bd08f4c90af861" +dependencies = [ + "bs58", + "coins-core", + "hmac 0.7.1", + "k256", + "lazy_static", + "serde", + "sha2 0.8.2", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0db08d2935d0f5471ca3031101bcd72a8d31f4c238971266b0bf0b234bcf08e6" +dependencies = [ + "bitvec 0.17.4", + "coins-bip32", + "hex", + "hmac 0.10.1", + "pbkdf2", + "rand 0.7.3", + "sha2 0.9.3", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d257d975731955ee86fa7f348000c3fea09c262e84c70c11e994a85aa4f467a7" +dependencies = [ + "base58check", + "base64 0.12.3", + "bech32", + "blake2", + "digest 0.9.0", + "generic-array 0.14.4", + "hex", + "ripemd160", + "serde", + "serde_derive", + "sha2 0.9.3", + "sha3", + "thiserror", +] + [[package]] name = "coins-ledger" version = "0.1.0" @@ -349,9 +482,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.4.1" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d82796b70971fbb603900a5edc797a4d9be0f9ec1257f83a1dba0aa374e3e9" +checksum = "9f6b64db6932c7e49332728e3a6bd82c6b7e16016607d20923b537c3bc4c0d5f" [[package]] name = "constant_time_eq" @@ -387,6 +520,26 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +[[package]] +name = "crypto-mac" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" +dependencies = [ + "generic-array 0.12.4", + "subtle 1.0.0", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array 0.14.4", + "subtle 2.4.0", +] + [[package]] name = "crypto-mac" version = "0.10.0" @@ -394,8 +547,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4857fd85a0c34b3c3297875b747c1e02e06b6a0ea32dd892d8192b9ce0813ea6" dependencies = [ "cipher", - "generic-array", - "subtle", + "generic-array 0.14.4", + "subtle 2.4.0", ] [[package]] @@ -409,24 +562,24 @@ dependencies = [ [[package]] name = "curl" -version = "0.4.34" +version = "0.4.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e268162af1a5fe89917ae25ba3b0a77c8da752bdc58e7dbb4f15b91fbd33756e" +checksum = "5a872858e9cb9e3b96c80dd78774ad9e32e44d3b05dc31e142b858d14aebc82c" dependencies = [ "curl-sys", "libc", "openssl-probe", "openssl-sys", "schannel", - "socket2", + "socket2 0.3.19", "winapi", ] [[package]] name = "curl-sys" -version = "0.4.39+curl-7.74.0" +version = "0.4.41+curl-7.75.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07a8ce861e7b68a0b394e814d7ee9f1b2750ff8bd10372c6ad3bacc10e86f874" +checksum = "0ec466abd277c7cab2905948f3e94d10bc4963f1f5d47921c1cc4ffd2028fe65" dependencies = [ "cc", "libc", @@ -444,19 +597,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f627126b946c25a4638eec0ea634fc52506dea98db118aae985118ce7c3d723f" dependencies = [ "byteorder", - "digest", + "digest 0.9.0", "rand_core 0.5.1", - "subtle", + "subtle 2.4.0", "zeroize", ] [[package]] name = "dbl" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2735145c3b9ba15f2d7a3ae8cdafcbc8c98a7bef7f62afe9d08bd99fbf7130de" +checksum = "37e797687b5f09528a48fcb63b6914d0255b8a6c760699a919af37042f09d9b3" dependencies = [ - "generic-array", + "generic-array 0.14.4", ] [[package]] @@ -468,13 +621,22 @@ dependencies = [ "const-oid", ] +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + [[package]] name = "digest" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array", + "generic-array 0.14.4", ] [[package]] @@ -483,8 +645,8 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fbdb4ff710acb4db8ca29f93b897529ea6d6a45626d5183b47e012aa6ae7e4" dependencies = [ - "elliptic-curve 0.8.4", - "hmac", + "elliptic-curve 0.8.5", + "hmac 0.10.1", "signature", ] @@ -507,44 +669,51 @@ dependencies = [ "ed25519", "rand 0.7.3", "serde", - "sha2", + "sha2 0.9.3", "zeroize", ] [[package]] -name = "elliptic-curve" -version = "0.8.4" +name = "either" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "592b1c857559479c056b73a3053c717108a70e4dce320ad28c79c63f5c2e62ba" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "elliptic-curve" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2db227e61a43a34915680bdda462ec0e212095518020a88a1f91acd16092c39" dependencies = [ - "bitvec 0.18.4", - "digest", + "bitvec 0.18.5", + "digest 0.9.0", "ff", - "generic-array", + "funty", + "generic-array 0.14.4", "group", "pkcs8", "rand_core 0.5.1", - "subtle", + "subtle 2.4.0", "zeroize", ] [[package]] name = "elliptic-curve" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96675863dd09400876af3f9348ecfa1090ee8c2f0b1febf369fef01fe271658" +checksum = "78fff5a5d53c2e45c2772aa2666904eaf5af581b9fc356b9da42b52bda088e6d" dependencies = [ "funty", - "generic-array", - "rand_core 0.6.1", - "subtle", + "generic-array 0.14.4", + "rand_core 0.6.2", + "subtle 2.4.0", ] [[package]] name = "encoding_rs" -version = "0.8.26" +version = "0.8.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801bbab217d7f79c0062f4f7205b5d4427c6d1a7bd7aafdd1475f7c59d62b283" +checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065" dependencies = [ "cfg-if 1.0.0", ] @@ -557,15 +726,15 @@ checksum = "1f1d4168fd77e9d9564bbdcb937efdad0df721dd159d2cb3f39d51efdbdf06f2" dependencies = [ "aes", "ctr", - "digest", + "digest 0.9.0", "hex", - "hmac", + "hmac 0.10.1", "pbkdf2", "rand 0.7.3", "scrypt", "serde", "serde_json", - "sha2", + "sha2 0.9.3", "sha3", "thiserror", "uuid", @@ -688,12 +857,12 @@ dependencies = [ "bincode", "bytes", "ecdsa", - "elliptic-curve 0.9.5", + "elliptic-curve 0.9.6", "ethabi", "ethers", "funty", "futures-util", - "generic-array", + "generic-array 0.14.4", "glob", "hex", "k256", @@ -762,8 +931,10 @@ name = "ethers-signers" version = "0.2.2" dependencies = [ "async-trait", + "coins-bip32", + "coins-bip39", "coins-ledger", - "elliptic-curve 0.9.5", + "elliptic-curve 0.9.6", "eth-keystore", "ethers", "ethers-core", @@ -772,22 +943,28 @@ dependencies = [ "hex", "rand 0.7.3", "serde_json", - "sha2", + "sha2 0.9.3", "tempfile", "thiserror", "tokio", "yubihsm", ] +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + [[package]] name = "ff" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01646e077d4ebda82b73f1bca002ea1e91561a77df2431a9e79729bcc31950ef" dependencies = [ - "bitvec 0.18.4", + "bitvec 0.18.5", "rand_core 0.5.1", - "subtle", + "subtle 2.4.0", ] [[package]] @@ -797,7 +974,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" dependencies = [ "byteorder", - "rand 0.8.1", + "rand 0.8.3", "rustc-hex", "static_assertions", ] @@ -825,9 +1002,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece68d15c92e84fa4f19d3780f1294e5ca82a78a6d515f1efaabcc144688be00" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" dependencies = [ "matches", "percent-encoding", @@ -841,9 +1018,9 @@ checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" [[package]] name = "futures" -version = "0.3.9" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c70be434c505aee38639abccb918163b63158a4b4bb791b45b7023044bdc3c9c" +checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1" dependencies = [ "futures-channel", "futures-core", @@ -938,6 +1115,15 @@ dependencies = [ "slab", ] +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + [[package]] name = "generic-array" version = "0.14.4" @@ -961,13 +1147,13 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4060f4657be78b8e766215b02b18a2e862d83745545de804638e2b545e81aee6" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi 0.10.1+wasi-snapshot-preview1", + "wasi 0.10.2+wasi-snapshot-preview1", ] [[package]] @@ -990,14 +1176,14 @@ checksum = "cc11f9f5fbf1943b48ae7c2bf6846e7d827a512d1be4f23af708f5ca5d01dde1" dependencies = [ "ff", "rand_core 0.5.1", - "subtle", + "subtle 2.4.0", ] [[package]] name = "h2" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b67e66362108efccd8ac053abafc8b7a8d86a37e6e48fc4f6f7485eb5e9e6a5" +checksum = "fc018e188373e2777d0ef2467ebff62a08e66c3f5857b23c8fbec3018210dc00" dependencies = [ "bytes", "fnv", @@ -1010,7 +1196,6 @@ dependencies = [ "tokio", "tokio-util", "tracing", - "tracing-futures", ] [[package]] @@ -1027,9 +1212,9 @@ checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" [[package]] name = "hermit-abi" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" dependencies = [ "libc", ] @@ -1051,14 +1236,24 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "hmac" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" +dependencies = [ + "crypto-mac 0.7.0", + "digest 0.8.1", +] + [[package]] name = "hmac" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" dependencies = [ - "crypto-mac", - "digest", + "crypto-mac 0.10.0", + "digest 0.9.0", ] [[package]] @@ -1074,19 +1269,20 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2861bd27ee074e5ee891e8b539837a9430012e249d7f0ca2d795650f579c1994" +checksum = "5dfb77c123b4e2f72a2069aeae0b4b4949cc7e966df277813fc16347e7549737" dependencies = [ "bytes", "http", + "pin-project-lite", ] [[package]] name = "httparse" -version = "1.3.4" +version = "1.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" +checksum = "615caabe2c3160b313d52ccc905335f4ed5f10881dd63dc5699d47e90be85691" [[package]] name = "httpdate" @@ -1096,9 +1292,9 @@ checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" [[package]] name = "hyper" -version = "0.14.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12219dc884514cb4a6a03737f4413c0e01c23a1b059b0156004b23f1e19dccbe" +checksum = "8bf09f61b52cfcf4c00de50df88ae423d6c02354e385a86341133b5338630ad1" dependencies = [ "bytes", "futures-channel", @@ -1111,7 +1307,7 @@ dependencies = [ "httpdate", "itoa", "pin-project", - "socket2", + "socket2 0.4.0", "tokio", "tower-service", "tracing", @@ -1135,9 +1331,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" +checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21" dependencies = [ "matches", "unicode-bidi", @@ -1173,9 +1369,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" +checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" dependencies = [ "autocfg", "hashbrown", @@ -1204,9 +1400,9 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "js-sys" -version = "0.3.46" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d7383929f7c9c7c2d0fa596f325832df98c3704f2c60553080f7127a58175" +checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c" dependencies = [ "wasm-bindgen", ] @@ -1219,8 +1415,8 @@ checksum = "cf02ecc966e1b7e8db1c81ac8f321ba24d1cfab5b634961fab10111f015858e1" dependencies = [ "cfg-if 1.0.0", "ecdsa", - "elliptic-curve 0.8.4", - "sha2", + "elliptic-curve 0.8.5", + "sha2 0.9.3", "sha3", ] @@ -1238,9 +1434,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.82" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" +checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" [[package]] name = "libusb1-sys" @@ -1268,11 +1464,11 @@ dependencies = [ [[package]] name = "log" -version = "0.4.11" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", ] [[package]] @@ -1295,9 +1491,9 @@ checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] name = "miniz_oxide" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" dependencies = [ "adler", "autocfg", @@ -1305,9 +1501,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.7.7" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e50ae3f04d169fcc9bde0b547d1c205219b7157e07ded9c5aff03e0637cb3ed7" +checksum = "cf80d3e903b34e0bd7282b218398aec54e082c840d9baf8339e0080a0c542956" dependencies = [ "libc", "log", @@ -1318,11 +1514,10 @@ dependencies = [ [[package]] name = "miow" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" dependencies = [ - "socket2", "winapi", ] @@ -1397,9 +1592,9 @@ dependencies = [ [[package]] name = "object" -version = "0.22.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397" +checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" [[package]] name = "once_cell" @@ -1407,6 +1602,12 @@ version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + [[package]] name = "opaque-debug" version = "0.3.0" @@ -1415,15 +1616,15 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.32" +version = "0.10.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70" +checksum = "a61075b62a23fef5a29815de7536d940aa35ce96d18ce0cc5076272db678a577" dependencies = [ "bitflags", "cfg-if 1.0.0", "foreign-types", - "lazy_static", "libc", + "once_cell", "openssl-sys", ] @@ -1435,9 +1636,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openssl-sys" -version = "0.9.60" +version = "0.9.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6" +checksum = "313752393519e876837e09e1fa183ddef0be7735868dced3196f4472d536277f" dependencies = [ "autocfg", "cc", @@ -1448,13 +1649,13 @@ dependencies = [ [[package]] name = "p256" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39f37a291d378ba3291c1fa4e925edb6729c8593d4c6064be79e4a4c12fa2d97" +checksum = "7ca0196a204bb3f33305ba4a48b38f6e6e621cba8603a4e0650e6532e0949de4" dependencies = [ "ecdsa", - "elliptic-curve 0.8.4", - "sha2", + "elliptic-curve 0.8.5", + "sha2 0.9.3", ] [[package]] @@ -1464,7 +1665,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea33960aac2200d19a5c9ab06a11ebd48a37a23144496632c358182e6765d80b" dependencies = [ "ecdsa", - "elliptic-curve 0.8.4", + "elliptic-curve 0.8.5", ] [[package]] @@ -1481,25 +1682,25 @@ dependencies = [ [[package]] name = "password-hash" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721a49e14f1803441886c688ba8b653b52e1dcc926969081d22384e300ea4106" +checksum = "85d8faea6c018131952a192ee55bd9394c51fc6f63294b668d97636e6f842d40" dependencies = [ "base64ct", - "rand_core 0.6.1", + "rand_core 0.6.2", ] [[package]] name = "pbkdf2" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "309c95c5f738c85920eb7062a2de29f3840d4f96974453fc9ac1ba078da9c627" +checksum = "bf916dd32dd26297907890d99dc2740e33f6bd9073965af4ccff2967962f5508" dependencies = [ "base64ct", - "crypto-mac", - "hmac", + "crypto-mac 0.10.0", + "hmac 0.10.1", "password-hash", - "sha2", + "sha2 0.9.3", ] [[package]] @@ -1510,18 +1711,18 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pin-project" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96fa8ebb90271c4477f144354485b8068bd8f6b78b428b01ba892ca26caf0b63" +checksum = "bc174859768806e91ae575187ada95c91a29e96a98dc5d2cd9a1fed039501ba6" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758669ae3558c6f74bd2a18b41f7ac0b5a195aea6639d6a9b5e5d1ad5ba24c0b" +checksum = "a490329918e856ed1b083f244e3bfe2d8c4f336407e4ea9e1a9f479ff09049e5" dependencies = [ "proc-macro2", "quote", @@ -1530,9 +1731,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827" +checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" [[package]] name = "pin-utils" @@ -1606,33 +1807,33 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro-nested" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] [[package]] name = "radium" -version = "0.4.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64de9a0c5361e034f1aefc9f71a86871ec870e766fe31a009734a989b329286a" +checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" [[package]] name = "radium" @@ -1655,13 +1856,13 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c24fcd450d3fa2b592732565aa4f17a27a61c65ece4726353e000939b0edee34" +checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" dependencies = [ "libc", "rand_chacha 0.3.0", - "rand_core 0.6.1", + "rand_core 0.6.2", "rand_hc 0.3.0", ] @@ -1682,7 +1883,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ "ppv-lite86", - "rand_core 0.6.1", + "rand_core 0.6.2", ] [[package]] @@ -1696,11 +1897,11 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ - "getrandom 0.2.1", + "getrandom 0.2.2", ] [[package]] @@ -1718,35 +1919,34 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" dependencies = [ - "rand_core 0.6.1", + "rand_core 0.6.2", ] [[package]] name = "redox_syscall" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570" +checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.4.3" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" +checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" dependencies = [ "aho-corasick", "memchr", "regex-syntax", - "thread_local", ] [[package]] name = "regex-syntax" -version = "0.6.22" +version = "0.6.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" +checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" [[package]] name = "remove_dir_all" @@ -1763,7 +1963,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf12057f289428dbf5c591c74bf10392e4a8003f993405a902f20117019022d4" dependencies = [ - "base64", + "base64 0.13.0", "bytes", "encoding_rs", "futures-core", @@ -1795,9 +1995,9 @@ dependencies = [ [[package]] name = "ring" -version = "0.16.19" +version = "0.16.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "024a1e66fea74c66c66624ee5622a7ff0e4b73a13b4f5c326ddb50c708944226" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" dependencies = [ "cc", "libc", @@ -1808,6 +2008,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "ripemd160" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eca4ecc81b7f313189bf73ce724400a07da2a6dac19588b03c8bd76a2dcc251" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + [[package]] name = "rlp" version = "0.5.0" @@ -1846,7 +2057,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "064fd21ff87c6e87ed4506e68beb42459caa4a0e2eb144932e6776768556980b" dependencies = [ - "base64", + "base64 0.13.0", "log", "ring", "sct", @@ -1880,16 +2091,16 @@ dependencies = [ [[package]] name = "scrypt" -version = "0.6.2" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc92172b99814ff0b66ad8aca73619156a00a5bed5b441bf543123f2556987e0" +checksum = "19230d10daad7f163d8c1fc8edf84fbe52ac71c2ebe5adf3f763aa1557b843e3" dependencies = [ "base64ct", - "hmac", + "hmac 0.10.1", "password-hash", "pbkdf2", "salsa20", - "sha2", + "sha2 0.9.3", ] [[package]] @@ -1904,9 +2115,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.0.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1759c2e3c8580017a484a7ac56d3abc5a6c1feadf88db2f3633f12ae4268c69" +checksum = "3670b1d2fdf6084d192bc71ead7aabe6c06aa2ea3fbd9cc3ac111fa5c2b1bd84" dependencies = [ "bitflags", "core-foundation", @@ -1917,9 +2128,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.0.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f99b9d5e26d2a71633cc4f2ebae7cc9f874044e0c351a27e17892d76dce5678b" +checksum = "3676258fd3cfe2c9a0ec99ce3038798d847ce3e4bb17746373eb9f0f1ac16339" dependencies = [ "core-foundation-sys", "libc", @@ -1927,9 +2138,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.124" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f" +checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" dependencies = [ "serde_derive", ] @@ -1946,9 +2157,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.124" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" dependencies = [ "proc-macro2", "quote", @@ -1980,15 +2191,27 @@ dependencies = [ [[package]] name = "sha-1" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce3cdf1b5e620a498ee6f2a171885ac7e22f0e12089ec4b3d22b84921792507c" +checksum = "dfebf75d25bd900fd1e7d11501efab59bc846dbc76196839663e6637bba9f25f" dependencies = [ - "block-buffer", + "block-buffer 0.9.0", "cfg-if 1.0.0", "cpuid-bool", - "digest", - "opaque-debug", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "sha2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug 0.2.3", ] [[package]] @@ -1997,11 +2220,11 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de" dependencies = [ - "block-buffer", + "block-buffer 0.9.0", "cfg-if 1.0.0", "cpuid-bool", - "digest", - "opaque-debug", + "digest 0.9.0", + "opaque-debug 0.3.0", ] [[package]] @@ -2010,10 +2233,10 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" dependencies = [ - "block-buffer", - "digest", + "block-buffer 0.9.0", + "digest 0.9.0", "keccak", - "opaque-debug", + "opaque-debug 0.3.0", ] [[package]] @@ -2022,7 +2245,7 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29f060a7d147e33490ec10da418795238fd7545bba241504d6b31a409f2e6210" dependencies = [ - "digest", + "digest 0.9.0", "rand_core 0.5.1", "signature_derive", ] @@ -2056,6 +2279,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "spin" version = "0.5.2" @@ -2068,6 +2301,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "subtle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" + [[package]] name = "subtle" version = "2.4.0" @@ -2076,9 +2315,9 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" [[package]] name = "syn" -version = "1.0.60" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" dependencies = [ "proc-macro2", "quote", @@ -2111,7 +2350,7 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if 1.0.0", "libc", - "rand 0.8.1", + "rand 0.8.3", "redox_syscall", "remove_dir_all", "winapi", @@ -2137,15 +2376,6 @@ dependencies = [ "syn", ] -[[package]] -name = "thread_local" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb9bc092d0d51e76b2b19d9d85534ffc9ec2db959a2523cdae0697e2972cd447" -dependencies = [ - "lazy_static", -] - [[package]] name = "time" version = "0.1.43" @@ -2167,9 +2397,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf8dbc19eb42fba10e8feaaec282fb50e2c14b2726d6301dbfeed0f73306a6f" +checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023" dependencies = [ "tinyvec_macros", ] @@ -2228,17 +2458,6 @@ dependencies = [ "webpki", ] -[[package]] -name = "tokio-stream" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4cdeb73537e63f98adcd73138af75e3f368ccaecffaa29d7eb61b9f5a440457" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-tungstenite" version = "0.13.0" @@ -2256,9 +2475,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.6.0" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36135b7e7da911f5f8b9331209f7fab4cc13498f3fff52f72a710c78187e3148" +checksum = "5143d049e85af7fbc36f5454d990e62c2df705b3589f123b71f441b6b59f443f" dependencies = [ "bytes", "futures-core", @@ -2266,14 +2485,13 @@ dependencies = [ "log", "pin-project-lite", "tokio", - "tokio-stream", ] [[package]] name = "tower-service" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" @@ -2317,7 +2535,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ada8297e8d70872fa9a551d93250a9f407beb9f37ef86494eb20012a2ff7c24" dependencies = [ - "base64", + "base64 0.13.0", "byteorder", "bytes", "http", @@ -2325,7 +2543,7 @@ dependencies = [ "input_buffer", "log", "native-tls", - "rand 0.8.1", + "rand 0.8.3", "sha-1", "url", "utf-8", @@ -2333,9 +2551,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" +checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" [[package]] name = "uint" @@ -2360,9 +2578,9 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606" +checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" dependencies = [ "tinyvec", ] @@ -2399,11 +2617,11 @@ checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" [[package]] name = "uuid" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "rand 0.7.3", + "getrandom 0.2.2", "serde", ] @@ -2415,9 +2633,9 @@ checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" [[package]] name = "version_check" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] name = "void" @@ -2443,15 +2661,15 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" -version = "0.10.1+wasi-snapshot-preview1" +version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c6c3420963c5c64bca373b25e77acb562081b9bb4dd5bb864187742186cea9" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.69" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e" +checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9" dependencies = [ "cfg-if 1.0.0", "serde", @@ -2461,9 +2679,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.69" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62" +checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae" dependencies = [ "bumpalo", "lazy_static", @@ -2476,9 +2694,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.19" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe9756085a84584ee9457a002b7cdfe0bfff169f45d2591d8be1345a6780e35" +checksum = "81b8b767af23de6ac18bf2168b690bed2902743ddf0fb39252e36f9e2bfc63ea" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -2488,9 +2706,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.69" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084" +checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2498,9 +2716,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.69" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549" +checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c" dependencies = [ "proc-macro2", "quote", @@ -2511,15 +2729,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.69" +version = "0.2.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158" +checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489" [[package]] name = "web-sys" -version = "0.3.46" +version = "0.3.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222b1ef9334f92a21d3fb53dc3fd80f30836959a90f9274a626d7e06315ba3c3" +checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be" dependencies = [ "js-sys", "wasm-bindgen", @@ -2537,9 +2755,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.21.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82015b7e0b8bad8185994674a13a93306bea76cf5a16c5a181382fd3a5ec2376" +checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" dependencies = [ "webpki", ] @@ -2594,12 +2812,12 @@ dependencies = [ "ccm", "chrono", "cmac", - "digest", + "digest 0.9.0", "ecdsa", "ed25519", "ed25519-dalek", "harp", - "hmac", + "hmac 0.10.1", "k256", "log", "p256", @@ -2609,9 +2827,9 @@ dependencies = [ "rusb", "serde", "serde_json", - "sha2", + "sha2 0.9.3", "signature", - "subtle", + "subtle 2.4.0", "thiserror", "uuid", "zeroize", diff --git a/ethers-core/src/types/mod.rs b/ethers-core/src/types/mod.rs index 05cba56a..116dfb00 100644 --- a/ethers-core/src/types/mod.rs +++ b/ethers-core/src/types/mod.rs @@ -13,6 +13,9 @@ pub use transaction::{Transaction, TransactionReceipt, TransactionRequest}; mod address_or_bytes; pub use address_or_bytes::AddressOrBytes; +mod path_or_string; +pub use path_or_string::PathOrString; + mod i256; pub use i256::I256; diff --git a/ethers-core/src/types/path_or_string.rs b/ethers-core/src/types/path_or_string.rs new file mode 100644 index 00000000..73997d9a --- /dev/null +++ b/ethers-core/src/types/path_or_string.rs @@ -0,0 +1,37 @@ +use std::path::{Path, PathBuf}; + +/// A type that can either be a `Path` or a `String` +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum PathOrString { + /// A path type + Path(PathBuf), + /// A string type + String(String), +} + +impl From for PathOrString { + fn from(p: PathBuf) -> Self { + PathOrString::Path(p) + } +} + +impl From<&str> for PathOrString { + fn from(s: &str) -> Self { + let path = Path::new(s); + if path.exists() { + PathOrString::Path(path.to_owned()) + } else { + PathOrString::String(s.to_owned()) + } + } +} + +impl PathOrString { + /// Reads the contents at path, or simply returns the string. + pub fn read(&self) -> Result { + match self { + PathOrString::Path(pathbuf) => std::fs::read_to_string(pathbuf), + PathOrString::String(s) => Ok(s.to_string()), + } + } +} diff --git a/ethers-providers/src/lib.rs b/ethers-providers/src/lib.rs index 8a95adf4..126430eb 100644 --- a/ethers-providers/src/lib.rs +++ b/ethers-providers/src/lib.rs @@ -1,5 +1,6 @@ #![cfg_attr(docsrs, feature(doc_cfg))] #![deny(broken_intra_doc_links)] +#![allow(clippy::type_complexity)] //! # Clients for interacting with Ethereum nodes //! //! This crate provides asynchronous [Ethereum JSON-RPC](https://github.com/ethereum/wiki/wiki/JSON-RPC) diff --git a/ethers-signers/Cargo.toml b/ethers-signers/Cargo.toml index f9283ec0..d3b9efd9 100644 --- a/ethers-signers/Cargo.toml +++ b/ethers-signers/Cargo.toml @@ -16,7 +16,8 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] ethers-core = { version = "0.2.2", path = "../ethers-core" } thiserror = { version = "1.0.24", default-features = false } - +coins-bip32 = "0.2.2" +coins-bip39 = "0.2.2" coins-ledger = { version = "0.1.0", default-features = false, optional = true } eth-keystore = { version = "0.2.0" } hex = { version = "0.4.3", default-features = false, features = ["std"] } diff --git a/ethers-signers/src/lib.rs b/ethers-signers/src/lib.rs index 4eb6431e..dd62fa41 100644 --- a/ethers-signers/src/lib.rs +++ b/ethers-signers/src/lib.rs @@ -39,7 +39,10 @@ //! [`Transaction`]: ethers_core::types::Transaction //! [`TransactionRequest`]: ethers_core::types::TransactionRequest mod wallet; -pub use wallet::Wallet; +pub use wallet::{MnemonicBuilder, Wallet, WalletError}; + +/// Re-export the BIP-32 crate so that wordlists can be accessed conveniently. +pub use coins_bip39; /// A wallet instantiated with a locally stored private key pub type LocalWallet = Wallet; diff --git a/ethers-signers/src/wallet/mnemonic.rs b/ethers-signers/src/wallet/mnemonic.rs new file mode 100644 index 00000000..b50a4b16 --- /dev/null +++ b/ethers-signers/src/wallet/mnemonic.rs @@ -0,0 +1,279 @@ +//! Specific helper functions for creating/loading a mnemonic private key following BIP-39 +//! specifications +use crate::{wallet::util::key_to_address, Wallet, WalletError}; + +use coins_bip32::path::DerivationPath; +use coins_bip39::{Mnemonic, Wordlist}; +use ethers_core::{k256::ecdsa::SigningKey, types::PathOrString, utils::to_checksum}; +use rand::Rng; +use std::{fs::File, io::Write, marker::PhantomData, path::PathBuf, str::FromStr}; +use thiserror::Error; + +const DEFAULT_DERIVATION_PATH_PREFIX: &str = "m/44'/60'/0'/0/"; + +/// Represents a structure that can resolve into a `Wallet`. +#[derive(Clone, Debug, PartialEq)] +pub struct MnemonicBuilder { + /// The mnemonic phrase can be supplied to the builder as a string or a path to the file whose + /// contents are the phrase. A builder that has a valid phrase should `build` the wallet. + phrase: Option, + /// The mnemonic builder can also be asked to generate a new random wallet by providing the + /// number of words in the phrase. By default this is set to 12. + word_count: usize, + /// The derivation path at which the extended private key child will be derived at. By default + /// the mnemonic builder uses the path: "m/44'/60'/0'/0/0". + derivation_path: DerivationPath, + /// Optional password for the mnemonic phrase. + password: Option, + /// Optional field that if enabled, writes the mnemonic phrase to disk storage at the provided + /// path. + write_to: Option, + /// PhantomData + _wordlist: PhantomData, +} + +/// Error produced by the mnemonic wallet module +#[derive(Error, Debug)] +pub enum MnemonicBuilderError { + /// Error suggests that a phrase (path or words) was expected but not found + #[error("Expected phrase not found")] + ExpectedPhraseNotFound, + /// Error suggests that a phrase (path or words) was not expected but found + #[error("Unexpected phrase found")] + UnexpectedPhraseFound, +} + +impl Default for MnemonicBuilder { + fn default() -> Self { + Self { + phrase: None, + word_count: 12usize, + derivation_path: DerivationPath::from_str(&format!( + "{}{}", + DEFAULT_DERIVATION_PATH_PREFIX, 0 + )) + .expect("should parse the default derivation path"), + password: None, + write_to: None, + _wordlist: PhantomData, + } + } +} + +impl MnemonicBuilder { + /// Sets the phrase in the mnemonic builder. The phrase can either be a string or a path to + /// the file that contains the phrase. Once a phrase is provided, the key will be generated + /// deterministically by calling the `build` method. + /// + /// # Example + /// + /// ``` + /// use ethers_signers::{MnemonicBuilder, coins_bip39::English}; + /// # async fn foo() -> Result<(), Box> { + /// + /// let wallet = MnemonicBuilder::::default() + /// .phrase("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about") + /// .build()?; + /// + /// # Ok(()) + /// # } + /// ``` + pub fn phrase>(mut self, phrase: P) -> Self { + self.phrase = Some(phrase.into()); + self + } + + /// Sets the word count of a mnemonic phrase to be generated at random. If the `phrase` field + /// is set, then `word_count` will be ignored. + /// + /// # Example + /// + /// ``` + /// use ethers_signers::{MnemonicBuilder, coins_bip39::English}; + /// # async fn foo() -> Result<(), Box> { + /// + /// let mut rng = rand::thread_rng(); + /// let wallet = MnemonicBuilder::::default() + /// .word_count(24) + /// .build_random(&mut rng)?; + /// + /// # Ok(()) + /// # } + /// ``` + pub fn word_count(mut self, count: usize) -> Self { + self.word_count = count; + self + } + + /// Sets the derivation path of the child key to be derived. The derivation path is calculated + /// using the default derivation path prefix used in Ethereum, i.e. "m/44'/60'/0'/0/{index}". + pub fn index>(mut self, index: U) -> Result { + self.derivation_path = DerivationPath::from_str(&format!( + "{}{}", + DEFAULT_DERIVATION_PATH_PREFIX, + index.into() + ))?; + Ok(self) + } + + /// Sets the derivation path of the child key to be derived. + pub fn derivation_path(mut self, path: &str) -> Result { + self.derivation_path = DerivationPath::from_str(path)?; + Ok(self) + } + + /// Sets the password used to construct the seed from the mnemonic phrase. + pub fn password(mut self, password: &str) -> Self { + self.password = Some(password.to_string()); + self + } + + /// Sets the path to which the randomly generated phrase will be written to. This field is + /// ignored when building a wallet from the provided mnemonic phrase. + pub fn write_to>(mut self, path: P) -> Self { + self.write_to = Some(path.into()); + self + } + + /// Builds a `LocalWallet` using the parameters set in mnemonic builder. This method expects + /// the phrase field to be set. + pub fn build(&self) -> Result, WalletError> { + let mnemonic = match &self.phrase { + Some(path_or_string) => { + let phrase = path_or_string.read()?; + Mnemonic::::new_from_phrase(&phrase)? + } + None => return Err(MnemonicBuilderError::ExpectedPhraseNotFound.into()), + }; + self.mnemonic_to_wallet(&mnemonic) + } + + /// Builds a `LocalWallet` using the parameters set in the mnemonic builder and constructing + /// the phrase using the provided random number generator. + pub fn build_random(&self, rng: &mut R) -> Result, WalletError> { + let mnemonic = match &self.phrase { + None => Mnemonic::::new_with_count(rng, self.word_count)?, + _ => return Err(MnemonicBuilderError::UnexpectedPhraseFound.into()), + }; + let wallet = self.mnemonic_to_wallet(&mnemonic)?; + + // Write the mnemonic phrase to storage if a directory has been provided. + if let Some(dir) = &self.write_to { + let mut file = File::create(dir.as_path().join(to_checksum(&wallet.address, None)))?; + file.write_all(mnemonic.to_phrase()?.as_bytes())?; + } + + Ok(wallet) + } + + fn mnemonic_to_wallet( + &self, + mnemonic: &Mnemonic, + ) -> Result, WalletError> { + let derived_priv_key = + mnemonic.derive_key(&self.derivation_path, self.password.as_deref())?; + let key: &SigningKey = derived_priv_key.as_ref(); + let signer = SigningKey::from_bytes(&key.to_bytes())?; + let address = key_to_address(&signer); + + Ok(Wallet:: { + signer, + address, + chain_id: None, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use crate::coins_bip39::English; + use tempfile::tempdir; + + const TEST_DERIVATION_PATH: &str = "m/44'/60'/0'/2/1"; + + #[tokio::test] + async fn mnemonic_deterministic() { + // Testcases have been taken from MyCryptoWallet + const TESTCASES: [(&str, u32, Option<&str>, &str); 4] = [ + ( + "work man father plunge mystery proud hollow address reunion sauce theory bonus", + 0u32, + Some("TREZOR123"), + "0x431a00DA1D54c281AeF638A73121B3D153e0b0F6", + ), + ( + "inject danger program federal spice bitter term garbage coyote breeze thought funny", + 1u32, + Some("LEDGER321"), + "0x231a3D0a05d13FAf93078C779FeeD3752ea1350C", + ), + ( + "fire evolve buddy tenant talent favorite ankle stem regret myth dream fresh", + 2u32, + None, + "0x1D86AD5eBb2380dAdEAF52f61f4F428C485460E9", + ), + ( + "thumb soda tape crunch maple fresh imitate cancel order blind denial giraffe", + 3u32, + None, + "0xFB78b25f69A8e941036fEE2A5EeAf349D81D4ccc", + ), + ]; + TESTCASES + .iter() + .for_each(|(phrase, index, password, expected_addr)| { + let wallet = match password { + Some(psswd) => MnemonicBuilder::::default() + .phrase(*phrase) + .index(*index) + .unwrap() + .password(psswd) + .build() + .unwrap(), + None => MnemonicBuilder::::default() + .phrase(*phrase) + .index(*index) + .unwrap() + .build() + .unwrap(), + }; + assert_eq!(&to_checksum(&wallet.address, None), expected_addr); + }) + } + + #[tokio::test] + async fn mnemonic_write_read() { + let dir = tempdir().unwrap(); + + // Construct a wallet from random mnemonic phrase and write it to the temp dir. + let mut rng = rand::thread_rng(); + let wallet1 = MnemonicBuilder::::default() + .word_count(24) + .derivation_path(TEST_DERIVATION_PATH) + .unwrap() + .write_to(dir.as_ref()) + .build_random(&mut rng) + .unwrap(); + + // Ensure that only one file has been created. + let paths = std::fs::read_dir(dir.as_ref()).unwrap(); + assert_eq!(paths.count(), 1); + + // Use the newly created file's path to instantiate wallet. + let phrase_path = dir.as_ref().join(to_checksum(&wallet1.address, None)); + let wallet2 = MnemonicBuilder::::default() + .phrase(phrase_path.to_str().unwrap()) + .derivation_path(TEST_DERIVATION_PATH) + .unwrap() + .build() + .unwrap(); + + // Ensure that both wallets belong to the same address. + assert_eq!(wallet1.address, wallet2.address); + + dir.close().unwrap(); + } +} diff --git a/ethers-signers/src/wallet/mod.rs b/ethers-signers/src/wallet/mod.rs index 2441aa37..f34f5d01 100644 --- a/ethers-signers/src/wallet/mod.rs +++ b/ethers-signers/src/wallet/mod.rs @@ -1,5 +1,12 @@ mod hash; + +mod mnemonic; +pub use mnemonic::{MnemonicBuilder, MnemonicBuilderError}; + mod private_key; +pub use private_key::WalletError; + +mod util; #[cfg(feature = "yubihsm")] mod yubi; diff --git a/ethers-signers/src/wallet/private_key.rs b/ethers-signers/src/wallet/private_key.rs index ae890852..b676c8f7 100644 --- a/ethers-signers/src/wallet/private_key.rs +++ b/ethers-signers/src/wallet/private_key.rs @@ -1,14 +1,13 @@ //! Specific helper functions for loading an offline K256 Private Key stored on disk use super::Wallet; +use crate::wallet::{mnemonic::MnemonicBuilderError, util::key_to_address}; +use coins_bip32::Bip32Error; +use coins_bip39::MnemonicError; use eth_keystore::KeystoreError; use ethers_core::{ - k256::{ - ecdsa::SigningKey, elliptic_curve::error::Error as K256Error, EncodedPoint as K256PublicKey, - }, + k256::ecdsa::{self, SigningKey}, rand::{CryptoRng, Rng}, - types::Address, - utils::keccak256, }; use std::{path::Path, str::FromStr}; use thiserror::Error; @@ -16,9 +15,27 @@ use thiserror::Error; #[derive(Error, Debug)] /// Error thrown by the Wallet module pub enum WalletError { + /// Error propagated from the BIP-32 crate + #[error(transparent)] + Bip32Error(#[from] Bip32Error), + /// Error propagated from the BIP-39 crate + #[error(transparent)] + Bip39Error(#[from] MnemonicError), /// Underlying eth keystore error #[error(transparent)] EthKeystoreError(#[from] KeystoreError), + /// Error propagated from k256's ECDSA module + #[error(transparent)] + EcdsaError(#[from] ecdsa::Error), + /// Error propagated from the hex crate. + #[error(transparent)] + HexError(#[from] hex::FromHexError), + /// Error propagated by IO operations + #[error(transparent)] + IoError(#[from] std::io::Error), + /// Error propagated from the mnemonic builder module. + #[error(transparent)] + MnemonicBuilderError(#[from] MnemonicBuilderError), } impl Clone for Wallet { @@ -33,8 +50,6 @@ impl Clone for Wallet { } impl Wallet { - // TODO: Add support for mnemonic - /// Creates a new random encrypted JSON with the provided password and stores it in the /// provided directory pub fn new_keystore(dir: P, rng: &mut R, password: S) -> Result @@ -44,8 +59,7 @@ impl Wallet { S: AsRef<[u8]>, { let (secret, _) = eth_keystore::new(dir, rng, password)?; - let signer = SigningKey::from_bytes(secret.as_slice()) - .expect("private key should always be convertible to signing key"); + let signer = SigningKey::from_bytes(secret.as_slice())?; let address = key_to_address(&signer); Ok(Self { signer, @@ -61,8 +75,7 @@ impl Wallet { S: AsRef<[u8]>, { let secret = eth_keystore::decrypt_key(keypath, password)?; - let signer = SigningKey::from_bytes(secret.as_slice()) - .expect("private key should always be convertible to signing key"); + let signer = SigningKey::from_bytes(secret.as_slice())?; let address = key_to_address(&signer); Ok(Self { signer, @@ -83,15 +96,6 @@ impl Wallet { } } -fn key_to_address(secret_key: &SigningKey) -> Address { - // TODO: Can we do this in a better way? - let uncompressed_pub_key = K256PublicKey::from(&secret_key.verify_key()).decompress(); - let public_key = uncompressed_pub_key.unwrap().to_bytes(); - debug_assert_eq!(public_key[0], 0x04); - let hash = keccak256(&public_key[1..]); - Address::from_slice(&hash[12..]) -} - impl PartialEq for Wallet { fn eq(&self, other: &Self) -> bool { self.signer.to_bytes().eq(&other.signer.to_bytes()) @@ -129,11 +133,11 @@ impl From for Wallet { } impl FromStr for Wallet { - type Err = K256Error; + type Err = WalletError; fn from_str(src: &str) -> Result { - let src = hex::decode(src).expect("invalid hex when reading PrivateKey"); - let sk = SigningKey::from_bytes(&src).unwrap(); // TODO + let src = hex::decode(src)?; + let sk = SigningKey::from_bytes(&src)?; Ok(sk.into()) } } @@ -142,6 +146,7 @@ impl FromStr for Wallet { mod tests { use super::*; use crate::Signer; + use ethers_core::types::Address; use std::fs; use tempfile::tempdir; diff --git a/ethers-signers/src/wallet/util.rs b/ethers-signers/src/wallet/util.rs new file mode 100644 index 00000000..dea317c8 --- /dev/null +++ b/ethers-signers/src/wallet/util.rs @@ -0,0 +1,14 @@ +use ethers_core::{ + k256::{ecdsa::SigningKey, EncodedPoint as K256PublicKey}, + types::Address, + utils::keccak256, +}; + +pub fn key_to_address(secret_key: &SigningKey) -> Address { + // TODO: Can we do this in a better way? + let uncompressed_pub_key = K256PublicKey::from(&secret_key.verify_key()).decompress(); + let public_key = uncompressed_pub_key.unwrap().to_bytes(); + debug_assert_eq!(public_key[0], 0x04); + let hash = keccak256(&public_key[1..]); + Address::from_slice(&hash[12..]) +}