From 90bc364f9fb12fe6fcef0117ba940bd33c2ce57f Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Fri, 29 Aug 2025 05:04:03 -0400 Subject: [PATCH] Replace `Ciphersuite::hash_to_F` The prior-present `Ciphersuite::hash_to_F` was a sin. Implementations took a DST, yet were not require to securely handle it. It was also biased towards the requirements of `modular-frost` as `ciphersuite` was originally written all those years ago, when `modular-frost` had needs exceeding what `ff`, `group` satisfied. Now, the hash is bound to produce an output which can be converted to a scalar with `ff::FromUniformBytes`. A new `hash_to_F`, which accepts a single argument of the value to hash (removing the potential to insecurely handle the DST by removing the DST entirely). Due to `digest` yielding a `GenericArray`, yet `FromUniformBytes` taking a `const usize`, the `ciphersuite` crate now defines a `FromUniformBytes` trait taking an array (then implemented for all satisfiers of `ff::FromUniformBytes`). In order to get the array type from the `GenericArray`, the output of the hash, `digest` is updated to the `0.11` release candidate which moves to `flexible-array` which solves that problem. The existing, specific `hash_to_F` functions have been moved to `modular-frost` as necessary. `flexible-array` itself is patched to a fork due to https://github.com/RustCrypto/hybrid-array/issues/131. --- Cargo.lock | 168 ++++++++++++++++------ Cargo.toml | 6 +- coordinator/tributary-sdk/Cargo.toml | 2 +- crypto/ciphersuite/Cargo.toml | 7 +- crypto/ciphersuite/README.md | 14 -- crypto/ciphersuite/kp256/Cargo.toml | 6 +- crypto/ciphersuite/kp256/src/lib.rs | 129 +---------------- crypto/ciphersuite/src/lib.rs | 29 ++-- crypto/dalek-ff-group/Cargo.toml | 6 +- crypto/dalek-ff-group/src/ciphersuite.rs | 49 +------ crypto/dkg/Cargo.toml | 2 +- crypto/dkg/dealer/Cargo.toml | 2 +- crypto/dkg/musig/Cargo.toml | 2 +- crypto/dkg/musig/src/lib.rs | 4 +- crypto/dkg/recovery/Cargo.toml | 2 +- crypto/ed448/Cargo.toml | 4 +- crypto/ed448/src/ciphersuite.rs | 51 +------ crypto/embedwards25519/Cargo.toml | 4 +- crypto/embedwards25519/src/lib.rs | 21 +-- crypto/frost/Cargo.toml | 9 +- crypto/frost/src/curve/dalek.rs | 22 +-- crypto/frost/src/curve/ed448.rs | 36 +++-- crypto/frost/src/curve/kp256.rs | 115 ++++++++++++++- crypto/frost/src/curve/mod.rs | 20 ++- crypto/schnorr/Cargo.toml | 2 +- crypto/schnorrkel/Cargo.toml | 2 +- crypto/secq256k1/Cargo.toml | 4 +- crypto/secq256k1/src/lib.rs | 17 +-- crypto/transcript/Cargo.toml | 12 +- crypto/transcript/src/lib.rs | 2 +- message-queue/src/messages.rs | 4 +- processor/bitcoin/src/scan.rs | 8 +- processor/scheduler/primitives/Cargo.toml | 2 +- processor/view-keys/Cargo.toml | 2 +- processor/view-keys/src/lib.rs | 2 +- substrate/node/src/rpc.rs | 2 +- substrate/primitives/src/account.rs | 2 +- 37 files changed, 355 insertions(+), 416 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fafab11b..4d8359de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -42,7 +42,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ - "crypto-common", + "crypto-common 0.1.6", "generic-array 0.14.7", ] @@ -353,7 +353,7 @@ dependencies = [ "ruint", "rustc-hash 2.1.1", "serde", - "sha3", + "sha3 0.10.8", "tiny-keccak", ] @@ -1524,6 +1524,15 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "blake2" +version = "0.11.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce3d950855224a23299348898f8a2127860e1afea78df3e51deebb89d1cb2f8f" +dependencies = [ + "digest 0.11.0-rc.0", +] + [[package]] name = "blake2b_simd" version = "1.0.3" @@ -1577,6 +1586,15 @@ dependencies = [ "generic-array 0.14.7", ] +[[package]] +name = "block-buffer" +version = "0.11.0-rc.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a229bfd78e4827c91b9b95784f69492c1b77c1ab75a45a8a037b139215086f94" +dependencies = [ + "hybrid-array", +] + [[package]] name = "blst" version = "0.3.15" @@ -1895,7 +1913,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "crypto-common", + "crypto-common 0.1.6", "inout", "zeroize", ] @@ -1904,7 +1922,7 @@ dependencies = [ name = "ciphersuite" version = "0.4.2" dependencies = [ - "digest 0.10.7", + "digest 0.11.0-rc.0", "ff", "ff-group-tests", "flexible-transcript", @@ -1929,13 +1947,12 @@ name = "ciphersuite-kp256" version = "0.4.0" dependencies = [ "ciphersuite 0.4.2", - "elliptic-curve", "ff-group-tests", "hex", "k256", "p256", "rand_core 0.6.4", - "sha2 0.10.9", + "sha2 0.11.0-rc.0", "zeroize", ] @@ -2326,6 +2343,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a23fa214dea9efd4dacee5a5614646b30216ae0f05d4bb51bafb50e9da1c5be" +dependencies = [ + "hybrid-array", +] + [[package]] name = "ctr" version = "0.9.2" @@ -2440,7 +2466,7 @@ dependencies = [ "hex", "rand_core 0.6.4", "rustversion", - "sha2 0.10.9", + "sha2 0.11.0-rc.0", "subtle", "zeroize", ] @@ -2517,7 +2543,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976" dependencies = [ "data-encoding", - "syn 1.0.109", + "syn 2.0.106", ] [[package]] @@ -2674,7 +2700,18 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", "const-oid", - "crypto-common", + "crypto-common 0.1.6", + "subtle", +] + +[[package]] +name = "digest" +version = "0.11.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460dd7f37e4950526b54a5a6b1f41b6c8e763c58eb9a8fc8fc05ba5c2f44ca7b" +dependencies = [ + "block-buffer 0.11.0-rc.4", + "crypto-common 0.2.0-rc.3", "subtle", ] @@ -2756,7 +2793,7 @@ dependencies = [ name = "dkg-evrf" version = "0.1.0" dependencies = [ - "blake2", + "blake2 0.10.6", "ciphersuite 0.4.2", "ciphersuite-kp256", "dalek-ff-group", @@ -2986,7 +3023,7 @@ dependencies = [ name = "embedwards25519" version = "0.1.0" dependencies = [ - "blake2", + "blake2 0.11.0-rc.0", "ciphersuite 0.4.2", "curve25519-dalek", "dalek-ff-group", @@ -3102,7 +3139,7 @@ dependencies = [ "group", "k256", "rand_core 0.6.4", - "sha3", + "sha3 0.10.8", "subtle", "tokio", ] @@ -3149,7 +3186,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f86a749cf851891866c10515ef6c299b5c69661465e9c3bbe7e07a2b77fb0f7" dependencies = [ - "blake2", + "blake2 0.10.6", "fs-err", "proc-macro2", "quote", @@ -3276,10 +3313,10 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" name = "flexible-transcript" version = "0.3.4" dependencies = [ - "blake2", - "digest 0.10.7", + "blake2 0.11.0-rc.0", + "digest 0.11.0-rc.0", "merlin", - "sha2 0.10.9", + "sha2 0.11.0-rc.0", "zeroize", ] @@ -3728,7 +3765,7 @@ name = "generalized-bulletproofs" version = "0.1.0" source = "git+https://github.com/monero-oxide/monero-oxide?rev=a6f8797007e768488568b821435cf5006517a962#a6f8797007e768488568b821435cf5006517a962" dependencies = [ - "blake2", + "blake2 0.10.6", "ciphersuite 0.4.99", "ff", "flexible-transcript", @@ -4174,6 +4211,14 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" +[[package]] +name = "hybrid-array" +version = "0.3.1" +source = "git+https://github.com/kayabaNerve/hybrid-array?rev=8caa508976c93696a67f40734537c91be7cecd96#8caa508976c93696a67f40734537c91be7cecd96" +dependencies = [ + "typenum", +] + [[package]] name = "hyper" version = "0.14.30" @@ -4685,7 +4730,7 @@ dependencies = [ [[package]] name = "k256" version = "0.13.4" -source = "git+https://github.com/kayabaNerve/elliptic-curves?rev=fc92333e222b7f0cbe268d2ca92ed572f71f3e1d#fc92333e222b7f0cbe268d2ca92ed572f71f3e1d" +source = "git+https://github.com/kayabaNerve/elliptic-curves?rev=4994c9ab163781a88cd4a49beae812a89a44e8c3#4994c9ab163781a88cd4a49beae812a89a44e8c3" dependencies = [ "cfg-if", "ecdsa", @@ -4704,6 +4749,15 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "keccak" +version = "0.2.0-pre.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7cdd4f0dc5807b9a2b25dd48a3f58e862606fe7bd47f41ecde36e97422d7e90" +dependencies = [ + "cpufeatures", +] + [[package]] name = "keccak-asm" version = "0.1.4" @@ -5936,7 +5990,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" dependencies = [ "byteorder", - "keccak", + "keccak 0.1.5", "rand_core 0.6.4", "zeroize", ] @@ -5957,7 +6011,7 @@ dependencies = [ "hex", "prime-field", "rand_core 0.6.4", - "sha3", + "sha3 0.11.0-rc.0", "zeroize", ] @@ -6021,10 +6075,10 @@ dependencies = [ "ciphersuite 0.4.2", "ciphersuite-kp256", "dalek-ff-group", - "digest 0.10.7", "dkg", "dkg-dealer", "dkg-recovery", + "elliptic-curve", "flexible-transcript", "hex", "minimal-ed448", @@ -6033,6 +6087,7 @@ dependencies = [ "rand_core 0.6.4", "schnorr-signatures", "serde_json", + "sha2 0.10.9", "subtle", "thiserror 2.0.16", "zeroize", @@ -6118,7 +6173,7 @@ dependencies = [ "dalek-ff-group", "group", "monero-io", - "sha3", + "sha3 0.10.8", "std-shims", "subtle", ] @@ -6172,7 +6227,7 @@ dependencies = [ "curve25519-dalek", "monero-generators", "monero-io", - "sha3", + "sha3 0.10.8", "std-shims", "zeroize", ] @@ -6286,7 +6341,7 @@ dependencies = [ "digest 0.10.7", "multihash-derive 0.8.0", "sha2 0.10.9", - "sha3", + "sha3 0.10.8", "unsigned-varint 0.7.2", ] @@ -6315,7 +6370,7 @@ dependencies = [ "ripemd", "sha1", "sha2 0.10.9", - "sha3", + "sha3 0.10.8", "strobe-rs", ] @@ -6714,8 +6769,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "p256" version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +source = "git+https://github.com/kayabaNerve/elliptic-curves?rev=4994c9ab163781a88cd4a49beae812a89a44e8c3#4994c9ab163781a88cd4a49beae812a89a44e8c3" dependencies = [ "ecdsa", "elliptic-curve", @@ -6873,7 +6927,7 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "592a28a24b09c9dc20ac8afaa6839abc417c720afe42c12e1e4a9d6aa2508d2e" dependencies = [ - "blake2", + "blake2 0.10.6", "crc32fast", "fs2", "hex", @@ -7245,8 +7299,7 @@ dependencies = [ [[package]] name = "primeorder" version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +source = "git+https://github.com/kayabaNerve/elliptic-curves?rev=4994c9ab163781a88cd4a49beae812a89a44e8c3#4994c9ab163781a88cd4a49beae812a89a44e8c3" dependencies = [ "elliptic-curve", ] @@ -9539,7 +9592,7 @@ dependencies = [ name = "secq256k1" version = "0.1.0" dependencies = [ - "blake2", + "blake2 0.11.0-rc.0", "ciphersuite 0.4.2", "ff-group-tests", "generalized-bulletproofs-ec-gadgets", @@ -9692,7 +9745,7 @@ dependencies = [ "async-lock", "bitcoin", "bitvec", - "blake2", + "blake2 0.10.6", "borsh", "ciphersuite 0.4.2", "ciphersuite-kp256", @@ -9754,7 +9807,7 @@ name = "serai-coordinator" version = "0.1.0" dependencies = [ "bitvec", - "blake2", + "blake2 0.10.6", "borsh", "ciphersuite 0.4.2", "dalek-ff-group", @@ -9791,7 +9844,7 @@ name = "serai-coordinator-libp2p-p2p" version = "0.1.0" dependencies = [ "async-trait", - "blake2", + "blake2 0.10.6", "borsh", "futures-util", "hex", @@ -9845,7 +9898,7 @@ dependencies = [ name = "serai-coordinator-tributary" version = "0.1.0" dependencies = [ - "blake2", + "blake2 0.10.6", "borsh", "ciphersuite 0.4.2", "dalek-ff-group", @@ -9868,7 +9921,7 @@ dependencies = [ name = "serai-cosign" version = "0.1.0" dependencies = [ - "blake2", + "blake2 0.10.6", "borsh", "log", "parity-scale-codec", @@ -10408,7 +10461,7 @@ dependencies = [ name = "serai-processor-key-gen" version = "0.1.0" dependencies = [ - "blake2", + "blake2 0.10.6", "borsh", "ciphersuite 0.4.2", "dkg-evrf", @@ -10456,7 +10509,7 @@ dependencies = [ name = "serai-processor-scanner" version = "0.1.0" dependencies = [ - "blake2", + "blake2 0.10.6", "borsh", "group", "hex", @@ -10488,7 +10541,7 @@ dependencies = [ name = "serai-processor-signers" version = "0.1.0" dependencies = [ - "blake2", + "blake2 0.10.6", "borsh", "ciphersuite 0.4.2", "dalek-ff-group", @@ -10887,6 +10940,17 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha2" +version = "0.11.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa1d2e6b3cc4e43a8258a9a3b17aa5dfd2cc5186c7024bba8a64aa65b2c71a59" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.11.0-rc.0", +] + [[package]] name = "sha3" version = "0.10.8" @@ -10894,7 +10958,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ "digest 0.10.7", - "keccak", + "keccak 0.1.5", +] + +[[package]] +name = "sha3" +version = "0.11.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e6a92fd180fd205defdc0b78288ce847c7309d329fd6647a814567e67db50e" +dependencies = [ + "digest 0.11.0-rc.0", + "keccak 0.2.0-pre.0", ] [[package]] @@ -11026,7 +11100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "850948bee068e713b8ab860fe1adc4d109676ab4c3b621fd8147f06b261f2f85" dependencies = [ "aes-gcm", - "blake2", + "blake2 0.10.6", "chacha20poly1305", "curve25519-dalek", "rand_core 0.6.4", @@ -11114,7 +11188,7 @@ version = "4.0.0-dev" source = "git+https://github.com/serai-dex/substrate#8587cd89bec74f789d4e23fdf776508a0ed5db6f" dependencies = [ "Inflector", - "blake2", + "blake2 0.10.6", "expander", "proc-macro-crate 1.3.1", "proc-macro2", @@ -11260,7 +11334,7 @@ source = "git+https://github.com/serai-dex/substrate#8587cd89bec74f789d4e23fdf77 dependencies = [ "array-bytes", "bitflags 1.3.2", - "blake2", + "blake2 0.10.6", "bounded-collections", "bs58", "dyn-clonable", @@ -11304,7 +11378,7 @@ dependencies = [ "blake2b_simd", "byteorder", "digest 0.10.7", - "sha3", + "sha3 0.10.8", "twox-hash", ] @@ -11799,7 +11873,7 @@ checksum = "fabb238a1cccccfa4c4fb703670c0d157e1256c1ba695abf1b93bd2bb14bab2d" dependencies = [ "bitflags 1.3.2", "byteorder", - "keccak", + "keccak 0.1.5", "subtle", "zeroize", ] @@ -12534,7 +12608,7 @@ dependencies = [ name = "tributary-sdk" version = "0.1.0" dependencies = [ - "blake2", + "blake2 0.10.6", "ciphersuite 0.4.2", "dalek-ff-group", "flexible-transcript", @@ -12747,7 +12821,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "crypto-common", + "crypto-common 0.1.6", "subtle", ] diff --git a/Cargo.toml b/Cargo.toml index c90cd7b9..052343cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -225,7 +225,11 @@ option-ext = { path = "patches/option-ext" } directories-next = { path = "patches/directories-next" } # Patch to include `FromUniformBytes<64>` over Scalar -k256 = { git = "https://github.com/kayabaNerve/elliptic-curves", rev = "fc92333e222b7f0cbe268d2ca92ed572f71f3e1d" } +k256 = { git = "https://github.com/kayabaNerve/elliptic-curves", rev = "4994c9ab163781a88cd4a49beae812a89a44e8c3" } +p256 = { git = "https://github.com/kayabaNerve/elliptic-curves", rev = "4994c9ab163781a88cd4a49beae812a89a44e8c3" } + +# https://github.com/RustCrypto/hybrid-array/issues/131 +hybrid-array = { git = "https://github.com/kayabaNerve/hybrid-array", rev = "8caa508976c93696a67f40734537c91be7cecd96" } [workspace.lints.clippy] unwrap_or_default = "allow" diff --git a/coordinator/tributary-sdk/Cargo.toml b/coordinator/tributary-sdk/Cargo.toml index 06f2937c..1aea3d15 100644 --- a/coordinator/tributary-sdk/Cargo.toml +++ b/coordinator/tributary-sdk/Cargo.toml @@ -6,7 +6,7 @@ license = "AGPL-3.0-only" repository = "https://github.com/serai-dex/serai/tree/develop/coordinator/tributary-sdk" authors = ["Luke Parker "] edition = "2021" -rust-version = "1.79" +rust-version = "1.85" [package.metadata.docs.rs] all-features = true diff --git a/crypto/ciphersuite/Cargo.toml b/crypto/ciphersuite/Cargo.toml index dad7350c..c211d033 100644 --- a/crypto/ciphersuite/Cargo.toml +++ b/crypto/ciphersuite/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/crypto/ciphersuite authors = ["Luke Parker "] keywords = ["ciphersuite", "ff", "group"] edition = "2021" -rust-version = "1.73" +rust-version = "1.85" [package.metadata.docs.rs] all-features = true @@ -24,7 +24,7 @@ rand_core = { version = "0.6", default-features = false } zeroize = { version = "^1.5", default-features = false, features = ["derive"] } subtle = { version = "^2.4", default-features = false } -digest = { version = "0.10", default-features = false, features = ["core-api"] } +digest = { version = "0.11.0-rc.0", default-features = false, features = ["block-api"] } transcript = { package = "flexible-transcript", path = "../transcript", version = "^0.3.2", default-features = false } ff = { version = "0.13", default-features = false, features = ["bits"] } @@ -38,7 +38,7 @@ rand_core = { version = "0.6", default-features = false, features = ["std"] } ff-group-tests = { version = "0.13", path = "../ff-group-tests" } [features] -alloc = ["std-shims"] +alloc = ["std-shims", "ff/alloc"] std = [ "alloc", @@ -49,7 +49,6 @@ std = [ "zeroize/std", "subtle/std", - "digest/std", "transcript/std", "ff/std", diff --git a/crypto/ciphersuite/README.md b/crypto/ciphersuite/README.md index 45eefb52..dd5d107b 100644 --- a/crypto/ciphersuite/README.md +++ b/crypto/ciphersuite/README.md @@ -17,10 +17,6 @@ Secp256k1 and P-256 are offered via [k256](https://crates.io/crates/k256) and [p256](https://crates.io/crates/p256), two libraries maintained by [RustCrypto](https://github.com/RustCrypto). -Their `hash_to_F` is the -[IETF's hash to curve](https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html), -yet applied to their scalar field. - Please see the [`ciphersuite-kp256`](https://docs.rs/ciphersuite-kp256) crate for more info. ### Ed25519/Ristretto @@ -29,12 +25,6 @@ Ed25519/Ristretto are offered via [dalek-ff-group](https://crates.io/crates/dalek-ff-group), an ff/group wrapper around [curve25519-dalek](https://crates.io/crates/curve25519-dalek). -Their `hash_to_F` is the wide reduction of SHA2-512, as used in -[RFC-8032](https://www.rfc-editor.org/rfc/rfc8032). This is also compliant with -the draft -[RFC-RISTRETTO](https://www.ietf.org/archive/id/draft-irtf-cfrg-ristretto255-decaf448-05.html). -The domain-separation tag is naively prefixed to the message. - Please see the [`dalek-ff-group`](https://docs.rs/dalek-ff-group) crate for more info. ### Ed448 @@ -43,8 +33,4 @@ Ed448 is offered via [minimal-ed448](https://crates.io/crates/minimal-ed448), an explicitly not recommended, unaudited, incomplete Ed448 implementation, limited to its prime-order subgroup. -Its `hash_to_F` is the wide reduction of SHAKE256, with a 114-byte output, as -used in [RFC-8032](https://www.rfc-editor.org/rfc/rfc8032). The -domain-separation tag is naively prefixed to the message. - Please see the [`minimal-ed448`](https://docs.rs/minimal-ed448) crate for more info. diff --git a/crypto/ciphersuite/kp256/Cargo.toml b/crypto/ciphersuite/kp256/Cargo.toml index 5f573a1f..ff4df971 100644 --- a/crypto/ciphersuite/kp256/Cargo.toml +++ b/crypto/ciphersuite/kp256/Cargo.toml @@ -21,9 +21,8 @@ rand_core = { version = "0.6", default-features = false } zeroize = { version = "^1.5", default-features = false, features = ["derive"] } -sha2 = { version = "0.10", default-features = false } +sha2 = { version = "0.11.0-rc.0", default-features = false } -elliptic-curve = { version = "0.13", default-features = false, features = ["hash2curve"] } p256 = { version = "^0.13.1", default-features = false, features = ["arithmetic", "bits", "hash2curve"] } k256 = { version = "^0.13.1", default-features = false, features = ["arithmetic", "bits", "hash2curve"] } @@ -43,9 +42,6 @@ std = [ "zeroize/std", - "sha2/std", - - "elliptic-curve/std", "p256/std", "k256/std", diff --git a/crypto/ciphersuite/kp256/src/lib.rs b/crypto/ciphersuite/kp256/src/lib.rs index 8736b2e6..4ff57a0b 100644 --- a/crypto/ciphersuite/kp256/src/lib.rs +++ b/crypto/ciphersuite/kp256/src/lib.rs @@ -3,15 +3,9 @@ use zeroize::Zeroize; -use sha2::Sha256; +use sha2::Sha512; -use elliptic_curve::{ - generic_array::GenericArray, - bigint::{NonZero, CheckedAdd, Encoding, U384}, - hash2curve::{Expander, ExpandMsg, ExpandMsgXmd}, -}; - -use ciphersuite::{group::ff::PrimeField, Ciphersuite}; +use ciphersuite::Ciphersuite; pub use k256; pub use p256; @@ -27,148 +21,31 @@ macro_rules! kp_curve { impl Ciphersuite for $Ciphersuite { type F = $lib::Scalar; type G = $lib::ProjectivePoint; - type H = Sha256; + type H = Sha512; const ID: &'static [u8] = $ID; fn generator() -> Self::G { $lib::ProjectivePoint::GENERATOR } - - fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F { - // While one of these two libraries does support directly hashing to the Scalar field, the - // other doesn't. While that's probably an oversight, this is a universally working method - - // This method is from - // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html - // Specifically, Section 5 - - // While that draft, overall, is intended for hashing to curves, that necessitates - // detailing how to hash to a finite field. The draft comments that its mechanism for - // doing so, which it uses to derive field elements, is also applicable to the scalar field - - // The hash_to_field function is intended to provide unbiased values - // In order to do so, a wide reduction from an extra k bits is applied, minimizing bias to - // 2^-k - // k is intended to be the bits of security of the suite, which is 128 for secp256k1 and - // P-256 - const K: usize = 128; - - // L is the amount of bytes of material which should be used in the wide reduction - // The 256 is for the bit-length of the primes, rounded up to the nearest byte threshold - // This is a simplification of the formula from the end of section 5 - const L: usize = (256 + K) / 8; // 48 - - // In order to perform this reduction, we need to use 48-byte numbers - // First, convert the modulus to a 48-byte number - // This is done by getting -1 as bytes, parsing it into a U384, and then adding back one - let mut modulus = [0; L]; - // The byte repr of scalars will be 32 big-endian bytes - // Set the lower 32 bytes of our 48-byte array accordingly - modulus[16 ..].copy_from_slice(&(Self::F::ZERO - Self::F::ONE).to_bytes()); - // Use a checked_add + unwrap since this addition cannot fail (being a 32-byte value with - // 48-bytes of space) - // While a non-panicking saturating_add/wrapping_add could be used, they'd likely be less - // performant - let modulus = U384::from_be_slice(&modulus).checked_add(&U384::ONE).unwrap(); - - // The defined P-256 and secp256k1 ciphersuites both use expand_message_xmd - let mut wide = U384::from_be_bytes({ - let mut bytes = [0; 48]; - ExpandMsgXmd::::expand_message(&[msg], &[dst], 48) - .unwrap() - .fill_bytes(&mut bytes); - bytes - }) - .rem(&NonZero::new(modulus).unwrap()) - .to_be_bytes(); - - // Now that this has been reduced back to a 32-byte value, grab the lower 32-bytes - let mut array = *GenericArray::from_slice(&wide[16 ..]); - let res = $lib::Scalar::from_repr(array).unwrap(); - - // Zeroize the temp values we can due to the possibility hash_to_F is being used for nonces - wide.zeroize(); - array.zeroize(); - res - } } }; } -#[cfg(test)] -fn test_oversize_dst() { - use sha2::Digest; - - // The draft specifies DSTs >255 bytes should be hashed into a 32-byte DST - let oversize_dst = [0x00; 256]; - let actual_dst = Sha256::digest([b"H2C-OVERSIZE-DST-".as_ref(), &oversize_dst].concat()); - // Test the hash_to_F function handles this - // If it didn't, these would return different values - assert_eq!(C::hash_to_F(&oversize_dst, &[]), C::hash_to_F(&actual_dst, &[])); -} - /// Ciphersuite for Secp256k1. -/// -/// hash_to_F is implemented via the IETF draft for hash to curve's hash_to_field (v16). #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] pub struct Secp256k1; kp_curve!("secp256k1", k256, Secp256k1, b"secp256k1"); #[test] fn test_secp256k1() { ff_group_tests::group::test_prime_group_bits::<_, k256::ProjectivePoint>(&mut rand_core::OsRng); - - // Ideally, a test vector from hash_to_field (not FROST) would be here - // Unfortunately, the IETF draft only provides vectors for field elements, not scalars - // Vectors have been requested in - // https://github.com/cfrg/draft-irtf-cfrg-hash-to-curve/issues/343 - - assert_eq!( - Secp256k1::hash_to_F( - b"FROST-secp256k1-SHA256-v11nonce", - &hex::decode( - "\ -80cbea5e405d169999d8c4b30b755fedb26ab07ec8198cda4873ed8ce5e16773\ -08f89ffe80ac94dcb920c26f3f46140bfc7f95b493f8310f5fc1ea2b01f4254c" - ) - .unwrap() - ) - .to_repr() - .iter() - .copied() - .collect::>(), - hex::decode("acc83278035223c1ba464e2d11bfacfc872b2b23e1041cf5f6130da21e4d8068").unwrap() - ); - - test_oversize_dst::(); } /// Ciphersuite for P-256. -/// -/// hash_to_F is implemented via the IETF draft for hash to curve's hash_to_field (v16). #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] pub struct P256; kp_curve!("p256", p256, P256, b"P-256"); #[test] fn test_p256() { ff_group_tests::group::test_prime_group_bits::<_, p256::ProjectivePoint>(&mut rand_core::OsRng); - - assert_eq!( - P256::hash_to_F( - b"FROST-P256-SHA256-v11nonce", - &hex::decode( - "\ -f4e8cf80aec3f888d997900ac7e3e349944b5a6b47649fc32186d2f1238103c6\ -0c9c1a0fe806c184add50bbdcac913dda73e482daf95dcb9f35dbb0d8a9f7731" - ) - .unwrap() - ) - .to_repr() - .iter() - .copied() - .collect::>(), - hex::decode("f871dfcf6bcd199342651adc361b92c941cb6a0d8c8c1a3b91d79e2c1bf3722d").unwrap() - ); - - test_oversize_dst::(); } diff --git a/crypto/ciphersuite/src/lib.rs b/crypto/ciphersuite/src/lib.rs index 701cafb5..7e37c561 100644 --- a/crypto/ciphersuite/src/lib.rs +++ b/crypto/ciphersuite/src/lib.rs @@ -14,7 +14,8 @@ use rand_core::{RngCore, CryptoRng}; use zeroize::Zeroize; use subtle::ConstantTimeEq; -use digest::{core_api::BlockSizeUser, Digest, HashMarker}; +pub use digest; +use digest::{array::ArraySize, block_api::BlockSizeUser, OutputSizeUser, Digest, HashMarker}; use transcript::SecureDigest; pub use group; @@ -26,13 +27,25 @@ use group::{ #[cfg(feature = "alloc")] use group::GroupEncoding; +pub trait FromUniformBytes { + fn from_uniform_bytes(bytes: &T) -> Self; +} +impl> FromUniformBytes<[u8; N]> for F { + fn from_uniform_bytes(bytes: &[u8; N]) -> Self { + F::from_uniform_bytes(bytes) + } +} + /// Unified trait defining a ciphersuite around an elliptic curve. pub trait Ciphersuite: 'static + Send + Sync + Clone + Copy + PartialEq + Eq + Debug + Zeroize { /// Scalar field element type. // This is available via G::Scalar yet `C::G::Scalar` is ambiguous, forcing horrific accesses - type F: PrimeField + PrimeFieldBits + Zeroize; + type F: PrimeField + + PrimeFieldBits + + Zeroize + + FromUniformBytes<<::OutputSize as ArraySize>::ArrayType>; /// Group element type. type G: Group + GroupOps + PrimeGroup + Zeroize + ConstantTimeEq; /// Hash algorithm used with this curve. @@ -46,16 +59,10 @@ pub trait Ciphersuite: // While group does provide this in its API, privacy coins may want to use a custom basepoint fn generator() -> Self::G; - /// Hash the provided domain-separation tag and message to a scalar. Ciphersuites MAY naively - /// prefix the tag to the message, enabling transpotion between the two. Accordingly, this - /// function should NOT be used in any scheme where one tag is a valid substring of another - /// UNLESS the specific Ciphersuite is verified to handle the DST securely. - /// - /// Verifying specific ciphersuites have secure tag handling is not recommended, due to it - /// breaking the intended modularity of ciphersuites. Instead, component-specific tags with - /// further purpose tags are recommended ("Schnorr-nonce", "Schnorr-chal"). #[allow(non_snake_case)] - fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F; + fn hash_to_F(data: &[u8]) -> Self::F { + Self::F::from_uniform_bytes(&Self::H::digest(data).into()) + } /// Generate a random non-zero scalar. #[allow(non_snake_case)] diff --git a/crypto/dalek-ff-group/Cargo.toml b/crypto/dalek-ff-group/Cargo.toml index 3b88e686..58a2fdbf 100644 --- a/crypto/dalek-ff-group/Cargo.toml +++ b/crypto/dalek-ff-group/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/crypto/dalek-ff-gr authors = ["Luke Parker "] keywords = ["curve25519", "ed25519", "ristretto", "dalek", "group"] edition = "2021" -rust-version = "1.73" +rust-version = "1.85" [package.metadata.docs.rs] all-features = true @@ -25,7 +25,7 @@ subtle = { version = "^2.4", default-features = false } rand_core = { version = "0.6", default-features = false } digest = { version = "0.10", default-features = false } -sha2 = { version = "0.10", default-features = false } +sha2 = { version = "0.11.0-rc.0", default-features = false } ff = { version = "0.13", default-features = false, features = ["bits"] } group = { version = "0.13", default-features = false } @@ -42,5 +42,5 @@ ff-group-tests = { path = "../ff-group-tests" } [features] alloc = ["zeroize/alloc", "ciphersuite/alloc", "curve25519-dalek/alloc"] -std = ["alloc", "zeroize/std", "subtle/std", "rand_core/std", "digest/std", "sha2/std", "ciphersuite/std"] +std = ["alloc", "zeroize/std", "subtle/std", "rand_core/std", "digest/std", "ciphersuite/std"] default = ["std"] diff --git a/crypto/dalek-ff-group/src/ciphersuite.rs b/crypto/dalek-ff-group/src/ciphersuite.rs index f552d305..170a3bee 100644 --- a/crypto/dalek-ff-group/src/ciphersuite.rs +++ b/crypto/dalek-ff-group/src/ciphersuite.rs @@ -1,6 +1,6 @@ use zeroize::Zeroize; -use sha2::{Digest, Sha512}; +use sha2::Sha512; use group::Group; use crate::Scalar; @@ -27,71 +27,24 @@ macro_rules! dalek_curve { fn generator() -> Self::G { $Point::generator() } - - fn hash_to_F(dst: &[u8], data: &[u8]) -> Self::F { - let mut digest = Sha512::new(); - digest.update(dst); - digest.update(data); - Scalar::from_hash(digest) - } } }; } /// Ciphersuite for Ristretto. -/// -/// hash_to_F is implemented with a naive concatenation of the dst and data, allowing transposition -/// between the two. This means `dst: b"abc", data: b"def"`, will produce the same scalar as -/// `dst: "abcdef", data: b""`. Please use carefully, not letting dsts be substrings of each other. #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] pub struct Ristretto; dalek_curve!("ristretto", Ristretto, RistrettoPoint, b"ristretto"); #[test] fn test_ristretto() { ff_group_tests::group::test_prime_group_bits::<_, RistrettoPoint>(&mut rand_core::OsRng); - - assert_eq!( - Ristretto::hash_to_F( - b"FROST-RISTRETTO255-SHA512-v11nonce", - &hex::decode( - "\ -81800157bb554f299fe0b6bd658e4c4591d74168b5177bf55e8dceed59dc80c7\ -5c3430d391552f6e60ecdc093ff9f6f4488756aa6cebdbad75a768010b8f830e" - ) - .unwrap() - ) - .to_bytes() - .as_ref(), - &hex::decode("40f58e8df202b21c94f826e76e4647efdb0ea3ca7ae7e3689bc0cbe2e2f6660c").unwrap() - ); } /// Ciphersuite for Ed25519, inspired by RFC-8032. -/// -/// hash_to_F is implemented with a naive concatenation of the dst and data, allowing transposition -/// between the two. This means `dst: b"abc", data: b"def"`, will produce the same scalar as -/// `dst: "abcdef", data: b""`. Please use carefully, not letting dsts be substrings of each other. #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] pub struct Ed25519; dalek_curve!("ed25519", Ed25519, EdwardsPoint, b"edwards25519"); #[test] fn test_ed25519() { ff_group_tests::group::test_prime_group_bits::<_, EdwardsPoint>(&mut rand_core::OsRng); - - // Ideally, a test vector from RFC-8032 (not FROST) would be here - // Unfortunately, the IETF draft doesn't provide any vectors for the derived challenges - assert_eq!( - Ed25519::hash_to_F( - b"FROST-ED25519-SHA512-v11nonce", - &hex::decode( - "\ -9d06a6381c7a4493929761a73692776772b274236fb5cfcc7d1b48ac3a9c249f\ -929dcc590407aae7d388761cddb0c0db6f5627aea8e217f4a033f2ec83d93509" - ) - .unwrap() - ) - .to_bytes() - .as_ref(), - &hex::decode("70652da3e8d7533a0e4b9e9104f01b48c396b5b553717784ed8d05c6a36b9609").unwrap() - ); } diff --git a/crypto/dkg/Cargo.toml b/crypto/dkg/Cargo.toml index 87f1e1b4..602e3318 100644 --- a/crypto/dkg/Cargo.toml +++ b/crypto/dkg/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/crypto/dkg" authors = ["Luke Parker "] keywords = ["dkg", "multisig", "threshold", "ff", "group"] edition = "2021" -rust-version = "1.73" +rust-version = "1.85" [package.metadata.docs.rs] all-features = true diff --git a/crypto/dkg/dealer/Cargo.toml b/crypto/dkg/dealer/Cargo.toml index 78b37167..c945c55f 100644 --- a/crypto/dkg/dealer/Cargo.toml +++ b/crypto/dkg/dealer/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/crypto/dkg/dealer" authors = ["Luke Parker "] keywords = ["dkg", "multisig", "threshold", "ff", "group"] edition = "2021" -rust-version = "1.73" +rust-version = "1.85" [package.metadata.docs.rs] all-features = true diff --git a/crypto/dkg/musig/Cargo.toml b/crypto/dkg/musig/Cargo.toml index bf56794c..3887368c 100644 --- a/crypto/dkg/musig/Cargo.toml +++ b/crypto/dkg/musig/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/crypto/dkg/musig" authors = ["Luke Parker "] keywords = ["dkg", "multisig", "threshold", "ff", "group"] edition = "2021" -rust-version = "1.79" +rust-version = "1.85" [package.metadata.docs.rs] all-features = true diff --git a/crypto/dkg/musig/src/lib.rs b/crypto/dkg/musig/src/lib.rs index 36f4fd31..b44b11c2 100644 --- a/crypto/dkg/musig/src/lib.rs +++ b/crypto/dkg/musig/src/lib.rs @@ -11,7 +11,7 @@ use std_shims::{ use zeroize::Zeroizing; -use ciphersuite::{group::GroupEncoding, Ciphersuite}; +use ciphersuite::{digest::Digest, group::GroupEncoding, FromUniformBytes, Ciphersuite}; pub use dkg::*; @@ -80,7 +80,7 @@ fn binding_factor_transcript( fn binding_factor(mut transcript: Vec, i: u16) -> C::F { transcript.extend(i.to_le_bytes()); - C::hash_to_F(b"dkg-musig", &transcript) + C::F::from_uniform_bytes(&C::H::digest(&transcript).into()) } #[allow(clippy::type_complexity)] diff --git a/crypto/dkg/recovery/Cargo.toml b/crypto/dkg/recovery/Cargo.toml index 9c85d701..c39ce2f9 100644 --- a/crypto/dkg/recovery/Cargo.toml +++ b/crypto/dkg/recovery/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/crypto/dkg/recover authors = ["Luke Parker "] keywords = ["dkg", "multisig", "threshold", "ff", "group"] edition = "2021" -rust-version = "1.73" +rust-version = "1.85" [package.metadata.docs.rs] all-features = true diff --git a/crypto/ed448/Cargo.toml b/crypto/ed448/Cargo.toml index 7e6ef2a5..290cb30f 100644 --- a/crypto/ed448/Cargo.toml +++ b/crypto/ed448/Cargo.toml @@ -19,7 +19,7 @@ workspace = true [dependencies] zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } -sha3 = { version = "0.10", default-features = false } +sha3 = { version = "0.11.0-rc.0", default-features = false } prime-field = { path = "../prime-field", default-features = false } ciphersuite = { path = "../ciphersuite", default-features = false } @@ -33,5 +33,5 @@ ff-group-tests = { path = "../ff-group-tests" } [features] alloc = ["zeroize/alloc", "prime-field/alloc", "ciphersuite/alloc"] -std = ["alloc", "zeroize/std", "sha3/std", "prime-field/std", "ciphersuite/std"] +std = ["alloc", "zeroize/std", "prime-field/std", "ciphersuite/std"] default = ["std"] diff --git a/crypto/ed448/src/ciphersuite.rs b/crypto/ed448/src/ciphersuite.rs index 1ffcd0f7..707f9fb3 100644 --- a/crypto/ed448/src/ciphersuite.rs +++ b/crypto/ed448/src/ciphersuite.rs @@ -3,15 +3,12 @@ use zeroize::Zeroize; use sha3::{ digest::{ typenum::U114, core_api::BlockSizeUser, Update, Output, OutputSizeUser, FixedOutput, - ExtendableOutput, XofReader, HashMarker, Digest, + ExtendableOutput, XofReader, HashMarker, }, Shake256, }; -use ciphersuite::{ - group::{ff::FromUniformBytes, Group}, - Ciphersuite, -}; +use ciphersuite::{group::Group, Ciphersuite}; use crate::{Scalar, Point}; @@ -52,11 +49,6 @@ impl FixedOutput for Shake256_114 { } impl HashMarker for Shake256_114 {} -/// Ciphersuite for Ed448, inspired by RFC-8032. This is not recommended for usage. -/// -/// hash_to_F is implemented with a naive concatenation of the dst and data, allowing transposition -/// between the two. This means `dst: b"abc", data: b"def"`, will produce the same scalar as -/// `dst: "abcdef", data: b""`. Please use carefully, not letting dsts be substrings of each other. #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] pub struct Ed448; impl Ciphersuite for Ed448 { @@ -69,48 +61,9 @@ impl Ciphersuite for Ed448 { fn generator() -> Self::G { Point::generator() } - - fn hash_to_F(dst: &[u8], data: &[u8]) -> Self::F { - let mut digest = Self::H::new(); - Update::update(&mut digest, dst); - Update::update(&mut digest, data); - let digest = digest.finalize(); - - let mut wide_scalar = [0; 114]; - wide_scalar.copy_from_slice(digest.as_ref()); - Scalar::from_uniform_bytes(&wide_scalar) - } } #[test] fn test_ed448() { - use ciphersuite::group::ff::PrimeField; - ff_group_tests::group::test_prime_group_bits::<_, Point>(&mut rand_core::OsRng); - - // Ideally, a test vector from RFC-8032 (not FROST) would be here - // Unfortunately, the IETF draft doesn't provide any vectors for the derived challenges - assert_eq!( - Ed448::hash_to_F( - b"FROST-ED448-SHAKE256-v11nonce", - &hex::decode( - "\ -89bf16040081ff2990336b200613787937ebe1f024b8cdff90eb6f1c741d91c1\ -4a2b2f5858a932ad3d3b18bd16e76ced3070d72fd79ae4402df201f5\ -25e754716a1bc1b87a502297f2a99d89ea054e0018eb55d39562fd01\ -00" - ) - .unwrap() - ) - .to_repr() - .as_ref(), - hex::decode( - "\ -67a6f023e77361707c6e894c625e809e80f33fdb310810053ae29e28\ -e7011f3193b9020e73c183a98cc3a519160ed759376dd92c94831622\ -00" - ) - .unwrap() - .as_slice() - ); } diff --git a/crypto/embedwards25519/Cargo.toml b/crypto/embedwards25519/Cargo.toml index 2863b25a..e2d84d89 100644 --- a/crypto/embedwards25519/Cargo.toml +++ b/crypto/embedwards25519/Cargo.toml @@ -27,7 +27,7 @@ short-weierstrass = { path = "../short-weierstrass", default-features = false } curve25519-dalek = { version = "4", default-features = false, features = ["legacy_compatibility"] } dalek-ff-group = { path = "../dalek-ff-group", version = "0.4", default-features = false } -blake2 = { version = "0.10", default-features = false } +blake2 = { version = "0.11.0-rc.0", default-features = false } ciphersuite = { path = "../ciphersuite", version = "0.4", default-features = false } generalized-bulletproofs-ec-gadgets = { git = "https://github.com/monero-oxide/monero-oxide", rev = "a6f8797007e768488568b821435cf5006517a962", default-features = false, optional = true } @@ -41,5 +41,5 @@ ff-group-tests = { path = "../ff-group-tests" } [features] alloc = ["std-shims", "zeroize/alloc", "prime-field/alloc", "short-weierstrass/alloc", "curve25519-dalek/alloc", "ciphersuite/alloc", "generalized-bulletproofs-ec-gadgets"] -std = ["alloc", "std-shims/std", "zeroize/std", "prime-field/std", "short-weierstrass/std", "blake2/std", "ciphersuite/std", "generalized-bulletproofs-ec-gadgets/std"] +std = ["alloc", "std-shims/std", "zeroize/std", "prime-field/std", "short-weierstrass/std", "ciphersuite/std", "generalized-bulletproofs-ec-gadgets/std"] default = ["std"] diff --git a/crypto/embedwards25519/src/lib.rs b/crypto/embedwards25519/src/lib.rs index c5811e2f..fafac7d7 100644 --- a/crypto/embedwards25519/src/lib.rs +++ b/crypto/embedwards25519/src/lib.rs @@ -10,7 +10,7 @@ use std_shims::io::{self, Read}; use prime_field::{subtle::Choice, zeroize::Zeroize}; use ciphersuite::group::{ - ff::{Field, PrimeField, FromUniformBytes}, + ff::{Field, PrimeField}, Group, }; @@ -53,7 +53,7 @@ impl ShortWeierstrass for Embedwards25519 { fn encode_compressed(x: Self::FieldElement, odd_y: Choice) -> Self::Repr { // The LE `x` coordinate, with if `y` is odd in the unused 256th bit let mut res = [0; 32]; - res.as_mut().copy_from_slice(x.to_repr().as_ref()); + res.copy_from_slice(x.to_repr().as_ref()); res[31] |= odd_y.unwrap_u8() << 7; res } @@ -65,7 +65,10 @@ impl ShortWeierstrass for Embedwards25519 { // Copy from the point's representation to the field's let mut repr = ::Repr::default(); - repr.as_mut().copy_from_slice(&bytes); + { + let repr: &mut [u8] = repr.as_mut(); + repr.copy_from_slice(&bytes); + } (repr, odd_y) } @@ -88,18 +91,6 @@ impl ciphersuite::Ciphersuite for Embedwards25519 { Point::generator() } - /// `hash_to_F` is implemented with a naive concatenation of the `dst` and `data`, allowing - /// transposition between the two. This means `dst: b"abc", data: b"def"`, will produce the same - /// scalar as `dst: "abcdef", data: b""`. Please use carefully, not letting `dst` valuess be - /// substrings of each other. - fn hash_to_F(dst: &[u8], data: &[u8]) -> Self::F { - use blake2::Digest; - let mut digest = Self::H::new(); - digest.update(dst); - digest.update(data); - >::from_uniform_bytes(&digest.finalize().into()) - } - // We override the provided impl, which compares against the reserialization, because // we already require canonicity #[cfg(feature = "alloc")] diff --git a/crypto/frost/Cargo.toml b/crypto/frost/Cargo.toml index 531f059f..572298a7 100644 --- a/crypto/frost/Cargo.toml +++ b/crypto/frost/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/crypto/frost" authors = ["Luke Parker "] keywords = ["frost", "multisig", "threshold"] edition = "2021" -rust-version = "1.79" +rust-version = "1.85" [package.metadata.docs.rs] all-features = true @@ -27,13 +27,14 @@ subtle = { version = "^2.4", default-features = false, features = ["std"] } hex = { version = "0.4", default-features = false, features = ["std"], optional = true } -digest = { version = "0.10", default-features = false, features = ["std"] } transcript = { package = "flexible-transcript", path = "../transcript", version = "^0.3.2", default-features = false, features = ["std", "recommended"] } dalek-ff-group = { path = "../dalek-ff-group", version = "0.4", default-features = false, features = ["std"], optional = true } minimal-ed448 = { path = "../ed448", version = "0.4", default-features = false, features = ["std"], optional = true } ciphersuite = { path = "../ciphersuite", version = "^0.4.1", default-features = false, features = ["std"] } +sha2 = { version = "0.10.0", default-features = false, optional = true } +elliptic-curve = { version = "0.13", default-features = false, features = ["hash2curve"], optional = true } ciphersuite-kp256 = { path = "../ciphersuite/kp256", version = "0.4", default-features = false, features = ["std"], optional = true } multiexp = { path = "../multiexp", version = "0.4", default-features = false, features = ["std", "batch"] } @@ -56,8 +57,8 @@ dkg-dealer = { path = "../dkg/dealer", default-features = false, features = ["st ed25519 = ["dalek-ff-group"] ristretto = ["dalek-ff-group"] -secp256k1 = ["ciphersuite-kp256"] -p256 = ["ciphersuite-kp256"] +secp256k1 = ["sha2", "elliptic-curve", "ciphersuite-kp256"] +p256 = ["sha2", "elliptic-curve", "ciphersuite-kp256"] ed448 = ["minimal-ed448"] diff --git a/crypto/frost/src/curve/dalek.rs b/crypto/frost/src/curve/dalek.rs index aa97adbd..6c9f067e 100644 --- a/crypto/frost/src/curve/dalek.rs +++ b/crypto/frost/src/curve/dalek.rs @@ -1,9 +1,6 @@ -use digest::Digest; - +use ciphersuite::{digest::Digest, FromUniformBytes, Ciphersuite}; use dalek_ff_group::Scalar; -use ciphersuite::Ciphersuite; - use crate::{curve::Curve, algorithm::Hram}; macro_rules! dalek_curve { @@ -20,6 +17,13 @@ macro_rules! dalek_curve { impl Curve for $Curve { const CONTEXT: &'static [u8] = $CONTEXT; + fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F { + let mut digest = ::H::new(); + digest.update(Self::CONTEXT); + digest.update(dst); + digest.update(msg); + Self::F::from_uniform_bytes(&digest.finalize().into()) + } } /// The challenge function for this ciphersuite. @@ -30,11 +34,13 @@ macro_rules! dalek_curve { fn hram(R: &<$Curve as Ciphersuite>::G, A: &<$Curve as Ciphersuite>::G, m: &[u8]) -> Scalar { let mut hash = <$Curve as Ciphersuite>::H::new(); if $chal.len() != 0 { - hash.update(&[$CONTEXT.as_ref(), $chal].concat()); + hash.update($CONTEXT); + hash.update($chal); } - Scalar::from_hash( - hash.chain_update(&[&R.compress().to_bytes(), &A.compress().to_bytes(), m].concat()), - ) + hash.update(R.compress().to_bytes()); + hash.update(A.compress().to_bytes()); + hash.update(m); + Scalar::from_uniform_bytes(&hash.finalize().into()) } } }; diff --git a/crypto/frost/src/curve/ed448.rs b/crypto/frost/src/curve/ed448.rs index 34836cd5..67821d33 100644 --- a/crypto/frost/src/curve/ed448.rs +++ b/crypto/frost/src/curve/ed448.rs @@ -1,11 +1,6 @@ -use digest::Digest; - +pub use ciphersuite::{digest::Digest, group::GroupEncoding, FromUniformBytes, Ciphersuite}; use minimal_ed448::{Scalar, Point}; pub use minimal_ed448::Ed448; -pub use ciphersuite::{ - group::{ff::FromUniformBytes, GroupEncoding}, - Ciphersuite, -}; use crate::{curve::Curve, algorithm::Hram}; @@ -13,6 +8,13 @@ const CONTEXT: &[u8] = b"FROST-ED448-SHAKE256-v1"; impl Curve for Ed448 { const CONTEXT: &'static [u8] = CONTEXT; + fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F { + let mut digest = ::H::new(); + digest.update(Self::CONTEXT); + digest.update(dst); + digest.update(msg); + Self::F::from_uniform_bytes(&digest.finalize().into()) + } } // The RFC-8032 Ed448 challenge function. @@ -21,20 +23,14 @@ pub(crate) struct Ietf8032Ed448Hram; impl Ietf8032Ed448Hram { #[allow(non_snake_case)] pub(crate) fn hram(context: &[u8], R: &Point, A: &Point, m: &[u8]) -> Scalar { - Scalar::from_uniform_bytes( - &<[u8; 114]>::try_from( - ::H::digest( - [ - &[b"SigEd448".as_ref(), &[0, u8::try_from(context.len()).unwrap()]].concat(), - context, - &[R.to_bytes().as_ref(), A.to_bytes().as_ref(), m].concat(), - ] - .concat(), - ) - .as_slice(), - ) - .unwrap(), - ) + let mut digest = ::H::new(); + digest.update(b"SigEd448"); + digest.update([0, u8::try_from(context.len()).unwrap()]); + digest.update(context); + digest.update(R.to_bytes()); + digest.update(A.to_bytes()); + digest.update(m); + Scalar::from_uniform_bytes(&digest.finalize().into()) } } diff --git a/crypto/frost/src/curve/kp256.rs b/crypto/frost/src/curve/kp256.rs index a3b3ecc9..2ffeb148 100644 --- a/crypto/frost/src/curve/kp256.rs +++ b/crypto/frost/src/curve/kp256.rs @@ -1,7 +1,85 @@ -use ciphersuite::{group::GroupEncoding, Ciphersuite}; +use core::convert::AsRef; + +use sha2::{digest::Digest, Sha256}; + +use ciphersuite::{ + group::{ + ff::{Field, PrimeField}, + GroupEncoding, + }, + Ciphersuite, +}; + +use elliptic_curve::{ + zeroize::Zeroize, + generic_array::{typenum::U32, GenericArray}, + bigint::{NonZero, CheckedAdd, Encoding, U384}, + hash2curve::{Expander, ExpandMsg, ExpandMsgXmd}, +}; use crate::{curve::Curve, algorithm::Hram}; +#[allow(non_snake_case)] +fn hash_to_F>>>( + dst: &[u8], + msg: &[u8], +) -> C::F { + // While one of these two libraries does support directly hashing to the Scalar field, the + // other doesn't. While that's probably an oversight, this is a universally working method + + // This method is from + // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html + // Specifically, Section 5 + + // While that draft, overall, is intended for hashing to curves, that necessitates + // detailing how to hash to a finite field. The draft comments that its mechanism for + // doing so, which it uses to derive field elements, is also applicable to the scalar field + + // The hash_to_field function is intended to provide unbiased values + // In order to do so, a wide reduction from an extra k bits is applied, minimizing bias to + // 2^-k + // k is intended to be the bits of security of the suite, which is 128 for secp256k1 and + // P-256 + const K: usize = 128; + + // L is the amount of bytes of material which should be used in the wide reduction + // The 256 is for the bit-length of the primes, rounded up to the nearest byte threshold + // This is a simplification of the formula from the end of section 5 + const L: usize = (256 + K) / 8; // 48 + + // In order to perform this reduction, we need to use 48-byte numbers + // First, convert the modulus to a 48-byte number + // This is done by getting -1 as bytes, parsing it into a U384, and then adding back one + let mut modulus = [0; L]; + // The byte repr of scalars will be 32 big-endian bytes + // Set the lower 32 bytes of our 48-byte array accordingly + modulus[16 ..].copy_from_slice(&(C::F::ZERO - C::F::ONE).to_repr()); + // Use a checked_add + unwrap since this addition cannot fail (being a 32-byte value with + // 48-bytes of space) + // While a non-panicking saturating_add/wrapping_add could be used, they'd likely be less + // performant + let modulus = U384::from_be_slice(&modulus).checked_add(&U384::ONE).unwrap(); + + // The defined P-256 and secp256k1 ciphersuites both use expand_message_xmd + let mut wide = U384::from_be_bytes({ + let mut bytes = [0; 48]; + ExpandMsgXmd::::expand_message(&[msg], &[dst], 48).unwrap().fill_bytes(&mut bytes); + bytes + }) + .rem(&NonZero::new(modulus).unwrap()) + .to_be_bytes(); + + // Now that this has been reduced back to a 32-byte value, grab the lower 32-bytes + let mut array = *GenericArray::from_slice(&wide[16 ..]); + let res = C::F::from_repr(array).unwrap(); + + // Zeroize the temp values we can due to the possibility `hash_to_F` is being used for + // nonces + wide.zeroize(); + array.zeroize(); + res +} + macro_rules! kp_curve { ( $feature: literal, @@ -15,6 +93,17 @@ macro_rules! kp_curve { impl Curve for $Curve { const CONTEXT: &'static [u8] = $CONTEXT; + + // These ciphersuites define their hash as SHA-512, yet FROST uses SHA-256 + fn hash(dst: &[u8], data: &[u8]) -> impl AsRef<[u8]> { + sha2::Sha256::digest([Self::CONTEXT, dst, data].concat()) + } + + fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F { + let dst = [Self::CONTEXT, dst].concat(); + let dst = dst.as_slice(); + hash_to_F::(dst, msg) + } } /// The challenge function for this ciphersuite. @@ -41,3 +130,27 @@ kp_curve!("p256", P256, IetfP256Hram, b"FROST-P256-SHA256-v1"); #[cfg(feature = "secp256k1")] kp_curve!("secp256k1", Secp256k1, IetfSecp256k1Hram, b"FROST-secp256k1-SHA256-v1"); + +#[cfg(test)] +fn test_oversize_dst>>>() { + use sha2::Digest; + + // The draft specifies DSTs >255 bytes should be hashed into a 32-byte DST + let oversize_dst = [0x00; 256]; + let actual_dst = Sha256::digest([b"H2C-OVERSIZE-DST-".as_slice(), &oversize_dst].concat()); + // Test the hash_to_F function handles this + // If it didn't, these would return different values + assert_eq!(hash_to_F::(&oversize_dst, &[]), hash_to_F::(&actual_dst, &[])); +} + +#[cfg(feature = "secp256k1")] +#[test] +fn test_secp256k1() { + test_oversize_dst::(); +} + +#[cfg(feature = "p256")] +#[test] +fn test_p256() { + test_oversize_dst::(); +} diff --git a/crypto/frost/src/curve/mod.rs b/crypto/frost/src/curve/mod.rs index 5012a619..ae0796b1 100644 --- a/crypto/frost/src/curve/mod.rs +++ b/crypto/frost/src/curve/mod.rs @@ -1,4 +1,4 @@ -use core::ops::Deref; +use core::{ops::Deref, convert::AsRef}; use std::io::{self, Read}; use rand_core::{RngCore, CryptoRng}; @@ -6,9 +6,8 @@ use rand_core::{RngCore, CryptoRng}; use zeroize::{Zeroize, Zeroizing}; use subtle::ConstantTimeEq; -use digest::{Digest, Output}; - pub use ciphersuite::{ + digest::Digest, group::{ ff::{Field, PrimeField}, Group, @@ -46,24 +45,23 @@ pub trait Curve: Ciphersuite { const CONTEXT: &'static [u8]; /// Hash the given dst and data to a byte vector. Used to instantiate H4 and H5. - fn hash(dst: &[u8], data: &[u8]) -> Output { + fn hash(dst: &[u8], data: &[u8]) -> impl AsRef<[u8]> { Self::H::digest([Self::CONTEXT, dst, data].concat()) } - /// Field element from hash. Used during key gen and by other crates under Serai as a general - /// utility. Used to instantiate H1 and H3. + /// Field element from hash. Used to instantiate H1 and H3. + /// + /// The `dst` MUST be prefixed by `Self::CONTEXT` by the implementor. #[allow(non_snake_case)] - fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F { - ::hash_to_F(&[Self::CONTEXT, dst].concat(), msg) - } + fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F; /// Hash the message for the binding factor. H4 from the IETF draft. - fn hash_msg(msg: &[u8]) -> Output { + fn hash_msg(msg: &[u8]) -> impl AsRef<[u8]> { Self::hash(b"msg", msg) } /// Hash the commitments for the binding factor. H5 from the IETF draft. - fn hash_commitments(commitments: &[u8]) -> Output { + fn hash_commitments(commitments: &[u8]) -> impl AsRef<[u8]> { Self::hash(b"com", commitments) } diff --git a/crypto/schnorr/Cargo.toml b/crypto/schnorr/Cargo.toml index db5c171d..009deb99 100644 --- a/crypto/schnorr/Cargo.toml +++ b/crypto/schnorr/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/crypto/schnorr" authors = ["Luke Parker "] keywords = ["schnorr", "ff", "group"] edition = "2021" -rust-version = "1.79" +rust-version = "1.85" [package.metadata.docs.rs] all-features = true diff --git a/crypto/schnorrkel/Cargo.toml b/crypto/schnorrkel/Cargo.toml index 889cf4ed..dfb10d9c 100644 --- a/crypto/schnorrkel/Cargo.toml +++ b/crypto/schnorrkel/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/crypto/schnorrkel" authors = ["Luke Parker "] keywords = ["frost", "multisig", "threshold", "schnorrkel"] edition = "2021" -rust-version = "1.79" +rust-version = "1.85" [package.metadata.docs.rs] all-features = true diff --git a/crypto/secq256k1/Cargo.toml b/crypto/secq256k1/Cargo.toml index 1c32cbbb..f49cb671 100644 --- a/crypto/secq256k1/Cargo.toml +++ b/crypto/secq256k1/Cargo.toml @@ -23,7 +23,7 @@ k256 = { version = "0.13", default-features = false, features = ["arithmetic"] } prime-field = { path = "../prime-field", default-features = false } short-weierstrass = { path = "../short-weierstrass", default-features = false } -blake2 = { version = "0.10", default-features = false } +blake2 = { version = "0.11.0-rc.0", default-features = false } ciphersuite = { path = "../ciphersuite", version = "0.4", default-features = false } generalized-bulletproofs-ec-gadgets = { git = "https://github.com/monero-oxide/monero-oxide", rev = "a6f8797007e768488568b821435cf5006517a962", default-features = false, optional = true } @@ -36,5 +36,5 @@ ff-group-tests = { path = "../ff-group-tests" } [features] alloc = ["std-shims", "generic-array/alloc", "k256/alloc", "prime-field/alloc", "short-weierstrass/alloc", "ciphersuite/alloc", "generalized-bulletproofs-ec-gadgets"] -std = ["alloc", "std-shims/std", "k256/std", "prime-field/std", "blake2/std", "ciphersuite/std", "generalized-bulletproofs-ec-gadgets/std"] +std = ["alloc", "std-shims/std", "k256/std", "prime-field/std", "ciphersuite/std", "generalized-bulletproofs-ec-gadgets/std"] default = ["std"] diff --git a/crypto/secq256k1/src/lib.rs b/crypto/secq256k1/src/lib.rs index 2f0a49ff..07c10395 100644 --- a/crypto/secq256k1/src/lib.rs +++ b/crypto/secq256k1/src/lib.rs @@ -13,10 +13,7 @@ use generic_array::{typenum::U33, GenericArray}; use k256::elliptic_curve::{ subtle::{Choice, ConstantTimeEq, ConditionallySelectable}, zeroize::Zeroize, - group::{ - ff::{PrimeField, FromUniformBytes}, - Group, - }, + group::{ff::PrimeField, Group}, sec1::Tag, }; @@ -121,18 +118,6 @@ impl ciphersuite::Ciphersuite for Secq256k1 { Point::generator() } - /// `hash_to_F` is implemented with a naive concatenation of the `dst` and `data`, allowing - /// transposition between the two. This means `dst: b"abc", data: b"def"`, will produce the same - /// scalar as `dst: "abcdef", data: b""`. Please use carefully, not letting `dst` valuess be - /// substrings of each other. - fn hash_to_F(dst: &[u8], data: &[u8]) -> Self::F { - use blake2::Digest; - let mut digest = Self::H::new(); - digest.update(dst); - digest.update(data); - >::from_uniform_bytes(&digest.finalize().into()) - } - // We override the provided impl, which compares against the reserialization, because // we already require canonicity #[cfg(feature = "alloc")] diff --git a/crypto/transcript/Cargo.toml b/crypto/transcript/Cargo.toml index 11daed9e..de4f282c 100644 --- a/crypto/transcript/Cargo.toml +++ b/crypto/transcript/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/crypto/transcript" authors = ["Luke Parker "] keywords = ["transcript"] edition = "2021" -rust-version = "1.73" +rust-version = "1.85" [package.metadata.docs.rs] all-features = true @@ -19,17 +19,17 @@ workspace = true [dependencies] zeroize = { version = "^1.5", default-features = false } -digest = { version = "0.10", default-features = false, features = ["core-api"] } +digest = { version = "0.11.0-rc.0", default-features = false, features = ["block-api"] } -blake2 = { version = "0.10", default-features = false, optional = true } +blake2 = { version = "0.11.0-rc.0", default-features = false, optional = true } merlin = { version = "3", default-features = false, optional = true } [dev-dependencies] -sha2 = { version = "0.10", default-features = false } -blake2 = { version = "0.10", default-features = false } +sha2 = { version = "0.11.0-rc.0", default-features = false } +blake2 = { version = "0.11.0-rc.0", default-features = false } [features] -std = ["zeroize/std", "digest/std", "blake2?/std", "merlin?/std"] +std = ["zeroize/std", "merlin?/std"] recommended = ["blake2"] tests = [] default = ["std"] diff --git a/crypto/transcript/src/lib.rs b/crypto/transcript/src/lib.rs index 4dc8ad1b..8363d781 100644 --- a/crypto/transcript/src/lib.rs +++ b/crypto/transcript/src/lib.rs @@ -8,7 +8,7 @@ use digest::{ typenum::{ consts::U32, marker_traits::NonZero, type_operators::IsGreaterOrEqual, operator_aliases::GrEq, }, - core_api::BlockSizeUser, + block_api::BlockSizeUser, Digest, Output, HashMarker, }; diff --git a/message-queue/src/messages.rs b/message-queue/src/messages.rs index e7c5a046..bcc4ef8c 100644 --- a/message-queue/src/messages.rs +++ b/message-queue/src/messages.rs @@ -52,7 +52,7 @@ pub fn message_challenge( transcript.append_message(b"msg", msg); transcript.domain_separate(b"signature"); transcript.append_message(b"nonce", nonce.to_bytes()); - ::hash_to_F(b"message_challenge", &transcript.challenge(b"challenge")) + ::hash_to_F(&transcript.challenge(b"challenge")) } pub fn ack_challenge( @@ -71,5 +71,5 @@ pub fn ack_challenge( transcript.append_message(b"id", id.to_le_bytes()); transcript.domain_separate(b"signature"); transcript.append_message(b"nonce", nonce.to_bytes()); - ::hash_to_F(b"ack_challenge", &transcript.challenge(b"challenge")) + ::hash_to_F(&transcript.challenge(b"challenge")) } diff --git a/processor/bitcoin/src/scan.rs b/processor/bitcoin/src/scan.rs index 3c884d93..c8a5fa74 100644 --- a/processor/bitcoin/src/scan.rs +++ b/processor/bitcoin/src/scan.rs @@ -19,13 +19,13 @@ use primitives::OutputType; use crate::hash_bytes; -const KEY_DST: &[u8] = b"Serai Bitcoin Processor Key Offset"; +// TODO: Bitcoin HD derivation, instead of these bespoke labels? static BRANCH_BASE_OFFSET: LazyLock<::F> = - LazyLock::new(|| Secp256k1::hash_to_F(KEY_DST, b"branch")); + LazyLock::new(|| Secp256k1::hash_to_F(b"branch")); static CHANGE_BASE_OFFSET: LazyLock<::F> = - LazyLock::new(|| Secp256k1::hash_to_F(KEY_DST, b"change")); + LazyLock::new(|| Secp256k1::hash_to_F(b"change")); static FORWARD_BASE_OFFSET: LazyLock<::F> = - LazyLock::new(|| Secp256k1::hash_to_F(KEY_DST, b"forward")); + LazyLock::new(|| Secp256k1::hash_to_F(b"forward")); // Unfortunately, we have per-key offsets as it's the root key plus the base offset may not be // even. While we could tweak the key until all derivations are even, that'd require significantly diff --git a/processor/scheduler/primitives/Cargo.toml b/processor/scheduler/primitives/Cargo.toml index a0408989..64141319 100644 --- a/processor/scheduler/primitives/Cargo.toml +++ b/processor/scheduler/primitives/Cargo.toml @@ -8,7 +8,7 @@ authors = ["Luke Parker "] keywords = [] edition = "2021" publish = false -rust-version = "1.79" +rust-version = "1.85" [package.metadata.docs.rs] all-features = true diff --git a/processor/view-keys/Cargo.toml b/processor/view-keys/Cargo.toml index 7af10d99..79be2c65 100644 --- a/processor/view-keys/Cargo.toml +++ b/processor/view-keys/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/serai-dex/serai/tree/develop/processor/view-key authors = ["Luke Parker "] keywords = [] edition = "2021" -rust-version = "1.73" +rust-version = "1.85" [package.metadata.docs.rs] all-features = true diff --git a/processor/view-keys/src/lib.rs b/processor/view-keys/src/lib.rs index c0d4c68e..0708836a 100644 --- a/processor/view-keys/src/lib.rs +++ b/processor/view-keys/src/lib.rs @@ -9,5 +9,5 @@ use ciphersuite::Ciphersuite; /// `k` is the index of the key to generate (enabling generating multiple view keys within a /// single context). pub fn view_key(k: u64) -> C::F { - C::hash_to_F(b"Serai DEX View Key", &k.to_le_bytes()) + C::hash_to_F(format!("Serai DEX View Key {k}").as_bytes()) } diff --git a/substrate/node/src/rpc.rs b/substrate/node/src/rpc.rs index 7ef8bbef..481b7ebb 100644 --- a/substrate/node/src/rpc.rs +++ b/substrate/node/src/rpc.rs @@ -143,9 +143,9 @@ where // We don't know the eth address before the smart contract is deployed. ExternalNetworkId::Ethereum => Ok(String::new()), ExternalNetworkId::Monero => { + // TODO: Serai view-key crate let view_private = zeroize::Zeroizing::new( ::hash_to_F( - b"Serai DEX Additional Key", &["Monero".as_bytes(), &0u64.to_le_bytes()].concat(), ) .0, diff --git a/substrate/primitives/src/account.rs b/substrate/primitives/src/account.rs index 61940f29..9680adc5 100644 --- a/substrate/primitives/src/account.rs +++ b/substrate/primitives/src/account.rs @@ -103,7 +103,7 @@ pub fn insecure_pair_from_name(name: &str) -> Pair { /// This key should never be considered a secure private key. It has effectively no entropy. #[cfg(feature = "std")] pub fn insecure_arbitrary_key_from_name(name: &str) -> C::F { - C::hash_to_F(b"insecure arbitrary key", name.as_bytes()) + C::hash_to_F(name.as_bytes()) } pub struct AccountLookup;