diff --git a/Cargo.lock b/Cargo.lock index a4f09637..338d9126 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "amplify" -version = "4.5.0" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8629db306c0bbeb0a402e2918bdcf0026b5ddb24c46460f3bf5410b350d98710" +checksum = "9e711289a6cb28171b4f0e6c8019c69ff9476050508dc082167575d458ff74d0" dependencies = [ "amplify_apfloat", "amplify_derive", @@ -23,21 +23,19 @@ dependencies = [ "amplify_syn", "ascii", "serde", - "serde_json", - "serde_yaml", "stringly_conversions", - "toml", "wasm-bindgen", ] [[package]] name = "amplify_apfloat" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5b7f29fad2a3def5dfbfed0da85b886eb927a18fe0296c06e39880b7a96db05" +checksum = "72e23f5ede99065fa6957a633498d2728d51016d61dae23b69c866112b7c61ee" dependencies = [ "amplify_num", - "bitflags 1.3.2", + "bitflags 2.4.2", + "wasm-bindgen", ] [[package]] @@ -54,9 +52,9 @@ dependencies = [ [[package]] name = "amplify_num" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9681187211554ab98f138ba159e90861b136c20afc680dcff2ba82d020721e27" +checksum = "04c009c5c4de814911b177e2ea59e4930bb918978ed3cce4900d846a6ceb0838" dependencies = [ "serde", "wasm-bindgen", @@ -75,9 +73,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.76" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59d2a3357dde987206219e78ecfbbb6e8dad06cbb65292758d3270e6254f7355" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" [[package]] name = "arrayref" @@ -102,13 +100,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.75" +version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] @@ -130,10 +128,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" [[package]] -name = "base64" -version = "0.21.5" +name = "base85" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +checksum = "36915bbaca237c626689b5bd14d02f2ba7a5a359d30a2a08be697392e3718079" +dependencies = [ + "thiserror", +] [[package]] name = "bitflags" @@ -143,9 +144,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "blake3" @@ -171,9 +172,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "d32a994c2b3ca201d9b263612a374263f05e7adde37c4707f693dcd375076d1f" [[package]] name = "byteorder" @@ -207,7 +208,7 @@ dependencies = [ [[package]] name = "commit_encoding_derive" -version = "0.10.0" +version = "0.11.0-beta.3" dependencies = [ "amplify", "amplify_syn", @@ -231,6 +232,7 @@ dependencies = [ "sha2", "strict_encoding", "strict_types", + "vesper-lang", ] [[package]] @@ -263,9 +265,9 @@ checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" [[package]] name = "cpufeatures" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] @@ -362,9 +364,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", @@ -394,15 +396,15 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" dependencies = [ "equivalent", "hashbrown", @@ -422,9 +424,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.151" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libredox" @@ -432,7 +434,7 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "libc", "redox_syscall", ] @@ -445,9 +447,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.6.4" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "miow" @@ -498,18 +500,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.71" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -566,9 +568,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", @@ -578,9 +580,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ "aho-corasick", "memchr", @@ -628,44 +630,35 @@ checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "serde" -version = "1.0.193" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.113" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" dependencies = [ "itoa", "ryu", "serde", ] -[[package]] -name = "serde_spanned" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" -dependencies = [ - "serde", -] - [[package]] name = "serde_str_helpers" version = "0.1.2" @@ -676,19 +669,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde_yaml" -version = "0.9.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15e0ef66bf939a7c890a0bf6d5a733c70202225f9888a89ed5c62298b019129" -dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", -] - [[package]] name = "sha2" version = "0.10.8" @@ -710,9 +690,9 @@ dependencies = [ [[package]] name = "strict_encoding" -version = "2.6.1" +version = "2.7.0-beta.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab7b75b4af0aff9dd97b68df262bf0e807b7d007cc860fa217943f898a05a5ab" +checksum = "a12eaa6985afa31deacc86cdc4935a36960ae09131a1f4e1db430127ebc4f05d" dependencies = [ "amplify", "half", @@ -721,9 +701,9 @@ dependencies = [ [[package]] name = "strict_encoding_derive" -version = "2.0.1" +version = "2.7.0-beta.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37064ec285e2a633465eb525c8698eea51373dee889fe310e0d32df8343e7f4f" +checksum = "3b1b064a62618a785e6d8f4df13d905dc335b56400d48f9b4f8b12dcba82b260" dependencies = [ "amplify_syn", "heck", @@ -734,17 +714,18 @@ dependencies = [ [[package]] name = "strict_types" -version = "1.6.3" +version = "2.7.0-beta.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d10cc45e67d452cfe0d87d4714c3250190d97479af3502bbd823651bfe0f505f" +checksum = "d66de5cdf197b68e13fcac9fad7ed288f44052a319a3df3abbaba9c6e52f735b" dependencies = [ "amplify", "baid58", - "base64", + "base85", "half", "indexmap", "sha2", "strict_encoding", + "vesper-lang", ] [[package]] @@ -770,9 +751,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.43" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ "proc-macro2", "quote", @@ -805,56 +786,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.51" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.51" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", -] - -[[package]] -name = "toml" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", + "syn 2.0.48", ] [[package]] @@ -875,18 +822,22 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" -[[package]] -name = "unsafe-libyaml" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" - [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "vesper-lang" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f72ebd3b32f16ee8ace2bd3058c2bfa0f4820992bd4ea86e73ba228bb13dd2b0" +dependencies = [ + "amplify", + "strict_encoding", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -895,9 +846,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.89" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -905,24 +856,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.89" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.89" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -930,22 +881,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.89" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.89" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" +checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" [[package]] name = "winapi" @@ -1034,12 +985,3 @@ name = "windows_x86_64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" - -[[package]] -name = "winnow" -version = "0.5.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5" -dependencies = [ - "memchr", -] diff --git a/Cargo.toml b/Cargo.toml index 52d91e44..53c786bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,11 @@ rust-version = "1.69" # Due to TOML in amplify dependency edition = "2021" license = "Apache-2.0" +[workspace.dependencies] +amplify = "4.6.0" +strict_encoding = "2.7.0-beta.1" +strict_types = "2.7.0-beta.1" + [package] name = "client_side_validation" version = { workspace = true } diff --git a/commit_verify/Cargo.toml b/commit_verify/Cargo.toml index 43b784d4..d142ca37 100644 --- a/commit_verify/Cargo.toml +++ b/commit_verify/Cargo.toml @@ -22,10 +22,11 @@ name = "commit-stl" required-features = ["stl"] [dependencies] -amplify = { version = "4.5.0", features = ["hex", "apfloat"] } -commit_encoding_derive = { version = "0.10.0", path = "derive" } -strict_encoding = "2.6.1" -strict_types = { version = "1.6.3", optional = true } +amplify = { workspace = true, features = ["hex", "apfloat"] } +strict_encoding = { workspace = true } +strict_types = { workspace = true } +vesper-lang = "0.1.0" +commit_encoding_derive = { version = "0.11.0-beta.3", path = "derive" } sha2 = "0.10.8" ripemd = "0.1.3" rand = { version = "0.8.5", optional = true } @@ -38,7 +39,7 @@ rand = "0.8.5" default = ["derive"] all = ["rand", "serde", "stl", "derive"] serde = ["serde_crate", "amplify/serde"] -stl = ["strict_types", "strict_types/base64"] +stl = ["strict_types/base85"] derive = [] [package.metadata.docs.rs] diff --git a/commit_verify/derive/Cargo.toml b/commit_verify/derive/Cargo.toml index f765d644..af53fb4d 100644 --- a/commit_verify/derive/Cargo.toml +++ b/commit_verify/derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "commit_encoding_derive" -version = "0.10.0" +version = { workspace = true } description = "Commitment encoding derivation macros" keywords = ["commitments", "proc-macro"] categories = ["development-tools", "encoding"] @@ -16,7 +16,7 @@ readme = "README.md" proc-macro = true [dependencies] -amplify = "4.0.0" +amplify = { workspace = true } quote = "1" syn = { version = "1", features = ["full"] } proc-macro2 = "1" @@ -25,4 +25,4 @@ amplify_syn = "2.0.0" [dev-dependencies] commit_verify = { path = ".." } compiletest_rs = "0.9.0" -strict_encoding = "2.1.1" +strict_encoding = { workspace = true } diff --git a/commit_verify/derive/src/derive.rs b/commit_verify/derive/src/derive.rs index eceaef5c..31cc8242 100644 --- a/commit_verify/derive/src/derive.rs +++ b/commit_verify/derive/src/derive.rs @@ -19,223 +19,43 @@ // See the License for the specific language governing permissions and // limitations under the License. -use amplify_syn::{DeriveInner, EnumKind, Field, FieldKind, Fields, Items, NamedField, Variant}; -use proc_macro2::{Ident, Span, TokenStream as TokenStream2}; -use quote::ToTokens; -use syn::{Error, Index, Result}; +use proc_macro2::TokenStream as TokenStream2; +use syn::Result; -use crate::params::{CommitDerive, FieldAttr, StrategyAttr}; - -struct DeriveCommit<'a>(&'a CommitDerive); +use crate::params::{CommitDerive, StrategyAttr}; impl CommitDerive { pub fn derive_encode(&self) -> Result { - match self.conf.strategy { - StrategyAttr::CommitEncoding => self.data.derive( - &self.conf.commit_crate, - &ident!(CommitEncode), - &DeriveCommit(self), - ), - other => self.derive_strategy(other), - } - } - - fn derive_strategy(&self, strategy: StrategyAttr) -> Result { let (impl_generics, ty_generics, where_clause) = self.data.generics.split_for_impl(); let trait_crate = &self.conf.commit_crate; + let commitment_id = &self.conf.id; let ident_name = &self.data.name; - let strategy_name = strategy.to_ident(); - - Ok(quote! { - #[automatically_derived] - impl #impl_generics #trait_crate::CommitStrategy for #ident_name #ty_generics #where_clause { - type Strategy = #trait_crate::strategies::#strategy_name; - } - }) - } - - fn derive_fields<'a>( - &self, - fields: impl Iterator, &'a Field)>, - ) -> Result { - let crate_name = &self.conf.commit_crate; - - let conceal_code = if self.conf.conceal { - quote! { - let me = self.conceal(); - } - } else { - quote! { - let me = self; - } - }; - - let mut field_encoding = Vec::new(); - for (no, (field_name, unnamed_field)) in fields.enumerate() { - let kind = match field_name { - Some(_) => FieldKind::Named, - None => FieldKind::Unnamed, - }; - let attr = FieldAttr::with(unnamed_field.attr.clone(), kind)?; - if attr.skip { - continue; - } - let field_name = field_name - .map(Ident::to_token_stream) - .unwrap_or_else(|| Index::from(no).to_token_stream()); - let field = if let Some(tag) = attr.merklize { - quote! { - { - use #crate_name::merkle::MerkleLeaves; - #crate_name::merkle::MerkleNode::merklize(#tag.to_be_bytes(), &me.#field_name).commit_encode(e); - } - } - } else { - quote! { - me.#field_name.commit_encode(e); - } - }; - field_encoding.push(field) - } - - Ok(quote! { - fn commit_encode(&self, e: &mut impl ::std::io::Write) { - use #crate_name::CommitEncode; - #conceal_code - #( #field_encoding )* - } - }) - } -} - -impl DeriveInner for DeriveCommit<'_> { - fn derive_unit_inner(&self) -> Result { - Err(Error::new( - Span::call_site(), - "CommitEncode must not be derived on a unit types. Use just a unit type instead when \ - encoding parent structure.", - )) - } - - fn derive_struct_inner(&self, fields: &Items) -> Result { - self.0 - .derive_fields(fields.iter().map(|f| (Some(&f.name), &f.field))) - } - - fn derive_tuple_inner(&self, fields: &Items) -> Result { - self.0.derive_fields(fields.iter().map(|f| (None, f))) - } - - fn derive_enum_inner(&self, variants: &Items) -> Result { - let crate_name = &self.0.conf.commit_crate; - - if variants.enum_kind() == EnumKind::Primitive { - return Err(Error::new( - Span::call_site(), - "primitive enums can't use `propagate` strategy", - )); - } - let conceal_code = if self.0.conf.conceal { - quote! { - let me = self.conceal(); - } - } else { - quote! { - let me = self; - } + let inner = match self.conf.strategy { + StrategyAttr::Strict => quote! { + engine.commit_to_serialized(self); + }, + StrategyAttr::ConcealStrict => quote! { + use #trait_crate::Conceal; + engine.commit_to_concealed(&self.conceal()); + }, + StrategyAttr::Transparent => quote! { + use amplify::Wrapper; + engine.commit_to_serialized(self.as_inner()); + }, + StrategyAttr::Merklize => quote! { + use amplify::Wrapper; + engine.commit_to_merkle(self.as_inner().merklize()); + }, }; - let mut write_variants = Vec::with_capacity(variants.len()); - for var in variants { - let var_name = &var.name; - match &var.fields { - Fields::Unit => { - write_variants.push(quote! { - Self::#var_name => {}, - }); - } - Fields::Unnamed(fields) if fields.is_empty() => { - write_variants.push(quote! { - Self::#var_name() => {}, - }); - } - Fields::Named(fields) if fields.is_empty() => { - write_variants.push(quote! { - Self::#var_name {} => {}, - }); - } - Fields::Unnamed(fields) => { - let mut field_idx = Vec::with_capacity(fields.len()); - let mut field_fragments = Vec::with_capacity(fields.len()); - for (no, field) in fields.iter().enumerate() { - let index = Ident::new(&format!("_{no}"), Span::call_site()); - let attr = FieldAttr::with(field.attr.clone(), FieldKind::Unnamed)?; - field_idx.push(index.clone()); - if attr.skip { - continue; - } - - if let Some(tag) = attr.merklize { - field_fragments.push(quote! { - MerkleNode::merklize(#tag.to_be_bytes(), #index).commit_encode(e); - }) - } else { - field_fragments.push(quote! { - #index.commit_encode(e); - }) - } - } - write_variants.push(quote! { - Self::#var_name( #( #field_idx ),* ) => { - #( #field_fragments )* - }, - }); - } - Fields::Named(fields) => { - let mut field_name = Vec::with_capacity(fields.len()); - let mut field_fragments = Vec::with_capacity(fields.len()); - for named_field in fields { - let attr = - FieldAttr::with(named_field.field.attr.clone(), FieldKind::Named)?; - let name = &named_field.name; - field_name.push(name.clone()); - if attr.skip { - continue; - } - - if let Some(tag) = attr.merklize { - field_fragments.push(quote! { - MerkleNode::merklize(#tag.to_be_bytes(), #name).commit_encode(e); - }) - } else { - field_fragments.push(quote! { - #name.commit_encode(e); - }) - } - } - - write_variants.push(quote! { - Self::#var_name { #( #field_name ),* } => { - #( #field_fragments )* - }, - }); - } - } - } - Ok(quote! { - #[allow(unused_imports, unused_variables)] - fn commit_encode(&self, e: &mut impl ::std::io::Write) { - use #crate_name::CommitEncode; - use #crate_name::merkle::{MerkleLeaves, MerkleNode}; - use ::strict_encoding::StrictSum; - - #conceal_code - me.variant_ord().commit_encode(e); + #[automatically_derived] + impl #impl_generics #trait_crate::CommitEncode for #ident_name #ty_generics #where_clause { + type CommitmentId = #commitment_id; - match self { - #( #write_variants )* + fn commit_encode(&self, engine: &mut #trait_crate::CommitEngine) { + #inner } } }) diff --git a/commit_verify/derive/src/params.rs b/commit_verify/derive/src/params.rs index e618e7ad..4b8c5678 100644 --- a/commit_verify/derive/src/params.rs +++ b/commit_verify/derive/src/params.rs @@ -19,37 +19,32 @@ // See the License for the specific language governing permissions and // limitations under the License. -use amplify_syn::{ - ArgValueReq, AttrReq, DataType, FieldKind, ListReq, ParametrizedAttr, TypeClass, ValueClass, -}; -use proc_macro2::{Ident, Span}; +use amplify_syn::{ArgValueReq, AttrReq, DataType, ParametrizedAttr, TypeClass}; +use proc_macro2::Span; use quote::ToTokens; -use syn::{DeriveInput, Error, Expr, Path, Result}; +use syn::{DeriveInput, Error, Path, Result}; const ATTR: &str = "commit_encode"; const ATTR_CRATE: &str = "crate"; -const ATTR_CONCEAL: &str = "conceal"; +const ATTR_ID: &str = "id"; const ATTR_STRATEGY: &str = "strategy"; -const ATTR_STRATEGY_COMMIT: &str = "propagate"; const ATTR_STRATEGY_STRICT: &str = "strict"; +const ATTR_STRATEGY_CONCEAL: &str = "conceal"; const ATTR_STRATEGY_TRANSPARENT: &str = "transparent"; -const ATTR_STRATEGY_INTO_U8: &str = "into_u8"; -const ATTR_MERKLIZE: &str = "merklize"; -const ATTR_SKIP: &str = "skip"; +const ATTR_STRATEGY_MERKLIZE: &str = "merklize"; pub struct ContainerAttr { pub commit_crate: Path, pub strategy: StrategyAttr, - pub conceal: bool, + pub id: Path, } #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum StrategyAttr { - CommitEncoding, - StrictEncoding, - ConcealStrictEncoding, + Strict, + ConcealStrict, Transparent, - IntoU8, + Merklize, } impl TryFrom<&Path> for StrategyAttr { @@ -57,82 +52,43 @@ impl TryFrom<&Path> for StrategyAttr { fn try_from(path: &Path) -> Result { match path.to_token_stream().to_string().as_str() { - ATTR_STRATEGY_COMMIT => Ok(StrategyAttr::CommitEncoding), - ATTR_STRATEGY_STRICT => Ok(StrategyAttr::StrictEncoding), + ATTR_STRATEGY_STRICT => Ok(StrategyAttr::Strict), + ATTR_STRATEGY_CONCEAL => Ok(StrategyAttr::ConcealStrict), ATTR_STRATEGY_TRANSPARENT => Ok(StrategyAttr::Transparent), - ATTR_STRATEGY_INTO_U8 => Ok(StrategyAttr::IntoU8), + ATTR_STRATEGY_MERKLIZE => Ok(StrategyAttr::Merklize), unknown => Err(Error::new( Span::call_site(), format!( "invalid commitment encoding value for `strategy` attribute `{unknown}`; only \ - `{ATTR_STRATEGY_TRANSPARENT}`, `{ATTR_STRATEGY_INTO_U8}`, \ - `{ATTR_STRATEGY_COMMIT}`, or `{ATTR_STRATEGY_STRICT}` are allowed" + `{ATTR_STRATEGY_TRANSPARENT}`, `{ATTR_STRATEGY_STRICT}`, \ + `{ATTR_STRATEGY_CONCEAL}`, or `{ATTR_STRATEGY_MERKLIZE}` are allowed" ), )), } } } -impl StrategyAttr { - pub fn to_ident(self) -> Ident { - match self { - StrategyAttr::CommitEncoding => { - panic!("StrategyAttr::CommitEncoding must be derived manually") - } - StrategyAttr::StrictEncoding => ident!(Strict), - StrategyAttr::ConcealStrictEncoding => ident!(ConcealStrict), - StrategyAttr::Transparent => ident!(IntoInner), - StrategyAttr::IntoU8 => ident!(IntoU8), - } - } -} - -pub struct FieldAttr { - pub merklize: Option, - pub skip: bool, -} - impl TryFrom for ContainerAttr { type Error = Error; fn try_from(mut params: ParametrizedAttr) -> Result { - let mut req = AttrReq::with(map![ + let req = AttrReq::with(map![ ATTR_CRATE => ArgValueReq::optional(TypeClass::Path), - ATTR_STRATEGY => ArgValueReq::optional(TypeClass::Path), + ATTR_ID => ArgValueReq::required(TypeClass::Path), + ATTR_STRATEGY => ArgValueReq::required(TypeClass::Path), ]); - req.path_req = ListReq::maybe_one(path!(conceal)); params.check(req)?; - let path = params - .arg_value(ATTR_STRATEGY) - .unwrap_or_else(|_| path!(propagate)); + let path = params.arg_value(ATTR_STRATEGY).expect("must be present"); + let strategy = StrategyAttr::try_from(&path)?; + let id = params.arg_value(ATTR_ID).expect("must be present"); - let mut strategy = StrategyAttr::try_from(&path)?; - let conceal = params.has_verbatim(ATTR_CONCEAL); - if conceal && strategy == StrategyAttr::StrictEncoding { - strategy = StrategyAttr::ConcealStrictEncoding - } Ok(ContainerAttr { commit_crate: params .arg_value(ATTR_CRATE) .unwrap_or_else(|_| path!(commit_verify)), strategy, - conceal, - }) - } -} - -impl FieldAttr { - pub fn with(mut params: ParametrizedAttr, _kind: FieldKind) -> Result { - let mut req = AttrReq::with(map![ - ATTR_MERKLIZE => ArgValueReq::optional(ValueClass::Expr), - ]); - req.path_req = ListReq::maybe_one(path!(skip)); - params.check(req)?; - - Ok(FieldAttr { - skip: params.has_verbatim(ATTR_SKIP), - merklize: params.arg_value(ATTR_MERKLIZE).ok(), + id, }) } } diff --git a/commit_verify/derive/tests/base.rs b/commit_verify/derive/tests/base.rs index 23f87c25..ec9db444 100644 --- a/commit_verify/derive/tests/base.rs +++ b/commit_verify/derive/tests/base.rs @@ -28,83 +28,72 @@ extern crate strict_encoding; mod common; -use std::convert::Infallible; +use std::fmt::Display; -use amplify::confinement::SmallVec; -use amplify::Wrapper; -use commit_verify::merkle::MerkleNode; -use commit_verify::mpc::MERKLE_LNPBP4_TAG; -use commit_verify::{CommitEncode, CommitmentId, Conceal}; +use amplify::{Bytes32, Wrapper}; +use commit_verify::{CommitEncode, CommitId, CommitmentId, Conceal, DigestExt, Sha256}; use strict_encoding::{StrictDecode, StrictDumb, StrictEncode}; const TEST_LIB: &str = "TestLib"; -fn verify_commit(t: T, c: impl AsRef<[u8]>) { - let mut e = Vec::::new(); - t.commit_encode(&mut e); - assert_eq!(e.as_slice(), c.as_ref(), "invalid commitment"); +#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From, Display)] +#[display(inner)] +#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = TEST_LIB)] +struct DumbId( + #[from] + #[from([u8; 32])] + Bytes32, +); + +impl CommitmentId for DumbId { + const TAG: &'static str = ""; +} + +impl From for DumbId { + fn from(value: Sha256) -> Self { value.finish().into() } +} + +fn verify_commit(value: T, expect: &'static str) +where T::CommitmentId: Display { + assert_eq!(&value.commit_id().to_string(), expect, "invalid commitment"); } #[test] fn strategy_transparent() -> common::Result { #[derive(Wrapper, Clone, PartialEq, Eq, Debug, From)] #[derive(CommitEncode)] - #[commit_encode(strategy = transparent)] + #[commit_encode(strategy = transparent, id = DumbId)] struct ShortLen(u16); - verify_commit(ShortLen(0), [0, 0]); + verify_commit(ShortLen(0), "2bb00b2f346511235882255a898a224b6858e18ebec0a11967eb51f0ed1a2ff5"); #[allow(clippy::mixed_case_hex_literals)] - verify_commit(ShortLen(0xFFde), [0xde, 0xFF]); + verify_commit( + ShortLen(0xFFde), + "0290490b549dfcb8a222d42abf53afbd9fadcef480bc61d7a9aeaf19288b394c", + ); Ok(()) } #[test] -fn strategy_into_u8() -> common::Result { +fn strategy_strict_enum() -> common::Result { #[derive(Copy, Clone, PartialEq, Eq, Debug)] + #[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] + #[strict_type(lib = TEST_LIB, tags = repr, into_u8, try_from_u8)] #[derive(CommitEncode)] - #[commit_encode(strategy = into_u8)] + #[commit_encode(strategy = strict, id = DumbId)] #[repr(u8)] enum Prim { + #[strict_type(dumb)] A, B, C, } - #[allow(clippy::from_over_into)] - impl Into for Prim { - fn into(self) -> u8 { self as u8 } - } - verify_commit(Prim::A, [0]); - verify_commit(Prim::B, [1]); - verify_commit(Prim::C, [2]); - - Ok(()) -} - -#[test] -fn strategy_default_tuple() -> common::Result { - #[derive(Clone, PartialEq, Eq, Debug)] - #[derive(CommitEncode)] - struct TaggedInfo(u16, u64); - - verify_commit(TaggedInfo(0xdead, 0xbeefcafebaddafec), [ - 0xad, 0xde, 0xec, 0xaf, 0xdd, 0xba, 0xfe, 0xca, 0xef, 0xbe, - ]); - - Ok(()) -} - -#[test] -fn strategy_commit_tuple() -> common::Result { - #[derive(Clone, PartialEq, Eq, Debug)] - #[derive(CommitEncode)] - #[commit_encode(strategy = propagate)] - struct TaggedInfo(u16, u64); - - verify_commit(TaggedInfo(0xdead, 0xbeefcafebaddafec), [ - 0xad, 0xde, 0xec, 0xaf, 0xdd, 0xba, 0xfe, 0xca, 0xef, 0xbe, - ]); + verify_commit(Prim::A, "82c0f0f259e8cffecead54325fadb48f15a4e761dae5ffaf31209993eacbb24d"); + verify_commit(Prim::B, "6db0981aac502e87a0498d169599ceace4c6480a182590d47e82d63b85cb3c72"); + verify_commit(Prim::C, "e4648d71abe10c0efd626b803ac86d57b1cdc8842f6baa9799ef95cf510784b6"); Ok(()) } @@ -115,52 +104,12 @@ fn strategy_strict_tuple() -> common::Result { #[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] #[strict_type(lib = TEST_LIB)] #[derive(CommitEncode)] - #[commit_encode(strategy = strict)] + #[commit_encode(strategy = strict, id = DumbId)] struct TaggedInfo(u16, u64); - verify_commit(TaggedInfo(0xdead, 0xbeefcafebaddafec), [ - 0xad, 0xde, 0xec, 0xaf, 0xdd, 0xba, 0xfe, 0xca, 0xef, 0xbe, - ]); - - Ok(()) -} - -#[test] -fn strategy_default_struct() -> common::Result { - #[derive(Clone, PartialEq, Eq, Debug)] - #[derive(CommitEncode)] - struct TaggedInfo { - a: u16, - b: u64, - } - verify_commit( - TaggedInfo { - a: 0xdead, - b: 0xbeefcafebaddafec, - }, - [0xad, 0xde, 0xec, 0xaf, 0xdd, 0xba, 0xfe, 0xca, 0xef, 0xbe], - ); - - Ok(()) -} - -#[test] -fn strategy_commit_struct() -> common::Result { - #[derive(Clone, PartialEq, Eq, Debug)] - #[derive(CommitEncode)] - #[commit_encode(strategy = propagate)] - struct TaggedInfo { - a: u16, - b: u64, - } - - verify_commit( - TaggedInfo { - a: 0xdead, - b: 0xbeefcafebaddafec, - }, - [0xad, 0xde, 0xec, 0xaf, 0xdd, 0xba, 0xfe, 0xca, 0xef, 0xbe], + TaggedInfo(0xdead, 0xbeefcafebaddafec), + "8506078e6f47e4b75470cb45a18922785f1a54ba4501473b80ba7b0c363d7490", ); Ok(()) @@ -172,7 +121,7 @@ fn strategy_strict_struct() -> common::Result { #[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] #[strict_type(lib = TEST_LIB)] #[derive(CommitEncode)] - #[commit_encode(strategy = strict)] + #[commit_encode(strategy = strict, id = DumbId)] struct TaggedInfo { a: u16, b: u64, @@ -183,74 +132,12 @@ fn strategy_strict_struct() -> common::Result { a: 0xdead, b: 0xbeefcafebaddafec, }, - [0xad, 0xde, 0xec, 0xaf, 0xdd, 0xba, 0xfe, 0xca, 0xef, 0xbe], + "8506078e6f47e4b75470cb45a18922785f1a54ba4501473b80ba7b0c363d7490", ); Ok(()) } -#[test] -fn tuple_generics() -> common::Result { - #[derive(Clone, PartialEq, Eq, Debug)] - #[derive(CommitEncode)] - struct Pair(A, B); - - #[derive(Clone, PartialEq, Eq, Debug)] - #[derive(CommitEncode)] - struct WhereConstraint, B: From>(A, B) - where - A: CommitEncode + From, - >::Error: From, - B: CommitEncode + Default; - - Ok(()) -} - -#[test] -fn struct_generics() -> common::Result { - #[derive(Clone, PartialEq, Eq, Debug)] - #[derive(CommitEncode)] - struct Field { - tag: u8, - value: V, - } - - #[derive(Clone, PartialEq, Eq, Debug)] - #[derive(CommitEncode)] - struct ComplexField<'a, V: CommitEncode> - where - for<'b> V: From<&'b str>, - &'a V: Default, - { - tag: u8, - value: &'a V, - } - - Ok(()) -} - -#[test] -fn enum_repr() -> common::Result { - #[derive(Copy, Clone, PartialEq, Eq, Debug)] - #[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] - #[strict_type(lib = TEST_LIB, tags = repr, into_u8, try_from_u8)] - #[derive(CommitEncode)] - #[commit_encode(strategy = into_u8)] - #[repr(u16)] - enum Cls { - One = 1, - #[strict_type(dumb)] - Two, - Three, - } - - verify_commit(Cls::One, [1]); - verify_commit(Cls::Two, [2]); - verify_commit(Cls::Three, [3]); - - Ok(()) -} - #[test] fn enum_associated() -> common::Result { #[allow(dead_code)] @@ -258,7 +145,7 @@ fn enum_associated() -> common::Result { #[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] #[strict_type(lib = TEST_LIB, tags = order)] #[derive(CommitEncode)] - #[commit_encode(strategy = strict)] + #[commit_encode(strategy = strict, id = DumbId)] enum Assoc { One { hash: [u8; 32], @@ -271,14 +158,12 @@ fn enum_associated() -> common::Result { Five {}, } - let mut res = vec![0; 33]; - res.extend([1]); verify_commit( Assoc::One { hash: default!(), ord: 1, }, - res, + "18cc83e934de8ad385ce41c8c9b6a2ee3331817907d6ccf8c5ba4ca3570e65a3", ); Ok(()) @@ -291,7 +176,7 @@ fn enum_custom_tags() -> common::Result { #[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] #[strict_type(lib = TEST_LIB, tags = order)] #[derive(CommitEncode)] - #[commit_encode(strategy = strict)] + #[commit_encode(strategy = strict, id = DumbId)] enum Assoc { #[strict_type(tag = 8)] One { hash: [u8; 32], ord: u8 }, @@ -312,58 +197,19 @@ fn enum_custom_tags() -> common::Result { hash: [8; 32], ord: 1, }, - res, + "67e6cd9574e329906d28ce7143aef7124372e04d09bd46b130445fec2baf9fc6", ); Ok(()) } -#[test] -fn enum_propagate() -> common::Result { - #[allow(dead_code)] - #[derive(Copy, Clone, PartialEq, Eq, Debug)] - #[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] - #[strict_type(lib = TEST_LIB, tags = order)] - #[derive(CommitEncode)] - enum Assoc { - #[strict_type(tag = 8)] - One { hash: [u8; 32], ord: u8 }, - #[strict_type(tag = 2)] - Two(u8, u16, #[commit_encode(skip)] u32), - #[strict_type(dumb, tag = 3)] - Three, - #[strict_type(tag = 4)] - Four(), - #[strict_type(tag = 5)] - Five {}, - Six { - a: u8, - #[commit_encode(skip)] - b: u16, - }, - } - - let mut res = vec![8; 33]; - res.extend([1]); - verify_commit( - Assoc::One { - hash: [8; 32], - ord: 1, - }, - res, - ); - verify_commit(Assoc::Two(0xfe, 0xdead, 0xbeefcafe), [2, 0xfe, 0xad, 0xde]); - - Ok(()) -} - #[test] fn conceal() -> common::Result { #[derive(Clone, PartialEq, Eq, Debug)] #[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] #[strict_type(lib = TEST_LIB, tags = order, dumb = { Self::Concealed(0) })] #[derive(CommitEncode)] - #[commit_encode(conceal, strategy = strict)] + #[commit_encode(strategy = conceal, id = DumbId)] enum Data { Revealed(u128), Concealed(u8), @@ -374,32 +220,15 @@ fn conceal() -> common::Result { fn conceal(&self) -> Self { Self::Concealed(0xde) } } - verify_commit(Data::Revealed(0xcafe1234), [1, 0xde]); - - Ok(()) -} - -#[test] -fn skip() -> common::Result { - #[derive(Clone, PartialEq, Eq, Debug)] - #[derive(CommitEncode)] - struct Data { - data: u8, - #[commit_encode(skip)] - bulletproof: Vec, - } - verify_commit( - Data { - data: 0xfe, - bulletproof: vec![0xde, 0xad], - }, - [0xfe], + Data::Revealed(0xcafe1234), + "fd5ee38918347000fc3cbf31def233b226d14a47bbc6bac18fd6389c3fd16d2e", ); Ok(()) } +/* TODO: Refactor #[test] fn merklize() -> common::Result { #[derive(Clone, PartialEq, Eq, Debug)] @@ -414,7 +243,7 @@ fn merklize() -> common::Result { pub struct Leaf(u16); impl CommitmentId for Leaf { const TAG: [u8; 32] = [0u8; 32]; - type Id = MerkleNode; + type Id = MerkleHash; } let test_vec = small_vec!(Leaf(0), Leaf(1), Leaf(2), Leaf(3)); @@ -422,8 +251,9 @@ fn merklize() -> common::Result { Tree { leaves: test_vec.clone(), }, - MerkleNode::merklize(MERKLE_LNPBP4_TAG.to_be_bytes(), &test_vec).as_slice(), + MerkleHash::merklize(&test_vec).as_slice(), ); Ok(()) } + */ diff --git a/commit_verify/src/commit.rs b/commit_verify/src/commit.rs index ea34c727..e0aee7c6 100644 --- a/commit_verify/src/commit.rs +++ b/commit_verify/src/commit.rs @@ -21,11 +21,6 @@ //! Base commit-verify scheme interface. -use amplify::Bytes32; -use sha2::Sha256; -use strict_encoding::{StrictEncode, StrictWriter}; - -use crate::digest::DigestExt; use crate::CommitmentProtocol; /// Error during commitment verification @@ -82,22 +77,6 @@ where Self: Eq + Sized } } -/// Commitment protocol which writes strict-encoded data into a hasher. -pub struct StrictEncodedProtocol; - -impl CommitmentProtocol for StrictEncodedProtocol {} - -impl CommitVerify for Bytes32 -where T: StrictEncode -{ - fn commit(msg: &T) -> Self { - let mut engine = Sha256::from_tag(*b"urn:lnpbp:lnpbp0007:strict:v01#A"); - let w = StrictWriter::with(u32::MAX as usize, &mut engine); - msg.strict_encode(w).ok(); - engine.finish().into() - } -} - /// Helpers for writing test functions working with commit-verify scheme #[cfg(test)] pub(crate) mod test_helpers { @@ -148,34 +127,3 @@ pub(crate) mod test_helpers { }); } } - -#[cfg(test)] -mod test { - use core::fmt::Debug; - use core::hash::Hash; - - use amplify::confinement::SmallVec; - use sha2::Digest; - - use super::test_helpers::*; - use super::*; - use crate::test_helpers::gen_messages; - use crate::UntaggedProtocol; - - #[derive(Debug, Display, Error)] - #[display(Debug)] - struct Error; - - #[derive(Clone, PartialEq, Eq, Debug, Hash)] - struct DummyHashCommitment([u8; 32]); - impl CommitVerify for DummyHashCommitment - where T: AsRef<[u8]> - { - fn commit(msg: &T) -> Self { Self(Sha256::digest(msg.as_ref()).into()) } - } - - #[test] - fn test_commit_verify() { - commit_verify_suite::, DummyHashCommitment>(gen_messages()); - } -} diff --git a/commit_verify/src/convolve.rs b/commit_verify/src/convolve.rs index 0aae5cc8..e6e91e8b 100644 --- a/commit_verify/src/convolve.rs +++ b/commit_verify/src/convolve.rs @@ -21,7 +21,7 @@ //! Convolved commitments (convolve-commit-verify scheme). -use crate::{CommitEncode, CommitmentProtocol, VerifyEq}; +use crate::{CommitmentProtocol, VerifyEq}; /// Error during commitment verification #[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)] @@ -47,7 +47,6 @@ pub trait ConvolveCommitProof where Self: Sized + VerifyEq, Source: ConvolveCommit, - Msg: CommitEncode, Protocol: CommitmentProtocol, { /// Supplement is a part of the proof data provided during commitment @@ -169,7 +168,6 @@ where pub trait ConvolveCommit where Self: Sized, - Msg: CommitEncode, Proof: ConvolveCommitProof, Protocol: CommitmentProtocol, { diff --git a/commit_verify/src/embed.rs b/commit_verify/src/embed.rs index de056af7..3009e717 100644 --- a/commit_verify/src/embed.rs +++ b/commit_verify/src/embed.rs @@ -21,7 +21,7 @@ //! Embedded commitments (commit-embed-verify scheme). -use crate::{CommitEncode, CommitmentProtocol}; +use crate::CommitmentProtocol; /// Error during commitment verification #[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error, From)] @@ -64,7 +64,6 @@ pub trait EmbedCommitProof where Self: Sized + VerifyEq, Container: EmbedCommitVerify, - Msg: CommitEncode, Protocol: CommitmentProtocol, { /// Restores original container before the commitment from the proof data @@ -127,7 +126,6 @@ where pub trait EmbedCommitVerify where Self: Sized, - Msg: CommitEncode, Protocol: CommitmentProtocol, { /// The proof of the commitment produced as a result of @@ -209,7 +207,7 @@ pub(crate) mod test_helpers { /// and provided container. pub fn embed_commit_verify_suite(messages: Vec, container: Container) where - Msg: AsRef<[u8]> + CommitEncode + Eq + Clone, + Msg: AsRef<[u8]> + Eq + Clone, Container: EmbedCommitVerify + Eq + Hash + Debug + Clone, Container::Proof: Clone, { @@ -255,7 +253,7 @@ pub(crate) mod test_helpers { /// and provided container. pub fn convolve_commit_verify_suite(messages: Vec, container: Source) where - Msg: AsRef<[u8]> + CommitEncode + Eq + Clone, + Msg: AsRef<[u8]> + Eq + Clone, Source: ConvolveCommit + VerifyEq + Eq + Hash + Debug + Clone, Source::Commitment: Clone + Debug + Hash + VerifyEq + Eq, [u8; 32]: ConvolveCommitProof, @@ -302,7 +300,7 @@ pub(crate) mod test_helpers { mod test { use core::fmt::Debug; - use amplify::confinement::{SmallVec, U32}; + use amplify::confinement::{SmallBlob, SmallVec, U32}; use sha2::Sha256; use super::test_helpers::*; @@ -316,13 +314,13 @@ mod test { struct Error; #[derive(Clone, PartialEq, Eq, Debug, Hash)] - struct DummyVec(SmallVec); + struct DummyVec(SmallBlob); #[derive(Clone, PartialEq, Eq, Debug, Hash)] - struct DummyProof(SmallVec); + struct DummyProof(SmallBlob); impl EmbedCommitProof for DummyProof - where T: AsRef<[u8]> + Clone + CommitEncode + where T: AsRef<[u8]> + Clone { fn restore_original_container( &self, @@ -333,7 +331,7 @@ mod test { } impl EmbedCommitVerify for DummyVec - where T: AsRef<[u8]> + Clone + CommitEncode + where T: AsRef<[u8]> + Clone { type Proof = DummyProof; type CommitError = Error; @@ -347,7 +345,7 @@ mod test { } impl ConvolveCommit for DummyVec - where T: AsRef<[u8]> + Clone + CommitEncode + where T: AsRef<[u8]> + Clone { type Commitment = [u8; 32]; type CommitError = Error; @@ -365,7 +363,7 @@ mod test { } impl ConvolveCommitProof for [u8; 32] - where T: AsRef<[u8]> + Clone + CommitEncode + where T: AsRef<[u8]> + Clone { type Suppl = [u8; 32]; diff --git a/commit_verify/src/encode.rs b/commit_verify/src/encode.rs deleted file mode 100644 index 5c592d02..00000000 --- a/commit_verify/src/encode.rs +++ /dev/null @@ -1,344 +0,0 @@ -// Client-side-validation foundation libraries. -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2023 by -// Dr. Maxim Orlovsky -// -// Copyright (C) 2019-2023 LNP/BP Standards Association. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Encoding and data preparation for commitment procedures in -//! client-side-validation as defined by [LNPBP-9] standard. -//! -//! Client-side-validation commitment process requires special encoding of -//! the data. While [`strict_encoding`] is the main standard for atomic data -//! types in client-side-validation world and should be used during internal -//! protocol-specific data validation, commitments may require processes of -//! merklization arrays of data items, or hiding confidential parts of the -//! data via hashing, pedersen commitments and so on. Thus, additionally to -//! strict encoding, a set of different encodings and data convolution and -//! hiding procedures are defined in `commit_verify` library. This includes: -//! - **merklization** procedure, operating special types of tagged hashes and -//! committing to the depth of each node; -//! - **conceal** procedure, making data confidential (transforming types into -//! confidential versions). -//! -//! [`CommitEncode`] is the main trait which should be implemented for all data -//! types participating in client-side-validation. It takes [`io::Write`] -//! encoder and serializes into it data which corresponds to the exact -//! commitment. These data mus be concealed, if needed, merkelized etc. The -//! encoder is usually a hash function of specific type, which may be keyed with -//! a tag. -//! -//! Main patterns of [`CommitEncode`] implementation can be automatically -//! applied to a type by using [`amplify::strategy`] adaptor. These patterns -//! include: -//! - [`strategies::IntoU8`], which converts the type into U8 using `Into` trait -//! and serializes it. -//! - [`strategies::IntoInner`], which converts the type into inner type using -//! `Wrapper` trait and serializes it. -//! - [`strategies::Strict`], which serializes the type into the hasher using -//! [`strict_encoding::StrictEncode`] implementation for the type. -//! - [`strategies::ConcealStrict`] does the same, but runs [`Conceal::conceal`] -//! on the self first, and serializes the result using strict encoding. -//! - [`strategies::Id`] can apply to types implementing [`CommitmentId`]. It -//! computes a single id for the type and then serializes it into the hasher. -//! - [`strategies::Merklize`] can apply to types implementing -//! [`super::merkle::MerkleLeaves`]. It merkelizes data provided by this trait -//! and serializes merkle root into the hasher. [`CommitmentId`] should be -//! implemented for types which has external identifiers -//! -//! [LNPBP-9]: https://github.com/LNP-BP/LNPBPs/blob/master/lnpbp-0009.md - -use std::io; -use std::marker::PhantomData; - -use crate::id::CommitmentId; -use crate::Conceal; - -/// Prepares the data to the *consensus commit* procedure by first running -/// necessary conceal and merklization procedures, and them performing strict -/// encoding for the resulted data. -pub trait CommitEncode { - /// Encodes the data for the commitment by writing them directly into a - /// [`io::Write`] writer instance - fn commit_encode(&self, e: &mut impl io::Write); -} - -/// Convenience macro for commit-encoding list of the data -#[macro_export] -macro_rules! commit_encode_list { - ( $encoder:ident; $($item:expr),+ ) => { - { - let mut len = 0usize; - $( - len += $item.commit_encode(&mut $encoder); - )+CommitId - len - } - } -} - -/// Marker trait defining specific encoding strategy which should be used for -/// automatic implementation of [`CommitEncode`]. -pub trait CommitStrategy { - /// Specific strategy. List of supported strategies: - /// - [`strategies::IntoU8`] - /// - [`strategies::IntoInner`] - /// - [`strategies::Strict`] - /// - [`strategies::ConcealStrict`] - /// - [`strategies::Id`] - /// - [`strategies::Merklize`] - type Strategy; -} - -/// Strategies simplifying implementation of [`CommitEncode`] trait. -/// -/// Implemented after concept by Martin Habovštiak -pub mod strategies { - use amplify::confinement::Confined; - use amplify::num::apfloat::ieee; - use amplify::num::{i1024, i256, i512, u1024, u24, u256, u512}; - use amplify::{Bytes32, Holder, Wrapper}; - use strict_encoding::{StrictEncode, StrictWriter}; - - use super::*; - use crate::merkle::{MerkleLeaves, MerkleNode}; - - /// Used only internally for blank implementation on reference types. - #[doc(hidden)] - pub enum AsRef {} - - /// Commits to the value by converting it into `u8` type. Useful for enum - /// types. - /// - /// Can apply only to types implementing `Into`. - pub enum IntoU8 {} - - /// Commits to the value by converting it into inner type. Useful for - /// newtypes. - /// - /// Can apply only to types implementing [`Wrapper`]. - pub enum IntoInner {} - - /// Commits to the value by running strict *encoding procedure* on the raw - /// data without any pre-processing. - /// - /// Should not be used for array types (require manual [`CommitEncode`] - /// implementation involving merklization) or data which may contain - /// confidential or sensitive information (in such case use - /// [`ConcealStrict`]). - /// - /// Can apply only to types implementing [`StrictEncode`] trait. - pub enum Strict {} - - /// Commits to the value data by first converting them into confidential - /// version (*concealing*) by running [`Conceal::conceal`] - /// first and returning its result serialized with strict encoding - /// rules. - /// - /// Can apply only to types implementing [`Conceal`] trait, where - /// [`Conceal::Concealed`] type must also implement [`StrictEncode`] trait. - pub enum ConcealStrict {} - - /// Commits to the value via commitment id of the type, which is serialized - /// into the hasher. - /// - /// Can apply only to types implementing [`CommitmentId`] trait. - pub enum Id {} - - /// Commits to the value by merklizing data provided by [`MerkleLeaves`] - /// implementation and serializes merkle root into the hasher. - /// - /// Can apply only to types implementing [`MerkleLeaves`] trait. - pub enum Merklize {} - - impl<'a, T> CommitEncode for Holder<&'a T, IntoU8> - where T: Copy + Into - { - fn commit_encode(&self, e: &mut impl io::Write) { - let raw = **self.as_type(); - e.write_all(&[raw.into()]).ok(); - } - } - - impl<'a, T> CommitEncode for Holder<&'a T, AsRef> - where T: CommitEncode - { - fn commit_encode(&self, e: &mut impl io::Write) { self.as_type().commit_encode(e); } - } - - impl<'a, T> CommitEncode for Holder<&'a T, IntoInner> - where - T: Wrapper, - T::Inner: CommitEncode, - { - fn commit_encode(&self, e: &mut impl io::Write) { - self.as_type().as_inner().commit_encode(e); - } - } - - impl<'a, T> CommitEncode for Holder<&'a T, Strict> - where T: StrictEncode - { - fn commit_encode(&self, e: &mut impl io::Write) { - let w = StrictWriter::with(u32::MAX as usize, e); - self.as_type().strict_encode(w).ok(); - } - } - - impl<'a, T> CommitEncode for Holder<&'a T, ConcealStrict> - where - T: Conceal, - T::Concealed: StrictEncode, - { - fn commit_encode(&self, e: &mut impl io::Write) { - let w = StrictWriter::with(u32::MAX as usize, e); - self.as_type().conceal().strict_encode(w).ok(); - } - } - impl<'a, T> CommitEncode for Holder<&'a T, Id> - where - T: CommitmentId, - T::Id: Into<[u8; 32]>, - { - fn commit_encode(&self, e: &mut impl io::Write) { - e.write_all(&self.as_type().commitment_id().into()).ok(); - } - } - - impl<'a, T, const MERKLE_ROOT_TAG: u128> CommitEncode for Holder<&'a T, Merklize> - where T: MerkleLeaves - { - fn commit_encode(&self, e: &mut impl io::Write) { - MerkleNode::merklize(MERKLE_ROOT_TAG.to_be_bytes(), *self.as_type()).commit_encode(e); - } - } - - impl CommitEncode for T - where - T: CommitStrategy, - for<'a> Holder<&'a T, T::Strategy>: CommitEncode, - { - fn commit_encode(&self, e: &mut impl io::Write) { Holder::new(self).commit_encode(e) } - } - - impl CommitStrategy for bool { - type Strategy = Strict; - } - impl CommitStrategy for u8 { - type Strategy = Strict; - } - impl CommitStrategy for u16 { - type Strategy = Strict; - } - impl CommitStrategy for u24 { - type Strategy = Strict; - } - impl CommitStrategy for u32 { - type Strategy = Strict; - } - impl CommitStrategy for u64 { - type Strategy = Strict; - } - impl CommitStrategy for u128 { - type Strategy = Strict; - } - impl CommitStrategy for u256 { - type Strategy = Strict; - } - impl CommitStrategy for u512 { - type Strategy = Strict; - } - impl CommitStrategy for u1024 { - type Strategy = Strict; - } - impl CommitStrategy for i8 { - type Strategy = Strict; - } - impl CommitStrategy for i16 { - type Strategy = Strict; - } - impl CommitStrategy for i32 { - type Strategy = Strict; - } - impl CommitStrategy for i64 { - type Strategy = Strict; - } - impl CommitStrategy for i128 { - type Strategy = Strict; - } - impl CommitStrategy for i256 { - type Strategy = Strict; - } - impl CommitStrategy for i512 { - type Strategy = Strict; - } - impl CommitStrategy for i1024 { - type Strategy = Strict; - } - - impl CommitStrategy for ieee::Half { - type Strategy = Strict; - } - impl CommitStrategy for ieee::Single { - type Strategy = Strict; - } - impl CommitStrategy for ieee::Double { - type Strategy = Strict; - } - impl CommitStrategy for ieee::X87DoubleExtended { - type Strategy = Strict; - } - impl CommitStrategy for ieee::Quad { - type Strategy = Strict; - } - impl CommitStrategy for ieee::Oct { - type Strategy = Strict; - } - - impl CommitStrategy for Bytes32 { - type Strategy = IntoInner; - } - - impl CommitStrategy for Box - where T: CommitStrategy - { - type Strategy = T::Strategy; - } - impl CommitStrategy for Option - where T: CommitStrategy - { - type Strategy = T::Strategy; - } - impl CommitStrategy for Confined, MIN, MAX> { - type Strategy = Strict; - } - - impl CommitStrategy for &T - where T: CommitEncode - { - type Strategy = AsRef; - } -} - -impl CommitEncode for [u8; 32] { - fn commit_encode(&self, e: &mut impl io::Write) { e.write_all(self).ok(); } -} - -impl CommitEncode for PhantomData { - fn commit_encode(&self, _: &mut impl io::Write) { /* nothing to do */ - } -} diff --git a/commit_verify/src/id.rs b/commit_verify/src/id.rs index 319cdf84..600e5470 100644 --- a/commit_verify/src/id.rs +++ b/commit_verify/src/id.rs @@ -19,27 +19,295 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::collections::{BTreeMap, BTreeSet}; +use std::fmt::{self, Display, Formatter}; +use std::hash::Hash; + +use amplify::confinement::{Confined, TinyVec, U64 as U64MAX}; +use amplify::Bytes32; use sha2::Sha256; +use strict_encoding::{Sizing, StreamWriter, StrictDumb, StrictEncode, StrictType}; +use strict_types::typesys::TypeFqn; + +use crate::{Conceal, DigestExt, MerkleHash, MerkleLeaves, LIB_NAME_COMMIT_VERIFY}; + +const COMMIT_MAX_LEN: usize = U64MAX; + +#[derive(Clone, Eq, PartialEq, Hash, Debug)] +pub enum CommitColType { + List, + Set, + Map { key: TypeFqn }, +} + +#[derive(Clone, Eq, PartialEq, Hash, Debug)] +pub enum CommitStep { + Serialized(TypeFqn), + Collection(CommitColType, Sizing, TypeFqn), + Hashed(TypeFqn), + Merklized(TypeFqn), + Concealed(TypeFqn), +} + +#[derive(Clone, Debug)] +pub struct CommitEngine { + finished: bool, + hasher: Sha256, + layout: TinyVec, +} + +fn commitment_fqn() -> TypeFqn { + TypeFqn::with( + libname!(T::STRICT_LIB_NAME), + T::strict_name().expect("commit encoder can commit only to named types"), + ) +} + +impl CommitEngine { + pub fn new(tag: &'static str) -> Self { + Self { + finished: false, + hasher: Sha256::from_tag(tag), + layout: empty!(), + } + } + + fn inner_commit_to(&mut self, value: &T) { + debug_assert!(!self.finished); + let writer = StreamWriter::new::(&mut self.hasher); + let ok = value.strict_write(writer).is_ok(); + debug_assert!(ok); + } + + pub fn commit_to_serialized(&mut self, value: &T) { + let fqn = commitment_fqn::(); + debug_assert!( + Some(&fqn.name) != MerkleHash::strict_name().as_ref() || + fqn.lib.as_str() != MerkleHash::STRICT_LIB_NAME, + "do not use commit_to_serialized for merklized collections, use commit_to_merkle \ + instead" + ); + debug_assert!( + Some(&fqn.name) != StrictHash::strict_name().as_ref() || + fqn.lib.as_str() != StrictHash::STRICT_LIB_NAME, + "do not use commit_to_serialized for StrictHash types, use commit_to_hash instead" + ); + self.layout + .push(CommitStep::Serialized(fqn)) + .expect("too many fields for commitment"); + + self.inner_commit_to::<_, COMMIT_MAX_LEN>(&value); + } + + pub fn commit_to_option(&mut self, value: &Option) { + let fqn = commitment_fqn::(); + self.layout + .push(CommitStep::Serialized(fqn)) + .expect("too many fields for commitment"); + + self.inner_commit_to::<_, COMMIT_MAX_LEN>(&value); + } + + pub fn commit_to_hash + StrictType>( + &mut self, + value: T, + ) { + let fqn = commitment_fqn::(); + self.layout + .push(CommitStep::Hashed(fqn)) + .expect("too many fields for commitment"); + + self.inner_commit_to::<_, 32>(&value.commit_id()); + } + + pub fn commit_to_merkle(&mut self, value: &T) + where T::Leaf: StrictType { + let fqn = commitment_fqn::(); + self.layout + .push(CommitStep::Merklized(fqn)) + .expect("too many fields for commitment"); + + let root = MerkleHash::merklize(value); + self.inner_commit_to::<_, 32>(&root); + } + + pub fn commit_to_concealed(&mut self, value: &T) + where + T: StrictType, + T::Concealed: StrictEncode, + { + let fqn = commitment_fqn::(); + self.layout + .push(CommitStep::Concealed(fqn)) + .expect("too many fields for commitment"); + + let concealed = value.conceal(); + self.inner_commit_to::<_, COMMIT_MAX_LEN>(&concealed); + } + + pub fn commit_to_list( + &mut self, + collection: &Confined, MIN, MAX>, + ) where + T: StrictEncode + StrictDumb, + { + let fqn = commitment_fqn::(); + let step = + CommitStep::Collection(CommitColType::List, Sizing::new(MIN as u64, MAX as u64), fqn); + self.layout + .push(step) + .expect("too many fields for commitment"); + self.inner_commit_to::<_, COMMIT_MAX_LEN>(&collection); + } + + pub fn commit_to_set( + &mut self, + collection: &Confined, MIN, MAX>, + ) where + T: Ord + StrictEncode + StrictDumb, + { + let fqn = commitment_fqn::(); + let step = + CommitStep::Collection(CommitColType::Set, Sizing::new(MIN as u64, MAX as u64), fqn); + self.layout + .push(step) + .expect("too many fields for commitment"); + self.inner_commit_to::<_, COMMIT_MAX_LEN>(&collection); + } -use crate::digest::DigestExt; -use crate::CommitEncode; + pub fn commit_to_map( + &mut self, + collection: &Confined, MIN, MAX>, + ) where + K: Ord + Hash + StrictEncode + StrictDumb, + V: StrictEncode + StrictDumb, + { + let key_fqn = commitment_fqn::(); + let val_fqn = commitment_fqn::(); + let step = CommitStep::Collection( + CommitColType::Map { key: key_fqn }, + Sizing::new(MIN as u64, MAX as u64), + val_fqn, + ); + self.layout + .push(step) + .expect("too many fields for commitment"); + self.inner_commit_to::<_, COMMIT_MAX_LEN>(&collection); + } + + pub fn as_layout(&mut self) -> &[CommitStep] { + self.finished = true; + self.layout.as_ref() + } + + pub fn into_layout(self) -> TinyVec { self.layout } + + pub fn set_finished(&mut self) { self.finished = true; } + + pub fn finish(self) -> Sha256 { self.hasher } + + pub fn finish_layout(self) -> (Sha256, TinyVec) { (self.hasher, self.layout) } +} + +/// Prepares the data to the *consensus commit* procedure by first running +/// necessary conceal and merklization procedures, and them performing strict +/// encoding for the resulted data. +pub trait CommitEncode { + /// Type of the resulting commitment. + type CommitmentId: CommitmentId; + + /// Encodes the data for the commitment by writing them directly into a + /// [`std::io::Write`] writer instance + fn commit_encode(&self, e: &mut CommitEngine); +} + +#[derive(Getters, Clone, Eq, PartialEq, Hash, Debug)] +pub struct CommitLayout { + idty: TypeFqn, + #[getter(as_copy)] + tag: &'static str, + fields: TinyVec, +} + +impl Display for CommitLayout { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(&self.to_vesper().display(), f) + } +} + +pub trait CommitmentId: Copy + Ord + From + StrictType { + const TAG: &'static str; +} + +pub trait CommitmentLayout: CommitEncode { + fn commitment_layout() -> CommitLayout; +} + +impl CommitmentLayout for T +where T: CommitEncode + StrictDumb +{ + fn commitment_layout() -> CommitLayout { + let dumb = Self::strict_dumb(); + let fields = dumb.commit().into_layout(); + CommitLayout { + idty: TypeFqn::with( + libname!(Self::CommitmentId::STRICT_LIB_NAME), + Self::CommitmentId::strict_name() + .expect("commitment types must have explicit type name"), + ), + tag: T::CommitmentId::TAG, + fields, + } + } +} /// High-level API used in client-side validation for producing a single /// commitment to the data, which includes running all necessary procedures like /// concealment with [`crate::Conceal`], merklization, strict encoding, /// wrapped into [`CommitEncode`], followed by the actual commitment to its /// output. -pub trait CommitmentId: CommitEncode { - const TAG: [u8; 32]; - - /// Type of the resulting commitment. - type Id: From<[u8; 32]>; +/// +/// The trait is separate from the `CommitEncode` to prevent custom +/// implementation of its methods, since `CommitId` can't be manually +/// implemented for any type since it has a generic blanket implementation. +pub trait CommitId: CommitEncode { + #[doc = hidden] + fn commit(&self) -> CommitEngine; /// Performs commitment to client-side-validated data - #[inline] - fn commitment_id(&self) -> Self::Id { - let mut engine = Sha256::from_tag(Self::TAG); + fn commit_id(&self) -> Self::CommitmentId; +} + +impl CommitId for T { + fn commit(&self) -> CommitEngine { + let mut engine = CommitEngine::new(T::CommitmentId::TAG); self.commit_encode(&mut engine); - engine.finish().into() + engine.set_finished(); + engine } + + fn commit_id(&self) -> Self::CommitmentId { self.commit().finish().into() } +} + +#[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] +#[wrapper(Deref, BorrowSlice, Display, FromStr, Hex, Index, RangeOps)] +#[derive(StrictDumb, strict_encoding::StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_COMMIT_VERIFY)] +#[cfg_attr( + feature = "serde", + derive(Serialize, Deserialize), + serde(crate = "serde_crate", transparent) +)] +pub struct StrictHash( + #[from] + #[from([u8; 32])] + Bytes32, +); + +impl CommitmentId for StrictHash { + const TAG: &'static str = "urn:ubideco:strict-types:value-hash#2024-02-10"; +} + +impl From for StrictHash { + fn from(hash: Sha256) -> Self { hash.finish().into() } } diff --git a/commit_verify/src/lib.rs b/commit_verify/src/lib.rs index ffb5ac96..6e9d0e2c 100644 --- a/commit_verify/src/lib.rs +++ b/commit_verify/src/lib.rs @@ -49,7 +49,6 @@ mod commit; mod conceal; mod convolve; mod embed; -mod encode; mod id; #[cfg(feature = "stl")] pub mod stl; @@ -57,14 +56,18 @@ pub mod stl; pub mod merkle; pub mod mpc; mod digest; +pub mod vesper; -pub use commit::{CommitVerify, StrictEncodedProtocol, TryCommitVerify, VerifyError}; +pub use commit::{CommitVerify, TryCommitVerify, VerifyError}; pub use conceal::Conceal; pub use convolve::{ConvolveCommit, ConvolveCommitProof, ConvolveVerifyError}; pub use digest::{Digest, DigestExt, Ripemd160, Sha256}; pub use embed::{EmbedCommitProof, EmbedCommitVerify, EmbedVerifyError, VerifyEq}; -pub use encode::{strategies, CommitEncode, CommitStrategy}; -pub use id::CommitmentId; +pub use id::{ + CommitColType, CommitEncode, CommitEngine, CommitId, CommitLayout, CommitStep, CommitmentId, + CommitmentLayout, StrictHash, +}; +pub use merkle::{MerkleBuoy, MerkleHash, MerkleLeaves, MerkleNode, NodeBranching}; pub const LIB_NAME_COMMIT_VERIFY: &str = "CommitVerify"; diff --git a/commit_verify/src/merkle.rs b/commit_verify/src/merkle.rs index f4d7e752..90e87d54 100644 --- a/commit_verify/src/merkle.rs +++ b/commit_verify/src/merkle.rs @@ -21,24 +21,27 @@ use core::{iter, slice}; use std::collections::{btree_set, BTreeSet}; -use std::io::Write; use std::ops::SubAssign; use amplify::confinement::Confined; use amplify::num::{u256, u5}; use amplify::{Bytes32, Wrapper}; use sha2::Sha256; +use strict_encoding::StrictEncode; use crate::digest::DigestExt; -use crate::encode::{strategies, CommitStrategy}; -use crate::{CommitEncode, CommitmentId, LIB_NAME_COMMIT_VERIFY}; +use crate::{CommitId, CommitmentId, LIB_NAME_COMMIT_VERIFY}; -/// Type of a merkle node branching. +/// Type of merkle node branching. #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_COMMIT_VERIFY, tags = repr, into_u8, try_from_u8)] +#[repr(u8)] pub enum NodeBranching { /// Void node: virtual node with no leafs. /// /// Used when the total width of the three is not a power two. + #[strict_type(dumb)] Void = 0x00, /// Node having just a single leaf, with the second branch being void. @@ -48,12 +51,52 @@ pub enum NodeBranching { Branch = 0x02, } -impl From for u8 { - fn from(value: NodeBranching) -> Self { value as u8 } +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = LIB_NAME_COMMIT_VERIFY)] +#[derive(CommitEncode)] +#[commit_encode(crate = crate, strategy = strict, id = MerkleHash)] +pub struct MerkleNode { + pub branching: NodeBranching, + pub depth: u8, + pub width: u256, + pub node1: MerkleHash, + pub node2: MerkleHash, } -impl CommitStrategy for NodeBranching { - type Strategy = strategies::IntoU8; +impl MerkleNode { + pub fn void(depth: impl Into, width: impl Into) -> Self { + Self::with(NodeBranching::Void, depth, width, VIRTUAL_LEAF, VIRTUAL_LEAF) + } + + pub fn single(depth: impl Into, width: impl Into, node: MerkleHash) -> Self { + Self::with(NodeBranching::Single, depth, width, node, VIRTUAL_LEAF) + } + + pub fn branches( + depth: impl Into, + width: impl Into, + node1: MerkleHash, + node2: MerkleHash, + ) -> Self { + Self::with(NodeBranching::Branch, depth, width, node1, node2) + } + + fn with( + branching: NodeBranching, + depth: impl Into, + width: impl Into, + node1: MerkleHash, + node2: MerkleHash, + ) -> Self { + Self { + branching, + depth: depth.into(), + width: width.into(), + node1, + node2, + } + } } /// Source data for creation of multi-message commitments according to [LNPBP-4] @@ -63,109 +106,83 @@ impl CommitStrategy for NodeBranching { #[derive(Wrapper, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, From)] #[wrapper(Deref, BorrowSlice, Display, FromStr, Hex, Index, RangeOps)] #[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] -#[strict_type(lib = LIB_NAME_COMMIT_VERIFY, dumb = MerkleNode(default!()))] -#[derive(CommitEncode)] -#[commit_encode(crate = crate, strategy = strict)] +#[strict_type(lib = LIB_NAME_COMMIT_VERIFY)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate", transparent) )] -pub struct MerkleNode( +pub struct MerkleHash( #[from] #[from([u8; 32])] Bytes32, ); -impl CommitmentId for MerkleNode { - const TAG: [u8; 32] = *b"urn:lnpbp:lnpbp0081:node:v01#23A"; - type Id = Self; +impl CommitmentId for MerkleHash { + const TAG: &'static str = "urn:ubideco:merkle:node#2024-01-31"; } -const VIRTUAL_LEAF: MerkleNode = MerkleNode(Bytes32::from_array([0xFF; 32])); +impl From for MerkleHash { + fn from(hash: Sha256) -> Self { hash.finish().into() } +} -impl MerkleNode { - pub fn void(tag: [u8; 16], depth: impl Into, width: impl Into) -> Self { - let virt = VIRTUAL_LEAF; - Self::with(NodeBranching::Void, tag, depth, width, virt, virt) - } +const VIRTUAL_LEAF: MerkleHash = MerkleHash(Bytes32::from_array([0xFF; 32])); - pub fn single( - tag: [u8; 16], - depth: impl Into, - width: impl Into, - node: MerkleNode, - ) -> Self { - let single = NodeBranching::Single; - Self::with(single, tag, depth, width, node, VIRTUAL_LEAF) +impl MerkleHash { + pub fn void(depth: impl Into, width: impl Into) -> Self { + MerkleNode::void(depth, width).commit_id() } - pub fn branches( - tag: [u8; 16], - depth: impl Into, - width: impl Into, - node1: MerkleNode, - node2: MerkleNode, - ) -> Self { - Self::with(NodeBranching::Branch, tag, depth, width, node1, node2) + pub fn single(depth: impl Into, width: impl Into, node: MerkleHash) -> Self { + MerkleNode::single(depth, width, node).commit_id() } - fn with( - branching: NodeBranching, - tag: [u8; 16], + pub fn branches( depth: impl Into, width: impl Into, - node1: MerkleNode, - node2: MerkleNode, + node1: MerkleHash, + node2: MerkleHash, ) -> Self { - let mut engine = Sha256::default(); - engine.write_all(&tag).ok(); - depth.into().commit_encode(&mut engine); - width.into().commit_encode(&mut engine); - branching.commit_encode(&mut engine); - node1.commit_encode(&mut engine); - node2.commit_encode(&mut engine); - engine.finish().into() + MerkleNode::branches(depth, width, node1, node2).commit_id() } } -impl MerkleNode { +impl MerkleHash { /// Merklization procedure that uses tagged hashes with depth commitments /// according to [LNPBP-81] standard of client-side-validation merklization. /// /// [LNPBP-81]: https://github.com/LNP-BP/LNPBPs/blob/master/lnpbp-0081.md - pub fn merklize(tag: [u8; 16], leaves: &impl MerkleLeaves) -> Self { - let mut nodes = leaves.merkle_leaves().map(|leaf| leaf.commitment_id()); - let len = nodes.len() as u32; - if len == 1 { + pub fn merklize(leaves: &impl MerkleLeaves) -> Self { + let mut nodes = leaves.merkle_leaves().map(|leaf| leaf.commit_id()); + let base_width = + u32::try_from(nodes.len()).expect("too many merkle leaves (more than 2^32)"); + if base_width == 1 { // If we have just one leaf, it's MerkleNode value is the root nodes.next().expect("length is 1") } else { - Self::_merklize(tag, nodes, u5::ZERO, len) + Self::_merklize(nodes, u5::ZERO, base_width, base_width) } } - pub fn _merklize( - tag: [u8; 16], - mut iter: impl ExactSizeIterator, + fn _merklize( + mut iter: impl ExactSizeIterator, depth: u5, - width: u32, + branch_width: u32, + base_width: u32, ) -> Self { - let len = iter.len() as u16; - - if len <= 2 { + if branch_width <= 2 { match (iter.next(), iter.next()) { - (None, None) => MerkleNode::void(tag, depth, width), - // Here, a single node means Merkle tree width nonequal to the power of 2, thus we + (None, None) => MerkleHash::void(depth, base_width), + // Here, a single node means Merkle tree width non-equal to the power of 2, thus we // need to process it with a special encoding. - (Some(branch), None) => MerkleNode::single(tag, depth, width, branch), + (Some(branch), None) => MerkleHash::single(depth, base_width, branch), (Some(branch1), Some(branch2)) => { - MerkleNode::branches(tag, depth, width, branch1, branch2) + MerkleHash::branches(depth, base_width, branch1, branch2) } (None, Some(_)) => unreachable!(), } } else { - let div = len / 2 + len % 2; + let div = branch_width / 2 + branch_width % 2; let slice = iter .by_ref() @@ -175,24 +192,42 @@ impl MerkleNode { // TODO: Do this without allocation .collect::>() .into_iter(); - let branch1 = Self::_merklize(tag, slice, depth + 1, width); - let branch2 = Self::_merklize(tag, iter, depth + 1, width); + let branch1 = Self::_merklize(slice, depth + 1, base_width, div); + let branch2 = Self::_merklize(iter, depth + 1, base_width, branch_width - div); - MerkleNode::branches(tag, depth, width, branch1, branch2) + MerkleHash::branches(depth, base_width, branch1, branch2) } } } pub trait MerkleLeaves { - type Leaf: CommitmentId; + type Leaf: CommitId; type LeafIter<'tmp>: ExactSizeIterator where Self: 'tmp; fn merkle_leaves(&self) -> Self::LeafIter<'_>; } +impl MerkleLeaves for Confined, MIN, { u8::MAX as usize }> +where T: CommitId + Copy +{ + type Leaf = T; + type LeafIter<'tmp> = iter::Copied> where Self: 'tmp; + + fn merkle_leaves(&self) -> Self::LeafIter<'_> { self.iter().copied() } +} + +impl MerkleLeaves for Confined, MIN, { u8::MAX as usize }> +where T: CommitId + Copy +{ + type Leaf = T; + type LeafIter<'tmp> = iter::Copied> where Self: 'tmp; + + fn merkle_leaves(&self) -> Self::LeafIter<'_> { self.iter().copied() } +} + impl MerkleLeaves for Confined, MIN, { u16::MAX as usize }> -where T: CommitmentId + Copy +where T: CommitId + Copy { type Leaf = T; type LeafIter<'tmp> = iter::Copied> where Self: 'tmp; @@ -201,7 +236,25 @@ where T: CommitmentId + Copy } impl MerkleLeaves for Confined, MIN, { u16::MAX as usize }> -where T: CommitmentId + Copy +where T: CommitId + Copy +{ + type Leaf = T; + type LeafIter<'tmp> = iter::Copied> where Self: 'tmp; + + fn merkle_leaves(&self) -> Self::LeafIter<'_> { self.iter().copied() } +} + +impl MerkleLeaves for Confined, MIN, { u32::MAX as usize }> +where T: CommitId + Copy +{ + type Leaf = T; + type LeafIter<'tmp> = iter::Copied> where Self: 'tmp; + + fn merkle_leaves(&self) -> Self::LeafIter<'_> { self.iter().copied() } +} + +impl MerkleLeaves for Confined, MIN, { u32::MAX as usize }> +where T: CommitId + Copy { type Leaf = T; type LeafIter<'tmp> = iter::Copied> where Self: 'tmp; diff --git a/commit_verify/src/mpc/atoms.rs b/commit_verify/src/mpc/atoms.rs index 5f3edf01..00c03448 100644 --- a/commit_verify/src/mpc/atoms.rs +++ b/commit_verify/src/mpc/atoms.rs @@ -19,15 +19,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::io::Write; - use amplify::confinement::MediumOrdMap; use amplify::num::u5; use amplify::{Bytes32, FromSliceError, Wrapper}; +use sha2::Sha256; +use strict_encoding::StrictDumb; -use crate::id::CommitmentId; -use crate::merkle::MerkleNode; -use crate::{strategies, CommitEncode, CommitStrategy}; +use crate::merkle::MerkleHash; +use crate::{CommitmentId, DigestExt}; pub const MPC_MINIMAL_DEPTH: u5 = u5::with(3); @@ -53,10 +52,6 @@ pub struct ProtocolId( Bytes32, ); -impl CommitStrategy for ProtocolId { - type Strategy = strategies::Strict; -} - impl ProtocolId { pub fn copy_from_slice(slice: &[u8]) -> Result { Bytes32::copy_from_slice(slice).map(Self) @@ -70,8 +65,6 @@ impl ProtocolId { #[wrapper(Deref, BorrowSlice, Display, FromStr, Hex, Index, RangeOps)] #[derive(StrictType, StrictEncode, StrictDecode)] #[strict_type(lib = crate::LIB_NAME_COMMIT_VERIFY)] -#[derive(CommitEncode)] -#[commit_encode(crate = crate, strategy = strict)] #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), @@ -90,15 +83,20 @@ impl Message { } #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, From)] +#[derive(StrictType, StrictEncode, StrictDecode)] +#[strict_type(lib = crate::LIB_NAME_COMMIT_VERIFY, tags = custom)] +#[derive(CommitEncode)] +#[commit_encode(crate = crate, strategy = strict, id = MerkleHash)] pub enum Leaf { + // We use this constant since we'd like to be distinct from NodeBranching values + #[strict_type(tag = 0x10)] Inhabited { protocol: ProtocolId, message: Message, }, - Entropy { - entropy: u64, - pos: u32, - }, + // We use this constant since we'd like to be distinct from NodeBranching values + #[strict_type(tag = 0x11)] + Entropy { entropy: u64, pos: u32 }, } impl Leaf { @@ -109,28 +107,8 @@ impl Leaf { } } -impl CommitEncode for Leaf { - fn commit_encode(&self, e: &mut impl Write) { - match self { - Leaf::Inhabited { protocol, message } => { - // We use this constant since we'd like to be distinct from NodeBranching values - 0x10.commit_encode(e); - protocol.commit_encode(e); - message.commit_encode(e); - } - Leaf::Entropy { entropy, pos } => { - // We use this constant since we'd like to be distinct from NodeBranching values - 0x11.commit_encode(e); - entropy.commit_encode(e); - pos.commit_encode(e); - } - } - } -} - -impl CommitmentId for Leaf { - const TAG: [u8; 32] = *b"urn:lnpbp:lnpbp0004:leaf:v01#23A"; - type Id = MerkleNode; +impl StrictDumb for Leaf { + fn strict_dumb() -> Self { Self::Entropy { entropy: 0, pos: 0 } } } /// Final [LNPBP-4] commitment value. @@ -154,8 +132,8 @@ pub struct Commitment( Bytes32, ); -impl CommitStrategy for Commitment { - type Strategy = strategies::Strict; +impl CommitmentId for Commitment { + const TAG: &'static str = "urn:ubideco:mpc:commitment#2024-01-31"; } impl Commitment { @@ -164,6 +142,10 @@ impl Commitment { } } +impl From for Commitment { + fn from(hasher: Sha256) -> Self { hasher.finish().into() } +} + /// Structured source multi-message data for commitment creation #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub struct MultiSource { diff --git a/commit_verify/src/mpc/block.rs b/commit_verify/src/mpc/block.rs index c28a7149..e7615d2e 100644 --- a/commit_verify/src/mpc/block.rs +++ b/commit_verify/src/mpc/block.rs @@ -28,13 +28,11 @@ use amplify::confinement::{Confined, LargeVec}; use amplify::num::u5; use strict_encoding::{StrictDeserialize, StrictEncode, StrictSerialize}; -use crate::id::CommitmentId; -use crate::merkle::{MerkleBuoy, MerkleNode}; +use crate::id::CommitId; +use crate::merkle::{MerkleBuoy, MerkleHash}; use crate::mpc::atoms::Leaf; use crate::mpc::tree::protocol_id_pos; -use crate::mpc::{ - Commitment, MerkleTree, Message, MessageMap, Proof, ProtocolId, MERKLE_LNPBP4_TAG, -}; +use crate::mpc::{Commitment, MerkleTree, Message, MessageMap, Proof, ProtocolId}; use crate::{Conceal, LIB_NAME_COMMIT_VERIFY}; /// commitment under protocol id {0} is absent from the known part of a given @@ -90,7 +88,7 @@ enum TreeNode { /// Depth of the node. depth: u5, /// Node hash. - hash: MerkleNode, + hash: MerkleHash, }, /// A tree leaf storing specific commitment under given protocol. CommitmentLeaf { @@ -102,10 +100,10 @@ enum TreeNode { } impl TreeNode { - fn with(hash1: MerkleNode, hash2: MerkleNode, depth: u5, width: u32) -> TreeNode { + fn with(hash1: MerkleHash, hash2: MerkleHash, depth: u5, width: u32) -> TreeNode { TreeNode::ConcealedNode { depth, - hash: MerkleNode::branches(MERKLE_LNPBP4_TAG.to_be_bytes(), depth, width, hash1, hash2), + hash: MerkleHash::branches(depth, width, hash1, hash2), } } @@ -120,13 +118,13 @@ impl TreeNode { pub fn is_leaf(&self) -> bool { matches!(self, TreeNode::CommitmentLeaf { .. }) } - pub fn to_merkle_node(self) -> MerkleNode { + pub fn to_merkle_node(self) -> MerkleHash { match self { TreeNode::ConcealedNode { hash, .. } => hash, TreeNode::CommitmentLeaf { protocol_id, message, - } => Leaf::inhabited(protocol_id, message).commitment_id(), + } => Leaf::inhabited(protocol_id, message).commit_id(), } } } @@ -136,7 +134,7 @@ impl TreeNode { #[derive(StrictType, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_COMMIT_VERIFY)] #[derive(CommitEncode)] -#[commit_encode(crate = crate, conceal, strategy = strict)] +#[commit_encode(crate = crate, strategy = conceal, id = Commitment)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] pub struct MerkleBlock { /// Tree depth (up to 16). @@ -175,7 +173,7 @@ impl From<&MerkleTree> for MerkleBlock { }) .unwrap_or_else(|| TreeNode::ConcealedNode { depth: tree.depth, - hash: Leaf::entropy(tree.entropy, pos).commitment_id(), + hash: Leaf::entropy(tree.entropy, pos).commit_id(), }) }); let cross_section = @@ -390,8 +388,8 @@ impl MerkleBlock { /// each one of them. pub fn merge_reveal(&mut self, other: MerkleBlock) -> Result { let orig = self.clone(); - let base_root = self.commitment_id(); - let merged_root = other.commitment_id(); + let base_root = self.commit_id(); + let merged_root = other.commit_id(); if base_root != merged_root { return Err(MergeError::UnrelatedBlocks { base_root, @@ -490,12 +488,12 @@ Failed merge: {self:#?}" ); assert_eq!( base_root, - self.commitment_id(), + self.commit_id(), "LNPBP-4 merge-reveal procedure is broken; please report the below data to the LNP/BP \ Standards Association Original commitment id: {base_root} Changed commitment id: {}", - self.commitment_id() + self.commit_id() ); Ok(self.cross_section.len() as u16) @@ -508,7 +506,7 @@ Changed commitment id: {}", protocol_id: ProtocolId, ) -> Result { self.conceal_except([protocol_id])?; - let mut map = BTreeMap::::new(); + let mut map = BTreeMap::::new(); for node in &self.cross_section { match node { TreeNode::ConcealedNode { depth, hash } => { @@ -564,7 +562,7 @@ Changed commitment id: {}", } impl Conceal for MerkleBlock { - type Concealed = MerkleNode; + type Concealed = Self; /// Reduces merkle tree into merkle tree root. fn conceal(&self) -> Self::Concealed { @@ -573,21 +571,14 @@ impl Conceal for MerkleBlock { .conceal_except([]) .expect("broken internal MerkleBlock structure"); debug_assert_eq!(concealed.cross_section.len(), 1); - concealed.cross_section[0].to_merkle_node() + concealed } } -impl CommitmentId for MerkleBlock { - const TAG: [u8; 32] = *b"urn:lnpbp:lnpbp0004:tree:v01#23A"; - type Id = Commitment; -} - /// A proof of the merkle commitment. #[derive(Getters, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)] #[derive(StrictType, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_COMMIT_VERIFY)] -#[derive(CommitEncode)] -#[commit_encode(crate = crate, strategy = strict)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))] pub struct MerkleProof { /// Position of the leaf in the tree. @@ -603,7 +594,7 @@ pub struct MerkleProof { /// Merkle proof path consisting of node hashing partners. #[getter(skip)] - path: Confined, 0, 32>, + path: Confined, 0, 32>, } impl Proof for MerkleProof {} @@ -616,13 +607,13 @@ impl MerkleProof { pub fn width(&self) -> u32 { 2u32.pow(self.depth() as u32) } /// Converts the proof into inner merkle path representation - pub fn into_path(self) -> Confined, 0, 32> { self.path } + pub fn into_path(self) -> Confined, 0, 32> { self.path } /// Constructs the proof into inner merkle path representation - pub fn to_path(&self) -> Confined, 0, 32> { self.path.clone() } + pub fn to_path(&self) -> Confined, 0, 32> { self.path.clone() } /// Returns inner merkle path representation - pub fn as_path(&self) -> &[MerkleNode] { &self.path } + pub fn as_path(&self) -> &[MerkleHash] { &self.path } /// Convolves the proof with the `message` under the given `protocol_id`, /// producing [`Commitment`]. @@ -632,7 +623,7 @@ impl MerkleProof { message: Message, ) -> Result { let block = MerkleBlock::with(self, protocol_id, message)?; - Ok(block.commitment_id()) + Ok(block.commit_id()) } } @@ -652,9 +643,9 @@ mod test { // Check we preserve entropy value assert_eq!(Some(tree.entropy), block.entropy); // Check if we remove entropy the commitment doesn't change - let cid1 = block.commitment_id(); + let cid1 = block.commit_id(); block.entropy = None; - let cid2 = block.commitment_id(); + let cid2 = block.commit_id(); assert_eq!(cid1, cid2); } @@ -667,13 +658,12 @@ mod test { let (pid, msg) = msgs.first_key_value().unwrap(); let leaf = Leaf::inhabited(*pid, *msg); let cid1 = block.cross_section.first().unwrap().to_merkle_node(); - let cid2 = leaf.commitment_id(); + let cid2 = leaf.commit_id(); assert_eq!(cid1, cid2); assert_eq!(tree.conceal(), block.conceal()); - assert_eq!(tree.root(), block.conceal()); assert_eq!(tree.root(), cid1); - assert_eq!(tree.commitment_id(), block.commitment_id()) + assert_eq!(tree.commit_id(), block.commit_id()) } #[test] @@ -684,8 +674,7 @@ mod test { let block = MerkleBlock::from(&tree); assert_eq!(tree.conceal(), block.conceal()); - assert_eq!(tree.root(), block.conceal()); - assert_eq!(tree.commitment_id(), block.commitment_id()) + assert_eq!(tree.commit_id(), block.commit_id()) } } @@ -697,8 +686,7 @@ mod test { let block = MerkleBlock::from(&tree); assert_eq!(tree.conceal(), block.conceal()); - assert_eq!(tree.root(), block.conceal()); - assert_eq!(tree.commitment_id(), block.commitment_id()) + assert_eq!(tree.commit_id(), block.commit_id()) } } @@ -730,7 +718,7 @@ mod test { } } - assert_eq!(merged_block.commitment_id(), mpc_tree.commitment_id()); + assert_eq!(merged_block.commit_id(), mpc_tree.commit_id()); } } } diff --git a/commit_verify/src/mpc/mod.rs b/commit_verify/src/mpc/mod.rs index daf52528..3993e512 100644 --- a/commit_verify/src/mpc/mod.rs +++ b/commit_verify/src/mpc/mod.rs @@ -33,15 +33,9 @@ pub use atoms::{ pub use block::{InvalidProof, LeafNotKnown, MergeError, MerkleBlock, MerkleProof}; pub use tree::{Error, MerkleTree}; -pub const MERKLE_LNPBP4_TAG: u128 = u128::from_le_bytes(*b"urn:lnpbp:lnpbp4"); - /// Marker trait for variates of LNPBP-4 commitment proofs, which differ by the /// amount of concealed information. pub trait Proof: - strict_encoding::StrictEncode - + strict_encoding::StrictDecode - + crate::CommitEncode - + Eq - + std::fmt::Debug + strict_encoding::StrictEncode + strict_encoding::StrictDecode + Eq + std::fmt::Debug { } diff --git a/commit_verify/src/mpc/tree.rs b/commit_verify/src/mpc/tree.rs index 26eb76b2..a0984c1f 100644 --- a/commit_verify/src/mpc/tree.rs +++ b/commit_verify/src/mpc/tree.rs @@ -19,15 +19,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -use amplify::confinement::{MediumOrdMap, SmallVec}; +use amplify::confinement::{LargeVec, MediumOrdMap}; use amplify::num::{u256, u5}; use amplify::Wrapper; pub use self::commit::Error; -use crate::merkle::MerkleNode; +use crate::merkle::MerkleHash; use crate::mpc::atoms::Leaf; -use crate::mpc::{Commitment, Message, MessageMap, Proof, ProtocolId, MERKLE_LNPBP4_TAG}; -use crate::{CommitmentId, Conceal, LIB_NAME_COMMIT_VERIFY}; +use crate::mpc::{Commitment, MerkleBlock, Message, MessageMap, Proof, ProtocolId}; +use crate::{Conceal, LIB_NAME_COMMIT_VERIFY}; /// Number of cofactor variants tried before moving to the next tree depth. #[allow(dead_code)] @@ -40,7 +40,7 @@ type OrderedMap = MediumOrdMap; #[derive(StrictDumb, StrictType, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_COMMIT_VERIFY)] #[derive(CommitEncode)] -#[commit_encode(crate = crate, conceal, strategy = strict)] +#[commit_encode(crate = crate, strategy = conceal, id = Commitment)] pub struct MerkleTree { /// Tree depth (up to 32). pub(super) depth: u5, @@ -60,28 +60,23 @@ pub struct MerkleTree { impl Proof for MerkleTree {} -impl CommitmentId for MerkleTree { - const TAG: [u8; 32] = *b"urn:lnpbp:lnpbp0004:tree:v01#23A"; - type Id = Commitment; -} - impl MerkleTree { - pub fn root(&self) -> MerkleNode { + pub fn root(&self) -> MerkleHash { let iter = (0..self.width()).map(|pos| { self.map .get(&pos) .map(|(protocol, msg)| Leaf::inhabited(*protocol, *msg)) .unwrap_or_else(|| Leaf::entropy(self.entropy, pos)) }); - let leaves = SmallVec::try_from_iter(iter).expect("u16-bound size"); - MerkleNode::merklize(MERKLE_LNPBP4_TAG.to_be_bytes(), &leaves) + let leaves = LargeVec::try_from_iter(iter).expect("tree width has u32-bound size"); + MerkleHash::merklize(&leaves) } } impl Conceal for MerkleTree { - type Concealed = MerkleNode; + type Concealed = MerkleBlock; - fn conceal(&self) -> Self::Concealed { self.root() } + fn conceal(&self) -> Self::Concealed { MerkleBlock::from(self.clone()).conceal() } } mod commit { @@ -249,14 +244,13 @@ mod test { use std::collections::BTreeSet; use amplify::num::u5; - use amplify::WriteCounter; + use amplify::Wrapper; use rand::random; - use sha2::Sha256; - use strict_encoding::StrictEncode; + use strict_encoding::{StreamWriter, StrictEncode}; use crate::mpc::tree::test_helpers::{make_random_messages, make_random_tree}; - use crate::mpc::MerkleTree; - use crate::{CommitEncode, CommitmentId, Conceal, DigestExt}; + use crate::mpc::MerkleBlock; + use crate::{CommitId, Conceal}; #[test] #[should_panic(expected = "Empty")] @@ -287,15 +281,35 @@ mod test { #[test] fn tree_huge() { + // Tree with 8192 protocol-messages: depth 23, cofactor 103. Serialized length + // 1081361 bytes. Takes 71589 msecs to generate + // Root is 58755c63bbcb1a648982956c90a471a3fc79b12ae97867828e2f0ce8c9f7e7db. + // Takes 560735 msecs to compute + + use std::time::Instant; + let count = 1_048_576 / 128; let msgs = make_random_messages(count); + + let start = Instant::now(); let tree = make_random_tree(&msgs); - let mut counter = WriteCounter::default(); - tree.strict_write(usize::MAX, &mut counter).unwrap(); + let elapsed_gen = start.elapsed(); + + let mut counter = StreamWriter::counter::<{ usize::MAX }>(); + tree.strict_write(&mut counter).unwrap(); eprintln!( - "Tree with {} protocol-messages: depth {}, cofactor {}. Serialized length {} bytes", - count, tree.depth, tree.cofactor, counter.count + "Tree with {count} protocol-messages: depth {}, cofactor {}. Serialized length {} \ + bytes. Takes {} msecs to generate", + tree.depth, + tree.cofactor, + counter.unconfine().count, + elapsed_gen.as_millis(), ); + + let start = Instant::now(); + let root = tree.root(); + let elapsed_root = start.elapsed(); + eprintln!("Root is {root}. Takes {} msecs to compute", elapsed_root.as_millis(),); } #[test] @@ -316,35 +330,23 @@ mod test { fn tree_conceal() { let msgs = make_random_messages(9); let tree = make_random_tree(&msgs); - assert_eq!(tree.conceal(), tree.root()); + assert_eq!(tree.conceal(), MerkleBlock::from(tree.clone()).conceal()); } #[test] fn tree_id() { let msgs = make_random_messages(9); let tree = make_random_tree(&msgs); - let id = tree.commitment_id(); + let id = tree.commit_id(); let root = tree.root(); - - let mut enc1 = vec![]; - let mut enc2 = vec![]; - tree.commit_encode(&mut enc1); - root.strict_write(usize::MAX, &mut enc2).unwrap(); - // Commitment encoding must be equal to the value of the Merkle root - assert_eq!(enc1, enc2); - - let mut engine = Sha256::from_tag(MerkleTree::TAG); - engine.input_raw(root.as_slice()); - let cmt = engine.finish(); - // Commitment id must be equal to the tag-hashed Merkle tree root - assert_eq!(id.as_slice(), &cmt); + assert_ne!(id.into_inner(), root.into_inner()); } #[test] fn tree_id_entropy() { let msgs = make_random_messages(9); let mut tree = make_random_tree(&msgs); - let id1 = tree.commitment_id(); + let id1 = tree.commit_id(); tree.entropy = loop { let entropy = random(); @@ -352,7 +354,7 @@ mod test { break entropy; } }; - let id2 = tree.commitment_id(); + let id2 = tree.commit_id(); assert_ne!(id1, id2); } diff --git a/commit_verify/src/stl.rs b/commit_verify/src/stl.rs index 8ab0f4ce..858d8a42 100644 --- a/commit_verify/src/stl.rs +++ b/commit_verify/src/stl.rs @@ -21,10 +21,10 @@ use strict_types::{CompileError, LibBuilder, TypeLib}; -use crate::{mpc, LIB_NAME_COMMIT_VERIFY}; +use crate::{mpc, MerkleHash, MerkleNode, StrictHash, LIB_NAME_COMMIT_VERIFY}; pub const LIB_ID_COMMIT_VERIFY: &str = - "urn:ubideco:stl:ZtHaBzu9ojbDahaGKEXe5v9DfSDxLERbLkEB23R6Q6V#rhino-cover-frog"; + "urn:ubideco:stl:57sPvZcwQaziec3ux249XoCMhziQpKB8Yw99U5oRwfqW#deluxe-safari-random"; fn _commit_verify_stl() -> Result { LibBuilder::new(libname!(LIB_NAME_COMMIT_VERIFY), tiny_bset! { @@ -34,6 +34,9 @@ fn _commit_verify_stl() -> Result { .transpile::() .transpile::() .transpile::() + .transpile::() + .transpile::() + .transpile::() .compile() } diff --git a/commit_verify/src/vesper.rs b/commit_verify/src/vesper.rs new file mode 100644 index 00000000..fbe3a847 --- /dev/null +++ b/commit_verify/src/vesper.rs @@ -0,0 +1,188 @@ +// Client-side-validation foundation libraries. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2024 by +// Dr. Maxim Orlovsky +// +// Copyright (C) 2024 LNP/BP Standards Association. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use amplify::confinement::{Confined, SmallVec, TinyVec}; +use strict_encoding::Ident; +use strict_types::layout::vesper::LenRange; +use strict_types::typesys::TypeFqn; +use vesper::{AttrVal, Attribute, Expression, Predicate, TExpr}; + +use crate::{CommitColType, CommitLayout, CommitStep}; + +pub type VesperCommit = TExpr; + +#[derive(Clone, Eq, PartialEq, Hash, Debug, Display)] +#[display(lowercase)] +pub enum Pred { + Commitment, + Serialized, + Hashed, + Merklized, + Concealed, + List, + Set, + Element, + Map, + #[display("mapKey")] + MapKey, + #[display("mapValue")] + MapValue, +} + +impl Predicate for Pred { + type Attr = Attr; +} + +#[derive(Clone, Eq, PartialEq, Hash, Debug)] +pub enum Attr { + Tagged(&'static str), + Concealed(TypeFqn), + LenRange(LenRange), + Hasher, +} +#[derive(Clone, Eq, PartialEq, Hash, Debug, Display)] +#[display(inner)] +pub enum AttrExpr { + Tag(&'static str), + LenRange(LenRange), +} + +impl Expression for AttrExpr {} + +impl Attribute for Attr { + type Expression = AttrExpr; + + fn name(&self) -> Option { + match self { + Attr::Tagged(_) => Some(tn!("tagged")), + Attr::Concealed(_) => Some(tn!("concealed")), + Attr::LenRange(_) => Some(tn!("len")), + Attr::Hasher => Some(tn!("hasher")), + } + } + + fn value(&self) -> AttrVal { + match self { + Attr::Tagged(tag) => AttrVal::Expr(AttrExpr::Tag(tag)), + Attr::Concealed(fqn) => AttrVal::Ident(fqn.name.to_ident()), + Attr::LenRange(range) => AttrVal::Expr(AttrExpr::LenRange(range.clone())), + Attr::Hasher => AttrVal::Ident(tn!("SHA256")), + } + } +} + +impl CommitStep { + fn subject(&self) -> Ident { + match self { + CommitStep::Serialized(fqn) => fqn, + CommitStep::Collection(_, _, fqn) => fqn, + CommitStep::Hashed(fqn) => fqn, + CommitStep::Merklized(fqn) => fqn, + CommitStep::Concealed(fqn) => fqn, + } + .name + .to_ident() + } + + fn predicate(&self) -> Pred { + match self { + CommitStep::Serialized(_) => Pred::Serialized, + CommitStep::Collection(CommitColType::List, _, _) => Pred::List, + CommitStep::Collection(CommitColType::Set, _, _) => Pred::Set, + CommitStep::Collection(CommitColType::Map { .. }, _, _) => Pred::Map, + CommitStep::Hashed(_) => Pred::Hashed, + CommitStep::Merklized(_) => Pred::Merklized, + CommitStep::Concealed(_) => Pred::Concealed, + } + } + + fn attributes(&self) -> SmallVec { + match self { + CommitStep::Collection(_, sizing, _) => small_vec![Attr::LenRange((*sizing).into())], + CommitStep::Concealed(from) => small_vec![Attr::Concealed(from.clone())], + CommitStep::Serialized(_) | CommitStep::Hashed(_) | CommitStep::Merklized(_) => none!(), + } + } + + fn content(&self) -> TinyVec> { + match self { + CommitStep::Collection(CommitColType::List, _, val) | + CommitStep::Collection(CommitColType::Set, _, val) => { + tiny_vec![Box::new(VesperCommit { + subject: val.name.to_ident(), + predicate: Pred::Element, + attributes: none!(), + content: none!(), + comment: None + })] + } + CommitStep::Collection(CommitColType::Map { key }, _, val) => { + tiny_vec![ + Box::new(VesperCommit { + subject: key.name.to_ident(), + predicate: Pred::MapKey, + attributes: none!(), + content: none!(), + comment: None + }), + Box::new(VesperCommit { + subject: val.name.to_ident(), + predicate: Pred::MapValue, + attributes: none!(), + content: none!(), + comment: None + }) + ] + } + CommitStep::Serialized(_) | + CommitStep::Hashed(_) | + CommitStep::Merklized(_) | + CommitStep::Concealed(_) => empty!(), + } + } +} + +impl CommitLayout { + pub fn to_vesper(&self) -> VesperCommit { + let subject = self.idty().name.to_ident(); + + // SecretSeal commitment tagged="" + // BlindSeal rec serialized + + let content = self.fields().iter().map(|field| { + Box::new(VesperCommit { + subject: field.subject(), + predicate: field.predicate(), + attributes: field.attributes(), + content: field.content(), + comment: None, + }) + }); + + VesperCommit { + subject, + predicate: Pred::Commitment, + attributes: confined_vec![Attr::Hasher, Attr::Tagged(self.tag())], + content: Confined::from_iter_unsafe(content), + comment: None, + } + } +} diff --git a/stl/CommitVerify@0.1.0.sta b/stl/CommitVerify@0.1.0.sta index c507e89b..274f691d 100644 --- a/stl/CommitVerify@0.1.0.sta +++ b/stl/CommitVerify@0.1.0.sta @@ -1,30 +1,33 @@ -----BEGIN STRICT TYPE LIB----- -Id: urn:ubideco:stl:ZtHaBzu9ojbDahaGKEXe5v9DfSDxLERbLkEB23R6Q6V +Id: 57sPvZcwQaziec3ux249XoCMhziQpKB8Yw99U5oRwfqW#deluxe-safari-random Name: CommitVerify Dependencies: - urn:ubideco:stl:9KALDYR8Nyjq4FdMW6kYoL7vdkWnqPqNuFnmE9qHpNjZ + DzTvt9gGhPUKD8Dkkjk9PDBhkJ4gtWxXWQjxnmUYLNrs#voyage-kimono-disco -DENvbW1pdFZlcmlmeQF7hIA8nvriESWnfCw5vHDS/ej5Q64N/Zz05oLtx2bKcANT -dGQBA1N0ZAEAIuTglum9fVyG9eHfXXcBav45xzzZNIVQlECJjKijeV4CVTUIAApD -b21taXRtZW50BQEABwAAQCAAC01lcmtsZUJsb2NrBgQFZGVwdGgCe4SAPJ764hEl -p3wsObxw0v3o+UOuDf2c9OaC7cdmynAi5OCW6b19XIb14d9ddwFq/jnHPNk0hVCU -QImMqKN5Xghjb2ZhY3RvcgAAAgxjcm9zc1NlY3Rpb24ACAFTQ5UPRDMqI//ogM9Q -588IBqEEzeBIaxPhDPwYg0Ow1wAAAAAAAAAA/////wAAAAAHZW50cm9weQAEAgAE -bm9uZQAAAAEEc29tZQAFAQAACApNZXJrbGVOb2RlBQEABwAAQCAAC01lcmtsZVBy -b29mBgMDcG9zAAAECGNvZmFjdG9yAAACBHBhdGgACAFVjTcH+EWGU4DuzEFVJOik -mWBR05SCQ/GU9/GRVyPp5gAAAAAAAAAAIAAAAAAAAAAKTWVya2xlVHJlZQYFBWRl -cHRoAnuEgDye+uIRJad8LDm8cNL96PlDrg39nPTmgu3HZspwIuTglum9fVyG9eHf -XXcBav45xzzZNIVQlECJjKijeV4HZW50cm9weQAACAhjb2ZhY3RvcgAAAghtZXNz -YWdlcwAKATCVfuYdYTRZuwUI5OGvPWohv9b7+x0xgqd55UV04FaxATU3qVEVyOqF -3FL3q4HycWVRBSZTlEJXr4kT6HvUm7HTAAAAAAAAAAD///8AAAAAAANtYXAACgAA -BAAFAgEwlX7mHWE0WbsFCOThrz1qIb/W+/sdMYKneeVFdOBWsQE1N6lRFcjqhdxS -96uB8nFlUQUmU5RCV6+JE+h71Jux0wAAAAAAAAAA////AAAAAAAHTWVzc2FnZQUB -AAcAAEAgAApQcm90b2NvbElkBQEABwAAQCAACFRyZWVOb2RlBAIADWNvbmNlYWxl -ZE5vZGUABgIFZGVwdGgCe4SAPJ764hElp3wsObxw0v3o+UOuDf2c9OaC7cdmynAi -5OCW6b19XIb14d9ddwFq/jnHPNk0hVCUQImMqKN5XgRoYXNoAVWNNwf4RYZTgO7M -QVUk6KSZYFHTlIJD8ZT38ZFXI+nmAQ5jb21taXRtZW50TGVhZgAGAgpwcm90b2Nv -bElkATCVfuYdYTRZuwUI5OGvPWohv9b7+x0xgqd55UV04FaxB21lc3NhZ2UBNTep -URXI6oXcUvergfJxZVEFJlOUQleviRPoe9SbsdM= +3`1{iZE18?WpZg|c>%!$%tl@;WNu_lcw-g2$nLVb<*lb*ENIx0;35YAw}=B%bYuY +oQ*>kj0A^Tl*p6J$36SYb7g#;qpQBTpwL(~+!(f@;t~vt?k^)sV3jhj3Z*6U9bZu +pBbOiwb2LJ#-AOH(ZWpZn5WkPIkV`~Nk1!QG#bZ7#>1k6TWEM#tEO?YD!yU6acy5 ++5>Uo2?YlHei-0Jn%{Sa8^mT+s=T=}Z?`J=~w8Q=GLzSfImTncuED0}GM}V{c|*V +{~tF0006EV{&hEb5mtwbZKvH00;rtwYiq_Rlwao{(T?aUNqayF^88E^#IUpx^^~; +)zDV}0000000030|Ns9000007Wo~qGZ*X}41OfmAZf|a7000011aog~WdH>M000O +IO=WUxY-LDcb7%zt00#g7Kp+4LO=WUxY-LVwWMu{g31V_#ZewU^Zf60zOl}Js;Lv +V7e1xlC`fl^8AoO?D+|y;s#+-J4VoSmWWMy!4XaE2K1$Sv=bZ7toAO&u3WMwe{IG +#g>Clv)aMjKgwAH@`bu1x<7g|G$};xvA~n-$_S1#WL-WikOco0|Rhxa{vGY2xD(%VPkY}asU7V +1aM(=XaEQSIG#g>Clv)aMjKgwAH@`bu1x<7g|G$};xvA~n-$_S0000000000AOHX +W000003Qc8lYiwmya%E)(1qEbfaCB$_!34}kUMys8WKDQu6}!mpvbyE1r(Y~+*pl +EP2LQK-W>|38j$F|Rkm*bpSUudIqf?xQ3WPbltNdpi4*91)SI!>0000000000|Ns9000000 +18re&015yA1ONpB0Wg(*<{e=)S-S-YmzVsZkZ +k>V@1=_p5>Oab-~jCR3C`SFec^=zG+gvC{wm0000000960{{R30000L~Wpi_3XJr +Ke00#g7Kp+4OPH$voLULhlV`yn^X9EKSc5i8900whuZf9&|0S01nVQyn+0t!%aZ* +*^CZ){0q1pxpD002NB018uda%p39NMUnm1pxpD002NB00>laWo1rpWMu>b01abrZ +ewL(Y-MClZ)9Zv1_A|SWpH$80>K2#MqVsrZe&e(V->r|?y|b&t*2isXxNhAA_oAs +h-O%D*p6J$36SYb7g#;qpQBTpwL(~+!(f@;t~vt?k_2dBb7%oLopt-$m)gMQu +nKY@^NKR1twFJLRYVe6X<)?o3Ya -----END STRICT TYPE LIB----- diff --git a/stl/CommitVerify@0.1.0.stl b/stl/CommitVerify@0.1.0.stl index 4fc0f2ec..00f633f4 100644 Binary files a/stl/CommitVerify@0.1.0.stl and b/stl/CommitVerify@0.1.0.stl differ diff --git a/stl/CommitVerify@0.1.0.sty b/stl/CommitVerify@0.1.0.sty index ad4d73d7..496c7a51 100644 --- a/stl/CommitVerify@0.1.0.sty +++ b/stl/CommitVerify@0.1.0.sty @@ -1,5 +1,5 @@ {- - Id: urn:ubideco:stl:ZtHaBzu9ojbDahaGKEXe5v9DfSDxLERbLkEB23R6Q6V#rhino-cover-frog + Id: urn:ubideco:stl:57sPvZcwQaziec3ux249XoCMhziQpKB8Yw99U5oRwfqW#deluxe-safari-random Name: CommitVerify Version: 0.1.0 Description: Client-side-validation deterministic commitments @@ -8,38 +8,59 @@ License: Apache-2.0 -} +@context typelib CommitVerify -import urn:ubideco:stl:9KALDYR8Nyjq4FdMW6kYoL7vdkWnqPqNuFnmE9qHpNjZ#justice-rocket-type as Std --- Imports: --- U5 := urn:ubideco:semid:3MDHMYsJt8d1gUiyx5vGCWcNLQ7biek6UTjHg3ksW4Bf#ground-volume-singer +import Std#DzTvt9gGhPUKD8Dkkjk9PDBhkJ4gtWxXWQjxnmUYLNrs#voyage-kimono-disco + use U5#nitro-george-nebula +@mnemonic(ventura-equal-think) +data Commitment : [Byte ^ 32] --- urn:ubideco:semid:F8mU5NPc8Z5CMnkSFGdF5UxrPsdcBS6B5DCyP5kJPgWc#ventura-equal-think -data Commitment :: [Byte ^ 32] --- urn:ubideco:semid:qp6pMjMCcukxxZdkM2PtfNWfJjXKoVHXtXSBCsYjQwY#transit-bogart-nissan -data MerkleBlock :: depth Std.U5 {- urn:ubideco:semid:3MDHMYsJt8d1gUiyx5vGCWcNLQ7biek6UTjHg3ksW4Bf#ground-volume-singer -} +@mnemonic(iris-explore-script) +data MerkleBlock : depth Std.U5#nitro-george-nebula , cofactor U16 , crossSection [TreeNode ^ ..0xffffffff] , entropy U64? --- urn:ubideco:semid:6kxYeCatpncbA9UiTdsFbxbxJdU56x6MdmTRkEeGAv6R#iceberg-rocket-velvet -data MerkleNode :: [Byte ^ 32] --- urn:ubideco:semid:9FbrjZLnMDfbrN9gEbWij5HNkxqAVaZBkoW2UvKdYw4B#canyon-exhibit-ravioli -data MerkleProof :: pos U32 + +@mnemonic(culture-metro-modular) +data MerkleHash : [Byte ^ 32] + +@mnemonic(input-mouse-amber) +data MerkleNode : branching NodeBranching + , depth U8 + , width U256 + , node1 MerkleHash + , node2 MerkleHash + +@mnemonic(father-adios-common) +data MerkleProof : pos U32 , cofactor U16 - , path [MerkleNode ^ ..0x20] --- urn:ubideco:semid:57jCv2LWrdn89GzuSYaH17f21N3su76uM2tEaG1dwwoT#russian-wedding-florida -data MerkleTree :: depth Std.U5 {- urn:ubideco:semid:3MDHMYsJt8d1gUiyx5vGCWcNLQ7biek6UTjHg3ksW4Bf#ground-volume-singer -} + , path [MerkleHash ^ ..0x20] + +@mnemonic(civil-left-nova) +data MerkleTree : depth Std.U5#nitro-george-nebula , entropy U64 , cofactor U16 , messages {ProtocolId -> ^ ..0xffffff Message} , map {U32 -> ^ ..0xffffff ProtocolId, Message} --- urn:ubideco:semid:4ajqScXjJ6wQ5af2zgBFzzP7k1qzD6DXXU28taQidCcA#shampoo-bishop-morgan -data Message :: [Byte ^ 32] --- urn:ubideco:semid:4GenVCt5Xq6xtnJDjT98FehgCS8rTmwEzbjwGkaUVjHz#gamma-banjo-corona -data ProtocolId :: [Byte ^ 32] --- urn:ubideco:semid:D7Q2eTnYyjN6gMZnZYrMG6gmRwmtnxyGLeqBbki8DFLv#greek-decimal-quiz -data TreeNode :: concealedNode (depth Std.U5 {- urn:ubideco:semid:3MDHMYsJt8d1gUiyx5vGCWcNLQ7biek6UTjHg3ksW4Bf#ground-volume-singer -}, hash MerkleNode) + +@mnemonic(shampoo-bishop-morgan) +data Message : [Byte ^ 32] + +@mnemonic(food-amanda-burger) +data NodeBranching : void | single | branch + + +@mnemonic(gamma-banjo-corona) +data ProtocolId : [Byte ^ 32] + +@mnemonic(cheese-final-locate) +data StrictHash : [Byte ^ 32] + +@mnemonic(empty-active-truck) +data TreeNode : concealedNode (depth Std.U5#nitro-george-nebula, hash MerkleHash) | commitmentLeaf (protocolId ProtocolId, message Message) +