diff --git a/.config/zepter.yaml b/.config/zepter.yaml index 24441e90b1a05..8bd03268e9f9f 100644 --- a/.config/zepter.yaml +++ b/.config/zepter.yaml @@ -12,7 +12,7 @@ workflows: # Check that `A` activates the features of `B`. 'propagate-feature', # These are the features to check: - '--features=try-runtime,runtime-benchmarks,std', + '--features=try-runtime,runtime-benchmarks,std,bandersnatch-experimental', # Do not try to add a new section into `[features]` of `A` only because `B` expose that feature. There are edge-cases where this is still needed, but we can add them manually. '--left-side-feature-missing=ignore', # Ignore the case that `A` it outside of the workspace. Otherwise it will report errors in external dependencies that we have no influence on. diff --git a/Cargo.lock b/Cargo.lock index 736fd100f1057..be807feec2144 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -303,15 +303,6 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - [[package]] name = "anstream" version = "0.6.11" @@ -404,7 +395,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb00293ba84f51ce3bd026bd0de55899c4e68f0a39a5728cebae3a73ffdc0a4f" dependencies = [ - "ark-ec", + "ark-ec 0.4.2", "ark-ff 0.4.2", "ark-std 0.4.0", ] @@ -416,7 +407,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20c7021f180a0cbea0380eba97c2af3c57074cdaffe0eef7e840e1c9f2841e55" dependencies = [ "ark-bls12-377", - "ark-ec", + "ark-ec 0.4.2", "ark-models-ext", "ark-std 0.4.0", ] @@ -427,20 +418,32 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" dependencies = [ - "ark-ec", + "ark-ec 0.4.2", "ark-ff 0.4.2", "ark-serialize 0.4.2", "ark-std 0.4.0", ] +[[package]] +name = "ark-bls12-381" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df4dcc01ff89867cd86b0da835f23c3f02738353aaee7dde7495af71363b8d5" +dependencies = [ + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", +] + [[package]] name = "ark-bls12-381-ext" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1dc4b3d08f19e8ec06e949712f95b8361e43f1391d94f65e4234df03480631c" dependencies = [ - "ark-bls12-381", - "ark-ec", + "ark-bls12-381 0.4.0", + "ark-ec 0.4.2", "ark-ff 0.4.2", "ark-models-ext", "ark-serialize 0.4.2", @@ -454,7 +457,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e0605daf0cc5aa2034b78d008aaf159f56901d92a52ee4f6ecdfdac4f426700" dependencies = [ "ark-bls12-377", - "ark-ec", + "ark-ec 0.4.2", "ark-ff 0.4.2", "ark-std 0.4.0", ] @@ -466,7 +469,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccee5fba47266f460067588ee1bf070a9c760bf2050c1c509982c5719aadb4f2" dependencies = [ "ark-bw6-761", - "ark-ec", + "ark-ec 0.4.2", "ark-ff 0.4.2", "ark-models-ext", "ark-std 0.4.0", @@ -479,7 +482,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" dependencies = [ "ark-ff 0.4.2", - "ark-poly", + "ark-poly 0.4.2", "ark-serialize 0.4.2", "ark-std 0.4.0", "derivative", @@ -490,6 +493,27 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash 0.8.11", + "ark-ff 0.5.0", + "ark-poly 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.2", + "itertools 0.13.0", + "num-bigint", + "num-integer", + "num-traits", + "zeroize", +] + [[package]] name = "ark-ed-on-bls12-377" version = "0.4.0" @@ -497,7 +521,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b10d901b9ac4b38f9c32beacedfadcdd64e46f8d7f8e88c1ae1060022cf6f6c6" dependencies = [ "ark-bls12-377", - "ark-ec", + "ark-ec 0.4.2", "ark-ff 0.4.2", "ark-std 0.4.0", ] @@ -508,7 +532,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524a4fb7540df2e1a8c2e67a83ba1d1e6c3947f4f9342cc2359fc2e789ad731d" dependencies = [ - "ark-ec", + "ark-ec 0.4.2", "ark-ed-on-bls12-377", "ark-ff 0.4.2", "ark-models-ext", @@ -521,20 +545,32 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9cde0f2aa063a2a5c28d39b47761aa102bda7c13c84fc118a61b87c7b2f785c" dependencies = [ - "ark-bls12-381", - "ark-ec", + "ark-bls12-381 0.4.0", + "ark-ec 0.4.2", "ark-ff 0.4.2", "ark-std 0.4.0", ] +[[package]] +name = "ark-ed-on-bls12-381-bandersnatch" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1786b2e3832f6f0f7c8d62d5d5a282f6952a1ab99981c54cd52b6ac1d8f02df5" +dependencies = [ + "ark-bls12-381 0.5.0", + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-std 0.5.0", +] + [[package]] name = "ark-ed-on-bls12-381-bandersnatch-ext" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d15185f1acb49a07ff8cbe5f11a1adc5a93b19e211e325d826ae98e98e124346" dependencies = [ - "ark-ec", - "ark-ed-on-bls12-381-bandersnatch", + "ark-ec 0.4.2", + "ark-ed-on-bls12-381-bandersnatch 0.4.0", "ark-ff 0.4.2", "ark-models-ext", "ark-std 0.4.0", @@ -578,6 +614,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec 0.7.4", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint", + "num-traits", + "paste", + "zeroize", +] + [[package]] name = "ark-ff-asm" version = "0.3.0" @@ -598,6 +654,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote 1.0.38", + "syn 2.0.98", +] + [[package]] name = "ark-ff-macros" version = "0.3.0" @@ -623,13 +689,26 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2 1.0.93", + "quote 1.0.38", + "syn 2.0.98", +] + [[package]] name = "ark-models-ext" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e9eab5d4b5ff2f228b763d38442adc9b084b0a465409b059fac5c2308835ec2" dependencies = [ - "ark-ec", + "ark-ec 0.4.2", "ark-ff 0.4.2", "ark-serialize 0.4.2", "ark-std 0.4.0", @@ -650,17 +729,18 @@ dependencies = [ ] [[package]] -name = "ark-scale" -version = "0.0.11" +name = "ark-poly" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51bd73bb6ddb72630987d37fa963e99196896c0d0ea81b7c894567e74a2f83af" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" dependencies = [ - "ark-ec", - "ark-ff 0.4.2", - "ark-serialize 0.4.2", - "ark-std 0.4.0", - "parity-scale-codec", - "scale-info", + "ahash 0.8.11", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.2", ] [[package]] @@ -669,7 +749,7 @@ version = "0.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f69c00b3b529be29528a6f2fd5fa7b1790f8bed81b9cdca17e326538545a179" dependencies = [ - "ark-ec", + "ark-ec 0.4.2", "ark-ff 0.4.2", "ark-serialize 0.4.2", "ark-std 0.4.0", @@ -677,21 +757,6 @@ dependencies = [ "scale-info", ] -[[package]] -name = "ark-secret-scalar" -version = "0.0.2" -source = "git+https://github.com/davxy/ring-vrf?branch=locked#c64ae9b1aad7755ae1bf88016002365ffcc4912e" -dependencies = [ - "ark-ec", - "ark-ff 0.4.2", - "ark-serialize 0.4.2", - "ark-std 0.4.0", - "ark-transcript 0.0.2 (git+https://github.com/davxy/ring-vrf?branch=locked)", - "digest 0.10.7", - "getrandom_or_panic", - "zeroize", -] - [[package]] name = "ark-serialize" version = "0.3.0" @@ -708,12 +773,25 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ - "ark-serialize-derive", + "ark-serialize-derive 0.4.2", "ark-std 0.4.0", "digest 0.10.7", "num-bigint", ] +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive 0.5.0", + "ark-std 0.5.0", + "arrayvec 0.7.4", + "digest 0.10.7", + "num-bigint", +] + [[package]] name = "ark-serialize-derive" version = "0.4.2" @@ -725,6 +803,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2 1.0.93", + "quote 1.0.38", + "syn 2.0.98", +] + [[package]] name = "ark-std" version = "0.3.0" @@ -746,30 +835,47 @@ dependencies = [ "rayon", ] +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "ark-transcript" -version = "0.0.2" -source = "git+https://github.com/davxy/ring-vrf?branch=locked#c64ae9b1aad7755ae1bf88016002365ffcc4912e" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c1c928edb9d8ff24cb5dcb7651d3a98494fff3099eee95c2404cd813a9139f" dependencies = [ - "ark-ff 0.4.2", - "ark-serialize 0.4.2", - "ark-std 0.4.0", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", "digest 0.10.7", "rand_core 0.6.4", "sha3 0.10.8", ] [[package]] -name = "ark-transcript" -version = "0.0.2" -source = "git+https://github.com/w3f/ark-transcript?rev=288e49d#288e49ddba6f8f8e67be6822715afe36b11c4e65" +name = "ark-vrf" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9501da18569b2afe0eb934fb7afd5a247d238b94116155af4dd068f319adfe6d" dependencies = [ - "ark-ff 0.4.2", - "ark-serialize 0.4.2", - "ark-std 0.4.0", + "ark-bls12-381 0.5.0", + "ark-ec 0.5.0", + "ark-ed-on-bls12-381-bandersnatch 0.5.0", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", "digest 0.10.7", - "rand_core 0.6.4", - "sha3 0.10.8", + "rand_chacha 0.3.1", + "sha2 0.10.8", + "w3f-ring-proof", + "zeroize", ] [[package]] @@ -1620,27 +1726,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "bandersnatch_vrfs" -version = "0.0.4" -source = "git+https://github.com/davxy/ring-vrf?branch=locked#c64ae9b1aad7755ae1bf88016002365ffcc4912e" -dependencies = [ - "ark-bls12-381", - "ark-ec", - "ark-ed-on-bls12-381-bandersnatch", - "ark-ff 0.4.2", - "ark-serialize 0.4.2", - "ark-std 0.4.0", - "dleq_vrf", - "rand_chacha 0.3.1", - "rand_core 0.6.4", - "ring 0.1.0", - "sha2 0.10.8", - "sp-ark-bls12-381", - "sp-ark-ed-on-bls12-381-bandersnatch", - "zeroize", -] - [[package]] name = "base-x" version = "0.2.11" @@ -3357,20 +3442,6 @@ dependencies = [ "unicode-width 0.2.0", ] -[[package]] -name = "common" -version = "0.1.0" -source = "git+https://github.com/davxy/ring-proof?branch=locked#a24b371b8d51725ac2ce195aa3369b31df6c9873" -dependencies = [ - "ark-ec", - "ark-ff 0.4.2", - "ark-poly", - "ark-serialize 0.4.2", - "ark-std 0.4.0", - "fflonk", - "getrandom_or_panic", -] - [[package]] name = "common-path" version = "1.0.0" @@ -4580,7 +4651,7 @@ dependencies = [ "sp-io 30.0.0", "sp-maybe-compressed-blob 11.0.0", "tracing", - "tracing-subscriber 0.3.18", + "tracing-subscriber", ] [[package]] @@ -5436,22 +5507,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" -[[package]] -name = "dleq_vrf" -version = "0.0.2" -source = "git+https://github.com/davxy/ring-vrf?branch=locked#c64ae9b1aad7755ae1bf88016002365ffcc4912e" -dependencies = [ - "ark-ec", - "ark-ff 0.4.2", - "ark-scale 0.0.12", - "ark-secret-scalar", - "ark-serialize 0.4.2", - "ark-std 0.4.0", - "ark-transcript 0.0.2 (git+https://github.com/davxy/ring-vrf?branch=locked)", - "arrayvec 0.7.4", - "zeroize", -] - [[package]] name = "dlmalloc" version = "0.2.4" @@ -5648,6 +5703,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2 1.0.93", + "quote 1.0.38", + "syn 2.0.98", +] + [[package]] name = "either" version = "1.13.0" @@ -5739,6 +5806,26 @@ dependencies = [ "syn 2.0.98", ] +[[package]] +name = "enum-ordinalize" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +dependencies = [ + "proc-macro2 1.0.93", + "quote 1.0.38", + "syn 2.0.98", +] + [[package]] name = "enumflags2" version = "0.7.11" @@ -6093,19 +6180,6 @@ dependencies = [ "subtle 2.5.0", ] -[[package]] -name = "fflonk" -version = "0.1.0" -source = "git+https://github.com/w3f/fflonk?rev=1e854f3#1e854f35e9a65d08b11a86291405cdc95baa0a35" -dependencies = [ - "ark-ec", - "ark-ff 0.4.2", - "ark-poly", - "ark-serialize 0.4.2", - "ark-std 0.4.0", - "merlin", -] - [[package]] name = "fiat-crypto" version = "0.2.5" @@ -6597,7 +6671,7 @@ dependencies = [ "sp-runtime 31.0.1", "sp-statement-store", "tempfile", - "tracing-subscriber 0.3.18", + "tracing-subscriber", ] [[package]] @@ -7409,6 +7483,7 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ + "allocator-api2", "foldhash", "serde", ] @@ -9751,15 +9826,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" -[[package]] -name = "matchers" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" -dependencies = [ - "regex-automata 0.1.10", -] - [[package]] name = "matchers" version = "0.1.0" @@ -15696,7 +15762,7 @@ dependencies = [ "sp-core 28.0.0", "sp-core-hashing", "sp-core-hashing-proc-macro", - "sp-crypto-ec-utils 0.10.0", + "sp-crypto-ec-utils", "sp-crypto-hashing 0.1.0", "sp-crypto-hashing-proc-macro 0.1.0", "sp-database", @@ -17284,7 +17350,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.2", + "rand_core 0.9.1", "zerocopy 0.8.20", ] @@ -17305,7 +17371,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.2", + "rand_core 0.9.1", ] [[package]] @@ -17325,9 +17391,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.9.2" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a509b1a2ffbe92afab0e55c8fd99dea1c280e8171bd2d88682bb20bc41cbc2c" +checksum = "a88e0da7a2c97baa202165137c158d0a2e824ac465d13d81046727b34cb247d3" dependencies = [ "getrandom 0.3.1", "zerocopy 0.8.20", @@ -17740,23 +17806,6 @@ dependencies = [ "subtle 2.5.0", ] -[[package]] -name = "ring" -version = "0.1.0" -source = "git+https://github.com/davxy/ring-proof?branch=locked#a24b371b8d51725ac2ce195aa3369b31df6c9873" -dependencies = [ - "ark-ec", - "ark-ff 0.4.2", - "ark-poly", - "ark-serialize 0.4.2", - "ark-std 0.4.0", - "ark-transcript 0.0.2 (git+https://github.com/w3f/ark-transcript?rev=288e49d)", - "arrayvec 0.7.4", - "blake2 0.10.6", - "common", - "fflonk", -] - [[package]] name = "ring" version = "0.16.20" @@ -19147,7 +19196,7 @@ dependencies = [ "substrate-test-runtime", "tempfile", "tracing", - "tracing-subscriber 0.3.18", + "tracing-subscriber", "wat", ] @@ -19986,8 +20035,8 @@ dependencies = [ "sp-tracing 16.0.0", "thiserror 1.0.65", "tracing", - "tracing-log 0.2.0", - "tracing-subscriber 0.3.18", + "tracing-log", + "tracing-subscriber", ] [[package]] @@ -20038,7 +20087,7 @@ dependencies = [ "tokio", "tokio-stream", "tracing", - "tracing-subscriber 0.3.18", + "tracing-subscriber", "zombienet-sdk", ] @@ -22050,24 +22099,6 @@ dependencies = [ "sp-arithmetic 23.0.0", ] -[[package]] -name = "sp-ark-bls12-381" -version = "0.4.2" -source = "git+https://github.com/paritytech/arkworks-substrate?rev=caa2eed#caa2eed74beb885dd07c7db5f916f2281dad818f" -dependencies = [ - "ark-bls12-381-ext", - "sp-crypto-ec-utils 0.4.1", -] - -[[package]] -name = "sp-ark-ed-on-bls12-381-bandersnatch" -version = "0.4.2" -source = "git+https://github.com/paritytech/arkworks-substrate?rev=caa2eed#caa2eed74beb885dd07c7db5f916f2281dad818f" -dependencies = [ - "ark-ed-on-bls12-381-bandersnatch-ext", - "sp-crypto-ec-utils 0.4.1", -] - [[package]] name = "sp-authority-discovery" version = "26.0.0" @@ -22226,8 +22257,8 @@ dependencies = [ name = "sp-core" version = "28.0.0" dependencies = [ + "ark-vrf", "array-bytes", - "bandersnatch_vrfs", "bitflags 1.3.2", "blake2 0.10.6", "bounded-collections", @@ -22435,43 +22466,22 @@ dependencies = [ "sp-crypto-hashing-proc-macro 0.1.0", ] -[[package]] -name = "sp-crypto-ec-utils" -version = "0.4.1" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" -dependencies = [ - "ark-bls12-377", - "ark-bls12-377-ext", - "ark-bls12-381", - "ark-bls12-381-ext", - "ark-bw6-761", - "ark-bw6-761-ext", - "ark-ec", - "ark-ed-on-bls12-377", - "ark-ed-on-bls12-377-ext", - "ark-ed-on-bls12-381-bandersnatch", - "ark-ed-on-bls12-381-bandersnatch-ext", - "ark-scale 0.0.11", - "sp-runtime-interface 17.0.0", - "sp-std 8.0.0", -] - [[package]] name = "sp-crypto-ec-utils" version = "0.10.0" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", - "ark-bls12-381", + "ark-bls12-381 0.4.0", "ark-bls12-381-ext", "ark-bw6-761", "ark-bw6-761-ext", - "ark-ec", + "ark-ec 0.4.2", "ark-ed-on-bls12-377", "ark-ed-on-bls12-377-ext", - "ark-ed-on-bls12-381-bandersnatch", + "ark-ed-on-bls12-381-bandersnatch 0.4.0", "ark-ed-on-bls12-381-bandersnatch-ext", - "ark-scale 0.0.12", + "ark-scale", "sp-runtime-interface 24.0.0", ] @@ -22531,16 +22541,6 @@ dependencies = [ "parking_lot 0.12.3", ] -[[package]] -name = "sp-debug-derive" -version = "8.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" -dependencies = [ - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.98", -] - [[package]] name = "sp-debug-derive" version = "14.0.0" @@ -22561,17 +22561,6 @@ dependencies = [ "syn 2.0.98", ] -[[package]] -name = "sp-externalities" -version = "0.19.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" -dependencies = [ - "environmental", - "parity-scale-codec", - "sp-std 8.0.0", - "sp-storage 13.0.0", -] - [[package]] name = "sp-externalities" version = "0.25.0" @@ -22961,24 +22950,6 @@ dependencies = [ "sp-weights 31.0.0", ] -[[package]] -name = "sp-runtime-interface" -version = "17.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" -dependencies = [ - "bytes", - "impl-trait-for-tuples", - "parity-scale-codec", - "primitive-types 0.12.2", - "sp-externalities 0.19.0", - "sp-runtime-interface-proc-macro 11.0.0", - "sp-std 8.0.0", - "sp-storage 13.0.0", - "sp-tracing 10.0.0", - "sp-wasm-interface 14.0.0", - "static_assertions", -] - [[package]] name = "sp-runtime-interface" version = "24.0.0" @@ -23043,18 +23014,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "sp-runtime-interface-proc-macro" -version = "11.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" -dependencies = [ - "Inflector", - "proc-macro-crate 1.3.1", - "proc-macro2 1.0.93", - "quote 1.0.38", - "syn 2.0.98", -] - [[package]] name = "sp-runtime-interface-proc-macro" version = "17.0.0" @@ -23232,11 +23191,6 @@ dependencies = [ "x25519-dalek", ] -[[package]] -name = "sp-std" -version = "8.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" - [[package]] name = "sp-std" version = "14.0.0" @@ -23247,19 +23201,6 @@ version = "14.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12f8ee986414b0a9ad741776762f4083cd3a5128449b982a3919c4df36874834" -[[package]] -name = "sp-storage" -version = "13.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" -dependencies = [ - "impl-serde 0.4.0", - "parity-scale-codec", - "ref-cast", - "serde", - "sp-debug-derive 8.0.0", - "sp-std 8.0.0", -] - [[package]] name = "sp-storage" version = "19.0.0" @@ -23320,18 +23261,6 @@ dependencies = [ "thiserror 1.0.65", ] -[[package]] -name = "sp-tracing" -version = "10.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" -dependencies = [ - "parity-scale-codec", - "sp-std 8.0.0", - "tracing", - "tracing-core", - "tracing-subscriber 0.2.25", -] - [[package]] name = "sp-tracing" version = "16.0.0" @@ -23340,7 +23269,7 @@ dependencies = [ "regex", "tracing", "tracing-core", - "tracing-subscriber 0.3.18", + "tracing-subscriber", ] [[package]] @@ -23352,7 +23281,7 @@ dependencies = [ "parity-scale-codec", "tracing", "tracing-core", - "tracing-subscriber 0.3.18", + "tracing-subscriber", ] [[package]] @@ -23508,19 +23437,6 @@ dependencies = [ "syn 2.0.98", ] -[[package]] -name = "sp-wasm-interface" -version = "14.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" -dependencies = [ - "anyhow", - "impl-trait-for-tuples", - "log", - "parity-scale-codec", - "sp-std 8.0.0", - "wasmtime", -] - [[package]] name = "sp-wasm-interface" version = "20.0.0" @@ -24501,7 +24417,7 @@ dependencies = [ "tokio", "tokio-util", "tracing", - "tracing-subscriber 0.3.18", + "tracing-subscriber", ] [[package]] @@ -25240,7 +25156,7 @@ checksum = "3dffced63c2b5c7be278154d76b479f9f9920ed34e7574201407f0b14e2bbb93" dependencies = [ "env_logger 0.11.3", "test-log-macros", - "tracing-subscriber 0.3.18", + "tracing-subscriber", ] [[package]] @@ -25911,17 +25827,6 @@ dependencies = [ "syn 2.0.98", ] -[[package]] -name = "tracing-log" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" -dependencies = [ - "lazy_static", - "log", - "tracing-core", -] - [[package]] name = "tracing-log" version = "0.2.0" @@ -25933,38 +25838,6 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "tracing-serde" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" -dependencies = [ - "serde", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" -dependencies = [ - "ansi_term", - "chrono", - "lazy_static", - "matchers 0.0.1", - "regex", - "serde", - "serde_json", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log 0.1.3", - "tracing-serde", -] - [[package]] name = "tracing-subscriber" version = "0.3.18" @@ -25972,7 +25845,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "chrono", - "matchers 0.1.0", + "matchers", "nu-ansi-term", "once_cell", "parking_lot 0.12.3", @@ -25983,7 +25856,7 @@ dependencies = [ "time", "tracing", "tracing-core", - "tracing-log 0.2.0", + "tracing-log", ] [[package]] @@ -26449,11 +26322,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7335e4c132c28cc43caef6adb339789e599e39adbe78da0c4d547fad48cbc331" dependencies = [ "ark-bls12-377", - "ark-bls12-381", - "ark-ec", + "ark-bls12-381 0.4.0", + "ark-ec 0.4.2", "ark-ff 0.4.2", "ark-serialize 0.4.2", - "ark-serialize-derive", + "ark-serialize-derive 0.4.2", "arrayref", "constcat", "digest 0.10.7", @@ -26466,6 +26339,52 @@ dependencies = [ "zeroize", ] +[[package]] +name = "w3f-pcs" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbe7a8d5c914b69392ab3b267f679a2e546fe29afaddce47981772ac71bd02e1" +dependencies = [ + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-poly 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "merlin", +] + +[[package]] +name = "w3f-plonk-common" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aca389e494fe08c5c108b512e2328309036ee1c0bc7bdfdb743fef54d448c8c" +dependencies = [ + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-poly 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "getrandom_or_panic", + "rand_core 0.6.4", + "w3f-pcs", +] + +[[package]] +name = "w3f-ring-proof" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a639379402ad51504575dbd258740383291ac8147d3b15859bdf1ea48c677de" +dependencies = [ + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-poly 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "ark-transcript", + "w3f-pcs", + "w3f-plonk-common", +] + [[package]] name = "wait-timeout" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index 873261b19f24f..8d16593324b74 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -625,6 +625,7 @@ ark-ed-on-bls12-377-ext = { version = "0.4.1", default-features = false } ark-ed-on-bls12-381-bandersnatch = { version = "0.4.0", default-features = false } ark-ed-on-bls12-381-bandersnatch-ext = { version = "0.4.1", default-features = false } ark-scale = { version = "0.0.12", default-features = false } +ark-vrf = { version = "0.1.0", default-features = false } array-bytes = { version = "6.2.2", default-features = false } arrayvec = { version = "0.7.4" } assert_cmd = { version = "2.0.14" } @@ -1454,6 +1455,7 @@ overflow-checks = true # # This list is ordered alphabetically. [profile.dev.package] +ark-vrf = { opt-level = 3 } blake2 = { opt-level = 3 } blake2b_simd = { opt-level = 3 } chacha20poly1305 = { opt-level = 3 } diff --git a/prdoc/pr_7669.prdoc b/prdoc/pr_7669.prdoc new file mode 100644 index 0000000000000..5f0e184326aa4 --- /dev/null +++ b/prdoc/pr_7669.prdoc @@ -0,0 +1,20 @@ +title: Introduce ark-ec-vrfs +doc: +- audience: Runtime Dev + description: |- + Superseeds `bandersnatch_vrfs` with [ark-vrf](https://crates.io/crates/ark-vrf) + + - Same crypto as JAM + - With a spec: github.com/davxy/bandersnatch-vrf-spec + - Published on crates.io + + https://github.com/paritytech/polkadot-sdk/pull/7670 follow up + + NOTE: this crypto is under experimental feat +crates: +- name: sp-core + bump: major +- name: sp-keystore + bump: major +- name: sp-keyring + bump: major diff --git a/substrate/client/keystore/Cargo.toml b/substrate/client/keystore/Cargo.toml index e46fafbc3729c..8a5fa29c5485d 100644 --- a/substrate/client/keystore/Cargo.toml +++ b/substrate/client/keystore/Cargo.toml @@ -41,6 +41,7 @@ bls-experimental = [ # It should not be used in production since the implementation and interface may still # be subject to significant changes. bandersnatch-experimental = [ + "sp-application-crypto/bandersnatch-experimental", "sp-core/bandersnatch-experimental", "sp-keystore/bandersnatch-experimental", ] diff --git a/substrate/frame/sassafras/Cargo.toml b/substrate/frame/sassafras/Cargo.toml index dd091b6f8ed79..571ccfcfbd831 100644 --- a/substrate/frame/sassafras/Cargo.toml +++ b/substrate/frame/sassafras/Cargo.toml @@ -10,6 +10,9 @@ description = "Consensus extension module for Sassafras consensus." readme = "README.md" publish = false +[package.metadata.polkadot-sdk] +exclude-from-umbrella = true + [lints] workspace = true diff --git a/substrate/frame/sassafras/src/data/25_tickets_100_auths.bin b/substrate/frame/sassafras/src/data/25_tickets_100_auths.bin index 4c50b06ad9f9c..9f72a34d53980 100644 Binary files a/substrate/frame/sassafras/src/data/25_tickets_100_auths.bin and b/substrate/frame/sassafras/src/data/25_tickets_100_auths.bin differ diff --git a/substrate/frame/sassafras/src/lib.rs b/substrate/frame/sassafras/src/lib.rs index f6c409833e333..35539fd35f22c 100644 --- a/substrate/frame/sassafras/src/lib.rs +++ b/substrate/frame/sassafras/src/lib.rs @@ -90,9 +90,6 @@ pub use pallet::*; const LOG_TARGET: &str = "sassafras::runtime"; -// Contextual string used by the VRF to generate per-block randomness. -const RANDOMNESS_VRF_CONTEXT: &[u8] = b"SassafrasOnChainRandomness"; - // Max length for segments holding unsorted tickets. const SEGMENT_MAX_SIZE: u32 = 128; @@ -202,6 +199,12 @@ pub mod pallet { #[pallet::getter(fn randomness_accumulator)] pub(crate) type RandomnessAccumulator = StorageValue<_, Randomness, ValueQuery>; + /// Per slot randomness used to feed the randomness accumulator. + /// + /// The value is ephemeral and is cleared on block finalization. + #[pallet::storage] + pub(crate) type SlotRandomness = StorageValue<_, Randomness>; + /// The configuration for the current epoch. #[pallet::storage] #[pallet::getter(fn config)] @@ -272,13 +275,7 @@ pub mod pallet { /// Ring verifier data for the current epoch. #[pallet::storage] - pub type RingVerifierData = StorageValue<_, vrf::RingVerifierData>; - - /// Slot claim VRF pre-output used to generate per-slot randomness. - /// - /// The value is ephemeral and is cleared on block finalization. - #[pallet::storage] - pub(crate) type ClaimTemporaryData = StorageValue<_, vrf::VrfPreOutput>; + pub type RingVerifierData = StorageValue<_, vrf::RingVerifierKey>; /// Genesis configuration for Sassafras protocol. #[pallet::genesis_config] @@ -326,12 +323,8 @@ pub mod pallet { Self::post_genesis_initialize(claim.slot); } - let randomness_pre_output = claim - .vrf_signature - .pre_outputs - .get(0) - .expect("Valid claim must have VRF signature; qed"); - ClaimTemporaryData::::put(randomness_pre_output); + let randomness = claim.vrf_signature.pre_output.make_bytes(); + SlotRandomness::::put(randomness); let trigger_weight = T::EpochChangeTrigger::trigger::(block_num); @@ -343,15 +336,8 @@ pub mod pallet { // to the accumulator. If we've determined that this block was the first in // a new epoch, the changeover logic has already occurred at this point // (i.e. `enact_epoch_change` has already been called). - let randomness_input = vrf::slot_claim_input( - &Self::randomness(), - CurrentSlot::::get(), - EpochIndex::::get(), - ); - let randomness_pre_output = ClaimTemporaryData::::take() + let randomness = SlotRandomness::::take() .expect("Unconditionally populated in `on_initialize`; `on_finalize` is always called after; qed"); - let randomness = randomness_pre_output - .make_bytes::(RANDOMNESS_VRF_CONTEXT, &randomness_input); Self::deposit_slot_randomness(&randomness); // Check if we are in the epoch's second half. @@ -399,7 +385,9 @@ pub mod pallet { return Err("Tickets shall be submitted in the first epoch half".into()) } - let Some(verifier) = RingVerifierData::::get().map(|v| v.into()) else { + let Some(verifier) = + RingVerifierData::::get().map(|vk| vrf::RingContext::verifier_no_context(vk)) + else { warn!(target: LOG_TARGET, "Ring verifier key not initialized"); return Err("Ring verifier key not initialized".into()) }; @@ -424,15 +412,8 @@ pub mod pallet { for ticket in tickets { debug!(target: LOG_TARGET, "Checking ring proof"); - let Some(ticket_id_pre_output) = ticket.signature.pre_outputs.get(0) else { - debug!(target: LOG_TARGET, "Missing ticket VRF pre-output from ring signature"); - continue - }; - let ticket_id_input = - vrf::ticket_id_input(&randomness, ticket.body.attempt_idx, epoch_idx); - // Check threshold constraint - let ticket_id = vrf::make_ticket_id(&ticket_id_input, &ticket_id_pre_output); + let ticket_id = vrf::make_ticket_id(&ticket.signature.pre_output); if ticket_id >= ticket_threshold { debug!(target: LOG_TARGET, "Ignoring ticket over threshold ({:032x} >= {:032x})", ticket_id, ticket_threshold); continue @@ -445,6 +426,8 @@ pub mod pallet { } // Check ring signature + let ticket_id_input = + vrf::ticket_id_input(&randomness, ticket.body.attempt_idx, epoch_idx); let sign_data = vrf::ticket_body_sign_data(&ticket.body, ticket_id_input); if !ticket.signature.ring_vrf_verify(&sign_data, &verifier) { debug!(target: LOG_TARGET, "Proof verification failure for ticket ({:032x})", ticket_id); @@ -585,9 +568,7 @@ impl Pallet { let pks: Vec<_> = authorities.iter().map(|auth| *auth.as_ref()).collect(); debug!(target: LOG_TARGET, "Building ring verifier (ring size: {})", pks.len()); - let verifier_data = ring_ctx - .verifier_data(&pks) - .expect("Failed to build ring verifier. This is a bug"); + let verifier_data = ring_ctx.verifier_key(&pks); RingVerifierData::::put(verifier_data); } diff --git a/substrate/frame/sassafras/src/mock.rs b/substrate/frame/sassafras/src/mock.rs index d7e2fb63dc2f4..aa190a8ce5039 100644 --- a/substrate/frame/sassafras/src/mock.rs +++ b/substrate/frame/sassafras/src/mock.rs @@ -176,7 +176,7 @@ pub fn make_prover(pair: &AuthorityPair) -> RingProver { .collect(); log::debug!("Building prover. Ring size: {}", pks.len()); - let prover = ring_ctx.prover(&pks, prover_idx.unwrap()).unwrap(); + let prover = ring_ctx.prover(&pks, prover_idx.unwrap()); log::debug!("Done"); prover @@ -201,7 +201,7 @@ pub fn make_ticket_body(attempt_idx: u32, pair: &AuthorityPair) -> (TicketId, Ti let ticket_id_input = vrf::ticket_id_input(&randomness, attempt_idx, epoch); let ticket_id_pre_output = pair.as_inner_ref().vrf_pre_output(&ticket_id_input); - let id = vrf::make_ticket_id(&ticket_id_input, &ticket_id_pre_output); + let id = vrf::make_ticket_id(&ticket_id_pre_output); // Make a dummy ephemeral public that hopefully is unique within one test instance. // In the tests, the values within the erased public are just used to compare diff --git a/substrate/frame/sassafras/src/tests.rs b/substrate/frame/sassafras/src/tests.rs index b3dc1ebed8650..193ec675a8d08 100644 --- a/substrate/frame/sassafras/src/tests.rs +++ b/substrate/frame/sassafras/src/tests.rs @@ -261,7 +261,7 @@ fn on_first_block_after_genesis() { // Post-initialization status - assert!(ClaimTemporaryData::::exists()); + assert!(SlotRandomness::::exists()); common_assertions(); println!("[DEBUG] {}", b2h(Sassafras::randomness_accumulator())); assert_eq!( @@ -273,12 +273,11 @@ fn on_first_block_after_genesis() { // Post-finalization status - assert!(!ClaimTemporaryData::::exists()); + assert!(!SlotRandomness::::exists()); common_assertions(); - println!("[DEBUG] {}", b2h(Sassafras::randomness_accumulator())); assert_eq!( Sassafras::randomness_accumulator(), - h2b("9f2b9fd19a772c34d437dcd8b84a927e73a5cb43d3d1cd00093223d60d2b4843"), + h2b("95a508cf10f877cf0457af3503a6cb3192763d5c15a7b9a58e40dc543efae889"), ); // Header data check @@ -332,23 +331,24 @@ fn on_normal_block() { // Post-initialization status - assert!(ClaimTemporaryData::::exists()); + assert!(SlotRandomness::::exists()); common_assertions(); println!("[DEBUG] {}", b2h(Sassafras::randomness_accumulator())); assert_eq!( Sassafras::randomness_accumulator(), - h2b("9f2b9fd19a772c34d437dcd8b84a927e73a5cb43d3d1cd00093223d60d2b4843"), + h2b("95a508cf10f877cf0457af3503a6cb3192763d5c15a7b9a58e40dc543efae889"), ); let header = finalize_block(end_block); // Post-finalization status - assert!(!ClaimTemporaryData::::exists()); + assert!(!SlotRandomness::::exists()); common_assertions(); + println!("[DEBUG] {}", b2h(Sassafras::randomness_accumulator())); assert_eq!( Sassafras::randomness_accumulator(), - h2b("be9261adb9686dfd3f23f8a276b7acc7f4beb3137070beb64c282ac22d84cbf0"), + h2b("5465cb257ad20cd4b9400a9fc85af7b1e2e72b59debd8ca06580dfb76bfca394"), ); // Header data check @@ -389,34 +389,34 @@ fn produce_epoch_change_digest_no_config() { // Post-initialization status - assert!(ClaimTemporaryData::::exists()); + assert!(SlotRandomness::::exists()); common_assertions(); println!("[DEBUG] {}", b2h(Sassafras::next_randomness())); assert_eq!( Sassafras::next_randomness(), - h2b("d3a18b857af6ecc7b52f047107e684fff0058b5722d540a296d727e37eaa55b3"), + h2b("c4d374ed47b71e1c29e57143db23861916ff2d0c59ead4c51070d42ff4af2830"), ); println!("[DEBUG] {}", b2h(Sassafras::randomness_accumulator())); assert_eq!( Sassafras::randomness_accumulator(), - h2b("bf0f1228f4ff953c8c1bda2cceb668bf86ea05d7ae93e26d021c9690995d5279"), + h2b("c6d84d1f389853959c39271a38010f2f27abe6ff56cc419cf9e89eafcae1ab5e"), ); let header = finalize_block(end_block); // Post-finalization status - assert!(!ClaimTemporaryData::::exists()); + assert!(!SlotRandomness::::exists()); common_assertions(); println!("[DEBUG] {}", b2h(Sassafras::next_randomness())); assert_eq!( Sassafras::next_randomness(), - h2b("d3a18b857af6ecc7b52f047107e684fff0058b5722d540a296d727e37eaa55b3"), + h2b("c4d374ed47b71e1c29e57143db23861916ff2d0c59ead4c51070d42ff4af2830"), ); println!("[DEBUG] {}", b2h(Sassafras::randomness_accumulator())); assert_eq!( Sassafras::randomness_accumulator(), - h2b("8a1ceb346036c386d021264b10912c8b656799668004c4a487222462b394cd89"), + h2b("6ca02b90e14ef11b3855069794da7e9d4007526b0588c426c3e3533b0b6ade7a"), ); // Header data check @@ -670,7 +670,7 @@ fn block_allowed_to_skip_epochs() { // Post-initialization status - assert!(ClaimTemporaryData::::exists()); + assert!(SlotRandomness::::exists()); assert_eq!(Sassafras::genesis_slot(), start_slot); assert_eq!(Sassafras::current_slot(), start_slot + offset); assert_eq!(Sassafras::epoch_index(), 4); @@ -829,9 +829,9 @@ fn submit_tickets_with_ring_proof_check_works() { // Check state after submission assert_eq!( TicketsMeta::::get(), - TicketsMetadata { unsorted_tickets_count: 16, tickets_count: [0, 0] }, + TicketsMetadata { unsorted_tickets_count: 13, tickets_count: [0, 0] }, ); - assert_eq!(UnsortedSegments::::get(0).len(), 16); + assert_eq!(UnsortedSegments::::get(0).len(), 13); assert_eq!(UnsortedSegments::::get(1).len(), 0); finalize_block(start_block); diff --git a/substrate/primitives/consensus/sassafras/Cargo.toml b/substrate/primitives/consensus/sassafras/Cargo.toml index eb9dfd34c595c..6e094bfc1edc1 100644 --- a/substrate/primitives/consensus/sassafras/Cargo.toml +++ b/substrate/primitives/consensus/sassafras/Cargo.toml @@ -11,6 +11,9 @@ documentation = "https://docs.rs/sp-consensus-sassafras" readme = "README.md" publish = false +[package.metadata.polkadot-sdk] +exclude-from-umbrella = true + [lints] workspace = true diff --git a/substrate/primitives/consensus/sassafras/src/vrf.rs b/substrate/primitives/consensus/sassafras/src/vrf.rs index f8def1b5f189f..4a18978d3db34 100644 --- a/substrate/primitives/consensus/sassafras/src/vrf.rs +++ b/substrate/primitives/consensus/sassafras/src/vrf.rs @@ -24,88 +24,48 @@ use codec::Encode; use sp_consensus_slots::Slot; pub use sp_core::bandersnatch::{ - ring_vrf::{RingProver, RingVerifier, RingVerifierData, RingVrfSignature}, + ring_vrf::{RingProver, RingVerifier, RingVerifierKey, RingVrfSignature}, vrf::{VrfInput, VrfPreOutput, VrfSignData, VrfSignature}, }; -/// Ring VRF domain size for Sassafras consensus. -pub const RING_VRF_DOMAIN_SIZE: u32 = 2048; +/// Ring size (aka authorities count) for Sassafras consensus. +pub const RING_SIZE: usize = 1024; -/// Bandersnatch VRF [`RingContext`] specialization for Sassafras using [`RING_VRF_DOMAIN_SIZE`]. -pub type RingContext = sp_core::bandersnatch::ring_vrf::RingContext; +/// Bandersnatch VRF [`RingContext`] specialization for Sassafras using [`RING_SIZE`]. +pub type RingContext = sp_core::bandersnatch::ring_vrf::RingContext; -fn vrf_input_from_data( - domain: &[u8], - data: impl IntoIterator>, -) -> VrfInput { - let buf = data.into_iter().fold(Vec::new(), |mut buf, item| { - let bytes = item.as_ref(); - buf.extend_from_slice(bytes); - let len = u8::try_from(bytes.len()).expect("private function with well known inputs; qed"); - buf.push(len); - buf - }); - VrfInput::new(domain, buf) -} - -/// VRF input to claim slot ownership during block production. +/// Input for slot claim pub fn slot_claim_input(randomness: &Randomness, slot: Slot, epoch: u64) -> VrfInput { - vrf_input_from_data( - b"sassafras-claim-v1.0", - [randomness.as_slice(), &slot.to_le_bytes(), &epoch.to_le_bytes()], - ) + let v = [b"sassafras-ticket", randomness.as_slice(), &slot.to_le_bytes(), &epoch.to_le_bytes()] + .concat(); + VrfInput::new(&v[..]) } /// Signing-data to claim slot ownership during block production. pub fn slot_claim_sign_data(randomness: &Randomness, slot: Slot, epoch: u64) -> VrfSignData { - let input = slot_claim_input(randomness, slot, epoch); - VrfSignData::new_unchecked( - b"sassafras-slot-claim-transcript-v1.0", - Option::<&[u8]>::None, - Some(input), - ) + let v = [b"sassafras-ticket", randomness.as_slice(), &slot.to_le_bytes(), &epoch.to_le_bytes()] + .concat(); + VrfSignData::new(&v[..], &[]) } /// VRF input to generate the ticket id. pub fn ticket_id_input(randomness: &Randomness, attempt: u32, epoch: u64) -> VrfInput { - vrf_input_from_data( - b"sassafras-ticket-v1.0", - [randomness.as_slice(), &attempt.to_le_bytes(), &epoch.to_le_bytes()], - ) -} - -/// VRF input to generate the revealed key. -pub fn revealed_key_input(randomness: &Randomness, attempt: u32, epoch: u64) -> VrfInput { - vrf_input_from_data( - b"sassafras-revealed-v1.0", - [randomness.as_slice(), &attempt.to_le_bytes(), &epoch.to_le_bytes()], - ) + let v = + [b"sassafras-ticket", randomness.as_slice(), &attempt.to_le_bytes(), &epoch.to_le_bytes()] + .concat(); + VrfInput::new(&v[..]) } /// Data to be signed via ring-vrf. pub fn ticket_body_sign_data(ticket_body: &TicketBody, ticket_id_input: VrfInput) -> VrfSignData { - VrfSignData::new_unchecked( - b"sassafras-ticket-body-transcript-v1.0", - Some(ticket_body.encode().as_slice()), - Some(ticket_id_input), - ) + VrfSignData { vrf_input: ticket_id_input, aux_data: ticket_body.encode() } } -/// Make ticket-id from the given VRF input and pre-output. +/// Make ticket-id from the given VRF pre-output. /// -/// Input should have been obtained via [`ticket_id_input`]. /// Pre-output should have been obtained from the input directly using the vrf -/// secret key or from the vrf signature pre-outputs. -pub fn make_ticket_id(input: &VrfInput, pre_output: &VrfPreOutput) -> TicketId { - let bytes = pre_output.make_bytes::<16>(b"ticket-id", input); +/// secret key or from the vrf signature pre-output. +pub fn make_ticket_id(preout: &VrfPreOutput) -> TicketId { + let bytes: [u8; 16] = preout.make_bytes()[..16].try_into().unwrap(); u128::from_le_bytes(bytes) } - -/// Make revealed key seed from a given VRF input and pre-output. -/// -/// Input should have been obtained via [`revealed_key_input`]. -/// Pre-output should have been obtained from the input directly using the vrf -/// secret key or from the vrf signature pre-outputs. -pub fn make_revealed_key_seed(input: &VrfInput, pre_output: &VrfPreOutput) -> [u8; 32] { - pre_output.make_bytes::<32>(b"revealed-seed", input) -} diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 92fc04ccf23fd..e0a409183ab6c 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -62,9 +62,7 @@ secp256k1 = { features = ["alloc", "recovery"], optional = true, workspace = tru # bls crypto w3f-bls = { optional = true, workspace = true } # bandersnatch crypto -bandersnatch_vrfs = { git = "https://github.com/davxy/ring-vrf", branch = "locked", default-features = false, features = [ - "substrate-curves", -], optional = true } +ark-vrf = { optional = true, workspace = true, features = ["bandersnatch", "ring"] } [dev-dependencies] criterion = { workspace = true, default-features = true } @@ -82,7 +80,7 @@ bench = false default = ["std"] std = [ - "bandersnatch_vrfs?/std", + "ark-vrf?/std", "bip39/rand", "bip39/std", "blake2/std", @@ -157,4 +155,4 @@ bls-experimental = ["w3f-bls"] # This feature adds Bandersnatch crypto primitives. # It should not be used in production since the implementation and interface may still # be subject to significant changes. -bandersnatch-experimental = ["bandersnatch_vrfs"] +bandersnatch-experimental = ["ark-vrf"] diff --git a/substrate/primitives/core/src/bandersnatch.rs b/substrate/primitives/core/src/bandersnatch.rs index 0ede8119ce3d9..891af7f72f59b 100644 --- a/substrate/primitives/core/src/bandersnatch.rs +++ b/substrate/primitives/core/src/bandersnatch.rs @@ -26,30 +26,32 @@ use crate::crypto::{ ByteArray, CryptoType, CryptoTypeId, DeriveError, DeriveJunction, Pair as TraitPair, PublicBytes, SecretStringError, SignatureBytes, UncheckedFrom, VrfPublic, }; - -use bandersnatch_vrfs::{CanonicalSerialize, SecretKey}; +use alloc::{vec, vec::Vec}; +use ark_vrf::{ + reexports::{ + ark_ec::CurveGroup, + ark_serialize::{CanonicalDeserialize, CanonicalSerialize}, + }, + suites::bandersnatch::{self, BandersnatchSha512Ell2 as BandersnatchSuite, Secret}, + Suite, +}; use codec::{Decode, DecodeWithMemTracking, Encode, EncodeLike, MaxEncodedLen}; use scale_info::TypeInfo; -use alloc::{vec, vec::Vec}; - /// Identifier used to match public keys against bandersnatch-vrf keys. pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"band"); -/// Context used to produce a plain signature without any VRF input/output. -pub const SIGNING_CTX: &[u8] = b"BandersnatchSigningContext"; - /// The byte length of secret key seed. pub const SEED_SERIALIZED_SIZE: usize = 32; /// The byte length of serialized public key. -pub const PUBLIC_SERIALIZED_SIZE: usize = 33; +pub const PUBLIC_SERIALIZED_SIZE: usize = 32; /// The byte length of serialized signature. -pub const SIGNATURE_SERIALIZED_SIZE: usize = 65; +pub const SIGNATURE_SERIALIZED_SIZE: usize = 64; /// The byte length of serialized pre-output. -pub const PREOUT_SERIALIZED_SIZE: usize = 33; +pub const PREOUT_SERIALIZED_SIZE: usize = 32; #[doc(hidden)] pub struct BandersnatchTag; @@ -61,10 +63,7 @@ impl CryptoType for Public { type Pair = Pair; } -/// Bandersnatch signature. -/// -/// The signature is created via the [`VrfSecret::vrf_sign`] using [`SIGNING_CTX`] as transcript -/// `label`. +/// Bandersnatch Schnorr signature. pub type Signature = SignatureBytes; impl CryptoType for Signature { @@ -77,8 +76,11 @@ type Seed = [u8; SEED_SERIALIZED_SIZE]; /// Bandersnatch secret key. #[derive(Clone)] pub struct Pair { - secret: SecretKey, + secret: Secret, seed: Seed, + // This is only read back in the sign operaton + #[allow(dead_code)] + prefix: Seed, } impl Pair { @@ -102,8 +104,12 @@ impl TraitPair for Pair { } let mut seed = [0; SEED_SERIALIZED_SIZE]; seed.copy_from_slice(seed_slice); - let secret = SecretKey::from_seed(&seed); - Ok(Pair { secret, seed }) + let h = ark_vrf::utils::hash::<::Hasher>(&seed); + // Extract and cache the high half. + let mut prefix = [0; SEED_SERIALIZED_SIZE]; + prefix.copy_from_slice(&h[32..64]); + let secret = Secret::from_seed(&seed); + Ok(Pair { secret, seed, prefix }) } /// Derive a child key from a series of given (hard) junctions. @@ -130,7 +136,7 @@ impl TraitPair for Pair { } fn public(&self) -> Public { - let public = self.secret.to_public(); + let public = self.secret.public(); let mut raw = [0; PUBLIC_SERIALIZED_SIZE]; public .serialize_compressed(raw.as_mut_slice()) @@ -138,26 +144,39 @@ impl TraitPair for Pair { Public::unchecked_from(raw) } - /// Sign a message. - /// - /// In practice this produce a Schnorr signature of a transcript composed by - /// the constant label [`SIGNING_CTX`] and `data` without any additional data. - /// - /// See [`vrf::VrfSignData`] for additional details. #[cfg(feature = "full_crypto")] fn sign(&self, data: &[u8]) -> Signature { - let data = vrf::VrfSignData::new_unchecked(SIGNING_CTX, &[data], None); - self.vrf_sign(&data).signature + // Deterministic nonce for plain Schnorr signature. + // Inspired by ed25519 + let h_in = [&self.prefix[..32], data].concat(); + let h = &ark_vrf::utils::hash::<::Hasher>(&h_in)[..32]; + let k = ark_vrf::codec::scalar_decode::(h); + let gk = BandersnatchSuite::generator() * k; + let c = BandersnatchSuite::challenge(&[&gk.into_affine(), &self.secret.public.0], data); + let s = k + c * self.secret.scalar; + let mut raw_signature = [0_u8; SIGNATURE_SERIALIZED_SIZE]; + bandersnatch::IetfProof { c, s } + .serialize_compressed(&mut raw_signature.as_mut_slice()) + .expect("serialization length is constant and checked by test; qed"); + Signature::from_raw(raw_signature) } fn verify>(signature: &Signature, data: M, public: &Public) -> bool { - let data = vrf::VrfSignData::new_unchecked(SIGNING_CTX, &[data.as_ref()], None); - let signature = - vrf::VrfSignature { signature: *signature, pre_outputs: vrf::VrfIosVec::default() }; - public.vrf_verify(&data, &signature) + let Ok(signature) = bandersnatch::IetfProof::deserialize_compressed(&signature.0[..]) + else { + return false + }; + let Ok(public) = bandersnatch::Public::deserialize_compressed(&public.0[..]) else { + return false + }; + let gs = BandersnatchSuite::generator() * signature.s; + let yc = public.0 * signature.c; + let rv = gs - yc; + let cv = BandersnatchSuite::challenge(&[&rv.into_affine(), &public.0], data.as_ref()); + signature.c == cv } - /// Return a vector filled with the seed (32 bytes). + /// Return a vector filled with the seed. fn to_raw_vec(&self) -> Vec { self.seed().to_vec() } @@ -170,42 +189,30 @@ impl CryptoType for Pair { /// Bandersnatch VRF types and operations. pub mod vrf { use super::*; - use crate::{bounded::BoundedVec, crypto::VrfCrypto, ConstU32}; - use bandersnatch_vrfs::{ - CanonicalDeserialize, CanonicalSerialize, IntoVrfInput, Message, PublicKey, - ThinVrfSignature, Transcript, - }; + use crate::crypto::VrfCrypto; - /// Max number of inputs/pre-outputs which can be handled by the VRF signing procedures. - /// - /// The number is quite arbitrary and chosen to fulfill the use cases found so far. - /// If required it can be extended in the future. - pub const MAX_VRF_IOS: u32 = 3; - - /// Bounded vector used for VRF inputs and pre-outputs. - /// - /// Can contain at most [`MAX_VRF_IOS`] elements. - pub type VrfIosVec = BoundedVec>; + /// [`VrfSignature`] serialized size. + pub const VRF_SIGNATURE_SERIALIZED_SIZE: usize = + PREOUT_SERIALIZED_SIZE + SIGNATURE_SERIALIZED_SIZE; /// VRF input to construct a [`VrfPreOutput`] instance and embeddable in [`VrfSignData`]. #[derive(Clone, Debug)] - pub struct VrfInput(pub(super) bandersnatch_vrfs::VrfInput); + pub struct VrfInput(pub(super) bandersnatch::Input); impl VrfInput { /// Construct a new VRF input. - pub fn new(domain: impl AsRef<[u8]>, data: impl AsRef<[u8]>) -> Self { - let msg = Message { domain: domain.as_ref(), message: data.as_ref() }; - VrfInput(msg.into_vrf_input()) + /// + /// Hash to Curve (H2C) using Elligator2. + pub fn new(data: &[u8]) -> Self { + Self(bandersnatch::Input::new(data).expect("H2C for Bandersnatch can't fail; qed")) } } /// VRF pre-output derived from [`VrfInput`] using a [`VrfSecret`]. /// - /// This object is used to produce an arbitrary number of verifiable pseudo random - /// bytes and is often called pre-output to emphasize that this is not the actual - /// output of the VRF but an object capable of generating the output. + /// This object is hashed to produce the actual VRF output. #[derive(Clone, Debug, PartialEq, Eq)] - pub struct VrfPreOutput(pub(super) bandersnatch_vrfs::VrfPreOut); + pub struct VrfPreOutput(pub(super) bandersnatch::Output); impl Encode for VrfPreOutput { fn encode(&self) -> Vec { @@ -220,22 +227,17 @@ pub mod vrf { impl Decode for VrfPreOutput { fn decode(i: &mut R) -> Result { let buf = <[u8; PREOUT_SERIALIZED_SIZE]>::decode(i)?; - let preout = - bandersnatch_vrfs::VrfPreOut::deserialize_compressed_unchecked(buf.as_slice()) - .map_err(|_| "vrf-preout decode error: bad preout")?; + let preout = bandersnatch::Output::deserialize_compressed_unchecked(buf.as_slice()) + .map_err(|_| "vrf-preout decode error: bad preout")?; Ok(VrfPreOutput(preout)) } } // `VrfPreOutput` resolves to: // ``` - // pub struct Affine { - // #[doc(hidden)] + // pub struct Affine { // pub x: P::BaseField, - // #[doc(hidden)] // pub y: P::BaseField, - // #[doc(hidden)] - // pub infinity: bool, // } // ``` // where each `P::BaseField` contains a `pub struct BigInt(pub [u64; N]);` @@ -261,101 +263,38 @@ pub mod vrf { /// Data to be signed via one of the two provided vrf flavors. /// - /// The object contains a transcript and a sequence of [`VrfInput`]s ready to be signed. + /// The object contains the VRF input and additional data to be signed together + /// with the VRF input. Additional data doesn't influence the VRF output. /// - /// The `transcript` summarizes a set of messages which are defining a particular - /// protocol by automating the Fiat-Shamir transform for challenge generation. - /// A good explanation of the topic can be found in Merlin [docs](https://merlin.cool/) - /// - /// The `inputs` is a sequence of [`VrfInput`]s which, during the signing procedure, are - /// first transformed to [`VrfPreOutput`]s. Both inputs and pre-outputs are then appended to - /// the transcript before signing the Fiat-Shamir transform result (the challenge). - /// - /// In practice, as a user, all these technical details can be easily ignored. - /// What is important to remember is: - /// - *Transcript* is an object defining the protocol and used to produce the signature. This - /// object doesn't influence the `VrfPreOutput`s values. - /// - *Vrf inputs* is some additional data which is used to produce *vrf pre-outputs*. This data - /// will contribute to the signature as well. + /// The `input` is a [`VrfInput`]s which, during the signing procedure, is first mapped + /// to a [`VrfPreOutput`]. #[derive(Clone)] pub struct VrfSignData { - /// Associated protocol transcript. - pub transcript: Transcript, - /// VRF inputs to be signed. - pub inputs: VrfIosVec, + /// VRF input. + pub vrf_input: VrfInput, + /// Additional data. + pub aux_data: Vec, } impl VrfSignData { /// Construct a new data to be signed. - /// - /// Fails if the `inputs` iterator yields more elements than [`MAX_VRF_IOS`] - /// - /// Refer to [`VrfSignData`] for details about transcript and inputs. - pub fn new( - transcript_label: &'static [u8], - transcript_data: impl IntoIterator>, - inputs: impl IntoIterator, - ) -> Result { - let inputs: Vec = inputs.into_iter().collect(); - if inputs.len() > MAX_VRF_IOS as usize { - return Err(()) - } - Ok(Self::new_unchecked(transcript_label, transcript_data, inputs)) - } - - /// Construct a new data to be signed. - /// - /// At most the first [`MAX_VRF_IOS`] elements of `inputs` are used. - /// - /// Refer to [`VrfSignData`] for details about transcript and inputs. - pub fn new_unchecked( - transcript_label: &'static [u8], - transcript_data: impl IntoIterator>, - inputs: impl IntoIterator, - ) -> Self { - let inputs: Vec = inputs.into_iter().collect(); - let inputs = VrfIosVec::truncate_from(inputs); - let mut transcript = Transcript::new_labeled(transcript_label); - transcript_data.into_iter().for_each(|data| transcript.append(data.as_ref())); - VrfSignData { transcript, inputs } - } - - /// Append a message to the transcript. - pub fn push_transcript_data(&mut self, data: &[u8]) { - self.transcript.append(data); - } - - /// Tries to append a [`VrfInput`] to the vrf inputs list. - /// - /// On failure, returns back the [`VrfInput`] parameter. - pub fn push_vrf_input(&mut self, input: VrfInput) -> Result<(), VrfInput> { - self.inputs.try_push(input) - } - - /// Get the challenge associated to the `transcript` contained within the signing data. - /// - /// Ignores the vrf inputs and outputs. - pub fn challenge(&self) -> [u8; N] { - let mut output = [0; N]; - let mut transcript = self.transcript.clone(); - let mut reader = transcript.challenge(b"bandersnatch challenge"); - reader.read_bytes(&mut output); - output + pub fn new(vrf_input_data: &[u8], aux_data: &[u8]) -> Self { + Self { vrf_input: VrfInput::new(vrf_input_data), aux_data: aux_data.to_vec() } } } /// VRF signature. /// - /// Includes both the transcript `signature` and the `pre-outputs` generated from the - /// [`VrfSignData::inputs`]. + /// Includes both the VRF proof and the pre-output generated from the + /// [`VrfSignData::vrf_input`]. /// /// Refer to [`VrfSignData`] for more details. #[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo)] pub struct VrfSignature { - /// Transcript signature. - pub signature: Signature, - /// VRF pre-outputs. - pub pre_outputs: VrfIosVec, + /// VRF pre-output. + pub pre_output: VrfPreOutput, + /// VRF proof. + pub proof: Signature, } #[cfg(feature = "full_crypto")] @@ -368,21 +307,21 @@ pub mod vrf { #[cfg(feature = "full_crypto")] impl VrfSecret for Pair { - fn vrf_sign(&self, data: &Self::VrfSignData) -> Self::VrfSignature { - const _: () = assert!(MAX_VRF_IOS == 3, "`MAX_VRF_IOS` expected to be 3"); - // Workaround to overcome backend signature generic over the number of IOs. - match data.inputs.len() { - 0 => self.vrf_sign_gen::<0>(data), - 1 => self.vrf_sign_gen::<1>(data), - 2 => self.vrf_sign_gen::<2>(data), - 3 => self.vrf_sign_gen::<3>(data), - _ => unreachable!(), - } + fn vrf_sign(&self, data: &VrfSignData) -> VrfSignature { + use ark_vrf::ietf::Prover; + let pre_output_impl = self.secret.output(data.vrf_input.0); + let pre_output = VrfPreOutput(pre_output_impl); + let proof_impl = self.secret.prove(data.vrf_input.0, pre_output.0, &data.aux_data); + let mut proof = Signature::default(); + proof_impl + .serialize_compressed(proof.0.as_mut_slice()) + .expect("serialization length is constant and checked by test; qed"); + VrfSignature { pre_output, proof } } fn vrf_pre_output(&self, input: &Self::VrfInput) -> Self::VrfPreOutput { - let pre_output = self.secret.vrf_preout(&input.0); - VrfPreOutput(pre_output) + let pre_output_impl = self.secret.output(input.0); + VrfPreOutput(pre_output_impl) } } @@ -394,97 +333,38 @@ pub mod vrf { } impl VrfPublic for Public { - fn vrf_verify(&self, data: &Self::VrfSignData, signature: &Self::VrfSignature) -> bool { - const _: () = assert!(MAX_VRF_IOS == 3, "`MAX_VRF_IOS` expected to be 3"); - let pre_outputs_len = signature.pre_outputs.len(); - if pre_outputs_len != data.inputs.len() { + fn vrf_verify(&self, data: &VrfSignData, signature: &VrfSignature) -> bool { + use ark_vrf::ietf::Verifier; + let Ok(public) = + bandersnatch::Public::deserialize_compressed_unchecked(self.as_slice()) + else { return false - } - // Workaround to overcome backend signature generic over the number of IOs. - match pre_outputs_len { - 0 => self.vrf_verify_gen::<0>(data, signature), - 1 => self.vrf_verify_gen::<1>(data, signature), - 2 => self.vrf_verify_gen::<2>(data, signature), - 3 => self.vrf_verify_gen::<3>(data, signature), - _ => unreachable!(), - } + }; + let Ok(proof) = + ark_vrf::ietf::Proof::deserialize_compressed_unchecked(signature.proof.as_slice()) + else { + return false + }; + public + .verify(data.vrf_input.0, signature.pre_output.0, &data.aux_data, &proof) + .is_ok() } } #[cfg(feature = "full_crypto")] impl Pair { - fn vrf_sign_gen(&self, data: &VrfSignData) -> VrfSignature { - let ios = core::array::from_fn(|i| self.secret.vrf_inout(data.inputs[i].0)); - - let thin_signature: ThinVrfSignature = - self.secret.sign_thin_vrf(data.transcript.clone(), &ios); - - let pre_outputs: Vec<_> = - thin_signature.preouts.into_iter().map(VrfPreOutput).collect(); - let pre_outputs = VrfIosVec::truncate_from(pre_outputs); - - let mut signature = VrfSignature { signature: Signature::default(), pre_outputs }; - - thin_signature - .proof - .serialize_compressed(signature.signature.0.as_mut_slice()) - .expect("serialization length is constant and checked by test; qed"); - - signature - } - - /// Generate an arbitrary number of bytes from the given `context` and VRF `input`. - pub fn make_bytes( - &self, - context: &'static [u8], - input: &VrfInput, - ) -> [u8; N] { - let transcript = Transcript::new_labeled(context); - let inout = self.secret.vrf_inout(input.0); - inout.vrf_output_bytes(transcript) - } - } - - impl Public { - fn vrf_verify_gen( - &self, - data: &VrfSignData, - signature: &VrfSignature, - ) -> bool { - let Ok(public) = PublicKey::deserialize_compressed_unchecked(self.as_slice()) else { - return false - }; - - let preouts: [bandersnatch_vrfs::VrfPreOut; N] = - core::array::from_fn(|i| signature.pre_outputs[i].0); - - // Deserialize only the proof, the rest has already been deserialized - // This is another hack used because backend signature type is generic over - // the number of ios. - let Ok(proof) = ThinVrfSignature::<0>::deserialize_compressed_unchecked( - signature.signature.as_slice(), - ) - .map(|s| s.proof) else { - return false - }; - let signature = ThinVrfSignature { proof, preouts }; - - let inputs = data.inputs.iter().map(|i| i.0); - - public.verify_thin_vrf(data.transcript.clone(), inputs, &signature).is_ok() + /// Generate VRF output bytes for the given `input`. + pub fn make_bytes(&self, input: &VrfInput) -> [u8; 32] { + self.vrf_pre_output(input).make_bytes() } } impl VrfPreOutput { - /// Generate an arbitrary number of bytes from the given `context` and VRF `input`. - pub fn make_bytes( - &self, - context: &'static [u8], - input: &VrfInput, - ) -> [u8; N] { - let transcript = Transcript::new_labeled(context); - let inout = bandersnatch_vrfs::VrfInOut { input: input.0, preoutput: self.0 }; - inout.vrf_output_bytes(transcript) + /// Generate VRF output bytes. + pub fn make_bytes(&self) -> [u8; 32] { + let mut bytes = [0_u8; 32]; + bytes.copy_from_slice(&self.0.hash()[..32]); + bytes } } } @@ -492,80 +372,62 @@ pub mod vrf { /// Bandersnatch Ring-VRF types and operations. pub mod ring_vrf { use super::{vrf::*, *}; - pub use bandersnatch_vrfs::ring::{RingProof, RingProver, RingVerifier, KZG}; - use bandersnatch_vrfs::{ring::VerifierKey, CanonicalDeserialize, PublicKey}; - - /// Overhead in the domain size with respect to the supported ring size. - /// - /// Some bits of the domain are reserved for the zk-proof to work. - pub const RING_DOMAIN_OVERHEAD: u32 = 257; + use bandersnatch::{RingProofParams, RingVerifierKey as RingVerifierKeyImpl}; + pub use bandersnatch::{RingProver, RingVerifier}; // Max size of serialized ring-vrf context given `domain_len`. - pub(crate) const fn ring_context_serialized_size(domain_len: u32) -> usize { - // const G1_POINT_COMPRESSED_SIZE: usize = 48; - // const G2_POINT_COMPRESSED_SIZE: usize = 96; + pub(crate) fn ring_context_serialized_size(ring_size: usize) -> usize { const G1_POINT_UNCOMPRESSED_SIZE: usize = 96; const G2_POINT_UNCOMPRESSED_SIZE: usize = 192; - const OVERHEAD_SIZE: usize = 20; + const OVERHEAD_SIZE: usize = 16; const G2_POINTS_NUM: usize = 2; - let g1_points_num = 3 * domain_len as usize + 1; - + let g1_points_num = ark_vrf::ring::pcs_domain_size::(ring_size); OVERHEAD_SIZE + g1_points_num * G1_POINT_UNCOMPRESSED_SIZE + G2_POINTS_NUM * G2_POINT_UNCOMPRESSED_SIZE } - pub(crate) const RING_VERIFIER_DATA_SERIALIZED_SIZE: usize = 388; - pub(crate) const RING_SIGNATURE_SERIALIZED_SIZE: usize = 755; - - /// remove as soon as soon as serialization is implemented by the backend - pub struct RingVerifierData { - /// Domain size. - pub domain_size: u32, - /// Verifier key. - pub verifier_key: VerifierKey, - } + /// [`RingVerifierKey`] serialized size. + pub const RING_VERIFIER_KEY_SERIALIZED_SIZE: usize = 384; + /// [`RingProof`] serialized size. + pub(crate) const RING_PROOF_SERIALIZED_SIZE: usize = 752; + /// [`RingVrfSignature`] serialized size. + pub const RING_SIGNATURE_SERIALIZED_SIZE: usize = + RING_PROOF_SERIALIZED_SIZE + PREOUT_SERIALIZED_SIZE; - impl From for RingVerifier { - fn from(vd: RingVerifierData) -> RingVerifier { - bandersnatch_vrfs::ring::make_ring_verifier(vd.verifier_key, vd.domain_size as usize) - } - } + /// Ring verifier key + pub struct RingVerifierKey(RingVerifierKeyImpl); - impl Encode for RingVerifierData { + impl Encode for RingVerifierKey { fn encode(&self) -> Vec { - const ERR_STR: &str = "serialization length is constant and checked by test; qed"; - let mut buf = [0; RING_VERIFIER_DATA_SERIALIZED_SIZE]; - self.domain_size.serialize_compressed(&mut buf[..4]).expect(ERR_STR); - self.verifier_key.serialize_compressed(&mut buf[4..]).expect(ERR_STR); - buf.encode() + let mut buf = Vec::with_capacity(RING_VERIFIER_KEY_SERIALIZED_SIZE); + self.0 + .serialize_compressed(&mut buf) + .expect("serialization length is constant and checked by test; qed"); + buf } } - impl Decode for RingVerifierData { - fn decode(i: &mut R) -> Result { - const ERR_STR: &str = "serialization length is constant and checked by test; qed"; - let buf = <[u8; RING_VERIFIER_DATA_SERIALIZED_SIZE]>::decode(i)?; - let domain_size = - ::deserialize_compressed_unchecked(&mut &buf[..4]) - .expect(ERR_STR); - let verifier_key = ::deserialize_compressed_unchecked(&mut &buf[4..]).expect(ERR_STR); - - Ok(RingVerifierData { domain_size, verifier_key }) + impl Decode for RingVerifierKey { + fn decode(input: &mut R) -> Result { + let mut buf = vec![0; RING_VERIFIER_KEY_SERIALIZED_SIZE]; + input.read(&mut buf[..])?; + let vk = RingVerifierKeyImpl::deserialize_compressed_unchecked(buf.as_slice()) + .map_err(|_| "RingVerifierKey decode error")?; + Ok(RingVerifierKey(vk)) } } - impl EncodeLike for RingVerifierData {} + impl EncodeLike for RingVerifierKey {} - impl MaxEncodedLen for RingVerifierData { + impl MaxEncodedLen for RingVerifierKey { fn max_encoded_len() -> usize { - <[u8; RING_VERIFIER_DATA_SERIALIZED_SIZE]>::max_encoded_len() + RING_VERIFIER_KEY_SERIALIZED_SIZE } } - impl TypeInfo for RingVerifierData { - type Identity = [u8; RING_VERIFIER_DATA_SERIALIZED_SIZE]; - + impl TypeInfo for RingVerifierKey { + type Identity = [u8; RING_VERIFIER_KEY_SERIALIZED_SIZE]; fn type_info() -> scale_info::Type { Self::Identity::type_info() } @@ -573,98 +435,97 @@ pub mod ring_vrf { /// Context used to construct ring prover and verifier. /// - /// Generic parameter `D` represents the ring domain size and drives - /// the max number of supported ring members [`RingContext::max_keyset_size`] - /// which is equal to `D - RING_DOMAIN_OVERHEAD`. + /// Generic parameter `R` represents the ring size. #[derive(Clone)] - pub struct RingContext(KZG); + pub struct RingContext(RingProofParams); - impl RingContext { + impl RingContext { /// Build an dummy instance for testing purposes. pub fn new_testing() -> Self { - Self(KZG::testing_kzg_setup([0; 32], D)) + Self(RingProofParams::from_seed(R, [0; 32])) } /// Get the keyset max size. pub fn max_keyset_size(&self) -> usize { - self.0.max_keyset_size() + self.0.max_ring_size() } /// Get ring prover for the key at index `public_idx` in the `public_keys` set. - pub fn prover(&self, public_keys: &[Public], public_idx: usize) -> Option { - let mut pks = Vec::with_capacity(public_keys.len()); - for public_key in public_keys { - let pk = PublicKey::deserialize_compressed_unchecked(public_key.as_slice()).ok()?; - pks.push(pk.0.into()); - } - - let prover_key = self.0.prover_key(pks); - let ring_prover = self.0.init_ring_prover(prover_key, public_idx); - Some(ring_prover) + pub fn prover(&self, public_keys: &[Public], public_idx: usize) -> RingProver { + let pks = Self::make_ring_vector(public_keys); + let prover_key = self.0.prover_key(&pks); + self.0.prover(prover_key, public_idx) } /// Get ring verifier for the `public_keys` set. - pub fn verifier(&self, public_keys: &[Public]) -> Option { - let mut pks = Vec::with_capacity(public_keys.len()); - for public_key in public_keys { - let pk = PublicKey::deserialize_compressed_unchecked(public_key.as_slice()).ok()?; - pks.push(pk.0.into()); - } + pub fn verifier(&self, public_keys: &[Public]) -> RingVerifier { + let vk = self.verifier_key(public_keys); + self.0.verifier(vk.0) + } - let verifier_key = self.0.verifier_key(pks); - let ring_verifier = self.0.init_ring_verifier(verifier_key); - Some(ring_verifier) + /// Build `RingVerifierKey` for lazy `RingVerifier` construction. + pub fn verifier_key(&self, public_keys: &[Public]) -> RingVerifierKey { + let pks = Self::make_ring_vector(public_keys); + RingVerifierKey(self.0.verifier_key(&pks)) } - /// Information required for a lazy construction of a ring verifier. - pub fn verifier_data(&self, public_keys: &[Public]) -> Option { - let mut pks = Vec::with_capacity(public_keys.len()); - for public_key in public_keys { - let pk = PublicKey::deserialize_compressed_unchecked(public_key.as_slice()).ok()?; - pks.push(pk.0.into()); - } - Some(RingVerifierData { - verifier_key: self.0.verifier_key(pks), - domain_size: self.0.domain_size, - }) + /// Constructs a `RingVerifier` from a `VerifierKey` without a `RingContext` instance. + /// + /// While this approach is computationally slightly less efficient than using a + /// pre-constructed `RingContext`, as some parameters need to be computed on-the-fly, it + /// is beneficial in memory or storage constrained environments. This avoids the need to + /// retain the full `RingContext` for ring signature verification. Instead, the + /// `VerifierKey` contains only the essential information needed to verify ring proofs. + pub fn verifier_no_context(verifier_key: RingVerifierKey) -> RingVerifier { + RingProofParams::verifier_no_context(verifier_key.0, R) + } + + fn make_ring_vector(public_keys: &[Public]) -> Vec { + use bandersnatch::AffinePoint; + public_keys + .iter() + .map(|pk| { + AffinePoint::deserialize_compressed_unchecked(pk.as_slice()) + .unwrap_or(RingProofParams::padding_point()) + }) + .collect() } } - impl Encode for RingContext { + impl Encode for RingContext { fn encode(&self) -> Vec { - let mut buf = vec![0; ring_context_serialized_size(D)]; + let mut buf = Vec::with_capacity(ring_context_serialized_size(R)); self.0 - .serialize_uncompressed(buf.as_mut_slice()) + .serialize_uncompressed(&mut buf) .expect("serialization length is constant and checked by test; qed"); buf } } - impl Decode for RingContext { - fn decode(input: &mut R) -> Result { - let mut buf = vec![0; ring_context_serialized_size(D)]; + impl Decode for RingContext { + fn decode(input: &mut I) -> Result { + let mut buf = vec![0; ring_context_serialized_size(R)]; input.read(&mut buf[..])?; - let kzg = KZG::deserialize_uncompressed_unchecked(buf.as_slice()) - .map_err(|_| "KZG decode error")?; - Ok(RingContext(kzg)) + let ctx = RingProofParams::deserialize_uncompressed_unchecked(buf.as_slice()) + .map_err(|_| "RingContext decode error")?; + Ok(RingContext(ctx)) } } - impl EncodeLike for RingContext {} + impl EncodeLike for RingContext {} - impl MaxEncodedLen for RingContext { + impl MaxEncodedLen for RingContext { fn max_encoded_len() -> usize { - ring_context_serialized_size(D) + ring_context_serialized_size(R) } } - impl TypeInfo for RingContext { + impl TypeInfo for RingContext { type Identity = Self; - fn type_info() -> scale_info::Type { let path = scale_info::Path::new("RingContext", module_path!()); let array_type_def = scale_info::TypeDefArray { - len: ring_context_serialized_size(D) as u32, + len: ring_context_serialized_size(R) as u32, type_param: scale_info::MetaType::new::(), }; let type_def = scale_info::TypeDef::Array(array_type_def); @@ -677,10 +538,10 @@ pub mod ring_vrf { Clone, Debug, PartialEq, Eq, Encode, Decode, DecodeWithMemTracking, MaxEncodedLen, TypeInfo, )] pub struct RingVrfSignature { + /// VRF pre-output. + pub pre_output: VrfPreOutput, /// Ring signature. - pub signature: [u8; RING_SIGNATURE_SERIALIZED_SIZE], - /// VRF pre-outputs. - pub pre_outputs: VrfIosVec, + pub proof: [u8; RING_PROOF_SERIALIZED_SIZE], } #[cfg(feature = "full_crypto")] @@ -691,41 +552,16 @@ pub mod ring_vrf { /// signing [`Pair`] is part of the ring from which the [`RingProver`] has /// been constructed. If not, the produced signature is just useless. pub fn ring_vrf_sign(&self, data: &VrfSignData, prover: &RingProver) -> RingVrfSignature { - const _: () = assert!(MAX_VRF_IOS == 3, "`MAX_VRF_IOS` expected to be 3"); - // Workaround to overcome backend signature generic over the number of IOs. - match data.inputs.len() { - 0 => self.ring_vrf_sign_gen::<0>(data, prover), - 1 => self.ring_vrf_sign_gen::<1>(data, prover), - 2 => self.ring_vrf_sign_gen::<2>(data, prover), - 3 => self.ring_vrf_sign_gen::<3>(data, prover), - _ => unreachable!(), - } - } - - fn ring_vrf_sign_gen( - &self, - data: &VrfSignData, - prover: &RingProver, - ) -> RingVrfSignature { - let ios = core::array::from_fn(|i| self.secret.vrf_inout(data.inputs[i].0)); - - let ring_signature: bandersnatch_vrfs::RingVrfSignature = - bandersnatch_vrfs::RingProver { ring_prover: prover, secret: &self.secret } - .sign_ring_vrf(data.transcript.clone(), &ios); - - let pre_outputs: Vec<_> = - ring_signature.preouts.into_iter().map(VrfPreOutput).collect(); - let pre_outputs = VrfIosVec::truncate_from(pre_outputs); - - let mut signature = - RingVrfSignature { pre_outputs, signature: [0; RING_SIGNATURE_SERIALIZED_SIZE] }; - - ring_signature - .proof - .serialize_compressed(signature.signature.as_mut_slice()) + use ark_vrf::ring::Prover; + let pre_output_impl = self.secret.output(data.vrf_input.0); + let pre_output = VrfPreOutput(pre_output_impl); + let proof_impl = + self.secret.prove(data.vrf_input.0, pre_output.0, &data.aux_data, prover); + let mut proof = [0; RING_PROOF_SERIALIZED_SIZE]; + proof_impl + .serialize_compressed(proof.as_mut_slice()) .expect("serialization length is constant and checked by test; qed"); - - signature + RingVrfSignature { pre_output, proof } } } @@ -735,45 +571,20 @@ pub mod ring_vrf { /// The signature is verifiable if it has been produced by a member of the ring /// from which the [`RingVerifier`] has been constructed. pub fn ring_vrf_verify(&self, data: &VrfSignData, verifier: &RingVerifier) -> bool { - const _: () = assert!(MAX_VRF_IOS == 3, "`MAX_VRF_IOS` expected to be 3"); - let preouts_len = self.pre_outputs.len(); - if preouts_len != data.inputs.len() { - return false - } - // Workaround to overcome backend signature generic over the number of IOs. - match preouts_len { - 0 => self.ring_vrf_verify_gen::<0>(data, verifier), - 1 => self.ring_vrf_verify_gen::<1>(data, verifier), - 2 => self.ring_vrf_verify_gen::<2>(data, verifier), - 3 => self.ring_vrf_verify_gen::<3>(data, verifier), - _ => unreachable!(), - } - } - - fn ring_vrf_verify_gen( - &self, - data: &VrfSignData, - verifier: &RingVerifier, - ) -> bool { - let Ok(vrf_signature) = - bandersnatch_vrfs::RingVrfSignature::<0>::deserialize_compressed_unchecked( - self.signature.as_slice(), - ) + use ark_vrf::ring::Verifier; + let Ok(proof) = + bandersnatch::RingProof::deserialize_compressed_unchecked(self.proof.as_slice()) else { return false }; - - let preouts: [bandersnatch_vrfs::VrfPreOut; N] = - core::array::from_fn(|i| self.pre_outputs[i].0); - - let signature = - bandersnatch_vrfs::RingVrfSignature { proof: vrf_signature.proof, preouts }; - - let inputs = data.inputs.iter().map(|i| i.0); - - bandersnatch_vrfs::RingVerifier(verifier) - .verify_ring_vrf(data.transcript.clone(), inputs, &signature) - .is_ok() + bandersnatch::Public::verify( + data.vrf_input.0, + self.pre_output.0, + &data.aux_data, + &proof, + verifier, + ) + .is_ok() } } } @@ -783,10 +594,10 @@ mod tests { use super::{ring_vrf::*, vrf::*, *}; use crate::crypto::{VrfPublic, VrfSecret, DEV_PHRASE}; - const DEV_SEED: &[u8; SEED_SERIALIZED_SIZE] = &[0xcb; SEED_SERIALIZED_SIZE]; - const TEST_DOMAIN_SIZE: u32 = 1024; + const TEST_SEED: &[u8; SEED_SERIALIZED_SIZE] = &[0xcb; SEED_SERIALIZED_SIZE]; + const TEST_RING_SIZE: usize = 16; - type TestRingContext = RingContext; + type TestRingContext = RingContext; #[allow(unused)] fn b2h(bytes: &[u8]) -> String { @@ -799,59 +610,57 @@ mod tests { #[test] fn backend_assumptions_sanity_check() { - let kzg = KZG::testing_kzg_setup([0; 32], TEST_DOMAIN_SIZE); - assert_eq!(kzg.max_keyset_size() as u32, TEST_DOMAIN_SIZE - RING_DOMAIN_OVERHEAD); + use bandersnatch::{Input, RingProofParams}; - assert_eq!(kzg.uncompressed_size(), ring_context_serialized_size(TEST_DOMAIN_SIZE)); + let ctx = RingProofParams::from_seed(TEST_RING_SIZE, [0_u8; 32]); - let pks: Vec<_> = (0..16) - .map(|i| SecretKey::from_seed(&[i as u8; 32]).to_public().0.into()) - .collect(); + let domain_size = ark_vrf::ring::pcs_domain_size::(TEST_RING_SIZE); + assert_eq!(domain_size, ctx.pcs.powers_in_g1.len()); + let domain_size2 = ark_vrf::ring::pcs_domain_size::(ctx.max_ring_size()); + assert_eq!(domain_size, domain_size2); + assert_eq!( + ark_vrf::ring::max_ring_size_from_pcs_domain_size::(domain_size), + ctx.max_ring_size() + ); - let secret = SecretKey::from_seed(&[0u8; 32]); + assert_eq!(ctx.uncompressed_size(), ring_context_serialized_size(TEST_RING_SIZE)); - let public = secret.to_public(); + let prover_key_index = 3; + let secret = Secret::from_seed(&[prover_key_index as u8; 32]); + let public = secret.public(); assert_eq!(public.compressed_size(), PUBLIC_SERIALIZED_SIZE); - let input = VrfInput::new(b"foo", &[]); - let preout = secret.vrf_preout(&input.0); + let input = Input::new(b"foo").unwrap(); + let preout = secret.output(input); assert_eq!(preout.compressed_size(), PREOUT_SERIALIZED_SIZE); - let verifier_key = kzg.verifier_key(pks.clone()); - assert_eq!(verifier_key.compressed_size() + 4, RING_VERIFIER_DATA_SERIALIZED_SIZE); - - let prover_key = kzg.prover_key(pks); - let ring_prover = kzg.init_ring_prover(prover_key, 0); + let ring_keys: Vec<_> = (0..TEST_RING_SIZE) + .map(|i| Secret::from_seed(&[i as u8; 32]).public().0.into()) + .collect(); - let data = VrfSignData::new_unchecked(b"mydata", &[b"tdata"], None); + let verifier_key = ctx.verifier_key(&ring_keys[..]); + assert_eq!(verifier_key.compressed_size(), RING_VERIFIER_KEY_SERIALIZED_SIZE); - let thin_signature: bandersnatch_vrfs::ThinVrfSignature<0> = - secret.sign_thin_vrf(data.transcript.clone(), &[]); - assert_eq!(thin_signature.compressed_size(), SIGNATURE_SERIALIZED_SIZE); + let prover_key = ctx.prover_key(&ring_keys); + let ring_prover = ctx.prover(prover_key, prover_key_index); - let ring_signature: bandersnatch_vrfs::RingVrfSignature<0> = - bandersnatch_vrfs::RingProver { ring_prover: &ring_prover, secret: &secret } - .sign_ring_vrf(data.transcript.clone(), &[]); - assert_eq!(ring_signature.compressed_size(), RING_SIGNATURE_SERIALIZED_SIZE); - } + { + use ark_vrf::ietf::Prover; + let proof = secret.prove(input, preout, &[]); + assert_eq!(proof.compressed_size(), SIGNATURE_SERIALIZED_SIZE); + } - #[test] - fn max_vrf_ios_bound_respected() { - let inputs: Vec<_> = (0..MAX_VRF_IOS - 1).map(|_| VrfInput::new(b"", &[])).collect(); - let mut sign_data = VrfSignData::new(b"", &[b""], inputs).unwrap(); - let res = sign_data.push_vrf_input(VrfInput::new(b"", b"")); - assert!(res.is_ok()); - let res = sign_data.push_vrf_input(VrfInput::new(b"", b"")); - assert!(res.is_err()); - let inputs: Vec<_> = (0..MAX_VRF_IOS + 1).map(|_| VrfInput::new(b"", b"")).collect(); - let res = VrfSignData::new(b"mydata", &[b"tdata"], inputs); - assert!(res.is_err()); + { + use ark_vrf::ring::Prover; + let proof = secret.prove(input, preout, &[], &ring_prover); + assert_eq!(proof.compressed_size(), RING_PROOF_SERIALIZED_SIZE); + } } #[test] fn derive_works() { let pair = Pair::from_string(&format!("{}//Alice//Hard", DEV_PHRASE), None).unwrap(); - let known = h2b("2b340c18b94dc1916979cb83daf3ed4ac106742ddc06afc42cf26be3b18a523f80"); + let known = h2b("f706ea7ee4eef553428a768dbf3a1ede0b389a9f75867ade317a61cbb4efeb01"); assert_eq!(pair.public().as_ref(), known); // Soft derivation not supported @@ -874,120 +683,79 @@ mod tests { #[test] fn sign_verify() { - let pair = Pair::from_seed(DEV_SEED); + let pair = Pair::from_seed(TEST_SEED); let public = pair.public(); - let msg = b"hello"; - + let msg = b"foo"; let signature = pair.sign(msg); assert!(Pair::verify(&signature, msg, &public)); } #[test] fn vrf_sign_verify() { - let pair = Pair::from_seed(DEV_SEED); + let pair = Pair::from_seed(TEST_SEED); let public = pair.public(); - - let i1 = VrfInput::new(b"dom1", b"foo"); - let i2 = VrfInput::new(b"dom2", b"bar"); - let i3 = VrfInput::new(b"dom3", b"baz"); - - let data = VrfSignData::new_unchecked(b"mydata", &[b"tdata"], [i1, i2, i3]); - + let data = VrfSignData::new(b"foo", b"aux"); let signature = pair.vrf_sign(&data); - assert!(public.vrf_verify(&data, &signature)); } #[test] - fn vrf_sign_verify_bad_inputs() { - let pair = Pair::from_seed(DEV_SEED); + fn vrf_sign_verify_with_bad_input() { + let pair = Pair::from_seed(TEST_SEED); let public = pair.public(); - - let i1 = VrfInput::new(b"dom1", b"foo"); - let i2 = VrfInput::new(b"dom2", b"bar"); - - let data = VrfSignData::new_unchecked(b"mydata", &[b"aaaa"], [i1.clone(), i2.clone()]); + let data = VrfSignData::new(b"foo", b"aux"); let signature = pair.vrf_sign(&data); - - let data = VrfSignData::new_unchecked(b"mydata", &[b"bbb"], [i1, i2.clone()]); + let data = VrfSignData::new(b"foo", b"bad"); assert!(!public.vrf_verify(&data, &signature)); - - let data = VrfSignData::new_unchecked(b"mydata", &[b"aaa"], [i2]); + let data = VrfSignData::new(b"bar", b"aux"); assert!(!public.vrf_verify(&data, &signature)); } #[test] - fn vrf_make_bytes_matches() { - let pair = Pair::from_seed(DEV_SEED); - - let i1 = VrfInput::new(b"dom1", b"foo"); - let i2 = VrfInput::new(b"dom2", b"bar"); - - let data = VrfSignData::new_unchecked(b"mydata", &[b"tdata"], [i1.clone(), i2.clone()]); + fn vrf_output_bytes_match() { + let pair = Pair::from_seed(TEST_SEED); + let data = VrfSignData::new(b"foo", b"aux"); let signature = pair.vrf_sign(&data); - - let o10 = pair.make_bytes::<32>(b"ctx1", &i1); - let o11 = signature.pre_outputs[0].make_bytes::<32>(b"ctx1", &i1); - assert_eq!(o10, o11); - - let o20 = pair.make_bytes::<48>(b"ctx2", &i2); - let o21 = signature.pre_outputs[1].make_bytes::<48>(b"ctx2", &i2); - assert_eq!(o20, o21); + let o0 = pair.make_bytes(&data.vrf_input); + let o1 = signature.pre_output.make_bytes(); + assert_eq!(o0, o1); } #[test] - fn encode_decode_vrf_signature() { - // Transcript data is hashed together and signed. - // It doesn't contribute to serialized length. - let pair = Pair::from_seed(DEV_SEED); - - let i1 = VrfInput::new(b"dom1", b"foo"); - let i2 = VrfInput::new(b"dom2", b"bar"); + fn vrf_signature_encode_decode() { + let pair = Pair::from_seed(TEST_SEED); - let data = VrfSignData::new_unchecked(b"mydata", &[b"tdata"], [i1.clone(), i2.clone()]); + let data = VrfSignData::new(b"data", b"aux"); let expected = pair.vrf_sign(&data); let bytes = expected.encode(); - let expected_len = - data.inputs.len() * PREOUT_SERIALIZED_SIZE + SIGNATURE_SERIALIZED_SIZE + 1; + let expected_len = PREOUT_SERIALIZED_SIZE + SIGNATURE_SERIALIZED_SIZE; assert_eq!(bytes.len(), expected_len); let decoded = VrfSignature::decode(&mut bytes.as_slice()).unwrap(); assert_eq!(expected, decoded); - - let data = VrfSignData::new_unchecked(b"mydata", &[b"tdata"], []); - let expected = pair.vrf_sign(&data); - - let bytes = expected.encode(); - - let decoded = VrfSignature::decode(&mut bytes.as_slice()).unwrap(); - assert_eq!(expected, decoded); } #[test] fn ring_vrf_sign_verify() { let ring_ctx = TestRingContext::new_testing(); - let mut pks: Vec<_> = (0..16).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect(); + let mut pks: Vec<_> = + (0..TEST_RING_SIZE).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect(); assert!(pks.len() <= ring_ctx.max_keyset_size()); - let pair = Pair::from_seed(DEV_SEED); + let pair = Pair::from_seed(TEST_SEED); // Just pick one index to patch with the actual public key let prover_idx = 3; pks[prover_idx] = pair.public(); + let prover = ring_ctx.prover(&pks, prover_idx); - let i1 = VrfInput::new(b"dom1", b"foo"); - let i2 = VrfInput::new(b"dom2", b"bar"); - let i3 = VrfInput::new(b"dom3", b"baz"); - - let data = VrfSignData::new_unchecked(b"mydata", &[b"tdata"], [i1, i2, i3]); - - let prover = ring_ctx.prover(&pks, prover_idx).unwrap(); + let data = VrfSignData::new(b"data", b"aux"); let signature = pair.ring_vrf_sign(&data, &prover); - let verifier = ring_ctx.verifier(&pks).unwrap(); + let verifier = ring_ctx.verifier(&pks); assert!(signature.ring_vrf_verify(&data, &verifier)); } @@ -995,18 +763,17 @@ mod tests { fn ring_vrf_sign_verify_with_out_of_ring_key() { let ring_ctx = TestRingContext::new_testing(); - let pks: Vec<_> = (0..16).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect(); - let pair = Pair::from_seed(DEV_SEED); + let pks: Vec<_> = + (0..TEST_RING_SIZE).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect(); + let pair = Pair::from_seed(TEST_SEED); - // Just pick one index to patch with the actual public key - let i1 = VrfInput::new(b"dom1", b"foo"); - let data = VrfSignData::new_unchecked(b"mydata", Some(b"tdata"), Some(i1)); + let data = VrfSignData::new(b"foo", b"aux"); // pair.public != pks[0] - let prover = ring_ctx.prover(&pks, 0).unwrap(); + let prover = ring_ctx.prover(&pks, 0); let signature = pair.ring_vrf_sign(&data, &prover); - let verifier = ring_ctx.verifier(&pks).unwrap(); + let verifier = ring_ctx.verifier(&pks); assert!(!signature.ring_vrf_verify(&data, &verifier)); } @@ -1014,71 +781,58 @@ mod tests { fn ring_vrf_make_bytes_matches() { let ring_ctx = TestRingContext::new_testing(); - let mut pks: Vec<_> = (0..16).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect(); + let mut pks: Vec<_> = + (0..TEST_RING_SIZE).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect(); assert!(pks.len() <= ring_ctx.max_keyset_size()); - let pair = Pair::from_seed(DEV_SEED); + let pair = Pair::from_seed(TEST_SEED); // Just pick one index to patch with the actual public key let prover_idx = 3; pks[prover_idx] = pair.public(); - let i1 = VrfInput::new(b"dom1", b"foo"); - let i2 = VrfInput::new(b"dom2", b"bar"); - let data = VrfSignData::new_unchecked(b"mydata", &[b"tdata"], [i1.clone(), i2.clone()]); + let data = VrfSignData::new(b"data", b"aux"); - let prover = ring_ctx.prover(&pks, prover_idx).unwrap(); + let prover = ring_ctx.prover(&pks, prover_idx); let signature = pair.ring_vrf_sign(&data, &prover); - let o10 = pair.make_bytes::<32>(b"ctx1", &i1); - let o11 = signature.pre_outputs[0].make_bytes::<32>(b"ctx1", &i1); - assert_eq!(o10, o11); - - let o20 = pair.make_bytes::<48>(b"ctx2", &i2); - let o21 = signature.pre_outputs[1].make_bytes::<48>(b"ctx2", &i2); - assert_eq!(o20, o21); + let o0 = pair.make_bytes(&data.vrf_input); + let o1 = signature.pre_output.make_bytes(); + assert_eq!(o0, o1); } #[test] - fn encode_decode_ring_vrf_signature() { + fn ring_vrf_signature_encode_decode() { let ring_ctx = TestRingContext::new_testing(); - let mut pks: Vec<_> = (0..16).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect(); + let mut pks: Vec<_> = + (0..TEST_RING_SIZE).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect(); assert!(pks.len() <= ring_ctx.max_keyset_size()); - let pair = Pair::from_seed(DEV_SEED); + let pair = Pair::from_seed(TEST_SEED); - // Just pick one... + // Just pick one index to patch with the actual public key let prover_idx = 3; pks[prover_idx] = pair.public(); - let i1 = VrfInput::new(b"dom1", b"foo"); - let i2 = VrfInput::new(b"dom2", b"bar"); - let i3 = VrfInput::new(b"dom3", b"baz"); + let data = VrfSignData::new(b"foo", b"aux"); - let data = VrfSignData::new_unchecked(b"mydata", &[b"tdata"], [i1, i2, i3]); - - let prover = ring_ctx.prover(&pks, prover_idx).unwrap(); + let prover = ring_ctx.prover(&pks, prover_idx); let expected = pair.ring_vrf_sign(&data, &prover); let bytes = expected.encode(); - - let expected_len = - data.inputs.len() * PREOUT_SERIALIZED_SIZE + RING_SIGNATURE_SERIALIZED_SIZE + 1; - assert_eq!(bytes.len(), expected_len); + assert_eq!(bytes.len(), RING_SIGNATURE_SERIALIZED_SIZE); let decoded = RingVrfSignature::decode(&mut bytes.as_slice()).unwrap(); assert_eq!(expected, decoded); } #[test] - fn encode_decode_ring_vrf_context() { + fn ring_vrf_context_encode_decode() { let ctx1 = TestRingContext::new_testing(); let enc1 = ctx1.encode(); - let _ti = ::type_info(); - - assert_eq!(enc1.len(), ring_context_serialized_size(TEST_DOMAIN_SIZE)); + assert_eq!(enc1.len(), ring_context_serialized_size(TEST_RING_SIZE)); assert_eq!(enc1.len(), TestRingContext::max_encoded_len()); let ctx2 = TestRingContext::decode(&mut enc1.as_slice()).unwrap(); @@ -1088,21 +842,20 @@ mod tests { } #[test] - fn encode_decode_verifier_data() { + fn verifier_key_encode_decode() { let ring_ctx = TestRingContext::new_testing(); - let pks: Vec<_> = (0..16).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect(); + let pks: Vec<_> = + (0..TEST_RING_SIZE).map(|i| Pair::from_seed(&[i as u8; 32]).public()).collect(); assert!(pks.len() <= ring_ctx.max_keyset_size()); - let verifier_data = ring_ctx.verifier_data(&pks).unwrap(); - let enc1 = verifier_data.encode(); + let verifier_key = ring_ctx.verifier_key(&pks); + let enc1 = verifier_key.encode(); + assert_eq!(enc1.len(), RING_VERIFIER_KEY_SERIALIZED_SIZE); + assert_eq!(RingVerifierKey::max_encoded_len(), RING_VERIFIER_KEY_SERIALIZED_SIZE); - assert_eq!(enc1.len(), RING_VERIFIER_DATA_SERIALIZED_SIZE); - assert_eq!(RingVerifierData::max_encoded_len(), RING_VERIFIER_DATA_SERIALIZED_SIZE); - - let vd2 = RingVerifierData::decode(&mut enc1.as_slice()).unwrap(); + let vd2 = RingVerifierKey::decode(&mut enc1.as_slice()).unwrap(); let enc2 = vd2.encode(); - assert_eq!(enc1, enc2); } } diff --git a/substrate/primitives/io/Cargo.toml b/substrate/primitives/io/Cargo.toml index 3b0078c66022c..b7cc7e91ce82c 100644 --- a/substrate/primitives/io/Cargo.toml +++ b/substrate/primitives/io/Cargo.toml @@ -104,4 +104,7 @@ bls-experimental = ["sp-keystore/bls-experimental"] # This feature adds Bandersnatch crypto primitives. # It should not be used in production since the implementation and interface may still # be subject to significant changes. -bandersnatch-experimental = ["sp-keystore/bandersnatch-experimental"] +bandersnatch-experimental = [ + "sp-core/bandersnatch-experimental", + "sp-keystore/bandersnatch-experimental", +] diff --git a/substrate/primitives/keyring/src/bandersnatch.rs b/substrate/primitives/keyring/src/bandersnatch.rs index 64d3c314124d5..b82cb166c7d7d 100644 --- a/substrate/primitives/keyring/src/bandersnatch.rs +++ b/substrate/primitives/keyring/src/bandersnatch.rs @@ -143,21 +143,21 @@ impl From for [u8; PUBLIC_RAW_LEN] { fn from(k: Keyring) -> Self { match k { Keyring::Alice => - hex2array!("9c8af77d3a4e3f6f076853922985b9e6724fc9675329087f47aff1ceaaae772180"), + hex2array!("4d8e57b723e8bb4eca5c28d79cb95b9e84b4e2319d9851d45504014633e55d01"), Keyring::Bob => - hex2array!("1abfbb76dc8374a1a6d93d59a5c81f07c18835f4681a6258aa0f514d363bff4780"), + hex2array!("aa6daf4784d581804d8f5cc1edb2ad171dbdf9c5188ddc071b11c3479c150c37"), Keyring::Charlie => - hex2array!("0f4a9990aca3d39a7cd8bf187e2e81a9ea6f9cedb2db405f2fffff384c5dd02680"), + hex2array!("331d681392223b35b92319e059d3dbc2869b2ef74400a70e678b4a5108c81ec0"), Keyring::Dave => - hex2array!("bd7a87d4dfa89926a408b5acbed554ae3b053fa3532531053295cbabf07d337000"), + hex2array!("374384c19a877040c84bb07fcf3aac74ff7fafface0b1c01a93fd2ddbf5c1660"), Keyring::Eve => - hex2array!("f992d5b8eac8fc004d521bee6edc1174cfa7fae3a1baec8262511ee351f9f85e00"), + hex2array!("14bdd9381e80c07b75b8f1e92d6b2e4652e5135beaad1eedb1b81ff01ee562ad"), Keyring::Ferdie => - hex2array!("1ce2613e89bc5c8e358aad884099cfb576a61176f2f9968cd0d486a04457245180"), + hex2array!("e13bd31b0575076479914c16c5ad69779f206375dbf19519219eeba3b10cc063"), Keyring::One => - hex2array!("a29e03ac273e521274d8e501a6242abd2ab393d7e197221a9113bdf8e2e5b34d00"), + hex2array!("03466a4de97ae18bc4604a3c40dfbddc6bac9f707c9b3c31a94a2c1725a03253"), Keyring::Two => - hex2array!("f968d47e819ddb18a9d0f2ebd16501680b1a3f07ee375c6f81310e5f99a04f4d00"), + hex2array!("0fda0d1336e8d6ee687ebf6d14eaa9b92b5601068e6159222623c8e14c004293"), } } } diff --git a/substrate/primitives/keystore/src/testing.rs b/substrate/primitives/keystore/src/testing.rs index 745f42e3477ab..7939ee81005a0 100644 --- a/substrate/primitives/keystore/src/testing.rs +++ b/substrate/primitives/keystore/src/testing.rs @@ -524,10 +524,7 @@ mod tests { let secret_uri = "//Alice"; let key_pair = bandersnatch::Pair::from_string(secret_uri, None).expect("Generates key pair"); - - let in1 = bandersnatch::vrf::VrfInput::new("in", "foo"); - let sign_data = - bandersnatch::vrf::VrfSignData::new_unchecked(b"Test", Some("m1"), Some(in1)); + let sign_data = bandersnatch::vrf::VrfSignData::new(b"vrf_input", b"aux_data"); let result = store.bandersnatch_vrf_sign(BANDERSNATCH, &key_pair.public(), &sign_data); assert!(result.unwrap().is_none()); @@ -555,15 +552,13 @@ mod tests { .collect(); let prover_idx = 3; - let prover = ring_ctx.prover(&pks, prover_idx).unwrap(); + let prover = ring_ctx.prover(&pks, prover_idx); let secret_uri = "//Alice"; let pair = bandersnatch::Pair::from_string(secret_uri, None).expect("Generates key pair"); pks[prover_idx] = pair.public(); - let in1 = bandersnatch::vrf::VrfInput::new("in1", "foo"); - let sign_data = - bandersnatch::vrf::VrfSignData::new_unchecked(b"Test", &["m1", "m2"], [in1]); + let sign_data = bandersnatch::vrf::VrfSignData::new(b"vrf_input", b"aux_data"); let result = store.bandersnatch_ring_vrf_sign(BANDERSNATCH, &pair.public(), &sign_data, &prover);