diff --git a/Cargo.lock b/Cargo.lock index b8fea0c0568fb..9a3dddeb9ffc2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -328,6 +328,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ark-ed-on-bls12-381-bandersnatch" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9cde0f2aa063a2a5c28d39b47761aa102bda7c13c84fc118a61b87c7b2f785c" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ff", + "ark-std", +] + [[package]] name = "ark-ff" version = "0.4.2" @@ -384,6 +396,21 @@ dependencies = [ "hashbrown 0.13.2", ] +[[package]] +name = "ark-secret-scalar" +version = "0.0.2" +source = "git+https://github.com/w3f/ring-vrf#4957177a717c7555c8df2869012201017b62e66b" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-serialize", + "ark-std", + "ark-transcript", + "digest 0.10.6", + "rand_core 0.6.4", + "zeroize", +] + [[package]] name = "ark-serialize" version = "0.4.2" @@ -417,6 +444,19 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "ark-transcript" +version = "0.0.2" +source = "git+https://github.com/w3f/ring-vrf#4957177a717c7555c8df2869012201017b62e66b" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "digest 0.10.6", + "rand_core 0.6.4", + "sha3", +] + [[package]] name = "array-bytes" version = "4.2.0" @@ -583,7 +623,7 @@ checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -605,7 +645,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -616,7 +656,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -670,6 +710,26 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "bandersnatch_vrfs" +version = "0.0.1" +source = "git+https://github.com/w3f/ring-vrf#4957177a717c7555c8df2869012201017b62e66b" +dependencies = [ + "ark-bls12-381", + "ark-ec", + "ark-ed-on-bls12-381-bandersnatch", + "ark-ff", + "ark-serialize", + "ark-std", + "dleq_vrf", + "fflonk", + "merlin 3.0.0", + "rand_core 0.6.4", + "ring 0.1.0", + "sha2 0.10.6", + "zeroize", +] + [[package]] name = "base-x" version = "0.2.11" @@ -757,13 +817,13 @@ dependencies = [ "lazy_static", "lazycell", "peeking_take_while", - "prettyplease 0.2.4", + "prettyplease 0.2.5", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -924,9 +984,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.12.1" +version = "3.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8" +checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b" [[package]] name = "byte-slice-cast" @@ -1237,9 +1297,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.2.1" +version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a19591b2ab0e3c04b588a0e04ddde7b9eaa423646d1b4a8092879216bf47473" +checksum = "1594fe2312ec4abf402076e407628f5c313e54c32ade058521df4ee34ecac8a8" dependencies = [ "clap 4.2.7", ] @@ -1253,7 +1313,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -1298,6 +1358,20 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "common" +version = "0.1.0" +source = "git+https://github.com/w3f/ring-proof#1e42bb632263f4dff86b400ec9a13af21db72360" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "fflonk", + "merlin 3.0.0", +] + [[package]] name = "concurrent-queue" version = "2.2.0" @@ -1738,7 +1812,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -1755,7 +1829,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -2023,7 +2097,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -2032,6 +2106,22 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "210ec60ae7d710bed8683e333e9d2855a8a56a3e9892b38bad3bb0d4d29b0d5e" +[[package]] +name = "dleq_vrf" +version = "0.0.2" +source = "git+https://github.com/w3f/ring-vrf#4957177a717c7555c8df2869012201017b62e66b" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-secret-scalar", + "ark-serialize", + "ark-std", + "ark-transcript", + "arrayvec 0.7.2", + "rand_core 0.6.4", + "zeroize", +] + [[package]] name = "doc-comment" version = "0.3.3" @@ -2097,15 +2187,16 @@ dependencies = [ [[package]] name = "ecdsa" -version = "0.16.6" +version = "0.16.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a48e5d537b8a30c0b023116d981b16334be1485af7ca68db3a2b7024cbc957fd" +checksum = "0997c976637b606099b9985693efa3581e84e41f5c11ba5255f88711058ad428" dependencies = [ "der 0.7.5", "digest 0.10.6", "elliptic-curve 0.13.4", "rfc6979 0.4.0", "signature 2.1.0", + "spki 0.7.2", ] [[package]] @@ -2227,7 +2318,7 @@ checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -2361,6 +2452,19 @@ dependencies = [ "subtle", ] +[[package]] +name = "fflonk" +version = "0.1.0" +source = "git+https://github.com/w3f/fflonk#f60bc946e2a4340b1c2d00d30c654e82a5887983" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "merlin 3.0.0", +] + [[package]] name = "fiat-crypto" version = "0.1.20" @@ -2581,7 +2685,7 @@ dependencies = [ "quote", "scale-info", "sp-arithmetic", - "syn 2.0.15", + "syn 2.0.16", "trybuild", ] @@ -2723,7 +2827,7 @@ dependencies = [ "proc-macro-warning", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -2734,7 +2838,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -2743,7 +2847,7 @@ version = "3.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -2961,7 +3065,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -3180,9 +3284,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f8a914c2987b688368b5138aa05321db91f4090cf26118185672ad588bce21" +checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" dependencies = [ "bytes", "fnv", @@ -3205,9 +3309,9 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "handlebars" -version = "4.3.6" +version = "4.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "035ef95d03713f2c347a72547b7cd38cbc9af7cd51e6099fb62d586d4a6dee3a" +checksum = "83c3372087601b532857d332f5957cbae686da52bb7810bf038c3e3c3cc2fa0d" dependencies = [ "log", "pest", @@ -3466,12 +3570,11 @@ dependencies = [ [[package]] name = "iana-time-zone-haiku" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cxx", - "cxx-build", + "cc", ] [[package]] @@ -3865,7 +3968,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" dependencies = [ "cfg-if", - "ecdsa 0.16.6", + "ecdsa 0.16.7", "elliptic-curve 0.13.4", "once_cell", "sha2 0.10.6", @@ -4085,9 +4188,9 @@ checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" [[package]] name = "libm" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" [[package]] name = "libp2p" @@ -4429,7 +4532,7 @@ dependencies = [ "libp2p-core", "libp2p-identity", "rcgen 0.10.0", - "ring", + "ring 0.16.20", "rustls 0.20.8", "thiserror", "webpki 0.22.0", @@ -4874,6 +4977,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -5431,7 +5546,7 @@ dependencies = [ [[package]] name = "node-sassafras" -version = "0.3.1-dev" +version = "0.3.2-dev" dependencies = [ "clap 4.2.7", "frame-benchmarking", @@ -5474,7 +5589,7 @@ dependencies = [ [[package]] name = "node-sassafras-runtime" -version = "0.3.1-dev" +version = "0.3.2-dev" dependencies = [ "frame-benchmarking", "frame-executive", @@ -5754,7 +5869,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", - "libm 0.2.6", + "libm 0.2.7", ] [[package]] @@ -6300,7 +6415,7 @@ version = "4.0.0-dev" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -7094,7 +7209,7 @@ dependencies = [ [[package]] name = "pallet-sassafras" -version = "0.3.1-dev" +version = "0.3.2-dev" dependencies = [ "array-bytes 4.2.0", "frame-benchmarking", @@ -7245,7 +7360,7 @@ dependencies = [ "proc-macro2", "quote", "sp-runtime", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -7530,9 +7645,9 @@ dependencies = [ [[package]] name = "parity-db" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd4572a52711e2ccff02b4973ec7e4a5b5c23387ebbfbd6cd42b34755714cefc" +checksum = "4890dcb9556136a4ec2b0c51fa4a08c8b733b829506af8fff2e853f3a065985b" dependencies = [ "blake2", "crc32fast", @@ -7725,7 +7840,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -7751,22 +7866,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.12" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.16", ] [[package]] @@ -7910,14 +8025,14 @@ version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e30165d31df606f5726b090ec7592c308a0eaf61721ff64c9a3018e344a8753e" dependencies = [ - "portable-atomic 1.3.1", + "portable-atomic 1.3.2", ] [[package]] name = "portable-atomic" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bbda379e6e462c97ea6afe9f6233619b202bbc4968d7caa6917788d2070a044" +checksum = "dc59d1bcc64fc5d021d67521f818db868368028108d37f0e98d74e33f68297b5" [[package]] name = "ppv-lite86" @@ -7991,12 +8106,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ceca8aaf45b5c46ec7ed39fff75f57290368c1846d33d24a122ca81416ab058" +checksum = "617feabb81566b593beb4886fb8c1f38064169dae4dccad0e3220160c3b37203" dependencies = [ "proc-macro2", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -8054,14 +8169,14 @@ checksum = "0e99670bafb56b9a106419397343bdbc8b8742c3cc449fec6345f86173f47cd4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "c4ec6d5fe0b140acb27c9a0444118cf55bfbb4e0b259739429abb4521dd67c16" dependencies = [ "unicode-ident", ] @@ -8222,7 +8337,7 @@ checksum = "67c10f662eee9c94ddd7135043e544f3c82fa839a1e7b865911331961b53186c" dependencies = [ "bytes", "rand 0.8.5", - "ring", + "ring 0.16.20", "rustc-hash", "rustls 0.20.8", "slab", @@ -8372,7 +8487,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" dependencies = [ "pem", - "ring", + "ring 0.16.20", "time 0.3.21", "x509-parser 0.13.2", "yasna", @@ -8385,7 +8500,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", - "ring", + "ring 0.16.20", "time 0.3.21", "yasna", ] @@ -8436,7 +8551,7 @@ checksum = "8d2275aab483050ab2a7364c1a46604865ee7d6906684e08db0f090acf74f9e7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -8526,6 +8641,21 @@ dependencies = [ "subtle", ] +[[package]] +name = "ring" +version = "0.1.0" +source = "git+https://github.com/w3f/ring-proof#1e42bb632263f4dff86b400ec9a13af21db72360" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "common", + "fflonk", + "merlin 3.0.0", +] + [[package]] name = "ring" version = "0.16.20" @@ -8693,7 +8823,7 @@ checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" dependencies = [ "base64 0.13.1", "log", - "ring", + "ring 0.16.20", "sct 0.6.1", "webpki 0.21.4", ] @@ -8705,7 +8835,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ "log", - "ring", + "ring 0.16.20", "sct 0.7.0", "webpki 0.22.0", ] @@ -8899,7 +9029,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -9350,7 +9480,7 @@ dependencies = [ [[package]] name = "sc-consensus-sassafras" -version = "0.3.1-dev" +version = "0.3.2-dev" dependencies = [ "async-trait", "fork-tree", @@ -10209,7 +10339,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -10277,9 +10407,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfdef77228a4c05dc94211441595746732131ad7f6530c6c18f045da7b7ab937" +checksum = "b569c32c806ec3abdf3b5869fb8bf1e0d275a7c1c9b0b05603d9464632649edf" dependencies = [ "bitvec", "cfg-if", @@ -10331,7 +10461,7 @@ dependencies = [ "arrayvec 0.5.2", "curve25519-dalek 2.1.3", "getrandom 0.1.16", - "merlin", + "merlin 2.0.1", "rand 0.7.3", "rand_core 0.5.1", "sha2 0.8.2", @@ -10357,7 +10487,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" dependencies = [ - "ring", + "ring 0.16.20", "untrusted", ] @@ -10367,7 +10497,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ - "ring", + "ring 0.16.20", "untrusted", ] @@ -10440,9 +10570,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.8.2" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +checksum = "ca2855b3715770894e67cbfa3df957790aa0c9edc3bf06efa1a84d77fa0839d1" dependencies = [ "bitflags", "core-foundation", @@ -10453,9 +10583,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" dependencies = [ "core-foundation-sys", "libc", @@ -10496,22 +10626,22 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.162" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71b2f6e1ab5c2b98c05f0f35b236b22e8df7ead6ffbf51d7808da7f8817e7ab6" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.162" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2a0814352fd64b58489904a44ea8d90cb1a91dcb6b4f5ebabc32c8318e93cb6" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -10705,7 +10835,7 @@ dependencies = [ "chacha20poly1305", "curve25519-dalek 4.0.0-rc.1", "rand_core 0.6.4", - "ring", + "ring 0.16.20", "rustc_version 0.4.0", "sha2 0.10.6", "subtle", @@ -10769,7 +10899,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -10989,10 +11119,10 @@ dependencies = [ [[package]] name = "sp-consensus-sassafras" -version = "0.3.1-dev" +version = "0.3.2-dev" dependencies = [ "async-trait", - "merlin", + "merlin 2.0.1", "parity-scale-codec", "scale-info", "serde", @@ -11023,6 +11153,8 @@ name = "sp-core" version = "7.0.0" dependencies = [ "array-bytes 4.2.0", + "arrayvec 0.7.2", + "bandersnatch_vrfs", "bitflags", "blake2", "bounded-collections", @@ -11038,7 +11170,7 @@ dependencies = [ "lazy_static", "libsecp256k1", "log", - "merlin", + "merlin 2.0.1", "parity-scale-codec", "parking_lot 0.12.1", "paste", @@ -11086,7 +11218,7 @@ dependencies = [ "proc-macro2", "quote", "sp-core-hashing", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -11103,7 +11235,7 @@ version = "5.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -11331,7 +11463,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -11566,7 +11698,7 @@ dependencies = [ "proc-macro2", "quote", "sp-version", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -11733,7 +11865,7 @@ dependencies = [ "lazy_static", "md-5", "rand 0.8.5", - "ring", + "ring 0.16.20", "subtle", "thiserror", "tokio", @@ -12011,7 +12143,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -12067,9 +12199,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.15" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" dependencies = [ "proc-macro2", "quote", @@ -12183,7 +12315,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -12314,9 +12446,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.0" +version = "1.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c786bf8134e5a3a166db9b29ab8f48134739014a3eca7bc6bfa95d673b136f" +checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" dependencies = [ "autocfg", "bytes", @@ -12339,7 +12471,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -12498,14 +12630,14 @@ checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", "valuable", @@ -12757,7 +12889,7 @@ dependencies = [ "log", "md-5", "rand 0.8.5", - "ring", + "ring 0.16.20", "stun", "thiserror", "tokio", @@ -12890,9 +13022,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.3.2" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dad5567ad0cf5b760e5665964bec1b47dfd077ba8a2544b513f3556d3d239a2" +checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2" dependencies = [ "getrandom 0.2.9", ] @@ -13028,7 +13160,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", "wasm-bindgen-shared", ] @@ -13062,7 +13194,7 @@ checksum = "4783ce29f09b9d93134d41297aded3a712b7b979e9c6f28c32cb88c973a94869" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -13200,7 +13332,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57d20cb3c59b788653d99541c646c561c9dd26506f25c0cebfe810659c54c6d7" dependencies = [ "downcast-rs", - "libm 0.2.6", + "libm 0.2.7", "memory_units", "num-rational", "num-traits", @@ -13214,7 +13346,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624e6333e861ef49095d2d678b76ebf30b06bf37effca845be7e5b87c90071b7" dependencies = [ "downcast-rs", - "libm 0.2.6", + "libm 0.2.7", "num-traits", "paste", ] @@ -13454,7 +13586,7 @@ version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" dependencies = [ - "ring", + "ring 0.16.20", "untrusted", ] @@ -13464,7 +13596,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" dependencies = [ - "ring", + "ring 0.16.20", "untrusted", ] @@ -13493,7 +13625,7 @@ dependencies = [ "rand 0.8.5", "rcgen 0.9.3", "regex", - "ring", + "ring 0.16.20", "rtcp", "rtp", "rustls 0.19.1", @@ -13558,7 +13690,7 @@ dependencies = [ "rand 0.8.5", "rand_core 0.6.4", "rcgen 0.9.3", - "ring", + "ring 0.16.20", "rustls 0.19.1", "sec1 0.3.0", "serde", @@ -14005,7 +14137,7 @@ dependencies = [ "lazy_static", "nom", "oid-registry 0.4.0", - "ring", + "ring 0.16.20", "rusticata-macros", "thiserror", "time 0.3.21", @@ -14084,7 +14216,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 712485c0f79e7..33c5397825121 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -338,3 +338,6 @@ inherits = "release" lto = "fat" # https://doc.rust-lang.org/rustc/codegen-options/index.html#codegen-units codegen-units = 1 + +#[patch."https://github.com/w3f/ring-vrf"] +# bandersnatch_vrfs = { path = "/mnt/ssd/users/develop/w3f/ring-vrf/bandersnatch_vrfs" } diff --git a/bin/node-sassafras/node/Cargo.toml b/bin/node-sassafras/node/Cargo.toml index fddc3636477df..00bd11461ad97 100644 --- a/bin/node-sassafras/node/Cargo.toml +++ b/bin/node-sassafras/node/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "node-sassafras" -version = "0.3.1-dev" +version = "0.3.2-dev" authors = ["Parity Technologies "] description = "Node testbed for Sassafras consensus." homepage = "https://substrate.io/" @@ -27,8 +27,8 @@ sc-telemetry = { version = "4.0.0-dev", path = "../../../client/telemetry" } sc-keystore = { version = "4.0.0-dev", path = "../../../client/keystore" } sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" } sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" } -sc-consensus-sassafras = { version = "0.3.1-dev", path = "../../../client/consensus/sassafras" } -sp-consensus-sassafras = { version = "0.3.1-dev", path = "../../../primitives/consensus/sassafras" } +sc-consensus-sassafras = { version = "0.3.2-dev", path = "../../../client/consensus/sassafras" } +sp-consensus-sassafras = { version = "0.3.2-dev", path = "../../../primitives/consensus/sassafras" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" } sc-consensus-grandpa = { version = "0.10.0-dev", path = "../../../client/consensus/grandpa" } @@ -57,7 +57,7 @@ frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarkin frame-benchmarking-cli = { version = "4.0.0-dev", path = "../../../utils/frame/benchmarking-cli" } # Local Dependencies -node-sassafras-runtime = { version = "0.3.1-dev", path = "../runtime" } +node-sassafras-runtime = { version = "0.3.2-dev", path = "../runtime" } # CLI-specific dependencies try-runtime-cli = { version = "0.10.0-dev", optional = true, path = "../../../utils/frame/try-runtime/cli" } diff --git a/bin/node-sassafras/node/src/chain_spec.rs b/bin/node-sassafras/node/src/chain_spec.rs index 6ba72c5397715..0636078bf60dd 100644 --- a/bin/node-sassafras/node/src/chain_spec.rs +++ b/bin/node-sassafras/node/src/chain_spec.rs @@ -11,7 +11,7 @@ use sp_core::{sr25519, Pair, Public}; use sp_runtime::traits::{IdentifyAccount, Verify}; // Genesis constants for Sassafras parameters configuration. -const SASSAFRAS_TICKETS_MAX_ATTEMPTS_NUMBER: u32 = 32; +const SASSAFRAS_TICKETS_MAX_ATTEMPTS_NUMBER: u32 = 16; const SASSAFRAS_TICKETS_REDUNDANCY_FACTOR: u32 = 1; /// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. diff --git a/bin/node-sassafras/runtime/Cargo.toml b/bin/node-sassafras/runtime/Cargo.toml index 8fe0108ae4de0..a2b99a096956c 100644 --- a/bin/node-sassafras/runtime/Cargo.toml +++ b/bin/node-sassafras/runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "node-sassafras-runtime" -version = "0.3.1-dev" +version = "0.3.2-dev" authors = ["Parity Technologies "] description = "Runtime testbed for Sassafras consensus." homepage = "https://substrate.io/" @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] } scale-info = { version = "2.1.1", default-features = false, features = ["derive"] } -pallet-sassafras = { version = "0.3.1-dev", default-features = false, path = "../../../frame/sassafras" } +pallet-sassafras = { version = "0.3.2-dev", default-features = false, path = "../../../frame/sassafras" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../../frame/balances" } pallet-session = { version = "4.0.0-dev", default-features = false, path = "../../../frame/session" } frame-support = { version = "4.0.0-dev", default-features = false, path = "../../../frame/support" } @@ -28,7 +28,7 @@ pallet-transaction-payment = { version = "4.0.0-dev", default-features = false, frame-executive = { version = "4.0.0-dev", default-features = false, path = "../../../frame/executive" } sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" } sp-block-builder = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/block-builder"} -sp-consensus-sassafras = { version = "0.3.1-dev", default-features = false, path = "../../../primitives/consensus/sassafras" } +sp-consensus-sassafras = { version = "0.3.2-dev", default-features = false, path = "../../../primitives/consensus/sassafras" } sp-core = { version = "7.0.0", default-features = false, path = "../../../primitives/core" } sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/inherents"} sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/offchain" } diff --git a/client/consensus/sassafras/Cargo.toml b/client/consensus/sassafras/Cargo.toml index 877c9a55a30d5..c6b5277095772 100644 --- a/client/consensus/sassafras/Cargo.toml +++ b/client/consensus/sassafras/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sc-consensus-sassafras" -version = "0.3.1-dev" +version = "0.3.2-dev" authors = ["Parity Technologies "] description = "Sassafras consensus algorithm for substrate" edition = "2021" @@ -32,7 +32,7 @@ sp-application-crypto = { version = "7.0.0", path = "../../../primitives/applica sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" } sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" } sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" } -sp-consensus-sassafras = { version = "0.3.1-dev", path = "../../../primitives/consensus/sassafras" } +sp-consensus-sassafras = { version = "0.3.2-dev", path = "../../../primitives/consensus/sassafras" } sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" } sp-core = { version = "7.0.0", path = "../../../primitives/core" } sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" } diff --git a/client/consensus/sassafras/src/authorship.rs b/client/consensus/sassafras/src/authorship.rs index ee8fc50baeb92..17da58e99f2f5 100644 --- a/client/consensus/sassafras/src/authorship.rs +++ b/client/consensus/sassafras/src/authorship.rs @@ -21,10 +21,10 @@ use super::*; use sp_consensus_sassafras::{ - digests::PreDigest, ticket_id, ticket_id_threshold, AuthorityId, Slot, TicketClaim, TicketData, - TicketEnvelope, TicketId, + digests::PreDigest, slot_claim_sign_data, ticket_id, ticket_id_threshold, AuthorityId, Slot, + TicketClaim, TicketData, TicketEnvelope, TicketId, }; -use sp_core::{twox_64, ByteArray}; +use sp_core::{twox_64, ByteArray, ed25519}; use std::pin::Pin; @@ -41,7 +41,7 @@ pub(crate) fn secondary_authority_index( /// If ticket is `None`, then the slot should be claimed using the fallback mechanism. pub(crate) fn claim_slot( slot: Slot, - epoch: &Epoch, + epoch: &mut Epoch, maybe_ticket: Option<(TicketId, TicketData)>, keystore: &KeystorePtr, ) -> Option<(PreDigest, AuthorityId)> { @@ -51,34 +51,38 @@ pub(crate) fn claim_slot( return None } + let mut vrf_sign_data = slot_claim_sign_data(&config.randomness, slot, epoch.epoch_idx); + let (authority_idx, ticket_claim) = match maybe_ticket { Some((ticket_id, ticket_data)) => { - log::debug!(target: LOG_TARGET, "[TRY PRIMARY]"); - let (authority_idx, ticket_secret) = epoch.tickets_aux.get(&ticket_id)?.clone(); + log::debug!(target: LOG_TARGET, "[TRY PRIMARY (slot {slot}, tkt = {ticket_id:16x})]"); + let (authority_idx, ticket_secret) = epoch.tickets_aux.remove(&ticket_id)?.clone(); log::debug!( target: LOG_TARGET, - "Ticket = [ticket: {:x?}, auth: {}, attempt: {}]", - ticket_id, + " got ticket: auth: {}, attempt: {}", authority_idx, ticket_data.attempt_idx ); - // TODO DAVXY : using ticket_secret - let _ = ticket_secret; - let erased_signature = [0; 64]; + + vrf_sign_data.push_transcript_data(&ticket_data.encode()); + + let data = vrf_sign_data.challenge::<32>(); + let erased_pair = ed25519::Pair::from_seed(&ticket_secret.erased_secret); + let erased_signature = *erased_pair.sign(&data).as_ref(); + let claim = TicketClaim { erased_signature }; (authority_idx, Some(claim)) }, None => { - log::debug!(target: LOG_TARGET, "[TRY SECONDARY]"); + log::debug!(target: LOG_TARGET, "[TRY SECONDARY (slot {slot})]"); (secondary_authority_index(slot, config), None) }, }; let authority_id = config.authorities.get(authority_idx as usize).map(|auth| &auth.0)?; - let vrf_input = slot_claim_vrf_input(&config.randomness, slot, epoch.epoch_idx); let vrf_signature = keystore - .sr25519_vrf_sign(AuthorityId::ID, authority_id.as_ref(), &vrf_input.into()) + .bandersnatch_vrf_sign(AuthorityId::ID, authority_id.as_ref(), &vrf_sign_data) .ok() .flatten()?; @@ -103,7 +107,8 @@ fn generate_epoch_tickets(epoch: &mut Epoch, keystore: &KeystorePtr) -> Vec Vec Vec Vec, Epoch>, ) -> Option { - debug!(target: LOG_TARGET, "Attempting to claim slot {}", slot); - // Get the next slot ticket from the runtime. let maybe_ticket = self.client.runtime_api().slot_ticket(parent_header.hash(), slot).ok()?; - // TODO-SASS-P2: remove me - debug!(target: LOG_TARGET, "parent {}", parent_header.hash()); + let mut epoch_changes = self.epoch_changes.shared_data_locked(); + let mut epoch = epoch_changes.viable_epoch_mut(epoch_descriptor, |slot| Epoch::genesis(&self.genesis_config, slot))?; let claim = authorship::claim_slot( slot, - self.epoch_changes - .shared_data() - .viable_epoch(epoch_descriptor, |slot| Epoch::genesis(&self.genesis_config, slot))? - .as_ref(), + &mut epoch.as_mut(), maybe_ticket, &self.keystore, ); @@ -282,6 +283,10 @@ where // TODO DAVXY SASS-32: this seal may be revisited. // We already have a VRF signature, this could be completelly redundant. // The header.hash() can be added to the VRF signed data. + // OR maybe we can maintain this seal but compute it using some of the data in the + // pre-digest + // Another option is to not recompute this signature and push (reuse) the one in the + // pre-digest as the seal let signature = self .keystore .sign_with( diff --git a/client/consensus/sassafras/src/lib.rs b/client/consensus/sassafras/src/lib.rs index 085f92c0ab57d..4635c77e1fa8b 100644 --- a/client/consensus/sassafras/src/lib.rs +++ b/client/consensus/sassafras/src/lib.rs @@ -77,10 +77,10 @@ use sp_runtime::{ pub use sp_consensus_sassafras::{ digests::{CompatibleDigestItem, ConsensusLog, NextEpochDescriptor, PreDigest}, inherents::SassafrasInherentData, - slot_claim_vrf_input, ticket_id_vrf_input, AuthorityId, AuthorityIndex, AuthorityPair, - AuthoritySignature, SassafrasApi, SassafrasAuthorityWeight, SassafrasConfiguration, - SassafrasEpochConfiguration, TicketClaim, TicketData, TicketEnvelope, TicketId, TicketSecret, - RANDOMNESS_LENGTH, SASSAFRAS_ENGINE_ID, + slot_claim_sign_data, slot_claim_vrf_input, ticket_id_vrf_input, AuthorityId, AuthorityIndex, + AuthorityPair, AuthoritySignature, SassafrasApi, SassafrasAuthorityWeight, + SassafrasConfiguration, SassafrasEpochConfiguration, TicketClaim, TicketData, TicketEnvelope, + TicketId, TicketSecret, RANDOMNESS_LENGTH, SASSAFRAS_ENGINE_ID, }; mod authorship; @@ -284,11 +284,10 @@ fn find_pre_digest(header: &B::Header) -> Result> if header.number().is_zero() { // Genesis block doesn't contain a pre digest so let's generate a // dummy one to not break any invariants in the rest of the code - use sp_consensus_sassafras::VrfInput; use sp_core::crypto::VrfSecret; let pair = sp_consensus_sassafras::AuthorityPair::from_seed(&[0u8; 32]); - let input = VrfInput::new(b"", &[]); - let vrf_signature = pair.as_ref().vrf_sign(&input.into()); + let data = sp_consensus_sassafras::slot_claim_sign_data(&Default::default(), 0.into(), 0); + let vrf_signature = pair.as_ref().vrf_sign(&data); return Ok(PreDigest { authority_idx: 0, slot: 0.into(), ticket_claim: None, vrf_signature }) } diff --git a/client/consensus/sassafras/src/tests.rs b/client/consensus/sassafras/src/tests.rs index f4e93798a1660..1438962d960f7 100644 --- a/client/consensus/sassafras/src/tests.rs +++ b/client/consensus/sassafras/src/tests.rs @@ -34,8 +34,8 @@ use sc_network_test::*; use sp_application_crypto::key_types::SASSAFRAS; use sp_blockchain::Error as TestError; use sp_consensus::{DisableProofRecording, NoNetwork as DummyOracle, Proposal}; -use sp_consensus_sassafras::{inherents::InherentDataProvider, slot_claim_vrf_input}; -use sp_keyring::Sr25519Keyring; +use sp_consensus_sassafras::inherents::InherentDataProvider; +use sp_keyring::BandersnatchKeyring as Keyring; use sp_keystore::{testing::MemoryKeystore, Keystore}; use sp_runtime::{Digest, DigestItem}; use sp_timestamp::Timestamp; @@ -172,9 +172,11 @@ fn create_test_block_import( .expect("can initialize block-import") } -fn create_test_keystore(authority: Sr25519Keyring) -> KeystorePtr { +fn create_test_keystore(authority: Keyring) -> KeystorePtr { let keystore = MemoryKeystore::new(); - keystore.sr25519_generate_new(SASSAFRAS, Some(&authority.to_seed())).unwrap(); + keystore + .bandersnatch_generate_new(SASSAFRAS, Some(&authority.to_seed())) + .unwrap(); keystore.into() } @@ -183,9 +185,9 @@ fn create_test_config() -> SassafrasConfiguration { slot_duration: SLOT_DURATION, epoch_duration: EPOCH_DURATION, authorities: vec![ - (Sr25519Keyring::Alice.public().into(), 1), - (Sr25519Keyring::Bob.public().into(), 1), - (Sr25519Keyring::Charlie.public().into(), 1), + (Keyring::Alice.public().into(), 1), + (Keyring::Bob.public().into(), 1), + (Keyring::Charlie.public().into(), 1), ], randomness: [0; 32], threshold_params: SassafrasEpochConfiguration { redundancy_factor: 1, attempts_number: 32 }, @@ -205,7 +207,7 @@ impl TestContext { let (block_import, link) = create_test_block_import(client.clone(), config.clone()); // Create a keystore with default testing key - let keystore = create_test_keystore(Sr25519Keyring::Alice); + let keystore = create_test_keystore(Keyring::Alice); let verifier = create_test_verifier(client.clone(), &link, config.clone()); @@ -289,7 +291,7 @@ impl TestContext { let parent_header = self.client.header(parent_hash).unwrap().unwrap(); let parent_number = *parent_header.number(); - let public = self.keystore.sr25519_public_keys(SASSAFRAS)[0]; + let public = self.keystore.bandersnatch_public_keys(SASSAFRAS)[0]; let proposer = block_on(self.init(&parent_header)).unwrap(); @@ -298,14 +300,12 @@ impl TestContext { parent_pre_digest.slot + 1 }); + // TODO DAVXY: here maybe we can use the epoch.randomness??? let epoch = self.epoch_data(&parent_hash, parent_number, slot); - let vrf_input = - slot_claim_vrf_input(&self.link.genesis_config.randomness, slot, epoch.epoch_idx); - let vrf_signature = self - .keystore - .sr25519_vrf_sign(SASSAFRAS, &public, &vrf_input.into()) - .unwrap() - .unwrap(); + let data = + slot_claim_sign_data(&self.link.genesis_config.randomness, slot, epoch.epoch_idx); + let vrf_signature = + self.keystore.bandersnatch_vrf_sign(SASSAFRAS, &public, &data).unwrap().unwrap(); let pre_digest = PreDigest { slot, authority_idx: 0, vrf_signature, ticket_claim: None }; let digest = sp_runtime::generic::Digest { @@ -320,7 +320,7 @@ impl TestContext { let hash = block.header.hash(); let signature = self .keystore - .sr25519_sign(SASSAFRAS, &public, hash.as_ref()) + .bandersnatch_sign(SASSAFRAS, &public, hash.as_ref()) .unwrap() .unwrap() .try_into() @@ -372,9 +372,9 @@ fn claim_secondary_slots_works() { let mut config = create_test_config(); config.randomness = [2; 32]; - let authorities = [Sr25519Keyring::Alice, Sr25519Keyring::Bob, Sr25519Keyring::Charlie]; + let authorities = [Keyring::Alice, Keyring::Bob, Keyring::Charlie]; - let epoch = Epoch { + let mut epoch = Epoch { epoch_idx: 1, start_slot: 6.into(), config: config.clone(), @@ -388,7 +388,7 @@ fn claim_secondary_slots_works() { for slot in 0..config.epoch_duration { if let Some((claim, auth_id2)) = - authorship::claim_slot(slot.into(), &epoch, None, &keystore) + authorship::claim_slot(slot.into(), &mut epoch, None, &keystore) { assert_eq!(claim.authority_idx as usize, auth_idx); assert_eq!(claim.slot, Slot::from(slot)); @@ -422,41 +422,44 @@ fn claim_primary_slots_works() { tickets_aux: Default::default(), }; - let keystore = create_test_keystore(Sr25519Keyring::Alice); + let keystore = create_test_keystore(Keyring::Alice); + let alice_authority_idx = 0_u32; - // Success if we have ticket aux data and the authority key in our keystore - // ticket-aux: OK , authority-key: OK => SUCCESS - - let authority_idx = 0u32; let ticket_id = 123; let ticket_data = TicketData { attempt_idx: 0, erased_public: [0; 32], revealed_public: [0; 32] }; let ticket_secret = TicketSecret { attempt_idx: 0, erased_secret: [0; 32] }; - epoch.tickets_aux.insert(ticket_id, (authority_idx, ticket_secret.clone())); - - let (pre_digest, auth_id) = - authorship::claim_slot(0.into(), &epoch, Some((ticket_id, ticket_data.clone())), &keystore) - .unwrap(); - - assert_eq!(pre_digest.authority_idx, authority_idx); - assert_eq!(auth_id, Sr25519Keyring::Alice.public().into()); // Fail if we have authority key in our keystore but not ticket aux data // ticket-aux: KO , authority-key: OK => FAIL - let ticket_id = 321; let claim = - authorship::claim_slot(0.into(), &epoch, Some((ticket_id, ticket_data.clone())), &keystore); + authorship::claim_slot(0.into(), &mut epoch, Some((ticket_id, ticket_data.clone())), &keystore); + assert!(claim.is_none()); + assert!(epoch.tickets_aux.is_empty()); + + // Success if we have ticket aux data and the authority key in our keystore + // ticket-aux: OK , authority-key: OK => SUCCESS + + epoch.tickets_aux.insert(ticket_id, (alice_authority_idx, ticket_secret.clone())); + + let (pre_digest, auth_id) = + authorship::claim_slot(0.into(), &mut epoch, Some((ticket_id, ticket_data.clone())), &keystore) + .unwrap(); + + assert!(epoch.tickets_aux.is_empty()); + assert_eq!(pre_digest.authority_idx, alice_authority_idx); + assert_eq!(auth_id, Keyring::Alice.public().into()); // Fail if we have ticket aux data but not the authority key in out keystore // ticket-aux: OK , authority-key: KO => FAIL - let authority_idx = 1u32; // we don't have this key - let ticket_id = 666; - epoch.tickets_aux.insert(ticket_id, (authority_idx, ticket_secret)); - let claim = authorship::claim_slot(0.into(), &epoch, Some((ticket_id, ticket_data)), &keystore); + epoch.tickets_aux.insert(ticket_id, (alice_authority_idx + 1, ticket_secret)); + + let claim = authorship::claim_slot(0.into(), &mut epoch, Some((ticket_id, ticket_data)), &keystore); assert!(claim.is_none()); + assert!(epoch.tickets_aux.is_empty()); } #[test] @@ -839,7 +842,7 @@ async fn sassafras_network_progress() { let net = SassafrasTestNet::new(3); let net = Arc::new(Mutex::new(net)); - let peers = [Sr25519Keyring::Alice, Sr25519Keyring::Bob, Sr25519Keyring::Charlie]; + let peers = [Keyring::Alice, Keyring::Bob, Keyring::Charlie]; let mut import_notifications = Vec::new(); let mut sassafras_workers = Vec::new(); diff --git a/client/consensus/sassafras/src/verification.rs b/client/consensus/sassafras/src/verification.rs index f83a4223ca05c..5a5dfc457ef80 100644 --- a/client/consensus/sassafras/src/verification.rs +++ b/client/consensus/sassafras/src/verification.rs @@ -20,7 +20,7 @@ use super::*; use sp_application_crypto::Wraps; -use sp_core::crypto::VrfPublic; +use sp_core::{crypto::VrfPublic, ed25519}; // Allowed slot drift. const MAX_SLOT_DRIFT: u64 = 1; @@ -81,35 +81,35 @@ fn check_header( None => return Err(sassafras_err(Error::SlotAuthorNotFound)), }; - // Check header signature + // Check header signature (aka the Seal) - // Check slot-vrf proof + let signature = seal + .as_sassafras_seal() + .ok_or_else(|| sassafras_err(Error::HeaderBadSeal(header.hash())))?; - let vrf_input = slot_claim_vrf_input(&config.randomness, pre_digest.slot, epoch.epoch_idx); - if !authority_id - .as_inner_ref() - .vrf_verify(&vrf_input.into(), &pre_digest.vrf_signature) - { - return Err(sassafras_err(Error::VrfVerificationFailed)) + let pre_hash = header.hash(); + if !AuthorityPair::verify(&signature, &pre_hash, &authority_id) { + return Err(sassafras_err(Error::BadSignature(pre_hash))) } - // let signature = seal - // .as_sassafras_seal() - // .ok_or_else(|| sassafras_err(Error::HeaderBadSeal(header.hash())))?; - - // let pre_hash = header.hash(); - // if !AuthorityPair::verify(&signature, &pre_hash, &authority_id) { - // return Err(sassafras_err(Error::BadSignature(pre_hash))) - // } + // Optionally check ticket ownership - // Check authorship method and claim + let mut vrf_sign_data = slot_claim_sign_data(&config.randomness, pre_digest.slot, epoch.epoch_idx); match (&maybe_ticket, &pre_digest.ticket_claim) { (Some((_ticket_id, ticket_data)), Some(ticket_claim)) => { log::debug!(target: LOG_TARGET, "checking primary"); - // TODO DAVXY: check erased_signature - let _public = ticket_data.erased_public; - let _signature = ticket_claim.erased_signature; + + vrf_sign_data.push_transcript_data(&ticket_data.encode()); + let challenge = vrf_sign_data.challenge::<32>(); + + let erased_public = ed25519::Public::from_raw(ticket_data.erased_public); + let erased_signature = + ed25519::Signature::from_raw(ticket_claim.erased_signature); + + if !ed25519::Pair::verify(&erased_signature, &challenge, &erased_public) { + return Err(sassafras_err(Error::BadSignature(pre_hash))) + } }, (None, None) => { log::debug!(target: LOG_TARGET, "checking secondary"); @@ -130,6 +130,12 @@ fn check_header( }, } + // Check per-slot vrf proof + + if !authority_id.as_inner_ref().vrf_verify(&vrf_sign_data, &pre_digest.vrf_signature) { + return Err(sassafras_err(Error::VrfVerificationFailed)) + } + let info = VerifiedHeaderInfo { authority_id, seal }; Ok(CheckedHeader::Checked(header, info)) diff --git a/client/keystore/src/local.rs b/client/keystore/src/local.rs index 4167e486ecf62..0fdbb24bf70b7 100644 --- a/client/keystore/src/local.rs +++ b/client/keystore/src/local.rs @@ -19,12 +19,13 @@ use parking_lot::RwLock; use sp_application_crypto::{AppCrypto, AppPair, IsWrappedBy}; -#[cfg(feature = "bls-experimental")] -use sp_core::{bls377, bls381}; use sp_core::{ + bandersnatch, crypto::{ByteArray, ExposeSecret, KeyTypeId, Pair as CorePair, SecretString, VrfSecret}, ecdsa, ed25519, sr25519, }; +#[cfg(feature = "bls-experimental")] +use sp_core::{bls377, bls381}; use sp_keystore::{Error as TraitError, Keystore, KeystorePtr}; use std::{ collections::HashMap, @@ -234,6 +235,48 @@ impl Keystore for LocalKeystore { Ok(sig) } + fn bandersnatch_public_keys(&self, key_type: KeyTypeId) -> Vec { + self.public_keys::(key_type) + } + + fn bandersnatch_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> std::result::Result { + self.generate_new::(key_type, seed) + } + + fn bandersnatch_sign( + &self, + key_type: KeyTypeId, + public: &bandersnatch::Public, + msg: &[u8], + ) -> std::result::Result, TraitError> { + self.sign::(key_type, public, msg) + } + + // TODO DAVXY + // Maybe we can expose just this bandersnatch sign (the above one reduces to this with + // input len = 0) + fn bandersnatch_vrf_sign( + &self, + key_type: KeyTypeId, + public: &bandersnatch::Public, + data: &bandersnatch::vrf::VrfSignData, + ) -> std::result::Result, TraitError> { + self.vrf_sign::(key_type, public, data) + } + + fn bandersnatch_vrf_output( + &self, + key_type: KeyTypeId, + public: &bandersnatch::Public, + input: &bandersnatch::vrf::VrfInput, + ) -> std::result::Result, TraitError> { + self.vrf_output::(key_type, public, input) + } + #[cfg(feature = "bls-experimental")] fn bls381_public_keys(&self, key_type: KeyTypeId) -> Vec { self.public_keys::(key_type) diff --git a/frame/sassafras/Cargo.toml b/frame/sassafras/Cargo.toml index 41b50759f39cf..592d50b33be0e 100644 --- a/frame/sassafras/Cargo.toml +++ b/frame/sassafras/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pallet-sassafras" -version = "0.3.1-dev" +version = "0.3.2-dev" authors = ["Parity Technologies "] edition = "2021" license = "Apache-2.0" @@ -22,7 +22,7 @@ pallet-session = { version = "4.0.0-dev", default-features = false, path = "../s pallet-timestamp = { version = "4.0.0-dev", default-features = false, path = "../timestamp" } scale-info = { version = "2.0.1", default-features = false, features = ["derive"] } sp-application-crypto = { version = "7.0.0", default-features = false, path = "../../primitives/application-crypto" } -sp-consensus-sassafras = { version = "0.3.1-dev", default-features = false, path = "../../primitives/consensus/sassafras" } +sp-consensus-sassafras = { version = "0.3.2-dev", default-features = false, path = "../../primitives/consensus/sassafras" } sp-io = { version = "7.0.0", default-features = false, path = "../../primitives/io" } sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" } diff --git a/frame/sassafras/src/lib.rs b/frame/sassafras/src/lib.rs index 3df4095335e3e..39a24041499f0 100644 --- a/frame/sassafras/src/lib.rs +++ b/frame/sassafras/src/lib.rs @@ -56,7 +56,7 @@ use sp_consensus_sassafras::{ digests::{ConsensusLog, NextEpochDescriptor, PreDigest}, AuthorityId, Epoch, EquivocationProof, Randomness, SassafrasAuthorityWeight, SassafrasConfiguration, SassafrasEpochConfiguration, Slot, TicketData, TicketEnvelope, - TicketId, RANDOMNESS_LENGTH, RANDOMNESS_VRF_CONTEXT, SASSAFRAS_ENGINE_ID, + TicketId, RANDOMNESS_LENGTH, SASSAFRAS_ENGINE_ID, }; use sp_io::hashing; use sp_runtime::{ @@ -80,7 +80,9 @@ pub mod session; // Re-export pallet symbols. pub use pallet::*; -const LOG_TARGET: &str = "runtime::sassafras 🌳"; +const LOG_TARGET: &str = "sassafras::runtime 🌳"; + +const RANDOMNESS_VRF_CONTEXT: &[u8] = b"SassafrasRandomness"; /// Tickets related metadata that is commonly used together. #[derive(Debug, Default, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen, Clone, Copy)] @@ -294,38 +296,27 @@ pub mod pallet { /// Block finalization fn on_finalize(_now: BlockNumberFor) { + // TODO DAVXY: check if is a disabled validator? + // At the end of the block, we can safely include the new VRF output from // this block into the randomness accumulator. If we've determined // that this block was the first in a new epoch, the changeover logic has - // already occurred at this point, so the + // already occurred at this point. let pre_digest = Initialized::::take() .expect("Finalization is called after initialization; qed."); - // TODO DAVXY P32: probably with the new vrf we don't need the authority id - // `inout` is sufficent - let authority_idx = pre_digest.authority_idx; - let authorities = Authorities::::get(); - let authority_id = authorities - .get(authority_idx as usize) - .expect("Authority should be valid at this point; qed"); - - // TODO DAVXY: check if is a disabled validator - let vrf_input = sp_consensus_sassafras::slot_claim_vrf_input( &Self::randomness(), CurrentSlot::::get(), EpochIndex::::get(), ); - let vrf_preout = &pre_digest.vrf_signature.output; - - let randomness = vrf_preout - .make_bytes::( - RANDOMNESS_VRF_CONTEXT, - &vrf_input, - authority_id.0.as_ref(), - ) - .expect("Can't fail? TODO DAVXY"); + let randomness = pre_digest + .vrf_signature + .vrf_outputs + .get(0) + .expect("vrf preout should have been already checked by the client; qed") + .make_bytes::(RANDOMNESS_VRF_CONTEXT, &vrf_input); Self::deposit_randomness(&randomness); @@ -362,7 +353,7 @@ pub mod pallet { ) -> DispatchResult { ensure_none(origin)?; - log::debug!(target: LOG_TARGET, "@@@@@@@@@@ received {} tickets", tickets.len()); + log::debug!(target: LOG_TARGET, "Received {} tickets", tickets.len()); // Check tickets score let next_auth = NextAuthorities::::get(); @@ -376,8 +367,9 @@ pub mod pallet { next_auth.len() as u32, ); - let epoch_idx = EpochIndex::::get(); - let randomness = CurrentRandomness::::get(); + // Get next epoch params + let randomness = NextRandomness::::get(); + let epoch_idx = EpochIndex::::get() + 1; let mut segment = BoundedVec::with_max_capacity(); for ticket in tickets.iter() { @@ -396,7 +388,8 @@ pub mod pallet { } if !segment.is_empty() { - log::debug!(target: LOG_TARGET, "@@@@@@@@@@ appending segment with {} tickets", segment.len()); + log::debug!(target: LOG_TARGET, "Appending segment with {} tickets", segment.len()); + segment.iter().for_each(|t| log::debug!(target: LOG_TARGET, " + {t:16x}")); let mut metadata = TicketsMeta::::get(); NextTicketsSegments::::insert(metadata.segments_count, segment); metadata.segments_count += 1; diff --git a/frame/sassafras/src/mock.rs b/frame/sassafras/src/mock.rs index 337a8d346cef2..5dde8abc11abd 100644 --- a/frame/sassafras/src/mock.rs +++ b/frame/sassafras/src/mock.rs @@ -182,8 +182,8 @@ fn slot_claim_vrf_signature(slot: Slot, pair: &AuthorityPair) -> VrfSignature { randomness = crate::NextRandomness::::get(); } - let vrf_input = sp_consensus_sassafras::slot_claim_vrf_input(&randomness, slot, epoch); - pair.as_ref().vrf_sign(&vrf_input.into()) + let data = sp_consensus_sassafras::slot_claim_sign_data(&randomness, slot, epoch); + pair.as_ref().vrf_sign(&data) } /// Produce a `PreDigest` instance for the given parameters. diff --git a/frame/sassafras/src/tests.rs b/frame/sassafras/src/tests.rs index dbb0d3af87cb9..c9e26f80fba04 100644 --- a/frame/sassafras/src/tests.rs +++ b/frame/sassafras/src/tests.rs @@ -149,7 +149,7 @@ fn on_first_block_after_genesis() { println!("{}", b2h(RandomnessAccumulator::::get())); assert_eq!( RandomnessAccumulator::::get(), - h2b("c3bcc82b9636bf12a9ba858ea6855b0b5a7a57803370e57cd87223f9d8d1a896"), + h2b("eb169de47822691578f74204ace5bc57c38f86f97e15a8abf71114541e7ca9e8"), ); // Header data check @@ -201,7 +201,7 @@ fn on_normal_block() { println!("{}", b2h(RandomnessAccumulator::::get())); assert_eq!( RandomnessAccumulator::::get(), - h2b("c3bcc82b9636bf12a9ba858ea6855b0b5a7a57803370e57cd87223f9d8d1a896"), + h2b("eb169de47822691578f74204ace5bc57c38f86f97e15a8abf71114541e7ca9e8"), ); let header = finalize_block(end_block); @@ -219,7 +219,7 @@ fn on_normal_block() { println!("{}", b2h(RandomnessAccumulator::::get())); assert_eq!( RandomnessAccumulator::::get(), - h2b("a44c15061d80d1f1b58abb3e002b9bd2d7135b3c8bef95a3af2ae5079a901135"), + h2b("c5e06d78bf5351b3a740c6838976e571ee14c595a206278f3f4ce0157f538318"), ); // Header data check @@ -257,12 +257,12 @@ fn produce_epoch_change_digest() { println!("{}", b2h(NextRandomness::::get())); assert_eq!( NextRandomness::::get(), - h2b("fec42ab12d7497cc8863b078774560790a5f1ee38d2b3a6b7448c4cc318c6e24"), + h2b("a7abdd705eb72383f60f6f093dea4bbfb65a1992099b4928ca30076f71a73682"), ); println!("{}", b2h(RandomnessAccumulator::::get())); assert_eq!( RandomnessAccumulator::::get(), - h2b("ba92c7ea134d29bd4c663e9a5811c0c76972606acbfdad354ab3cc9d400f756c"), + h2b("a9d8fc258ba0274d7815664b4e153904c44d2e850e98cffc0ba03ea018611348"), ); let header = finalize_block(end_block); @@ -279,12 +279,12 @@ fn produce_epoch_change_digest() { println!("{}", b2h(NextRandomness::::get())); assert_eq!( NextRandomness::::get(), - h2b("fec42ab12d7497cc8863b078774560790a5f1ee38d2b3a6b7448c4cc318c6e24"), + h2b("a7abdd705eb72383f60f6f093dea4bbfb65a1992099b4928ca30076f71a73682"), ); println!("{}", b2h(RandomnessAccumulator::::get())); assert_eq!( RandomnessAccumulator::::get(), - h2b("cea876f919ae1f6cdc8a93e91199d75bd162fb0b930df7168a66cdafc3ddd23c"), + h2b("53b4e087baba183a2973552ba57b6c8f489959c8e5f838d59884d37c6d494e2f"), ); // Header data check @@ -378,11 +378,11 @@ fn submit_segments_works() { assert_eq!(meta.segments_count, segments_count); assert_eq!(meta.tickets_count, [0, 0]); let seg = NextTicketsSegments::::get(0); - assert_eq!(seg.len(), 5); + assert_eq!(seg.len(), 3); let seg = NextTicketsSegments::::get(1); - assert_eq!(seg.len(), 6); + assert_eq!(seg.len(), 5); let seg = NextTicketsSegments::::get(2); - assert_eq!(seg.len(), 4); + assert_eq!(seg.len(), 5); }) } @@ -525,8 +525,8 @@ fn submit_enact_claim_tickets() { let mut expected_ids: Vec<_> = tickets .iter() .map(|t| { - let epoch_idx = Sassafras::epoch_index(); - let randomness = Sassafras::randomness(); + let epoch_idx = Sassafras::epoch_index() + 1; + let randomness = Sassafras::next_randomness(); let vrf_input = sp_consensus_sassafras::ticket_id_vrf_input( &randomness, t.data.attempt_idx, diff --git a/primitives/application-crypto/src/bandersnatch.rs b/primitives/application-crypto/src/bandersnatch.rs new file mode 100644 index 0000000000000..68adee8061c00 --- /dev/null +++ b/primitives/application-crypto/src/bandersnatch.rs @@ -0,0 +1,57 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Bandersnatch VRF application crypto types. + +use crate::{KeyTypeId, RuntimePublic}; +pub use sp_core::bandersnatch::*; +use sp_std::vec::Vec; + +mod app { + crate::app_crypto!(super, sp_core::testing::BANDERSNATCH); +} + +#[cfg(feature = "full_crypto")] +pub use app::Pair as AppPair; +pub use app::{Public as AppPublic, Signature as AppSignature}; + +impl RuntimePublic for Public { + type Signature = Signature; + + fn all(_key_type: KeyTypeId) -> Vec { + // sp_io::crypto::bandersnatch_public_keys(key_type) + unimplemented!() + } + + fn generate_pair(key_type: KeyTypeId, seed: Option>) -> Self { + sp_io::crypto::bandersnatch_generate(key_type, seed) + } + + fn sign>(&self, _key_type: KeyTypeId, _msg: &M) -> Option { + // sp_io::crypto::bandersnatch_sign(key_type, self, msg.as_ref()) + unimplemented!() + } + + fn verify>(&self, _msg: &M, _signature: &Self::Signature) -> bool { + // sp_io::crypto::bandersnatch_verify(signature, msg.as_ref(), self) + unimplemented!() + } + + fn to_raw_vec(&self) -> Vec { + sp_core::crypto::ByteArray::to_raw_vec(self) + } +} diff --git a/primitives/application-crypto/src/lib.rs b/primitives/application-crypto/src/lib.rs index 3e8f2f5a77b3a..2c4f4835bd20a 100644 --- a/primitives/application-crypto/src/lib.rs +++ b/primitives/application-crypto/src/lib.rs @@ -41,6 +41,11 @@ pub use serde; #[doc(hidden)] pub use sp_std::{ops::Deref, vec::Vec}; +pub use traits::*; + +mod traits; + +pub mod bandersnatch; #[cfg(feature = "bls-experimental")] pub mod bls377; #[cfg(feature = "bls-experimental")] @@ -48,9 +53,6 @@ pub mod bls381; pub mod ecdsa; pub mod ed25519; pub mod sr25519; -mod traits; - -pub use traits::*; /// Declares `Public`, `Pair` and `Signature` types which are functionally equivalent /// to the corresponding types defined by `$module` but are new application-specific diff --git a/primitives/application-crypto/src/traits.rs b/primitives/application-crypto/src/traits.rs index 88d4bf36915d0..d8869f19d0dab 100644 --- a/primitives/application-crypto/src/traits.rs +++ b/primitives/application-crypto/src/traits.rs @@ -31,7 +31,7 @@ use sp_std::{fmt::Debug, vec::Vec}; /// Typically, the implementers of this trait are its associated types themselves. /// This provides a convenient way to access generic information about the scheme /// given any of the associated types. -pub trait AppCrypto: 'static + Send + Sync + Sized + CryptoType + Clone { +pub trait AppCrypto: 'static + Send + Sized + CryptoType + Clone { /// Identifier for application-specific key type. const ID: KeyTypeId; diff --git a/primitives/consensus/sassafras/Cargo.toml b/primitives/consensus/sassafras/Cargo.toml index 3a58dd5a8f5fa..73de4164041a3 100644 --- a/primitives/consensus/sassafras/Cargo.toml +++ b/primitives/consensus/sassafras/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sp-consensus-sassafras" -version = "0.3.1-dev" +version = "0.3.2-dev" authors = ["Parity Technologies "] description = "Primitives for Sassafras consensus" edition = "2021" diff --git a/primitives/consensus/sassafras/src/digests.rs b/primitives/consensus/sassafras/src/digests.rs index d44d227b7ed9a..0ffc5e998223c 100644 --- a/primitives/consensus/sassafras/src/digests.rs +++ b/primitives/consensus/sassafras/src/digests.rs @@ -19,13 +19,12 @@ use super::{ ticket::TicketClaim, AuthorityId, AuthorityIndex, AuthoritySignature, Randomness, - SassafrasAuthorityWeight, SassafrasEpochConfiguration, Slot, SASSAFRAS_ENGINE_ID, + SassafrasAuthorityWeight, SassafrasEpochConfiguration, Slot, VrfSignature, SASSAFRAS_ENGINE_ID, }; use scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_core::sr25519::vrf::VrfSignature; use sp_runtime::{DigestItem, RuntimeDebug}; use sp_std::vec::Vec; diff --git a/primitives/consensus/sassafras/src/lib.rs b/primitives/consensus/sassafras/src/lib.rs index 6838f4d175762..4ee21f5dd3f64 100644 --- a/primitives/consensus/sassafras/src/lib.rs +++ b/primitives/consensus/sassafras/src/lib.rs @@ -32,20 +32,20 @@ use sp_runtime::{ConsensusEngineId, RuntimeDebug}; use sp_std::vec::Vec; pub use sp_consensus_slots::{Slot, SlotDuration}; -pub use sp_core::sr25519::vrf::{VrfInput, VrfOutput, VrfProof, VrfSignData, VrfSignature}; +pub use sp_core::bandersnatch::vrf::{VrfInput, VrfOutput, VrfSignData, VrfSignature}; pub mod digests; pub mod inherents; pub mod ticket; pub use ticket::{ - slot_claim_vrf_input, ticket_id, ticket_id_threshold, ticket_id_vrf_input, TicketClaim, - TicketData, TicketEnvelope, TicketId, TicketSecret, + slot_claim_sign_data, slot_claim_vrf_input, ticket_id, ticket_id_threshold, + ticket_id_vrf_input, TicketClaim, TicketData, TicketEnvelope, TicketId, TicketSecret, }; mod app { - use sp_application_crypto::{app_crypto, key_types::SASSAFRAS, sr25519}; - app_crypto!(sr25519, SASSAFRAS); + use sp_application_crypto::{app_crypto, bandersnatch, key_types::SASSAFRAS}; + app_crypto!(bandersnatch, SASSAFRAS); } /// Key type for Sassafras protocol. @@ -54,9 +54,6 @@ pub const KEY_TYPE: KeyTypeId = sp_application_crypto::key_types::SASSAFRAS; /// Consensus engine identifier. pub const SASSAFRAS_ENGINE_ID: ConsensusEngineId = *b"SASS"; -/// VRF context used for per-slot randomness generation. -pub const RANDOMNESS_VRF_CONTEXT: &[u8] = b"SassafrasRandomnessVRFContext"; - /// VRF output length for per-slot randomness. pub const RANDOMNESS_LENGTH: usize = 32; diff --git a/primitives/consensus/sassafras/src/ticket.rs b/primitives/consensus/sassafras/src/ticket.rs index 9f37198314ce5..0cedae3541809 100644 --- a/primitives/consensus/sassafras/src/ticket.rs +++ b/primitives/consensus/sassafras/src/ticket.rs @@ -21,10 +21,7 @@ use super::{Randomness, SASSAFRAS_ENGINE_ID}; use scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_consensus_slots::Slot; -use sp_core::sr25519::vrf::{VrfInput, VrfOutput}; - -/// VRF context used for ticket-id generation. -const TICKET_ID_VRF_CONTEXT: &[u8] = b"SassafrasTicketIdVRFContext"; +use sp_core::bandersnatch::vrf::{VrfInput, VrfOutput, VrfSignData}; /// Ticket identifier. /// @@ -82,14 +79,24 @@ pub fn slot_claim_vrf_input(randomness: &Randomness, slot: Slot, epoch: u64) -> VrfInput::new( &SASSAFRAS_ENGINE_ID, &[ - (b"type", b"ticket-claim-transcript"), + (b"type", b"slot-claim"), + (b"randomness", randomness), (b"slot", &slot.to_le_bytes()), (b"epoch", &epoch.to_le_bytes()), - (b"randomness", randomness), ], ) } +/// Signing-data to claim slot ownership during block production. +/// +/// Input randomness is current epoch randomness. +pub fn slot_claim_sign_data(randomness: &Randomness, slot: Slot, epoch: u64) -> VrfSignData { + let vrf_input = slot_claim_vrf_input(randomness, slot, epoch); + + VrfSignData::from_iter(&SASSAFRAS_ENGINE_ID, &[b"slot-claim-transcript"], [vrf_input]) + .expect("can't fail; qed") +} + /// VRF input to generate the ticket id. /// /// Input randomness is current epoch randomness. @@ -97,10 +104,10 @@ pub fn ticket_id_vrf_input(randomness: &Randomness, attempt: u32, epoch: u64) -> VrfInput::new( &SASSAFRAS_ENGINE_ID, &[ - (b"type", b"ticket-id-transcript"), + (b"type", b"ticket-id"), + (b"randomness", randomness), (b"attempt", &attempt.to_le_bytes()), (b"epoch", &epoch.to_le_bytes()), - (b"randomness", randomness), ], ) } @@ -109,13 +116,9 @@ pub fn ticket_id_vrf_input(randomness: &Randomness, attempt: u32, epoch: u64) -> /// /// Input generally obtained via `ticket_id_vrf_input`. /// Output can be obtained directly using the vrf secret key or from the signature. -// TODO DAVXY: with new VRF authority-id is not necessary pub fn ticket_id(vrf_input: &VrfInput, vrf_output: &VrfOutput) -> TicketId { - let public = sp_core::sr25519::Public::from_raw([0; 32]); - vrf_output - .make_bytes::<16>(TICKET_ID_VRF_CONTEXT, vrf_input, &public) - .map(|bytes| u128::from_le_bytes(bytes)) - .unwrap_or(u128::MAX) + let bytes = vrf_output.make_bytes::<16>(b"vrf-out", vrf_input); + u128::from_le_bytes(bytes) } /// Computes the threshold for a given epoch as T = (x*s)/(a*v), where: diff --git a/primitives/core/Cargo.toml b/primitives/core/Cargo.toml index f99ed6c53efc6..8a431ed34e954 100644 --- a/primitives/core/Cargo.toml +++ b/primitives/core/Cargo.toml @@ -13,6 +13,8 @@ documentation = "https://docs.rs/sp-core" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +bandersnatch_vrfs = { git = "https://github.com/w3f/ring-vrf", default-features = false } +arrayvec = { version = "0.7.2", default-features = false } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive","max-encoded-len"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } log = { version = "0.4.17", default-features = false } @@ -72,12 +74,14 @@ bench = false [features] default = ["std"] std = [ + "arrayvec/std", "merlin/std", "full_crypto", "log/std", "thiserror", "lazy_static", "parking_lot", + "bandersnatch_vrfs/getrandom", "bounded-collections/std", "primitive-types/std", "primitive-types/serde", diff --git a/primitives/core/src/bandersnatch.rs b/primitives/core/src/bandersnatch.rs new file mode 100644 index 0000000000000..f0af2ae705911 --- /dev/null +++ b/primitives/core/src/bandersnatch.rs @@ -0,0 +1,692 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! TODO DOCS. + +// #![allow(unused)] + +#[cfg(feature = "std")] +use crate::crypto::Ss58Codec; +use crate::crypto::{ + ByteArray, CryptoType, CryptoTypeId, Derive, Public as TraitPublic, UncheckedFrom, VrfPublic, +}; +#[cfg(feature = "full_crypto")] +use crate::crypto::{DeriveError, DeriveJunction, Pair as TraitPair, SecretStringError, VrfSecret}; + +#[cfg(feature = "full_crypto")] +use bandersnatch_vrfs::SecretKey; +use codec::{Decode, Encode, MaxEncodedLen}; +use scale_info::TypeInfo; + +use sp_runtime_interface::pass_by::PassByInner; +use sp_std::vec::Vec; + +/// Identifier used to match public keys against bandersnatch-vrf keys. +pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"bs38"); + +#[cfg(feature = "full_crypto")] +const SIGNING_CTX: &[u8] = b"SigningContext"; +#[cfg(feature = "full_crypto")] +const SEED_SERIALIZED_LEN: usize = 32; +const PUBLIC_SERIALIZED_LEN: usize = 32; +const SIGNATURE_SERIALIZED_LEN: usize = 64; + +/// XXX. +#[cfg_attr(feature = "full_crypto", derive(Hash))] +#[derive( + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Encode, + Decode, + PassByInner, + MaxEncodedLen, + TypeInfo, +)] +pub struct Public(pub [u8; PUBLIC_SERIALIZED_LEN]); + +impl UncheckedFrom<[u8; PUBLIC_SERIALIZED_LEN]> for Public { + fn unchecked_from(raw: [u8; PUBLIC_SERIALIZED_LEN]) -> Self { + Public(raw) + } +} + +impl AsRef<[u8; PUBLIC_SERIALIZED_LEN]> for Public { + fn as_ref(&self) -> &[u8; PUBLIC_SERIALIZED_LEN] { + &self.0 + } +} + +impl AsRef<[u8]> for Public { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl AsMut<[u8]> for Public { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0[..] + } +} + +impl TryFrom<&[u8]> for Public { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() != PUBLIC_SERIALIZED_LEN { + return Err(()) + } + let mut r = [0u8; PUBLIC_SERIALIZED_LEN]; + r.copy_from_slice(data); + Ok(Self::unchecked_from(r)) + } +} + +impl ByteArray for Public { + const LEN: usize = PUBLIC_SERIALIZED_LEN; +} + +impl TraitPublic for Public {} + +impl CryptoType for Public { + #[cfg(feature = "full_crypto")] + type Pair = Pair; +} + +impl Derive for Public {} + +impl sp_std::fmt::Debug for Public { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + let s = self.to_ss58check(); + write!(f, "{} ({}...)", crate::hexdisplay::HexDisplay::from(&self.0), &s[0..8]) + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + Ok(()) + } +} + +/// TODO davxy: DOCS +#[cfg_attr(feature = "full_crypto", derive(Hash))] +#[derive(Clone, Copy, PartialEq, Eq, Encode, Decode, PassByInner, MaxEncodedLen, TypeInfo)] +pub struct Signature([u8; SIGNATURE_SERIALIZED_LEN]); + +impl UncheckedFrom<[u8; SIGNATURE_SERIALIZED_LEN]> for Signature { + fn unchecked_from(raw: [u8; SIGNATURE_SERIALIZED_LEN]) -> Self { + Signature(raw) + } +} + +impl AsRef<[u8]> for Signature { + fn as_ref(&self) -> &[u8] { + &self.0[..] + } +} + +impl AsMut<[u8]> for Signature { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0[..] + } +} + +impl TryFrom<&[u8]> for Signature { + type Error = (); + + fn try_from(data: &[u8]) -> Result { + if data.len() != SIGNATURE_SERIALIZED_LEN { + return Err(()) + } + let mut r = [0u8; SIGNATURE_SERIALIZED_LEN]; + r.copy_from_slice(data); + Ok(Self::unchecked_from(r)) + } +} + +impl ByteArray for Signature { + const LEN: usize = SIGNATURE_SERIALIZED_LEN; +} + +impl CryptoType for Signature { + #[cfg(feature = "full_crypto")] + type Pair = Pair; +} + +impl sp_std::fmt::Debug for Signature { + #[cfg(feature = "std")] + fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + write!(f, "{}", crate::hexdisplay::HexDisplay::from(&self.0)) + } + + #[cfg(not(feature = "std"))] + fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result { + Ok(()) + } +} + +/// The raw secret seed, which can be used to recreate the `Pair`. +#[cfg(feature = "full_crypto")] +type Seed = [u8; SEED_SERIALIZED_LEN]; + +/// TODO davxy: DOCS +#[cfg(feature = "full_crypto")] +#[derive(Clone)] +pub struct Pair(SecretKey); + +#[cfg(feature = "full_crypto")] +impl TraitPair for Pair { + type Seed = Seed; + type Public = Public; + type Signature = Signature; + + /// Make a new key pair from secret seed material. + /// + /// The slice must be 64 bytes long or it will return an error. + fn from_seed_slice(seed_slice: &[u8]) -> Result { + if seed_slice.len() != SEED_SERIALIZED_LEN { + return Err(SecretStringError::InvalidSeedLength) + } + let mut seed_raw = [0; SEED_SERIALIZED_LEN]; + seed_raw.copy_from_slice(seed_slice); + let secret = SecretKey::from_seed(&seed_raw); + Ok(Pair(secret)) + } + + /// Derive a child key from a series of given (hard) junctions. + /// + /// Soft junctions are not supported. + fn derive>( + &self, + path: Iter, + _seed: Option, + ) -> Result<(Pair, Option), DeriveError> { + // TODO davxy is this good? + let derive_hard_junction = |secret_seed, cc| -> Seed { + ("bandersnatch-vrf-HDKD", secret_seed, cc).using_encoded(sp_core_hashing::blake2_256) + }; + + let mut acc = [0; SEED_SERIALIZED_LEN]; + for j in path { + match j { + DeriveJunction::Soft(_cc) => return Err(DeriveError::SoftKeyInPath), + DeriveJunction::Hard(cc) => acc = derive_hard_junction(acc, cc), + } + } + Ok((Self::from_seed(&acc), Some(acc))) + } + + /// Get the public key. + fn public(&self) -> Public { + let public = self.0.to_public(); + let mut raw = [0; PUBLIC_SERIALIZED_LEN]; + public.0.serialize(raw.as_mut_slice()).expect("key buffer length is good; qed"); + Public::unchecked_from(raw) + } + + /// Sign raw data. + fn sign(&self, data: &[u8]) -> Signature { + let data = vrf::VrfSignData::new(SIGNING_CTX, &[data], vrf::VrfIosVec::default()); + self.vrf_sign(&data).signature + } + + /// Verify a signature on a message. + /// + /// Returns true if the signature is good. + fn verify>(signature: &Self::Signature, data: M, public: &Self::Public) -> bool { + let data = vrf::VrfSignData::new(SIGNING_CTX, &[data.as_ref()], vrf::VrfIosVec::default()); + let signature = vrf::VrfSignature { + signature: signature.clone(), + vrf_outputs: vrf::VrfIosVec::default(), + }; + public.vrf_verify(&data, &signature) + } + + /// Return a vec filled with seed raw data. + fn to_raw_vec(&self) -> Vec { + // TODO davxy: makes sense??? Should we returne the seed or serialized secret key? + // If we return the serialized secret there is no method to reconstruct if ... + // unimplemented!() + panic!() + } +} + +#[cfg(feature = "full_crypto")] +impl CryptoType for Pair { + type Pair = Pair; +} + +/// VRF related 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, + }; + + const PREOUT_SERIALIZED_LEN: usize = 32; + + /// Max number of VRF inputs/outputs + pub const MAX_VRF_IOS: u32 = 3; + + pub(super) type VrfIosVec = BoundedVec>; + + /// Input to be used for VRF sign and verify operations. + #[derive(Clone)] + pub struct VrfInput(pub(super) bandersnatch_vrfs::VrfInput); + + impl VrfInput { + /// Build a new VRF input. + /// + /// Each message tuple has the form: (domain, data). + // TODO: Maybe we should access directly the transcript. + // I see a commented method in bandersnatch_vrfs crate that fullfil what we need... + pub fn new(label: &'static [u8], messages: &[(&[u8], &[u8])]) -> Self { + let _ = label; + let mut buf = Vec::new(); + messages.into_iter().for_each(|(domain, message)| { + buf.extend_from_slice(domain); + buf.extend_from_slice(message); + }); + let msg = Message { domain: b"TODO-DAVXY-FIXME", message: buf.as_slice() }; + VrfInput(msg.into_vrf_input()) + } + } + + /// TODO davxy docs + #[derive(Clone, Debug, PartialEq, Eq)] + pub struct VrfOutput(pub(super) bandersnatch_vrfs::VrfPreOut); + + impl Encode for VrfOutput { + fn encode(&self) -> Vec { + let mut bytes = [0; PREOUT_SERIALIZED_LEN]; + self.0 + .serialize_compressed(bytes.as_mut_slice()) + .expect("preout serialization can't fail"); + bytes.encode() + } + } + + impl Decode for VrfOutput { + fn decode(i: &mut R) -> Result { + let buf = <[u8; PREOUT_SERIALIZED_LEN]>::decode(i)?; + let preout = bandersnatch_vrfs::VrfPreOut::deserialize_compressed(buf.as_slice()) + .map_err(|_| "vrf-preout decode error: bad preout")?; + Ok(VrfOutput(preout)) + } + } + + impl MaxEncodedLen for VrfOutput { + fn max_encoded_len() -> usize { + <[u8; PREOUT_SERIALIZED_LEN]>::max_encoded_len() + } + } + + impl TypeInfo for VrfOutput { + type Identity = [u8; PREOUT_SERIALIZED_LEN]; + + fn type_info() -> scale_info::Type { + Self::Identity::type_info() + } + } + + /// TODO davxy docs + pub struct VrfSignData { + /// Associated Fiat-Shamir transcript + pub transcript: Transcript, + /// VRF inputs to be signed. + pub vrf_inputs: VrfIosVec, + } + + impl VrfSignData { + /// Construct a new data to be signed. + pub fn new>>( + label: &'static [u8], + transcript_data: &[&[u8]], + vrf_inputs: T, + ) -> Self { + let mut transcript = Transcript::new_labeled(label); + transcript_data.iter().for_each(|data| transcript.append_slice(data)); + VrfSignData { transcript, vrf_inputs: vrf_inputs.into() } + } + + /// Construct a new data to be signed from an iterator of `VrfInputs`. + /// + /// Returns `Err` if the `vrf_inputs` yields more elements than `MAX_VRF_IOS` + pub fn from_iter>( + label: &'static [u8], + transcript_data: &[&[u8]], + vrf_inputs: T, + ) -> Result { + let vrf_inputs: Vec = vrf_inputs.into_iter().collect(); + let bounded = VrfIosVec::try_from(vrf_inputs).map_err(|_| ())?; + Ok(Self::new(label, transcript_data, bounded)) + } + + /// Appends a message to the transcript + pub fn push_transcript_data( + &mut self, + data: &[u8], + ) { + self.transcript.append_slice(data); + } + + /// Appends a `VrfInput` to the vrf inputs to be signed. + /// On failure, returns the `VrfInput`. + pub fn push_vrf_input( + &mut self, + vrf_input: VrfInput, + ) -> Result<(), VrfInput> { + self.vrf_inputs.try_push(vrf_input) + } + + /// Create challenge from input transcript within the signing data. + pub fn challenge(&self) -> [u8; N] { + let mut output = [0; N]; + let mut t = self.transcript.clone(); + let mut reader = t.challenge(b"Prehashed for Ed25519"); + reader.read_bytes(&mut output); + output + } + } + + /// VRF signature. + #[derive(Clone, Debug, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo)] + pub struct VrfSignature { + /// VRF signature + pub signature: Signature, + /// VRF pre-outputs + pub vrf_outputs: VrfIosVec, + } + + #[cfg(feature = "full_crypto")] + impl VrfCrypto for Pair { + type VrfInput = VrfInput; + type VrfOutput = VrfOutput; + type VrfSignData = VrfSignData; + type VrfSignature = VrfSignature; + } + + #[cfg(feature = "full_crypto")] + impl VrfSecret for Pair { + fn vrf_sign(&self, data: &Self::VrfSignData) -> Self::VrfSignature { + // Hack used because backend signature type is generic over the number of ios + // @burdges can we provide a vec or boxed version? + match data.vrf_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), + _ => panic!("Max VRF inputs is set to: {}", MAX_VRF_IOS), + } + } + + fn vrf_output(&self, input: &Self::VrfInput) -> Self::VrfOutput { + let output = self.0 .0.vrf_preout(&input.0); + VrfOutput(output) + } + } + + impl VrfCrypto for Public { + type VrfInput = VrfInput; + type VrfOutput = VrfOutput; + type VrfSignData = VrfSignData; + type VrfSignature = VrfSignature; + } + + impl VrfPublic for Public { + fn vrf_verify(&self, data: &Self::VrfSignData, signature: &Self::VrfSignature) -> bool { + let preouts_len = signature.vrf_outputs.len(); + if preouts_len != data.vrf_inputs.len() { + return false + } + // Hack used because backend signature type is generic over the number of ios + // @burdges can we provide a vec or boxed version? + match preouts_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), + _ => panic!("Max VRF input messages is set to: {}", MAX_VRF_IOS), + } + } + } + + #[cfg(feature = "full_crypto")] + impl Pair { + fn vrf_sign_gen(&self, data: &VrfSignData) -> VrfSignature { + let ios: Vec<_> = data + .vrf_inputs + .iter() + .map(|i| self.0.clone().0.vrf_inout(i.0.clone())) + .collect(); + + let signature: ThinVrfSignature = + self.0.sign_thin_vrf(data.transcript.clone(), ios.as_slice()); + + let mut sign_bytes = [0; SIGNATURE_SERIALIZED_LEN]; + signature + .signature + .serialize_compressed(sign_bytes.as_mut_slice()) + .expect("serialization can't fail"); + + let outputs: Vec<_> = signature.preoutputs.into_iter().map(VrfOutput).collect(); + let outputs = VrfIosVec::truncate_from(outputs); + VrfSignature { signature: Signature(sign_bytes), vrf_outputs: outputs } + } + + /// Generate output bytes from the given VRF input. + /// + /// Index is relative to one of the `VrfInput` messages used during construction. + pub fn make_bytes( + &self, + context: &'static [u8], + input: &VrfInput, + ) -> [u8; N] { + let transcript = Transcript::new_labeled(context); + let inout = self.0.clone().0.vrf_inout(input.0.clone()); + inout.vrf_output_bytes(transcript) + } + } + + impl Public { + fn vrf_verify_gen( + &self, + data: &VrfSignData, + signature: &VrfSignature, + ) -> bool { + let Ok(public) = PublicKey::deserialize_compressed(self.as_ref()) else { + return false + }; + + let Ok(preouts) = signature + .vrf_outputs + .iter() + .map(|o| o.0.clone()) + .collect::>() + .into_inner() else { + return false + }; + + // 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. @burdges can we provide a vec or boxed version? + let Ok(signature) = ThinVrfSignature::<0>::deserialize_compressed(signature.signature.as_ref()).map(|s| s.signature) else { + return false + }; + let signature = ThinVrfSignature { signature, preoutputs: preouts }; + + let inputs = data.vrf_inputs.iter().map(|i| i.0.clone()); + + signature.verify_thin_vrf(data.transcript.clone(), inputs, &public).is_ok() + } + } + + impl VrfOutput { + /// Generate output bytes for the given 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.clone(), preoutput: self.0.clone() }; + inout.vrf_output_bytes(transcript) + } + } +} + +#[cfg(test)] +mod tests { + use super::{vrf::*, *}; + use crate::crypto::{VrfPublic, VrfSecret, DEV_PHRASE}; + const DEV_SEED: &[u8; SEED_SERIALIZED_LEN] = &[0; SEED_SERIALIZED_LEN]; + + #[allow(unused)] + fn b2h(bytes: &[u8]) -> String { + array_bytes::bytes2hex("", bytes) + } + + fn h2b(hex: &str) -> Vec { + array_bytes::hex2bytes_unchecked(hex) + } + + #[test] + fn backend_assumptions_check() { + let pair = SecretKey::from_seed(DEV_SEED); + let public = pair.to_public(); + + assert_eq!(public.0.size_of_serialized(), PUBLIC_SERIALIZED_LEN); + } + + #[test] + fn derive_hard_known_pair() { + let pair = Pair::from_string(&format!("{}//Alice", DEV_PHRASE), None).unwrap(); + // known address of DEV_PHRASE with 1.1 + let known = h2b("b0d3648bd5a3542afa16c06fee04cba37cc55c83a8894d36d87897bda0c65eec"); + assert_eq!(pair.public().as_ref(), known); + } + + #[test] + fn verify_known_signature() { + let pair = Pair::from_seed(DEV_SEED); + let public = pair.public(); + + let signature_raw = + h2b("524b0cbc4eb9579e2cd115fe55e2625e8265b3ea599ac903e67b08c2c669780cf43ca9c1e0a8a63c1dba121a606f95d3466cfe1880acc502c2792775125a7fcc" + ); + let signature = Signature::from_slice(&signature_raw).unwrap(); + + assert!(Pair::verify(&signature, b"hello", &public)); + } + + #[test] + fn sign_verify() { + let pair = Pair::from_seed(DEV_SEED); + let public = pair.public(); + let msg = b"hello"; + + let signature = pair.sign(msg); + assert!(Pair::verify(&signature, msg, &public)); + } + + #[test] + fn vrf_sign_verify() { + let pair = Pair::from_seed(DEV_SEED); + let public = pair.public(); + + let i1 = VrfInput::new(b"in1", &[(b"dom1", b"foo"), (b"dom2", b"bar")]); + let i2 = VrfInput::new(b"in2", &[(b"domx", b"hello")]); + let i3 = VrfInput::new(b"in3", &[(b"domy", b"yay"), (b"domz", b"nay")]); + + let data = VrfSignData::from_iter(b"mydata", &[b"tdata"], [i1, i2, i3]).unwrap(); + + 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); + let public = pair.public(); + + let i1 = VrfInput::new(b"in1", &[(b"dom1", b"foo"), (b"dom2", b"bar")]); + let i2 = VrfInput::new(b"in2", &[(b"domx", b"hello")]); + + let data = + VrfSignData::from_iter(b"mydata", &[b"tdata"], [i1.clone(), i2.clone()]).unwrap(); + + let signature = pair.vrf_sign(&data); + + let data = VrfSignData::from_iter(b"mydata", &[b"data"], [i1, i2.clone()]).unwrap(); + assert!(!public.vrf_verify(&data, &signature)); + + let data = VrfSignData::from_iter(b"mydata", &[b"tdata"], [i2]).unwrap(); + assert!(!public.vrf_verify(&data, &signature)); + } + + #[test] + fn vrf_make_bytes_matches() { + let pair = Pair::from_seed(DEV_SEED); + + let i1 = VrfInput::new(b"in1", &[(b"dom1", b"foo"), (b"dom2", b"bar")]); + let i2 = VrfInput::new(b"in2", &[(b"domx", b"hello")]); + let data = + VrfSignData::from_iter(b"mydata", &[b"tdata"], [i1.clone(), i2.clone()]).unwrap(); + let signature = pair.vrf_sign(&data); + + let o10 = pair.make_bytes::<32>(b"ctx1", &i1); + let o11 = signature.vrf_outputs[0].make_bytes::<32>(b"ctx1", &i1); + assert_eq!(o10, o11); + + let o20 = pair.make_bytes::<48>(b"ctx2", &i2); + let o21 = signature.vrf_outputs[1].make_bytes::<48>(b"ctx2", &i2); + assert_eq!(o20, o21); + } + + #[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"in1", &[(b"dom1", b"foo"), (b"dom2", b"bar")]); + let i2 = VrfInput::new(b"in2", &[(b"domx", b"hello")]); + let data = + VrfSignData::from_iter(b"mydata", &[b"tdata"], [i1.clone(), i2.clone()]).unwrap(); + let expected = pair.vrf_sign(&data); + + let bytes = expected.encode(); + + let decoded = VrfSignature::decode(&mut &bytes[..]).unwrap(); + assert_eq!(expected, decoded); + + let data = VrfSignData::from_iter(b"mydata", &[b"tdata"], []).unwrap(); + let expected = pair.vrf_sign(&data); + + let bytes = expected.encode(); + + let decoded = VrfSignature::decode(&mut &bytes[..]).unwrap(); + assert_eq!(expected, decoded); + } +} diff --git a/primitives/core/src/crypto.rs b/primitives/core/src/crypto.rs index 04a71f93ee168..1f66965d785fc 100644 --- a/primitives/core/src/crypto.rs +++ b/primitives/core/src/crypto.rs @@ -15,9 +15,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// tag::description[] //! Cryptographic utilities. -// end::description[] use crate::{ed25519, sr25519}; #[cfg(feature = "std")] @@ -480,7 +478,7 @@ pub trait ByteArray: AsRef<[u8]> + AsMut<[u8]> + for<'a> TryFrom<&'a [u8], Error } /// Trait suitable for typical cryptographic key public type. -pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send + Sync {} +pub trait Public: ByteArray + Derive + CryptoType + PartialEq + Eq + Clone + Send {} /// An opaque 32-byte cryptographic identifier. #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, MaxEncodedLen, TypeInfo)] @@ -828,7 +826,7 @@ impl sp_std::str::FromStr for SecretUri { /// /// For now it just specifies how to create a key from a phrase and derivation path. #[cfg(feature = "full_crypto")] -pub trait Pair: CryptoType + Sized + Clone + Send + Sync + 'static { +pub trait Pair: CryptoType + Sized + Clone + Send + 'static { /// The type which is used to encode a public key. type Public: Public + Hash; diff --git a/primitives/core/src/lib.rs b/primitives/core/src/lib.rs index f9541b02e2903..d00bc4dd70d5f 100644 --- a/primitives/core/src/lib.rs +++ b/primitives/core/src/lib.rs @@ -55,6 +55,7 @@ pub mod crypto; pub mod hexdisplay; pub use paste; +pub mod bandersnatch; #[cfg(feature = "bls-experimental")] pub mod bls; pub mod defer; diff --git a/primitives/core/src/testing.rs b/primitives/core/src/testing.rs index 6faf4ffa3042a..a1889d6779af6 100644 --- a/primitives/core/src/testing.rs +++ b/primitives/core/src/testing.rs @@ -21,10 +21,12 @@ use crate::crypto::KeyTypeId; /// Key type for generic Ed25519 key. pub const ED25519: KeyTypeId = KeyTypeId(*b"ed25"); -/// Key type for generic Sr 25519 key. +/// Key type for generic Sr25519 key. pub const SR25519: KeyTypeId = KeyTypeId(*b"sr25"); /// Key type for generic ECDSA key. pub const ECDSA: KeyTypeId = KeyTypeId(*b"ecds"); +/// Key type for generic Bandersnatch key. +pub const BANDERSNATCH: KeyTypeId = KeyTypeId(*b"bb12"); /// Key type for generic BLS12-377 key. pub const BLS377: KeyTypeId = KeyTypeId(*b"bls7"); /// Key type for generic BLS12-381 key. diff --git a/primitives/io/src/lib.rs b/primitives/io/src/lib.rs index 750b5d5924637..050effbb1a003 100644 --- a/primitives/io/src/lib.rs +++ b/primitives/io/src/lib.rs @@ -45,6 +45,7 @@ use sp_core::{ use sp_keystore::KeystoreExt; use sp_core::{ + bandersnatch, crypto::KeyTypeId, ecdsa, ed25519, offchain::{ @@ -1140,6 +1141,19 @@ pub trait Crypto { .map_err(|_| EcdsaVerifyError::BadSignature)?; Ok(pubkey.serialize()) } + + /// DAVXY + fn bandersnatch_generate( + &mut self, + id: KeyTypeId, + seed: Option>, + ) -> bandersnatch::Public { + let seed = seed.as_ref().map(|s| std::str::from_utf8(s).expect("Seed is valid utf8!")); + self.extension::() + .expect("No `keystore` associated for the current context!") + .bandersnatch_generate_new(id, seed) + .expect("`bandernatch_generate` failed") + } } /// Interface that provides functions for hashing with different algorithms. diff --git a/primitives/keyring/src/bandersnatch.rs b/primitives/keyring/src/bandersnatch.rs new file mode 100644 index 0000000000000..a61e9dafef877 --- /dev/null +++ b/primitives/keyring/src/bandersnatch.rs @@ -0,0 +1,241 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Support code for the runtime. A set of test accounts. + +pub use sp_core::bandersnatch; +use sp_core::{ + bandersnatch::{Pair, Public, Signature}, + crypto::UncheckedFrom, + ByteArray, Pair as PairT, H256, +}; +use sp_runtime::AccountId32; + +use lazy_static::lazy_static; +use std::{collections::HashMap, ops::Deref, sync::Mutex}; + +/// Set of test accounts. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, strum::EnumIter)] +pub enum Keyring { + Alice, + Bob, + Charlie, + Dave, + Eve, + Ferdie, + One, + Two, +} + +impl Keyring { + pub fn from_public(who: &Public) -> Option { + Self::iter().find(|&k| &Public::from(k) == who) + } + + pub fn from_account_id(who: &AccountId32) -> Option { + Self::iter().find(|&k| &k.to_account_id() == who) + } + + pub fn from_raw_public(who: [u8; 32]) -> Option { + Self::from_public(&Public::unchecked_from(who)) + } + + pub fn to_raw_public(self) -> [u8; 32] { + *Public::from(self).as_ref() + } + + pub fn from_h256_public(who: H256) -> Option { + Self::from_public(&Public::unchecked_from(who.into())) + } + + pub fn to_h256_public(self) -> H256 { + AsRef::<[u8; 32]>::as_ref(&Public::from(self)).into() + } + + pub fn to_raw_public_vec(self) -> Vec { + Public::from(self).to_raw_vec() + } + + pub fn to_account_id(self) -> AccountId32 { + self.to_raw_public().into() + } + + pub fn sign(self, msg: &[u8]) -> Signature { + Pair::from(self).sign(msg) + } + + pub fn pair(self) -> Pair { + Pair::from_string(&format!("//{}", <&'static str>::from(self)), None) + .expect("static values are known good; qed") + } + + /// Returns an iterator over all test accounts. + pub fn iter() -> impl Iterator { + ::iter() + } + + pub fn public(self) -> Public { + self.pair().public() + } + + pub fn to_seed(self) -> String { + format!("//{}", self) + } + + /// Create a crypto `Pair` from a numeric value. + pub fn numeric(idx: usize) -> Pair { + Pair::from_string(&format!("//{}", idx), None).expect("numeric values are known good; qed") + } + + /// Get account id of a `numeric` account. + pub fn numeric_id(idx: usize) -> AccountId32 { + (*AsRef::<[u8; 32]>::as_ref(&Self::numeric(idx).public())).into() + } +} + +impl From for &'static str { + fn from(k: Keyring) -> Self { + match k { + Keyring::Alice => "Alice", + Keyring::Bob => "Bob", + Keyring::Charlie => "Charlie", + Keyring::Dave => "Dave", + Keyring::Eve => "Eve", + Keyring::Ferdie => "Ferdie", + Keyring::One => "One", + Keyring::Two => "Two", + } + } +} + +#[derive(Debug)] +pub struct ParseKeyringError; + +impl std::fmt::Display for ParseKeyringError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "ParseKeyringError") + } +} + +impl std::str::FromStr for Keyring { + type Err = ParseKeyringError; + + fn from_str(s: &str) -> Result::Err> { + match s { + "Alice" => Ok(Keyring::Alice), + "Bob" => Ok(Keyring::Bob), + "Charlie" => Ok(Keyring::Charlie), + "Dave" => Ok(Keyring::Dave), + "Eve" => Ok(Keyring::Eve), + "Ferdie" => Ok(Keyring::Ferdie), + "One" => Ok(Keyring::One), + "Two" => Ok(Keyring::Two), + _ => Err(ParseKeyringError), + } + } +} + +lazy_static! { + static ref PRIVATE_KEYS: Mutex> = + Mutex::new(Keyring::iter().map(|who| (who, who.pair())).collect()); + static ref PUBLIC_KEYS: HashMap = PRIVATE_KEYS + .lock() + .unwrap() + .iter() + .map(|(&who, pair)| (who, pair.public())) + .collect(); +} + +impl From for AccountId32 { + fn from(k: Keyring) -> Self { + k.to_account_id() + } +} + +impl From for Public { + fn from(k: Keyring) -> Self { + *(*PUBLIC_KEYS).get(&k).unwrap() + } +} + +impl From for Pair { + fn from(k: Keyring) -> Self { + k.pair() + } +} + +impl From for [u8; 32] { + fn from(k: Keyring) -> Self { + *(*PUBLIC_KEYS).get(&k).unwrap().as_ref() + } +} + +impl From for H256 { + fn from(k: Keyring) -> Self { + AsRef::<[u8; 32]>::as_ref(PUBLIC_KEYS.get(&k).unwrap()).into() + } +} + +impl From for &'static [u8; 32] { + fn from(k: Keyring) -> Self { + PUBLIC_KEYS.get(&k).unwrap().as_ref() + } +} + +impl AsRef<[u8; 32]> for Keyring { + fn as_ref(&self) -> &[u8; 32] { + PUBLIC_KEYS.get(self).unwrap().as_ref() + } +} + +impl AsRef for Keyring { + fn as_ref(&self) -> &Public { + PUBLIC_KEYS.get(self).unwrap() + } +} + +impl Deref for Keyring { + type Target = [u8; 32]; + fn deref(&self) -> &[u8; 32] { + PUBLIC_KEYS.get(self).unwrap().as_ref() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use sp_core::{bandersnatch::Pair, Pair as PairT}; + + #[test] + fn should_work() { + assert!(Pair::verify( + &Keyring::Alice.sign(b"I am Alice!"), + b"I am Alice!", + &Keyring::Alice.public(), + )); + assert!(!Pair::verify( + &Keyring::Alice.sign(b"I am Alice!"), + b"I am Bob!", + &Keyring::Alice.public(), + )); + assert!(!Pair::verify( + &Keyring::Alice.sign(b"I am Alice!"), + b"I am Alice!", + &Keyring::Bob.public(), + )); + } +} diff --git a/primitives/keyring/src/lib.rs b/primitives/keyring/src/lib.rs index 7432aff12544a..fba15a121e818 100644 --- a/primitives/keyring/src/lib.rs +++ b/primitives/keyring/src/lib.rs @@ -23,11 +23,15 @@ pub mod sr25519; /// Test account crypto for ed25519. pub mod ed25519; +/// Test account crypto for bandersnatch. +pub mod bandersnatch; + /// Convenience export: Sr25519's Keyring is exposed as `AccountKeyring`, /// since it tends to be used for accounts (although it may also be used /// by authorities). pub use sr25519::Keyring as AccountKeyring; +pub use bandersnatch::Keyring as BandersnatchKeyring; pub use ed25519::Keyring as Ed25519Keyring; pub use sr25519::Keyring as Sr25519Keyring; diff --git a/primitives/keystore/src/lib.rs b/primitives/keystore/src/lib.rs index 1d2a27cb8726c..d67f2cb2d5c69 100644 --- a/primitives/keystore/src/lib.rs +++ b/primitives/keystore/src/lib.rs @@ -19,12 +19,13 @@ pub mod testing; -#[cfg(feature = "bls-experimental")] -use sp_core::{bls377, bls381}; use sp_core::{ + bandersnatch, crypto::{ByteArray, CryptoTypeId, KeyTypeId}, ecdsa, ed25519, sr25519, }; +#[cfg(feature = "bls-experimental")] +use sp_core::{bls377, bls381}; use std::sync::Arc; @@ -174,6 +175,40 @@ pub trait Keystore: Send + Sync { msg: &[u8; 32], ) -> Result, Error>; + /// DAVXY TODO + fn bandersnatch_public_keys(&self, key_type: KeyTypeId) -> Vec; + + /// DAVXY TODO + fn bandersnatch_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> Result; + + /// DAVXY TODO + fn bandersnatch_sign( + &self, + key_type: KeyTypeId, + public: &bandersnatch::Public, + msg: &[u8], + ) -> Result, Error>; + + /// DAVXY TODO + fn bandersnatch_vrf_sign( + &self, + key_type: KeyTypeId, + public: &bandersnatch::Public, + input: &bandersnatch::vrf::VrfSignData, + ) -> Result, Error>; + + /// DAVXY TODO + fn bandersnatch_vrf_output( + &self, + key_type: KeyTypeId, + public: &bandersnatch::Public, + input: &bandersnatch::vrf::VrfInput, + ) -> Result, Error>; + #[cfg(feature = "bls-experimental")] /// Returns all bls12-381 public keys for the given key type. fn bls381_public_keys(&self, id: KeyTypeId) -> Vec; @@ -258,6 +293,7 @@ pub trait Keystore: Send + Sync { /// - sr25519 /// - ed25519 /// - ecdsa + /// - bandersnatch /// - bls381 /// - bls377 /// @@ -291,6 +327,11 @@ pub trait Keystore: Send + Sync { self.ecdsa_sign(id, &public, msg)?.map(|s| s.encode()) }, + bandersnatch::CRYPTO_ID => { + let public = bandersnatch::Public::from_slice(public) + .map_err(|_| Error::ValidationError("Invalid public key format".into()))?; + self.bandersnatch_sign(id, &public, msg)?.map(|s| s.encode()) + }, #[cfg(feature = "bls-experimental")] bls381::CRYPTO_ID => { let public = bls381::Public::from_slice(public) diff --git a/primitives/keystore/src/testing.rs b/primitives/keystore/src/testing.rs index e18931a7af883..b9c685397fb6f 100644 --- a/primitives/keystore/src/testing.rs +++ b/primitives/keystore/src/testing.rs @@ -19,12 +19,13 @@ use crate::{Error, Keystore, KeystorePtr}; -#[cfg(feature = "bls-experimental")] -use sp_core::{bls377, bls381}; use sp_core::{ + bandersnatch, crypto::{ByteArray, KeyTypeId, Pair, VrfSecret}, ecdsa, ed25519, sr25519, }; +#[cfg(feature = "bls-experimental")] +use sp_core::{bls377, bls381}; use parking_lot::RwLock; use std::{collections::HashMap, sync::Arc}; @@ -214,6 +215,45 @@ impl Keystore for MemoryKeystore { Ok(sig) } + fn bandersnatch_public_keys(&self, key_type: KeyTypeId) -> Vec { + self.public_keys::(key_type) + } + + fn bandersnatch_generate_new( + &self, + key_type: KeyTypeId, + seed: Option<&str>, + ) -> Result { + self.generate_new::(key_type, seed) + } + + fn bandersnatch_sign( + &self, + key_type: KeyTypeId, + public: &bandersnatch::Public, + msg: &[u8], + ) -> Result, Error> { + self.sign::(key_type, public, msg) + } + + fn bandersnatch_vrf_sign( + &self, + key_type: KeyTypeId, + public: &bandersnatch::Public, + data: &bandersnatch::vrf::VrfSignData, + ) -> Result, Error> { + self.vrf_sign::(key_type, public, data) + } + + fn bandersnatch_vrf_output( + &self, + key_type: KeyTypeId, + public: &bandersnatch::Public, + input: &bandersnatch::vrf::VrfInput, + ) -> Result, Error> { + self.vrf_output::(key_type, public, input) + } + #[cfg(feature = "bls-experimental")] fn bls381_public_keys(&self, key_type: KeyTypeId) -> Vec { self.public_keys::(key_type) diff --git a/test-utils/runtime/Cargo.toml b/test-utils/runtime/Cargo.toml index 8b1dee38726ad..f8e3778953759 100644 --- a/test-utils/runtime/Cargo.toml +++ b/test-utils/runtime/Cargo.toml @@ -18,7 +18,7 @@ sp-application-crypto = { version = "7.0.0", default-features = false, path = ". sp-consensus-aura = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/aura" } sp-consensus-babe = { version = "0.10.0-dev", default-features = false, path = "../../primitives/consensus/babe" } sp-consensus-beefy = { version = "4.0.0-dev", default-features = false, path = "../../primitives/consensus/beefy" } -sp-consensus-sassafras = { version = "0.3.1-dev", default-features = false, path = "../../primitives/consensus/sassafras" } +sp-consensus-sassafras = { version = "0.3.2-dev", default-features = false, path = "../../primitives/consensus/sassafras" } sp-block-builder = { version = "4.0.0-dev", default-features = false, path = "../../primitives/block-builder" } codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = ["derive"] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } @@ -36,7 +36,7 @@ sp-session = { version = "4.0.0-dev", default-features = false, path = "../../pr sp-api = { version = "4.0.0-dev", default-features = false, path = "../../primitives/api" } sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" } pallet-babe = { version = "4.0.0-dev", default-features = false, path = "../../frame/babe" } -pallet-sassafras = { version = "0.3.1-dev", default-features = false, path = "../../frame/sassafras" } +pallet-sassafras = { version = "0.3.2-dev", default-features = false, path = "../../frame/sassafras" } pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../frame/balances" } pallet-root-testing = { version = "1.0.0-dev", default-features = false, path = "../../frame/root-testing" } pallet-sudo = { version = "4.0.0-dev", default-features = false, path = "../../frame/sudo" } diff --git a/test-utils/runtime/src/genesismap.rs b/test-utils/runtime/src/genesismap.rs index 5e730800dc028..0323ab6053403 100644 --- a/test-utils/runtime/src/genesismap.rs +++ b/test-utils/runtime/src/genesismap.rs @@ -23,11 +23,11 @@ use super::{ use codec::Encode; use sc_service::construct_genesis_block; use sp_core::{ - sr25519, + bandersnatch, sr25519, storage::{well_known_keys, StateVersion, Storage}, Pair, }; -use sp_keyring::{AccountKeyring, Sr25519Keyring}; +use sp_keyring::AccountKeyring; use sp_runtime::{ traits::{Block as BlockT, Hash as HashT, Header as HeaderT}, BuildStorage, @@ -54,9 +54,9 @@ impl Default for GenesisStorageBuilder { fn default() -> Self { Self::new( vec![ - Sr25519Keyring::Alice.into(), - Sr25519Keyring::Bob.into(), - Sr25519Keyring::Charlie.into(), + AccountKeyring::Alice.into(), + AccountKeyring::Bob.into(), + AccountKeyring::Charlie.into(), ], (0..16_usize) .into_iter() @@ -109,11 +109,18 @@ impl GenesisStorageBuilder { /// Builds the `GenesisConfig` and returns its storage. pub fn build(self) -> Storage { - let authorities_sr25519: Vec<_> = self + let authorities_sr25519: Vec = + self.authorities.clone().into_iter().map(|id| id.into()).collect(); + + let authorities_bandersnatch: Vec = self .authorities - .clone() - .into_iter() - .map(|id| sr25519::Public::from(id)) + .iter() + .map(|id| { + use sp_keyring::bandersnatch::Keyring as BandersnatchKeyring; + use std::str::FromStr; + let seed: &'static str = AccountKeyring::from_public(id).unwrap().into(); + BandersnatchKeyring::from_str(&seed).unwrap().into() + }) .collect(); let genesis_config = GenesisConfig { @@ -129,11 +136,7 @@ impl GenesisStorageBuilder { epoch_config: Some(crate::TEST_RUNTIME_BABE_EPOCH_CONFIGURATION), }, sassafras: pallet_sassafras::GenesisConfig { - authorities: authorities_sr25519 - .clone() - .into_iter() - .map(|x| (x.into(), 1)) - .collect(), + authorities: authorities_bandersnatch.into_iter().map(|x| (x.into(), 1)).collect(), epoch_config: sp_consensus_sassafras::SassafrasEpochConfiguration { redundancy_factor: 1, attempts_number: 32, diff --git a/test-utils/runtime/src/lib.rs b/test-utils/runtime/src/lib.rs index 9963acde47d0b..b1ee221a99a59 100644 --- a/test-utils/runtime/src/lib.rs +++ b/test-utils/runtime/src/lib.rs @@ -135,20 +135,6 @@ pub struct TransferData { pub amount: Balance, pub nonce: Index, } -// TODO DAVXY -// impl From> for Extrinsic { -// fn from(call: pallet_sassafras::Call) -> Self { -// use pallet_sassafras::Call; -// match call { -// Call::submit_tickets { tickets: _ } => Extrinsic::Sassafras, -// Call::plan_config_change { config: _ } => Extrinsic::Sassafras, -// Call::report_equivocation_unsigned { equivocation_proof: _ } => Extrinsic::Sassafras, -// _ => panic!( -// "Unexpected Sassafras call type: {:?}, unable to converto to Extrinsic", -// call -// ), -// } -// } /// The address format for describing accounts. pub type Address = sp_core::sr25519::Public; @@ -715,8 +701,9 @@ impl_runtime_apis! { Sassafras::slot_ticket_id(slot) } - fn slot_ticket(slot: sp_consensus_sassafras::Slot) -> Option<(sp_consensus_sassafras::TicketId, - sp_consensus_sassafras::TicketData)> { + fn slot_ticket( + slot: sp_consensus_sassafras::Slot + ) -> Option<(sp_consensus_sassafras::TicketId, sp_consensus_sassafras::TicketData)> { Sassafras::slot_ticket(slot) } @@ -921,6 +908,10 @@ pub mod storage_key_generator { vec![b"Babe", b"NextAuthorities"], vec![b"Babe", b"SegmentIndex"], vec![b"Babe", b":__STORAGE_VERSION__:"], + vec![b"Sassafras", b":__STORAGE_VERSION__:"], + vec![b"Sassafras", b"EpochConfig"], + vec![b"Sassafras", b"Authorities"], + vec![b"Sassafras", b"NextAuthorities"], vec![b"Balances", b":__STORAGE_VERSION__:"], vec![b"Balances", b"TotalIssuance"], vec![b"SubstrateTest", b"Authorities"], @@ -975,31 +966,30 @@ pub mod storage_key_generator { /// origin. pub fn get_expected_storage_hashed_keys() -> Vec { [ - //System|:__STORAGE_VERSION__: + // System|:__STORAGE_VERSION__: "00771836bebdd29870ff246d305c578c4e7b9012096b41c4eb3aaf947f6ea429", - //SubstrateTest|Authorities + // SubstrateTest|Authorities "00771836bebdd29870ff246d305c578c5e0621c4869aa60c02be9adcc98a0d1d", - //Babe|:__STORAGE_VERSION__: + // Babe|:__STORAGE_VERSION__: "1cb6f36e027abb2091cfb5110ab5087f4e7b9012096b41c4eb3aaf947f6ea429", - //Babe|Authorities + // Babe|Authorities "1cb6f36e027abb2091cfb5110ab5087f5e0621c4869aa60c02be9adcc98a0d1d", - //Babe|SegmentIndex + // Babe|SegmentIndex "1cb6f36e027abb2091cfb5110ab5087f66e8f035c8adbe7f1547b43c51e6f8a4", - //Babe|NextAuthorities + // Babe|NextAuthorities "1cb6f36e027abb2091cfb5110ab5087faacf00b9b41fda7a9268821c2a2b3e4c", - //Babe|EpochConfig + // Babe|EpochConfig "1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef", - //System|:__STORAGE_VERSION__: + // System|:__STORAGE_VERSION__: "26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429", - //System|UpgradedToU32RefCount + // System|UpgradedToU32RefCount "26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710", - //System|ParentHash + // System|ParentHash "26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc", - //System::BlockHash|0 + // System::BlockHash|0 "26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746bb1bdbcacd6ac9340000000000000000", - //System|UpgradedToTripleRefCount + // System|UpgradedToTripleRefCount "26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439", - // System|Account|blake2_128Concat("//11") "26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da901cae4e3edfbb32c91ed3f01ab964f4eeeab50338d8e5176d3141802d7b010a55dadcd5f23cf8aaafa724627e967e90e", // System|Account|blake2_128Concat("//4") @@ -1046,6 +1036,14 @@ pub mod storage_key_generator { "3a65787472696e7369635f696e646578", // :heappages "3a686561707061676573", + // Sassafras|__STORAGE_VERSION__: + "be5e1f844c68e483aa815e45bbd9d3184e7b9012096b41c4eb3aaf947f6ea429", + // Sassafras|Authorities + "be5e1f844c68e483aa815e45bbd9d3185e0621c4869aa60c02be9adcc98a0d1d", + // Sassafras|NextAuthorities + "be5e1f844c68e483aa815e45bbd9d318aacf00b9b41fda7a9268821c2a2b3e4c", + // Sassafras|EpochConfig + "be5e1f844c68e483aa815e45bbd9d318dc6b171b77304263c292cc3ea5ed31ef", // Balances|:__STORAGE_VERSION__: "c2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429", // Balances|TotalIssuance @@ -1078,6 +1076,32 @@ mod tests { prelude::*, runtime::TestAPI, DefaultTestClientBuilderExt, TestClientBuilder, }; + fn babe_pre_digest() -> DigestItem { + use sp_consensus_babe::digests::{ + CompatibleDigestItem, PreDigest, SecondaryPlainPreDigest, + }; + DigestItem::babe_pre_digest(PreDigest::SecondaryPlain(SecondaryPlainPreDigest { + authority_index: 0, + slot: 0.into(), + })) + } + + fn sassafras_pre_digest() -> DigestItem { + use sp_consensus_sassafras::{ + digests::{CompatibleDigestItem, PreDigest}, + slot_claim_sign_data, AuthorityPair, + }; + use sp_core::crypto::{Pair, VrfSecret}; + let data = slot_claim_sign_data(&Default::default(), 0.into(), 0); + let vrf_signature = AuthorityPair::from_seed(&[0u8; 32]).as_ref().vrf_sign(&data); + DigestItem::sassafras_pre_digest(PreDigest { + authority_idx: 0, + slot: 0.into(), + vrf_signature, + ticket_claim: None, + }) + } + #[test] fn heap_pages_is_respected() { // This tests that the on-chain `HEAP_PAGES` parameter is respected. @@ -1102,7 +1126,8 @@ mod tests { // Create a block that sets the `:heap_pages` to 32 pages of memory which corresponds to // ~2048k of heap memory. let (new_at_hash, block) = { - let mut builder = client.new_block(Default::default()).unwrap(); + let digest = Digest { logs: vec![babe_pre_digest(), sassafras_pre_digest()] }; + let mut builder = client.new_block(digest).unwrap(); builder.push_storage_change(HEAP_PAGES.to_vec(), Some(32u64.encode())).unwrap(); let block = builder.build().unwrap().block; let hash = block.header.hash();