depolymerization

wire gateway for Bitcoin/Ethereum
Log | Files | Refs | Submodules | README | LICENSE

commit 4e1f47bcc56639427b99de6bff49830ee586b63d
parent 68bbc03b5ca437704281ba69808325ff2f3c9fb1
Author: Antoine A <>
Date:   Fri, 12 Nov 2021 10:55:17 +0100

Clean code and start benchmarking

Diffstat:
MCargo.lock | 496+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
MCargo.toml | 10++++++++--
Abenches/metadata.rs | 27+++++++++++++++++++++++++++
Asrc/lib.rs | 178+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/main.rs | 195++++++++++++++-----------------------------------------------------------------
5 files changed, 657 insertions(+), 249 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -32,6 +32,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38de00daab4eac7d753e97697066238d67ce9d7e2d823ab4f72fe14af29f3f33" [[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] name = "autocfg" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -113,19 +124,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] -name = "block-buffer" -version = "0.9.0" +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + +[[package]] +name = "bstr" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ - "generic-array", + "lazy_static", + "memchr", + "regex-automata", + "serde", ] [[package]] -name = "bs58" -version = "0.4.0" +name = "bumpalo" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" +checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" [[package]] name = "byteorder" @@ -134,10 +154,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] +name = "cast" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" +dependencies = [ + "rustc_version", +] + +[[package]] name = "cc" -version = "1.0.71" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" [[package]] name = "cfg-if" @@ -146,10 +175,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "cfg_aliases" -version = "0.1.1" +name = "clap" +version = "2.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "bitflags", + "textwrap", + "unicode-width", +] [[package]] name = "clipboard-win" @@ -163,12 +197,105 @@ dependencies = [ ] [[package]] -name = "cpufeatures" -version = "0.2.1" +name = "criterion" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" dependencies = [ - "libc", + "atty", + "cast", + "clap", + "criterion-plot", + "csv", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "csv" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" +dependencies = [ + "bstr", + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", ] [[package]] @@ -179,11 +306,10 @@ dependencies = [ "bitcoin-bech32", "bitcoincore-rpc", "bs58", + "criterion", "digest", "fastrand", "rustyline", - "sha2", - "static_init", ] [[package]] @@ -217,6 +343,12 @@ dependencies = [ ] [[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] name = "endian-type" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -274,6 +406,12 @@ dependencies = [ ] [[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] name = "heck" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -283,6 +421,15 @@ dependencies = [ ] [[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] name = "instant" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -292,12 +439,30 @@ dependencies = [ ] [[package]] +name = "itertools" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" +dependencies = [ + "either", +] + +[[package]] name = "itoa" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] +name = "js-sys" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" +dependencies = [ + "wasm-bindgen", +] + +[[package]] name = "jsonrpc" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -310,19 +475,16 @@ dependencies = [ ] [[package]] -name = "libc" -version = "0.2.107" +name = "lazy_static" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] -name = "lock_api" -version = "0.4.5" +name = "libc" +version = "0.2.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" -dependencies = [ - "scopeguard", -] +checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219" [[package]] name = "log" @@ -371,34 +533,56 @@ dependencies = [ ] [[package]] -name = "opaque-debug" -version = "0.3.0" +name = "num-traits" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] [[package]] -name = "parking_lot" -version = "0.11.2" +name = "num_cpus" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" dependencies = [ - "instant", - "lock_api", - "parking_lot_core", + "hermit-abi", + "libc", ] [[package]] -name = "parking_lot_core" -version = "0.8.5" +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "plotters" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi", + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c" + +[[package]] +name = "plotters-svg" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9" +dependencies = [ + "plotters-backend", ] [[package]] @@ -430,6 +614,31 @@ dependencies = [ ] [[package]] +name = "rayon" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] name = "redox_syscall" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -449,6 +658,36 @@ dependencies = [ ] [[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] name = "rustyline" version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -479,6 +718,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[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 = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -504,6 +752,12 @@ dependencies = [ ] [[package]] +name = "semver" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" + +[[package]] name = "serde" version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -513,6 +767,16 @@ dependencies = [ ] [[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + +[[package]] name = "serde_derive" version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -535,67 +799,45 @@ dependencies = [ ] [[package]] -name = "sha2" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" -dependencies = [ - "block-buffer", - "cfg-if", - "cpufeatures", - "digest", - "opaque-debug", -] - -[[package]] name = "smallvec" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] -name = "static_init" -version = "1.0.1" +name = "str-buf" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12a91dc56a0b47b48a3150157803b02cf82aa4c15ed499cb9b7ee0ff39941b1" -dependencies = [ - "bitflags", - "cfg_aliases", - "libc", - "parking_lot", - "parking_lot_core", - "static_init_macro", - "winapi", -] +checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" [[package]] -name = "static_init_macro" -version = "1.0.1" +name = "syn" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b3fb6e118f42ea83548bb2194a79f5cbc8866fc38d87f6548139a7fac10e732" +checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" dependencies = [ - "cfg_aliases", - "memchr", "proc-macro2", "quote", - "syn", + "unicode-xid", ] [[package]] -name = "str-buf" -version = "1.0.5" +name = "textwrap" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] [[package]] -name = "syn" -version = "1.0.81" +name = "tinytemplate" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", + "serde", + "serde_json", ] [[package]] @@ -635,12 +877,87 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] +name = "wasm-bindgen" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" + +[[package]] +name = "web-sys" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -657,6 +974,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml @@ -7,12 +7,18 @@ edition = "2021" [dependencies] bitcoincore-rpc = "0.14.0" -sha2 = "0.9.8" bs58 = "0.4.0" fastrand = "1.5.0" digest = "0.9.0" argh = "0.1.6" rustyline = "9.0.0" bitcoin-bech32 = "0.12.1" -static_init = "1.0.1" + +[dev-dependencies] +# statistics-driven micro-benchmarks +criterion = "0.3.5" + +[[bench]] +name = "metadata" +harness = false diff --git a/benches/metadata.rs b/benches/metadata.rs @@ -0,0 +1,27 @@ +use bitcoin_bech32::constants::Network; +use criterion::{criterion_group, criterion_main, Criterion}; +use depolymerization::{ + decode_segwit_msg, encode_segwit_msg, + utils::{rand_addresses, rand_key}, +}; + +fn criterion_benchmark(c: &mut Criterion) { + let mut group = c.benchmark_group("SegWit addresses"); + group.bench_function("encode", |b| { + b.iter_batched( + rand_key, + |key| encode_segwit_msg(Network::Bitcoin, &key), + criterion::BatchSize::SmallInput, + ); + }); + group.bench_function("decode", |b| { + b.iter_batched( + || rand_addresses(&rand_key()), + |addrs| decode_segwit_msg(&addrs), + criterion::BatchSize::SmallInput, + ); + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/src/lib.rs b/src/lib.rs @@ -0,0 +1,178 @@ +use std::{collections::BTreeMap, iter::repeat_with}; + +use bitcoin_bech32::{constants::Network, u5, WitnessProgram}; +use bitcoincore_rpc::bitcoin::Amount; + +pub fn segwit_min_amount() -> Amount { + // https://github.com/bitcoin/bitcoin/blob/master/src/policy/policy.cpp + return Amount::from_sat(294); +} + +fn encode_segwit_address( + network: Network, + is_first: bool, + magic_id: &[u8; 4], + key_half: &[u8; 16], +) -> String { + // Combine magic_it and the key half + let mut buf = vec![0u8; 20]; + buf[..4].copy_from_slice(magic_id); + buf[4..].copy_from_slice(key_half); + // Toggle first bit for ordering + if is_first { + buf[0] &= 0b0111_1111 // Unset first bit + } else { + buf[0] |= 0b1000_0000 // Set first bit + } + // Encode into an fake segwit address + WitnessProgram::new(u5::try_from_u8(0).unwrap(), buf, network) + .unwrap() + .to_address() +} + +pub fn encode_segwit_msg(network: Network, msg: &[u8; 32]) -> [String; 2] { + // Generate a random magic identifier + let mut magic_id = [0; 4]; + // TODO use secure os based random + magic_id.fill_with(|| fastrand::u8(..)); + // Split key in half; + let mut split = ([0; 16], [0; 16]); + split.0.copy_from_slice(&msg[..16]); + split.1.copy_from_slice(&msg[16..]); + [ + encode_segwit_address(network, true, &magic_id, &split.0), + encode_segwit_address(network, false, &magic_id, &split.1), + ] +} + +#[derive(Debug, Clone)] +pub enum DecodeError { + MissingSeqWitAddress, + MagicIdCollision, +} + +pub fn decode_segwit_msg(segwit_addrs: &[impl AsRef<str>]) -> Result<[u8; 32], DecodeError> { + if segwit_addrs.len() < 2 { + return Err(DecodeError::MissingSeqWitAddress); + } + + let decoded: Vec<[u8; 20]> = segwit_addrs + .into_iter() + .filter_map(|addr| { + WitnessProgram::from_address(addr.as_ref()) + .ok() + .and_then(|wp| { + let pg = wp.program(); + if pg.len() == 20 { + let mut buf = [0; 20]; + buf.copy_from_slice(pg); + Some(buf) + } else { + None + } + }) + }) + .collect(); + + if decoded.len() < 2 { + return Err(DecodeError::MissingSeqWitAddress); + } + + let mut parts: Vec<(bool, [u8; 4], &[u8; 16])> = decoded + .iter() + .map(|c| { + let mut magic_id: [u8; 4] = c[..4].try_into().unwrap(); + let key_half: &[u8; 16] = c[4..].try_into().unwrap(); + let is_first = !c[0] & 0b1000_0000 == 0; + // Clear first bit + magic_id[0] &= 0b0111_1111; + (is_first, magic_id, key_half) + }) + .collect(); + let mut map = BTreeMap::new(); + + for (_, magic, _) in &parts { + match map.get_mut(magic) { + Some(prev) => *prev = true, + None => { + map.insert(*magic, false); + } + } + } + map.retain(|_, many| *many); + assert_eq!(map.len(), 1, "Two possible magic id"); + let magic_id = map.into_keys().next().unwrap(); + parts.retain(|(_, magic, _)| *magic == magic_id); + assert_eq!(parts.len(), 2, "Magic ID collision"); + + let mut key = [0; 32]; + for (is_first, _, half) in parts { + key[is_first as usize * 16..][..16].copy_from_slice(half); + } + Ok(key) +} + +pub mod utils { + use std::iter::repeat_with; + + use bitcoin_bech32::{constants::Network, u5, WitnessProgram}; + + use crate::encode_segwit_msg; + + pub fn rand_key() -> [u8; 32] { + let mut key = [0; 32]; + key.fill_with(|| fastrand::u8(..)); + key + } + + pub fn rand_addresses(key: &[u8; 32]) -> Vec<String> { + let mut rng_address: Vec<String> = std::iter::repeat_with(|| { + let key: Vec<u8> = repeat_with(|| fastrand::u8(..)).take(20).collect(); + WitnessProgram::new(u5::try_from_u8(0).unwrap(), key, Network::Bitcoin) + .unwrap() + .to_address() + }) + .take(2) + .collect(); + + let mut addresses = encode_segwit_msg(Network::Bitcoin, &key).to_vec(); + addresses.append(&mut rng_address); + fastrand::shuffle(&mut addresses); + addresses + } +} + +#[cfg(test)] +mod test { + use bitcoin_bech32::constants::Network; + + use crate::{ + decode_segwit_msg, encode_segwit_msg, + utils::{rand_addresses, rand_key}, + }; + + #[test] + fn test_shuffle() { + for _ in 0..1000 { + let key = rand_key(); + let mut addresses = encode_segwit_msg(Network::Bitcoin, &key); + fastrand::shuffle(&mut addresses); + let decoded = + decode_segwit_msg(&addresses.iter().map(|s| s.as_str()).collect::<Vec<&str>>()) + .unwrap(); + assert_eq!(key, decoded); + } + } + + #[test] + fn test_shuffle_many() { + for _ in 0..1000 { + let key = rand_key(); + let addresses = rand_addresses(&key); + let decoded = + decode_segwit_msg(&addresses.iter().map(|s| s.as_str()).collect::<Vec<&str>>()) + .unwrap(); + assert_eq!(key, decoded); + } + } +} diff --git a/src/main.rs b/src/main.rs @@ -1,8 +1,4 @@ -use std::{ - collections::{BTreeMap, HashSet}, - iter::repeat_with, - path::PathBuf, -}; +use std::{collections::HashSet, iter::repeat_with, path::PathBuf, str::FromStr}; use bitcoin_bech32::{constants::Network, u5, WitnessProgram}; use bitcoincore_rpc::{ @@ -10,19 +6,31 @@ use bitcoincore_rpc::{ jsonrpc::serde_json::Value, Auth, Client, RpcApi, }; -use static_init::dynamic; - -// https://github.com/bitcoin/bitcoin/blob/master/src/policy/policy.cpp -#[dynamic] -static LEGACY_MIN_AMOUNT: Amount = Amount::from_sat(546); -#[dynamic] -static SEGWIT_MIN_AMOUNT: Amount = Amount::from_sat(294); +use depolymerization::{decode_segwit_msg, encode_segwit_msg, segwit_min_amount}; const CLIENT: &str = "client"; const WIRE: &str = "wire"; -const DATA_PATH: &str = "C:/Users/antoi/AppData/Roaming/Bitcoin/regtest"; const RPC_URL: &str = "http://localhost:18443"; +fn get_data_path() -> PathBuf { + // https://github.com/bitcoin/bitcoin/blob/master/doc/bitcoin-conf.md#:~:text=By%20default%2C%20the%20configuration%20file,file%3E%20option%20in%20the%20bitcoin. + if cfg!(target_os = "windows") { + PathBuf::from_str(&std::env::var("APPDATA").unwrap()) + .unwrap() + .join("Bitcoin") + } else if cfg!(target_os = "linux") { + PathBuf::from_str(&std::env::var("HOME").unwrap()) + .unwrap() + .join(".bitcoin") + } else if cfg!(target_os = "macos") { + PathBuf::from_str(&std::env::var("HOME").unwrap()) + .unwrap() + .join("Library/Application Support/Bitcoin") + } else { + unimplemented!("Only windows, linux or macos") + } +} + #[derive(argh::FromArgs)] /// Bitcoin metadata tester struct Args { @@ -38,158 +46,17 @@ struct Args { #[argh(option)] msg: Option<String>, } - -fn encode_segwit_address( - network: Network, - is_first: bool, - magic_id: &[u8; 4], - key_half: &[u8; 16], -) -> String { - // Combine magic_it and the key half - let mut buf = vec![0u8; 20]; - buf[..4].copy_from_slice(magic_id); - buf[4..].copy_from_slice(key_half); - // Toggle first bit for ordering - if is_first { - buf[0] &= 0b0111_1111 // Unset first bit - } else { - buf[0] |= 0b1000_0000 // Set first bit - } - // Encode into an fake segwit address - WitnessProgram::new(u5::try_from_u8(0).unwrap(), buf, network) - .unwrap() - .to_address() -} - -fn encode_segwit_key(network: Network, key: &[u8; 32]) -> [String; 2] { - // Generate a random magic identifier - let mut magic_id = [0; 4]; - // TODO use secure os based random - magic_id.fill_with(|| fastrand::u8(..)); - // Split key in half; - let mut split = ([0; 16], [0; 16]); - split.0.copy_from_slice(&key[..16]); - split.1.copy_from_slice(&key[16..]); - [ - encode_segwit_address(network, true, &magic_id, &split.0), - encode_segwit_address(network, false, &magic_id, &split.1), - ] -} - -#[derive(Debug, Clone)] -pub enum DecodeError { - MissingSeqWitAddress, - MagicIdCollision, -} - -fn decode_segwit_msg(segwit_addrs: &[&str]) -> Result<[u8; 32], DecodeError> { - if segwit_addrs.len() < 2 { - return Err(DecodeError::MissingSeqWitAddress); - } - - let decoded: Vec<[u8; 20]> = segwit_addrs - .into_iter() - .filter_map(|addr| { - WitnessProgram::from_address(addr).ok().and_then(|wp| { - let pg = wp.program(); - if pg.len() == 20 { - let mut buf = [0; 20]; - buf.copy_from_slice(pg); - Some(buf) - } else { - None - } - }) - }) - .collect(); - - if decoded.len() < 2 { - return Err(DecodeError::MissingSeqWitAddress); - } - - let mut parts: Vec<(bool, [u8; 4], &[u8; 16])> = decoded - .iter() - .map(|c| { - let mut magic_id: [u8; 4] = c[..4].try_into().unwrap(); - let key_half: &[u8; 16] = c[4..].try_into().unwrap(); - let is_first = !c[0] & 0b1000_0000 == 0; - // Clear first bit - magic_id[0] &= 0b0111_1111; - (is_first, magic_id, key_half) - }) - .collect(); - let mut map = BTreeMap::new(); - - for (_, magic, _) in &parts { - match map.get_mut(magic) { - Some(prev) => *prev = true, - None => { - map.insert(*magic, false); - } - } - } - map.retain(|_, many| *many); - assert_eq!(map.len(), 1, "Two possible magic id"); - let magic_id = map.into_keys().next().unwrap(); - parts.retain(|(_, magic, _)| *magic == magic_id); - assert_eq!(parts.len(), 2, "Magic ID collision"); - - let mut key = [0; 32]; - for (is_first, _, half) in parts { - key[is_first as usize * 16..][..16].copy_from_slice(half); - } - Ok(key) -} - -#[test] -fn test_shuffle() { - for _ in 0..1000 { - let mut key = [0; 32]; - key.fill_with(|| fastrand::u8(..)); - let mut addresses = encode_segwit_key(Network::Bitcoin, &key); - fastrand::shuffle(&mut addresses); - let decoded = - decode_segwit_msg(&addresses.iter().map(|s| s.as_str()).collect::<Vec<&str>>()) - .unwrap(); - assert_eq!(key, decoded); - } -} - -#[test] -fn test_shuffle_many() { - for _ in 0..1000 { - let mut rng_address: Vec<String> = std::iter::repeat_with(|| { - let key: Vec<u8> = repeat_with(|| fastrand::u8(..)).take(20).collect(); - WitnessProgram::new(u5::try_from_u8(0).unwrap(), key, Network::Bitcoin) - .unwrap() - .to_address() - }) - .take(2) - .collect(); - - let mut key = [0; 32]; - key.fill_with(|| fastrand::u8(..)); - let mut addresses = encode_segwit_key(Network::Bitcoin, &key).to_vec(); - addresses.append(&mut rng_address); - fastrand::shuffle(&mut addresses); - let decoded = - decode_segwit_msg(&addresses.iter().map(|s| s.as_str()).collect::<Vec<&str>>()) - .unwrap(); - assert_eq!(key, decoded); - } -} - fn common_rpc() -> Client { Client::new( RPC_URL, - Auth::CookieFile(PathBuf::from(DATA_PATH).join(".cookie")), + Auth::CookieFile(get_data_path().join("regtest").join(".cookie")), ) .expect("Failed to open common client") } fn wallet_rpc(wallet: &str) -> Client { Client::new( &format!("{}/wallet/{}", RPC_URL, wallet), - Auth::CookieFile(PathBuf::from(DATA_PATH).join(".cookie")), + Auth::CookieFile(get_data_path().join("regtest").join(".cookie")), ) .expect(&format!("Failed to open wallet '{}' client", wallet)) } @@ -224,9 +91,13 @@ fn send_with_metadata( amount: Amount, metadata: &[u8], ) -> bitcoincore_rpc::Result<Txid> { - let addresses = encode_segwit_key(Network::Regtest, &metadata.try_into().unwrap()); + let addresses = encode_segwit_msg(Network::Regtest, &metadata.try_into().unwrap()); let mut recipients = vec![(to.to_string(), amount)]; - recipients.extend(addresses.into_iter().map(|addr| (addr, *SEGWIT_MIN_AMOUNT))); + recipients.extend( + addresses + .into_iter() + .map(|addr| (addr, segwit_min_amount())), + ); send_many(rpc, recipients) } @@ -243,7 +114,7 @@ fn last_metadata(rpc: &Client) -> bitcoincore_rpc::Result<Vec<u8>> { .unwrap() .into_iter() .filter_map(|it| { - if it["value"].as_f64().unwrap() == SEGWIT_MIN_AMOUNT.as_btc() { + if it["value"].as_f64().unwrap() == segwit_min_amount().as_btc() { Some(it["scriptPubKey"]["address"].as_str().unwrap()) } else { None @@ -256,7 +127,7 @@ fn last_metadata(rpc: &Client) -> bitcoincore_rpc::Result<Vec<u8>> { fn main() { { let existing_wallets: HashSet<String> = - std::fs::read_dir(PathBuf::from(DATA_PATH).join("wallets")) + std::fs::read_dir(get_data_path().join("regtest").join("wallets")) .unwrap() .filter_map(|it| it.ok()) .map(|it| it.file_name().to_string_lossy().to_string()) @@ -309,7 +180,7 @@ fn main() { send_with_metadata( &client_rpc, &wire_addr, - *LEGACY_MIN_AMOUNT, + Amount::from_sat(4200), line.as_bytes(), ) .unwrap(); @@ -328,7 +199,7 @@ fn main() { } else { // Send metadata let metadata: Vec<u8> = repeat_with(|| fastrand::u8(..)).take(32).collect(); - send_with_metadata(&client_rpc, &wire_addr, *LEGACY_MIN_AMOUNT, &metadata).unwrap(); + send_with_metadata(&client_rpc, &wire_addr, Amount::from_sat(4200), &metadata).unwrap(); // Mine one block client_rpc.generate_to_address(1, &client_addr).unwrap(); // Read metadata