diff --git a/Cargo.lock b/Cargo.lock index 0486aa2..ac1bc92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "ansi-escapes" version = "0.1.1" @@ -62,6 +77,124 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "async-attributes" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-executor" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0c4a4f319e45986f347ee47fef8bf5e81c9abc3f6f58dc2391439f30df65f0" +dependencies = [ + "async-lock", + "async-task", + "concurrent-queue", + "fastrand 2.0.1", + "futures-lite", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" +dependencies = [ + "async-channel", + "async-executor", + "async-io", + "async-lock", + "blocking", + "futures-lite", + "once_cell", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite", + "log", + "parking", + "polling", + "rustix 0.37.27", + "slab", + "socket2", + "waker-fn", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-attributes", + "async-channel", + "async-global-executor", + "async-io", + "async-lock", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-task" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.1.0" @@ -133,6 +266,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + [[package]] name = "bitvec" version = "1.0.1" @@ -163,6 +302,22 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blocking" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c36a4d0d48574b3dd360b4b7d95cc651d2b6557b6402848a27d4b228a473e2a" +dependencies = [ + "async-channel", + "async-lock", + "async-task", + "fastrand 2.0.1", + "futures-io", + "futures-lite", + "piper", + "tracing", +] + [[package]] name = "bnum" version = "0.7.0" @@ -182,6 +337,12 @@ dependencies = [ "sha2", ] +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + [[package]] name = "byte-slice-cast" version = "1.2.2" @@ -200,6 +361,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "cfg-if" version = "1.0.0" @@ -212,6 +379,33 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17cc5e6b5ab06331c33589842070416baa137e8b0eb912b008cfd4a78ada7919" +[[package]] +name = "ciborium" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" + +[[package]] +name = "ciborium-ll" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "clap" version = "4.4.7" @@ -264,6 +458,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "concurrent-queue" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "const-oid" version = "0.9.5" @@ -304,6 +507,75 @@ dependencies = [ "libc", ] +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools 0.10.5", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + [[package]] name = "crunchy" version = "0.2.2" @@ -410,6 +682,37 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + [[package]] name = "ff" version = "0.13.0" @@ -438,6 +741,110 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +[[package]] +name = "futures" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" + +[[package]] +name = "futures-executor" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-macro" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "futures-sink" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" + +[[package]] +name = "futures-task" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" + +[[package]] +name = "futures-util" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -471,6 +878,18 @@ dependencies = [ "wasi 0.11.0+wasi-snapshot-preview1", ] +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "group" version = "0.13.0" @@ -482,6 +901,12 @@ dependencies = [ "subtle", ] +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + [[package]] name = "hashbrown" version = "0.13.2" @@ -500,6 +925,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + [[package]] name = "hex" version = "0.4.3" @@ -570,6 +1001,37 @@ dependencies = [ "hashbrown 0.14.2", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys", +] + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix 0.38.21", + "windows-sys", +] + [[package]] name = "itertools" version = "0.10.5" @@ -594,6 +1056,15 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "js-sys" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "k256" version = "0.13.1" @@ -608,6 +1079,15 @@ dependencies = [ "signature", ] +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -620,12 +1100,42 @@ version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +dependencies = [ + "value-bag", +] + [[package]] name = "memchr" version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + [[package]] name = "nu-ansi-term" version = "0.49.0" @@ -656,6 +1166,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-rational" version = "0.4.1" @@ -682,6 +1203,12 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + [[package]] name = "parity-scale-codec" version = "3.6.5" @@ -708,6 +1235,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "paste" version = "1.0.14" @@ -724,6 +1257,29 @@ dependencies = [ "hmac", ] +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "piper" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +dependencies = [ + "atomic-waker", + "fastrand 2.0.1", + "futures-io", +] + [[package]] name = "pkcs8" version = "0.10.2" @@ -734,6 +1290,50 @@ dependencies = [ "spki", ] +[[package]] +name = "plotters" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" + +[[package]] +name = "plotters-svg" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -791,23 +1391,28 @@ dependencies = [ [[package]] name = "rad" -version = "0.1.0" +version = "0.2.0" dependencies = [ "ansi-escapes", + "async-std", "base64", "bip32", "bip39", "clap", "const_format", + "criterion", "default-args", + "futures", "hex", "itertools 0.11.0", "k256", "nu-ansi-term", + "num-iter", "primitive-types", "qrencode", "radix-engine-common", "rand 0.7.3", + "rayon", "scrypto", "thiserror", "unindent", @@ -856,7 +1461,7 @@ name = "radix-engine-interface" version = "1.0.1" source = "git+https://github.com/radixdlt/radixdlt-scrypto#d16b3ffa65fea417e9c6d01d76456a0b36c060fa" dependencies = [ - "bitflags", + "bitflags 1.3.2", "const-sha1", "hex", "lazy_static", @@ -956,12 +1561,34 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "regex" version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" dependencies = [ + "aho-corasick", + "memchr", "regex-automata", "regex-syntax", ] @@ -972,6 +1599,8 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" dependencies = [ + "aho-corasick", + "memchr", "regex-syntax", ] @@ -1006,6 +1635,33 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys", +] + +[[package]] +name = "rustix" +version = "0.38.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys 0.4.11", + "windows-sys", +] + [[package]] name = "rustversion" version = "1.0.14" @@ -1018,6 +1674,15 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "sbor" version = "1.0.1" @@ -1053,6 +1718,12 @@ dependencies = [ "syn 1.0.93", ] +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "scrypto" version = "1.0.1" @@ -1095,7 +1766,7 @@ name = "scrypto-schema" version = "1.0.1" source = "git+https://github.com/radixdlt/radixdlt-scrypto#d16b3ffa65fea417e9c6d01d76456a0b36c060fa" dependencies = [ - "bitflags", + "bitflags 1.3.2", "radix-engine-common", "sbor", "serde", @@ -1167,6 +1838,25 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "spki" version = "0.7.2" @@ -1275,6 +1965,16 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -1307,6 +2007,22 @@ dependencies = [ "winnow", ] +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" + [[package]] name = "typenum" version = "1.17.0" @@ -1367,12 +2083,34 @@ dependencies = [ "serde", ] +[[package]] +name = "value-bag" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a72e1902dde2bd6441347de2b70b7f5d59bf157c6c62f0c44572607a1d55bbe" + [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "waker-fn" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" + +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -1385,6 +2123,113 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.38", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afec9963e3d0994cac82455b2b3502b81a7f40f9a0d32181f7528d9f4b43e02" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" + +[[package]] +name = "web-sys" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index dfeb32b..34bc96c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rad" -version = "0.1.0" +version = "0.2.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -23,17 +23,28 @@ itertools = "0.11.0" unindent = "0.2.3" const_format = "0.2.32" primitive-types = "0.12.2" +default-args = "1.0.0" +async-std = { version = "1.12.0", features = ["attributes"] } +futures = "0.3.29" +num-iter = "0.1.43" +rayon = "1.8.0" [dev-dependencies] -default-args = "1.0.0" +criterion = "0.5.1" [[bin]] name = "rad" +test = false + +[[bench]] +name = "my_benchmark" +harness = false [profile.test] opt-level = 3 debug = true debug-assertions = false +panic = "abort" overflow-checks = false lto = false incremental = false @@ -45,7 +56,10 @@ opt-level = 3 codegen-units = 1 panic = "abort" strip = "symbols" -debug = false lto = true debug-assertions = false overflow-checks = false +debug = true + +[profile.bench] +debug = true \ No newline at end of file diff --git a/benches/my_benchmark.rs b/benches/my_benchmark.rs new file mode 100644 index 0000000..b7d277e --- /dev/null +++ b/benches/my_benchmark.rs @@ -0,0 +1,28 @@ +use std::time::Duration; + +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use rad::{ + find_par::par_find, + input, + params::{Bip39WordCount, MAX_INDEX}, + run_config::RunConfig, +}; + +pub fn criterion_benchmark(c: &mut Criterion) { + let mut group = c.benchmark_group("benchmarking"); + group + .sample_size(10) + .measurement_time(Duration::from_secs(200)); // target "xyz" takes ~150 sec on Macbook Pro M2 + group.bench_function("benchy", |b| { + b.iter(|| { + black_box(par_find( + input!("p").unwrap(), + RunConfig::new(false, 0, false, false), + )) + }) + }); + group.finish(); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/src/bin/rad.rs b/src/bin/rad.rs index 0346ab2..a9e6594 100644 --- a/src/bin/rad.rs +++ b/src/bin/rad.rs @@ -1,9 +1,10 @@ use clap::{Parser, Subcommand}; use rad::file_reader::suffixes_from_file; -use rad::find::{find_all, find_n}; +use rad::find_par::par_find; use rad::info::{INFO_DONATION_ADDR_ONLY, INFO_WITH_DONATION_QR}; use rad::params::{Bip39WordCount, BruteForceInput}; use rad::run_config::RunConfig; +use std::time::SystemTime; #[derive(Parser)] #[command(name = "rad", version)] @@ -22,29 +23,6 @@ struct Cli { #[command(subcommand)] target_suffixes: TargetSuffixes, - /// If we want to continue searching for more vanity accounts for a given - /// target after we have found one. If `false` is passed, we will remove - /// the target after first account is found (better performance). If `true`, - /// the program will find multiple matches per target. - #[arg(short = 'c', long, default_value_t = false)] - multi_match_per_target: bool, - - /// How many matches PER MMEMONIC we will search for until program exits, - /// `0` means run forver. Any other value means stop program after than - /// many vanity accounts have been found. - #[arg(short = 'n', long, default_value_t = 0)] - matches_per_mnemonic: usize, - - /// How often you want the program to print any progress, use `0` to not print any progress. - /// Since finding accounts can take a very long time if 6 character long targets are used - /// it can be nice to see some kind of progress, you typicall want this to be a high number - /// like 10k - 1M, depending on how fast your machine is. - /// - /// If you are piping the output to a pager, e.g. `less` you typicall want to specify `0` to - /// this argument, so not have to scroll meaningless progress prints. - #[arg(short = 'p', long = "pulse", default_value_t = 10000)] - print_pulse: u32, - /// The number of indices to test per mnemonic, /// is used, which is convenient if you find a lot of nice vanity account using the same /// mnemonic, you have less number of mnemonics you need to manage. @@ -74,20 +52,20 @@ fn main() { let input = BruteForceInput::new_splitting_targets( &csv_string, cli.end_index, - cli.multi_match_per_target, + true, Bip39WordCount::Twelve, - Option::None, + None, ) .expect("Valid input"); - let run_config = RunConfig::new(cli.print_pulse); - let matches_per_mnemonic = cli.matches_per_mnemonic; + let run_config = RunConfig::new(true, 0, true, true); println!("{}", INFO_WITH_DONATION_QR); - match matches_per_mnemonic { - 0 => find_all(input, run_config), - _ => { - find_n(cli.matches_per_mnemonic, input, run_config); - () - } - } + let now = SystemTime::now(); + let vec = par_find(input, run_config); + let time_elapsed = now.elapsed().unwrap(); + println!( + "✅ Exiting program, ran for '{}' ms, found #{} results", + time_elapsed.as_millis(), + vec.len() + ); } diff --git a/src/find.rs b/src/find.rs deleted file mode 100644 index 71edc8a..0000000 --- a/src/find.rs +++ /dev/null @@ -1,138 +0,0 @@ -use crate::info::INFO_DONATION_ADDR_ONLY; -use crate::params::{BruteForceInput, MAX_SUFFIX_LENGTH}; -use crate::run_config::RunConfig; -use crate::utils::mnemonic_from_u256; -use crate::vanity::Vanity; - -use ansi_escapes::EraseLines; -use base64::{engine::general_purpose, Engine as _}; -use bip32::{ChildNumber, Seed, XPrv}; -use primitive_types::U256; -use radix_engine_common::prelude::{ - AddressBech32Encoder, ComponentAddress, NetworkDefinition, Secp256k1PublicKey, -}; -use std::ops::AddAssign; - -pub fn find(input: BruteForceInput, run_config: RunConfig, mut on_result: F) -> () -where - F: FnMut(Vanity) -> bool, -{ - let find_multiple_accounts_per_target = input.find_multiple_accounts_per_target; - let mut targets_left = input.targets.clone(); - let mut int = input.int(); - - let mut attempts_since_last_find = U256::zero(); - println!("{}", input); - let mut done = false; - while !done { - let mnemonic = mnemonic_from_u256(&int, &input.mnemonic_word_count); - let mnemonic_phrase = mnemonic.to_string(); // bip39 crate (since it support 12 word mnemonics) - let seed_ = mnemonic.to_seed(""); // bip39 crate (since it support 12 word mnemonics) - let seed = Seed::new(seed_); // bip32 create - let seed_fingerprint = general_purpose::STANDARD_NO_PAD.encode(&seed_[56..]); - let intermediary_path_ = "m/44'/1022'/0'/0"; - let intermediary_path = intermediary_path_.parse().expect("intermediary path"); - let intermediary_xprv = XPrv::derive_from_path(&seed, &intermediary_path).expect("hd key"); - - if input.index_end() > 100000 { - // don't wanna print to often - println!("🔮 Trying mnemonic: {}\n", mnemonic_phrase); - } - for index in 0u32..input.index_end() { - if done { - return; - } - // Radix Olympia BIP44-LIKE path (last component is incorrectly hardened.) - let child_xprv = intermediary_xprv - .derive_child(ChildNumber::new(index, true).unwrap()) - .expect("bip44 LIKE"); - let child_xpub = child_xprv.public_key(); - let verification_key = child_xpub.public_key(); - let public_key_point: k256::EncodedPoint = verification_key.to_encoded_point(true); - let public_key_bytes = public_key_point.as_bytes(); - let re_secp256k1_pubkey = - Secp256k1PublicKey::try_from(public_key_bytes).expect("RE secp256k1 pubkey"); - let address_data = - ComponentAddress::virtual_account_from_public_key(&re_secp256k1_pubkey); - let address_encoder = AddressBech32Encoder::new(&NetworkDefinition::mainnet()); - let address = address_encoder - .encode(&address_data.to_vec()[..]) - .expect("bech32 account address"); - - let suffix = &address[address.len() - MAX_SUFFIX_LENGTH..]; - - let mut to_remove: Vec = Vec::new(); - for target in &targets_left { - // for target_index in 0..targets_left.len() { - // let target = &targets_left[target_index]; - if suffix.ends_with(target) { - let result = Vanity { - target: target.clone(), - address: address.clone(), - derivation_path: format!("{}/{}'", intermediary_path_, index).to_string(), - index: index, - mnemonic: mnemonic_phrase.clone(), - public_key_bytes: Vec::from(public_key_bytes), - bip39_seed_fingerprint: seed_fingerprint.clone(), - }; - attempts_since_last_find = U256::zero(); - println!( - "{}\n{}{}\n{}", - "🎯".repeat(40), - result.to_string(), - INFO_DONATION_ADDR_ONLY.to_string(), - "🎯".repeat(40), - ); - if !on_result(result) { - done = true; - } - - if !find_multiple_accounts_per_target { - to_remove.push(target.clone()); - } - } - } - - if !find_multiple_accounts_per_target { - targets_left.retain(|t| !to_remove.contains(t)); - - if targets_left.is_empty() { - done = true; - break; - } - } - - attempts_since_last_find.add_assign(U256::one()); - - if !run_config.print_pulse.is_zero() { - if attempts_since_last_find.clone() % run_config.print_pulse == U256::zero() { - print!("{}", EraseLines(2)); - println!("⏳ Attempts since last find: {}", attempts_since_last_find); - } - } - } - int.add_assign(U256::one()); - int = int % input.max_int(); - } -} - -pub fn find_all(input: BruteForceInput, run_config: RunConfig) -> () { - find(input, run_config, |_| { - return true; // continue - }); -} - -pub fn find_n(n: usize, input: BruteForceInput, run_config: RunConfig) -> Vec { - let mut results: Vec = Vec::new(); - - find(input, run_config, |v| { - results.push(v); - if results.len() == n { - return false; - } else { - return true; - } - }); - - return results; -} diff --git a/src/find_par.rs b/src/find_par.rs new file mode 100644 index 0000000..4d68058 --- /dev/null +++ b/src/find_par.rs @@ -0,0 +1,108 @@ +use crate::hdwallet::{vanity_from_childkey, ChildKey, HDWallet}; +use crate::info::INFO_DONATION_ADDR_ONLY; +use crate::params::BruteForceInput; +use crate::run_config::RunConfig; +use crate::vanity::Vanity; + +use std::collections::HashSet; +use std::ops::Range; +use std::sync::{Arc, Mutex}; + +use rayon::prelude::{IntoParallelIterator, ParallelIterator}; + +pub fn cond_print(vanity: &Vanity, run_config: &RunConfig) { + if run_config.print_found_vanity_result { + print_vanity(vanity); + } +} +pub fn print_vanity(vanity: &Vanity) { + println!( + "{}\n{}{}\n{}", + "🎯".repeat(40), + vanity.to_string(), + INFO_DONATION_ADDR_ONLY.to_string(), + "🎯".repeat(40), + ); +} + +fn par_do_do_find( + range: Range, + wallet: &Box, + check_if_done: E, + on_childkey: F, +) -> Vec +where + E: Fn(u32) -> Option + Send + Sync, + F: Fn(ChildKey) -> Option + Send + Sync, +{ + range + .into_par_iter() + .map(|i| check_if_done(i)) + .while_some() + .map(|i| wallet.derive_child(i)) + .map(|c| on_childkey(c)) + .filter_map(|x| x) + .collect() +} + +fn par_do_find( + run_config: RunConfig, + wallet: Box, + end_index: u32, + targets: Arc>>, +) -> Vec { + par_do_do_find( + 0..end_index, + &wallet, + |i| { + if targets.lock().unwrap().is_empty() { + None + } else { + Some(i) + } + }, + |c| { + let suff = c.suffix.clone(); + + let mut result: Option = Option::None; + let mut trgts = targets.lock().unwrap(); + for target in trgts.iter() { + if suff.ends_with(target) { + let vanity = vanity_from_childkey(&c, target, &wallet); + cond_print(&vanity, &run_config); + result = Some(vanity); + break; + } else { + continue; + } + } + if let Some(v) = &result { + (*trgts).remove(&v.target); + } + return result; + }, + ) +} + +fn _par_find( + run_config: RunConfig, + wallet: Box, + end_index: u32, + targets_: HashSet, +) -> Vec { + let targets = Arc::new(Mutex::new(targets_.clone())); + par_do_find(run_config.clone(), wallet, end_index, targets) +} + +pub fn par_find(input: BruteForceInput, run_config: RunConfig) -> Vec { + if run_config.print_input { + println!("{}", input); + } + let wallet = HDWallet::from_entropy(input.int()).unwrap(); + _par_find( + run_config, + Box::new(wallet), + input.index_end(), + input.targets, + ) +} diff --git a/src/hdwallet.rs b/src/hdwallet.rs new file mode 100644 index 0000000..5c11312 --- /dev/null +++ b/src/hdwallet.rs @@ -0,0 +1,140 @@ +use crate::params::{Bip39WordCount, MAX_SUFFIX_LENGTH}; +use crate::run_error::RunError; +use crate::utils::mnemonic_from_u256; +use crate::vanity::Vanity; +use base64::{engine::general_purpose, Engine as _}; +use bip32::{ChildNumber, DerivationPath, Seed, XPrv}; +use bip39::Mnemonic; +use primitive_types::U256; +use radix_engine_common::prelude::{ + AddressBech32Encoder, ComponentAddress, NetworkDefinition, Secp256k1PublicKey, +}; + +#[derive(Clone)] +pub struct Path { + pub index: u32, + pub derivation_path: DerivationPath, +} +impl Path { + pub fn to_string(&self) -> String { + self.derivation_path.to_string() + } + pub fn child(&self, index: u32) -> Self { + Self { + index, + derivation_path: format!("{}/{}'", self.derivation_path.to_string(), index) + .parse() + .unwrap(), + } + } +} + +pub struct HDWallet { + pub entropy: U256, + pub mnemonic: Mnemonic, + pub intermediary_key_priv: XPrv, + pub intermediary_key_path: Path, + pub seed: Seed, + pub mnemonic_phrase: String, +} + +pub const BASE_PATH: &str = "m/44'/1022'/0'/0"; + +impl HDWallet { + pub fn fingerprint(&self) -> String { + general_purpose::STANDARD_NO_PAD.encode(&self.seed.as_bytes()[56..]) + } + + fn new(entropy: U256, mnemonic: Mnemonic) -> Result { + let seed = Seed::new(mnemonic.to_seed("")); // bip32 create + + let intermediary_path = BASE_PATH + .parse() + .map_err(|_| RunError::ParseDerivationPath)?; + + let key = XPrv::derive_from_path(&seed, &intermediary_path) + .map_err(|_| RunError::DeriveChildKeyFromPath)?; + + let path = Path { + index: 0, + derivation_path: intermediary_path, + }; + + Ok(Self { + entropy, + mnemonic: mnemonic.clone(), + seed, + intermediary_key_priv: key, + intermediary_key_path: path, + mnemonic_phrase: mnemonic.to_string(), + }) + } + + pub fn from_mnemonic_phrase(mnemonic_phrase: &str) -> Result { + // let mnemonic = Mnemonic::from(mnemonic_phrase); + let mnemonic = + Mnemonic::parse(mnemonic_phrase).map_err(|_| RunError::MnemonicFromPhrase)?; + let entropy_bytes = mnemonic.to_entropy(); + let entropy = U256::from_big_endian(&entropy_bytes.as_slice()); + return Self::new(entropy, mnemonic); + } + + pub fn from_entropy(entropy: U256) -> Result { + let mnemonic = mnemonic_from_u256(&entropy, &Bip39WordCount::Twelve); + return Self::new(entropy, mnemonic); + } +} + +#[derive(Clone)] +pub struct ChildKey { + pub index: u32, + pub key: XPrv, + pub public_key_bytes: Vec, + pub address: String, + pub suffix: String, +} + +impl HDWallet { + pub fn derive_child(&self, index: u32) -> ChildKey { + // let path = self.intermediary_key_path.child(index); + + let child_xprv = self + .intermediary_key_priv + .derive_child(ChildNumber::new(index, true).unwrap()) + .unwrap(); + + let child_xpub = child_xprv.public_key(); + let verification_key = child_xpub.public_key(); + let public_key_point: k256::EncodedPoint = verification_key.to_encoded_point(true); + let public_key_bytes = public_key_point.as_bytes(); + let re_secp256k1_pubkey = + Secp256k1PublicKey::try_from(public_key_bytes).expect("RE secp256k1 pubkey"); + let address_data = ComponentAddress::virtual_account_from_public_key(&re_secp256k1_pubkey); + let address_encoder = AddressBech32Encoder::new(&NetworkDefinition::mainnet()); + let address = address_encoder + .encode(&address_data.to_vec()[..]) + .expect("bech32 account address"); + + let suffix = &address[address.len() - MAX_SUFFIX_LENGTH..]; + + return ChildKey { + index, + key: child_xprv, + public_key_bytes: re_secp256k1_pubkey.to_vec().clone(), + address: address.clone(), + suffix: suffix.to_string(), + }; + } +} + +pub fn vanity_from_childkey(child_key: &ChildKey, target: &str, wallet: &HDWallet) -> Vanity { + Vanity { + target: target.to_string(), + address: child_key.address.clone(), + address_suffix: child_key.suffix.clone(), + index: child_key.index, + public_key_bytes: child_key.public_key_bytes.clone(), + mnemonic: wallet.mnemonic_phrase.clone(), + bip39_seed_fingerprint: wallet.fingerprint(), + } +} diff --git a/src/lib.rs b/src/lib.rs index 42876c5..407da94 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,11 @@ pub mod error; pub mod file_reader; -pub mod find; +pub mod find_par; +pub mod hdwallet; pub mod info; pub mod params; pub mod run_config; +pub mod run_error; +pub mod test_utils; pub mod utils; pub mod vanity; diff --git a/src/params.rs b/src/params.rs index 78e0086..04c958c 100644 --- a/src/params.rs +++ b/src/params.rs @@ -1,10 +1,11 @@ +use std::collections::HashSet; + use crate::error::TargetSuffixError; use primitive_types::{U128, U256}; use rand::Rng; -use std::collections::HashSet; use unindent::unindent; -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone)] pub enum Bip39WordCount { Twelve, #[allow(dead_code)] @@ -19,14 +20,14 @@ impl Bip39WordCount { } pub fn max_int(&self) -> U256 { match self { - Self::Twelve => U256::from(U128::MAX), //BigUint::from_bytes_be(&[0xffu8; 16]), + Self::Twelve => U256::from(U128::MAX), Self::TwentyFour => U256::MAX, } } } /// Parameters use to control how and which vanity accounts are found. -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone)] pub struct BruteForceInput { /// The target suffixes to search for, must be validated before set. pub targets: HashSet, diff --git a/src/run_config.rs b/src/run_config.rs index 5e11591..3e0ce5d 100644 --- a/src/run_config.rs +++ b/src/run_config.rs @@ -3,15 +3,27 @@ use primitive_types::U256; /// Configuration controlling how program is run, but not /// relating to which vanity accounts are found, just how /// program executes. +#[derive(Clone)] pub struct RunConfig { + pub print_found_vanity_result: bool, /// `0` means don't print anything pub print_pulse: U256, + pub print_mnemonic: bool, + pub print_input: bool, } impl RunConfig { - pub fn new(print_pulse: u32) -> Self { + pub fn new( + print_found_vanity_result: bool, + print_pulse: u32, + print_mnemonic: bool, + print_input: bool, + ) -> Self { Self { + print_found_vanity_result, print_pulse: U256::from(print_pulse), + print_mnemonic, + print_input, } } } diff --git a/src/run_error.rs b/src/run_error.rs new file mode 100644 index 0000000..b745ba4 --- /dev/null +++ b/src/run_error.rs @@ -0,0 +1,22 @@ +use thiserror::Error; + +#[derive(Debug, Error, PartialEq)] +pub enum RunError { + #[error("Failed to parse a bip32 path from string")] + ParseDerivationPath, + + #[error("Failed to derive a child key from a derivation path")] + DeriveChildKeyFromPath, + + #[error("Failed to parse mnemonic from phrase")] + MnemonicFromPhrase, + + #[error("Failed to parse PublicKey from bytes")] + PublicKeyFromBytes, + + #[error("Failed to encode Address from PublicKey")] + AddressFromPublicKey, + + #[error("Invalid target '{0}', contains forbidden character {1}.")] + InvalidBech32Character(String, char), +} diff --git a/src/test_utils.rs b/src/test_utils.rs new file mode 100644 index 0000000..ddcdadf --- /dev/null +++ b/src/test_utils.rs @@ -0,0 +1,41 @@ +extern crate default_args; +use crate::{ + error::TargetSuffixError, + params::{Bip39WordCount, BruteForceInput}, +}; + +default_args::default_args! { + export pub fn crate::test_utils::input( + targets: &str, + max_index: u32 = MAX_INDEX, + find_multiple_accounts_per_target: bool = false, + mnemonic_word_count: Bip39WordCount = Bip39WordCount::Twelve, + brute_force_seed: Option<&'static [u8]> = Option::None, + ) -> Result { + BruteForceInput::new_splitting_targets( + targets, + max_index, + find_multiple_accounts_per_target, + mnemonic_word_count, + brute_force_seed + ) + } +} + +default_args::default_args! { + export pub fn crate::test_utils::input_deterministic( + targets: &str, + max_index: u32 = MAX_INDEX, + find_multiple_accounts_per_target: bool = false, + mnemonic_word_count: Bip39WordCount = Bip39WordCount::Twelve, + brute_force_seed: &'static [u8] = b"rusty vanity", + ) -> BruteForceInput { + input!( + targets, + max_index, + find_multiple_accounts_per_target, + mnemonic_word_count, + Option::Some(brute_force_seed) + ).unwrap() + } +} diff --git a/src/utils.rs b/src/utils.rs index bdc57f6..8f06b96 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -10,3 +10,4 @@ pub fn mnemonic_from_u256(u: &U256, word_count: &Bip39WordCount) -> Mnemonic { vec.drain(0..vec.len() - word_count.byte_count()); return Mnemonic::from_entropy(&vec).unwrap(); } + diff --git a/src/vanity.rs b/src/vanity.rs index c78c0c5..5cc9465 100644 --- a/src/vanity.rs +++ b/src/vanity.rs @@ -5,10 +5,14 @@ use nu_ansi_term::{ use base64::{engine::general_purpose, Engine as _}; use qrencode::{render::unicode, QrCode}; +use crate::hdwallet::BASE_PATH; + +#[derive(Debug, PartialEq, Clone)] pub struct Vanity { pub target: String, pub address: String, - pub derivation_path: String, + /// Last 6 chars of the address, stored property for higher performance, used to check match against `target`. + pub address_suffix: String, pub index: u32, pub public_key_bytes: Vec, pub mnemonic: String, @@ -20,6 +24,9 @@ pub struct Vanity { } impl Vanity { + pub fn derivation_path(&self) -> String { + format!("{}/{}'", BASE_PATH, self.index) + } pub fn public_key_hex(&self) -> String { hex::encode(&self.public_key_bytes) } @@ -85,7 +92,7 @@ impl std::fmt::Display for Vanity { write!( f, "Address: {} (🎯 '{}')\nPath: {}\nPublicKey: {}\nIn Babylon mobile app: 'Import from a Legacy Wallet', by scanning:\n{}\n{}", - self.address, self.target, self.derivation_path, self.public_key_hex(), self.cap33_qr_code_string(), self.mnemonic_phrase_grid_string() + self.address, self.target, self.derivation_path(), self.public_key_hex(), self.cap33_qr_code_string(), self.mnemonic_phrase_grid_string() ) } } diff --git a/tests/tests.rs b/tests/tests.rs index 2527fed..2936a6f 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,245 +1,145 @@ -use rusty_vanity::{ - error::TargetSuffixError, - find::{find, find_n}, - params::{Bip39WordCount, BruteForceInput, MAX_INDEX}, - run_config::RunConfig, - vanity::Vanity, -}; -extern crate default_args; -use default_args::default_args; -// use test::Bencher; - -default_args! { - fn input( - targets: &str, - max_index: u32 = MAX_INDEX, - find_multiple_accounts_per_target: bool = false, - mnemonic_word_count: Bip39WordCount = Bip39WordCount::Twelve, - brute_force_seed: Option<&'static [u8]> = Option::None, - ) -> Result { - BruteForceInput::new_splitting_targets( - targets, - max_index, - find_multiple_accounts_per_target, - mnemonic_word_count, - brute_force_seed - ) +#[cfg(test)] +mod tests { + + use std::collections::HashSet; + + use primitive_types::U256; + use rad::{ + error::TargetSuffixError, + find_par::par_find, + hdwallet::HDWallet, + input, + params::{Bip39WordCount, MAX_INDEX}, + run_config::RunConfig, + }; + + #[test] + fn empty_targets_str() { + assert_eq!( + input!(""), + Err(TargetSuffixError::TargetsStringMustNotBeEmpty) + ); } -} -default_args! { - fn input_deterministic( - targets: &str, - max_index: u32 = MAX_INDEX, - find_multiple_accounts_per_target: bool = false, - mnemonic_word_count: Bip39WordCount = Bip39WordCount::Twelve, - brute_force_seed: &'static [u8] = b"rusty vanity", - ) -> BruteForceInput { - input!( - targets, - max_index, - find_multiple_accounts_per_target, - mnemonic_word_count, - Option::Some(brute_force_seed) - ).unwrap() + #[test] + fn empty_target_suffix_trailing() { + assert_eq!( + input!("a,,"), + Err(TargetSuffixError::TargetSuffixMustNotBeEmpty) + ); } -} - -fn _find(input: BruteForceInput, on_result: F) -> () -where - F: FnMut(Vanity) -> bool, -{ - find(input, RunConfig::new(0), on_result) -} - -fn _find_one(input: BruteForceInput) -> Vanity { - let mut result: Option = Option::None; - _find(input, |v| { - result = Option::Some(v); - return false; - }); - - return result.expect("one result"); -} - -pub fn _find_n(n: usize, input: BruteForceInput) -> Vec { - find_n(n, input, RunConfig::new(0)) -} - -#[test] -fn empty_targets_str() { - assert_eq!( - input!(""), - Err(TargetSuffixError::TargetsStringMustNotBeEmpty) - ); -} - -#[test] -fn empty_target_suffix_trailing() { - assert_eq!( - input!("a,,"), - Err(TargetSuffixError::TargetSuffixMustNotBeEmpty) - ); -} -#[test] -fn empty_target_suffix_leading() { - assert_eq!( - input!(",a"), - Err(TargetSuffixError::TargetSuffixMustNotBeEmpty) - ); -} + #[test] + fn empty_target_suffix_leading() { + assert_eq!( + input!(",a"), + Err(TargetSuffixError::TargetSuffixMustNotBeEmpty) + ); + } -#[test] -fn long_suffix() { - assert_eq!( - input!("verylong"), - Err(TargetSuffixError::TooLongTargetSuffix( - "verylong".to_string(), - 8 - )) - ); -} + #[test] + fn long_suffix() { + assert_eq!( + input!("verylong"), + Err(TargetSuffixError::TooLongTargetSuffix( + "verylong".to_string(), + 8 + )) + ); + } -#[test] -fn invalid_char_i() { - assert_eq!( - input!("hi"), - Err(TargetSuffixError::InvalidBech32Character( - "hi".to_string(), - 'i' - )) - ); -} + #[test] + fn invalid_char_i() { + assert_eq!( + input!("hi"), + Err(TargetSuffixError::InvalidBech32Character( + "hi".to_string(), + 'i' + )) + ); + } -#[test] -fn invalid_char_b() { - assert_eq!( - input!("burn"), - Err(TargetSuffixError::InvalidBech32Character( - "burn".to_string(), - 'b' - )) - ); -} + #[test] + fn invalid_char_b() { + assert_eq!( + input!("burn"), + Err(TargetSuffixError::InvalidBech32Character( + "burn".to_string(), + 'b' + )) + ); + } -#[test] -fn invalid_char_o() { - assert_eq!( - input!("some"), - Err(TargetSuffixError::InvalidBech32Character( - "some".to_string(), - 'o' - )) - ); -} + #[test] + fn invalid_char_o() { + assert_eq!( + input!("some"), + Err(TargetSuffixError::InvalidBech32Character( + "some".to_string(), + 'o' + )) + ); + } -#[test] -fn invalid_chars() { - assert_eq!( - input!("bio"), - Err(TargetSuffixError::InvalidBech32Character( - "bio".to_string(), - 'b' - )) - ); -} + #[test] + fn invalid_chars() { + assert_eq!( + input!("bio"), + Err(TargetSuffixError::InvalidBech32Character( + "bio".to_string(), + 'b' + )) + ); + } -#[test] -fn one() { - let result = _find_one(input_deterministic!("9")); - assert_eq!(result.target, "9"); - assert_eq!( - result.mnemonic, - "abandon abandon abandon top fire riot tonight attract gesture infant fringe vibrant" - ); - assert_eq!( - result.address, - "account_rdx16xx7xu4mel6nae8kphnfsnh2qp24j658huglyamy35u8djmfwxc0a9" - ); - assert_eq!(result.bip39_seed_fingerprint, "g1E2tnS4bUc"); - assert_eq!( - result.cap33_export_string_account_part(), - "S^A7YA0KWtH020Y7skhc2IGszGSi+fp8ROHNKev7mtmkx5^12^g1E2tnS4bUc|9|12}" - ); - assert_eq!(result.derivation_path, "m/44'/1022'/0'/0/12'"); - assert_eq!( - result.public_key_hex(), - "03b600d0a5ad1f4db463bb2485cd881accc64a2f9fa7c44e1cd29ebfb9ad9a4c79" - ); - assert_eq!( - result.cap33_export_string(), - "1^0^12]S^A7YA0KWtH020Y7skhc2IGszGSi+fp8ROHNKev7mtmkx5^12^g1E2tnS4bUc|9|12}" - ); -} + #[test] + fn entropy() { + let wallet = HDWallet::from_entropy(U256::one()); + assert_eq!(wallet.unwrap().entropy, U256::one()); + } -#[test] -fn n_3_find_multiple_accounts_per_target() { - let n: usize = 3; - let tx: &str = "tx"; - let ty = "ty"; - let find_multiple_accounts_per_target = true; - let results = _find_n( - n, - input_deterministic!( - &format!("{tx},{ty}"), - MAX_INDEX, - find_multiple_accounts_per_target - ), - ); - - assert_eq!(results.len(), n); - - assert_eq!( - results - .into_iter() - .map(|v| v.target) - .collect::>(), - Vec::from([tx, ty, ty]) - ); -} + #[test] + fn mnemonic() { + let wallet = HDWallet::from_entropy(U256::zero()); + assert_eq!(wallet.unwrap().mnemonic_phrase, "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"); + } -#[test] -fn n_3_find_single_accounts_per_target() { - let n: usize = 3; - let tx: &str = "tx"; - let ty = "ty"; - let targets = [tx, ty]; - let find_multiple_accounts_per_target = false; - let results = _find_n( - n, - input_deterministic!( - &targets.join(","), - MAX_INDEX, - find_multiple_accounts_per_target - ), - ); - - assert_eq!(results.len(), targets.len()); // not `n`, - - assert_eq!( - results - .into_iter() - .map(|v| v.target) - .collect::>(), - targets - ); -} + #[test] + fn test_key() { + let wallet = HDWallet::from_mnemonic_phrase( + "gentle hawk winner rain embrace erosion call update photo frost fatal wrestle", + ) + .unwrap(); + let key0 = wallet.derive_child(0); + assert_eq!(key0.index, 0); + // https://github.com/radixdlt/babylon-wallet-ios/blob/40c7b8d671611ca7a8ba52e0b5e82044d9cebd68/RadixWalletTests/ProfileTests/TestVectors/ProfileVersion100/multi_profile_snapshots_test_version_100.json#L494 + assert_eq!( + hex::encode(key0.public_key_bytes), + "02f669a43024d90fde69351ccc53022c2f86708d9b3c42693640733c5778235da5" + ); + + let key1 = wallet.derive_child(1); + assert_eq!(key1.index, 1); + // https://github.com/radixdlt/babylon-wallet-ios/blob/40c7b8d671611ca7a8ba52e0b5e82044d9cebd68/RadixWalletTests/ProfileTests/TestVectors/ProfileVersion100/multi_profile_snapshots_test_version_100.json#L542 + assert_eq!( + hex::encode(key1.public_key_bytes), + "023a41f437972033fa83c3c4df08dc7d68212ccac07396a29aca971ad5ba3c27c8" + ); + } -#[test] -fn xrd() { - assert_eq!( - _find_one(input_deterministic!("xrd")).address, - "account_rdx16xl72qyxvhkjtmyxeazl4tcgjh5n3hse6xfnr3ku0utlk9myp47xrd" - ); + #[test] + fn find_vanity_suffix_xx_yy() { + let run_config = RunConfig::new(false, 0, false, false); + let vec = par_find( + input!("xx,yy").unwrap(), + RunConfig::new(false, 0, false, false), + ); + + assert_eq!( + vec.into_iter() + .map(|v| v.target) + .collect::>(), + HashSet::from(["xx", "yy"].map(|x| x.to_string())) + ); + } } - -// #[bench] -// fn deterministic(b: &mut Bencher) { -// b.iter(|| { -// assert_eq!( -// find_one(input_deterministic!("a")).address, -// "account_rdx16xcsekplyt3cvqdqntcz37zgt8wageuznmgthfzkfrj8ye5ay5k7xa" -// ); -// }); -// }