mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-09 12:49:23 +00:00
Smash the singular Ciphersuite trait into multiple
This helps identify where the various functionalities are used, or rather, not used. The `Ciphersuite` trait present in `patches/ciphersuite`, facilitating the entire FCMP++ tree, only requires the markers _and_ canonical point decoding. I've opened a PR to upstream such a trait into `group` (https://github.com/zkcrypto/group/pull/68). `WrappedGroup` is still justified for as long as `Group::generator` exists. Moving `::generator()` to its own trait, on an independent structure (upstream) would be massively appreciated. @tarcieri also wanted to update from `fn generator()` to `const GENERATOR`, which would encourage further discussion on https://github.com/zkcrypto/group/issues/32 and https://github.com/zkcrypto/group/issues/45, which have been stagnant. The `Id` trait is occasionally used yet really should be first off the chopping block. Finally, `WithPreferredHash` is only actually used around a third of the time, which more than justifies it being a separate trait. --- Updates `dalek_ff_group::Scalar` to directly re-export `curve25519_dalek::Scalar`, as without issue. `dalek_ff_group::RistrettoPoint` also could be replaced with an export of `curve25519_dalek::RistrettoPoint`, yet the coordinator relies on how we implemented `Hash` on it for the hell of it so it isn't worth it at this time. `dalek_ff_group::EdwardsPoint` can't be replaced for an re-export of `curve25519_dalek::SubgroupPoint` as it doesn't implement `zeroize`, `subtle` traits within a released, non-yanked version. Relevance to https://github.com/serai-dex/serai/issues/201 and https://github.com/dalek-cryptography/curve25519-dalek/issues/811#issuecomment-3247732746. Also updates the `Ristretto` ciphersuite to prefer `Blake2b-512` over `SHA2-512`. In order to maintain compliance with FROST's IETF standard, `modular-frost` defines its own ciphersuite for Ristretto which still uses `SHA2-512`.
This commit is contained in:
186
Cargo.lock
generated
186
Cargo.lock
generated
@@ -1526,11 +1526,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blake2"
|
name = "blake2"
|
||||||
version = "0.11.0-rc.0"
|
version = "0.11.0-rc.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ce3d950855224a23299348898f8a2127860e1afea78df3e51deebb89d1cb2f8f"
|
checksum = "1edac47499deef695d9431bf241c75ea29f4cf3dcb78d39e19b31515e4ad3b08"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"digest 0.11.0-rc.0",
|
"digest 0.11.0-rc.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1588,11 +1588,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block-buffer"
|
name = "block-buffer"
|
||||||
version = "0.11.0-rc.4"
|
version = "0.11.0-rc.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a229bfd78e4827c91b9b95784f69492c1b77c1ab75a45a8a037b139215086f94"
|
checksum = "e9ef36a6fcdb072aa548f3da057640ec10859eb4e91ddf526ee648d50c76a949"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hybrid-array",
|
"hybrid-array",
|
||||||
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1922,13 +1923,11 @@ dependencies = [
|
|||||||
name = "ciphersuite"
|
name = "ciphersuite"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"digest 0.11.0-rc.0",
|
"digest 0.11.0-rc.1",
|
||||||
"ff",
|
"ff",
|
||||||
"ff-group-tests",
|
"ff-group-tests",
|
||||||
"flexible-transcript",
|
|
||||||
"group",
|
"group",
|
||||||
"hex",
|
"hex",
|
||||||
"rand_core 0.6.4",
|
|
||||||
"std-shims",
|
"std-shims",
|
||||||
"subtle",
|
"subtle",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
@@ -1939,7 +1938,9 @@ name = "ciphersuite"
|
|||||||
version = "0.4.99"
|
version = "0.4.99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"dalek-ff-group 0.4.6",
|
"dalek-ff-group 0.5.0",
|
||||||
|
"std-shims",
|
||||||
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1952,7 +1953,7 @@ dependencies = [
|
|||||||
"k256",
|
"k256",
|
||||||
"p256",
|
"p256",
|
||||||
"rand_core 0.6.4",
|
"rand_core 0.6.4",
|
||||||
"sha2 0.11.0-rc.0",
|
"sha2 0.11.0-rc.2",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2345,9 +2346,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-common"
|
name = "crypto-common"
|
||||||
version = "0.2.0-rc.3"
|
version = "0.2.0-rc.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8a23fa214dea9efd4dacee5a5614646b30216ae0f05d4bb51bafb50e9da1c5be"
|
checksum = "6a8235645834fbc6832939736ce2f2d08192652269e11010a6240f61b908a1c6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hybrid-array",
|
"hybrid-array",
|
||||||
]
|
]
|
||||||
@@ -2371,6 +2372,7 @@ dependencies = [
|
|||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
"curve25519-dalek-derive",
|
"curve25519-dalek-derive",
|
||||||
"digest 0.10.7",
|
"digest 0.10.7",
|
||||||
|
"ff",
|
||||||
"fiat-crypto",
|
"fiat-crypto",
|
||||||
"group",
|
"group",
|
||||||
"rand_core 0.6.4",
|
"rand_core 0.6.4",
|
||||||
@@ -2454,28 +2456,27 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dalek-ff-group"
|
name = "dalek-ff-group"
|
||||||
version = "0.4.6"
|
version = "0.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"blake2 0.11.0-rc.2",
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"crypto-bigint 0.6.1",
|
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"digest 0.10.7",
|
|
||||||
"ff-group-tests",
|
"ff-group-tests",
|
||||||
"hex",
|
"hex",
|
||||||
"prime-field",
|
"prime-field",
|
||||||
"rand_core 0.6.4",
|
"rand_core 0.6.4",
|
||||||
"sha2 0.11.0-rc.0",
|
"sha2 0.11.0-rc.2",
|
||||||
"subtle",
|
"subtle",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dalek-ff-group"
|
name = "dalek-ff-group"
|
||||||
version = "0.4.99"
|
version = "0.5.99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crypto-bigint 0.5.5",
|
"crypto-bigint 0.5.5",
|
||||||
"crypto-bigint 0.6.1",
|
"crypto-bigint 0.6.1",
|
||||||
"dalek-ff-group 0.4.6",
|
"dalek-ff-group 0.5.0",
|
||||||
"prime-field",
|
"prime-field",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2551,7 +2552,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976"
|
checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"data-encoding",
|
"data-encoding",
|
||||||
"syn 2.0.106",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2714,13 +2715,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.11.0-rc.0"
|
version = "0.11.0-rc.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "460dd7f37e4950526b54a5a6b1f41b6c8e763c58eb9a8fc8fc05ba5c2f44ca7b"
|
checksum = "3a4aae35a0fcbe22ff1be50fe96df72002d5a4a6fb4aae9193cf2da0daa36da2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block-buffer 0.11.0-rc.4",
|
"block-buffer 0.11.0-rc.5",
|
||||||
"crypto-common 0.2.0-rc.3",
|
"crypto-common 0.2.0-rc.4",
|
||||||
"subtle",
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2801,10 +2803,10 @@ dependencies = [
|
|||||||
name = "dkg-evrf"
|
name = "dkg-evrf"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blake2 0.11.0-rc.0",
|
"blake2 0.11.0-rc.2",
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"ciphersuite-kp256",
|
"ciphersuite-kp256",
|
||||||
"dalek-ff-group 0.4.6",
|
"dalek-ff-group 0.5.0",
|
||||||
"dkg",
|
"dkg",
|
||||||
"dkg-recovery",
|
"dkg-recovery",
|
||||||
"ec-divisors",
|
"ec-divisors",
|
||||||
@@ -2829,7 +2831,7 @@ name = "dkg-musig"
|
|||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"dalek-ff-group 0.4.6",
|
"dalek-ff-group 0.5.0",
|
||||||
"dkg",
|
"dkg",
|
||||||
"dkg-recovery",
|
"dkg-recovery",
|
||||||
"multiexp",
|
"multiexp",
|
||||||
@@ -2920,9 +2922,9 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "ec-divisors"
|
name = "ec-divisors"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/monero-oxide/monero-oxide?rev=a6f8797007e768488568b821435cf5006517a962#a6f8797007e768488568b821435cf5006517a962"
|
source = "git+https://github.com/monero-oxide/monero-oxide?rev=7216a2e84c7671c167c3d81eafe0d2b1f418f102#7216a2e84c7671c167c3d81eafe0d2b1f418f102"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dalek-ff-group 0.4.99",
|
"dalek-ff-group 0.5.99",
|
||||||
"ff",
|
"ff",
|
||||||
"group",
|
"group",
|
||||||
"rand_core 0.6.4",
|
"rand_core 0.6.4",
|
||||||
@@ -3031,10 +3033,9 @@ dependencies = [
|
|||||||
name = "embedwards25519"
|
name = "embedwards25519"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blake2 0.11.0-rc.0",
|
"blake2 0.11.0-rc.2",
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"dalek-ff-group 0.4.6",
|
|
||||||
"ff-group-tests",
|
"ff-group-tests",
|
||||||
"generalized-bulletproofs-ec-gadgets",
|
"generalized-bulletproofs-ec-gadgets",
|
||||||
"hex",
|
"hex",
|
||||||
@@ -3321,10 +3322,10 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
|||||||
name = "flexible-transcript"
|
name = "flexible-transcript"
|
||||||
version = "0.3.4"
|
version = "0.3.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blake2 0.11.0-rc.0",
|
"blake2 0.11.0-rc.2",
|
||||||
"digest 0.11.0-rc.0",
|
"digest 0.11.0-rc.1",
|
||||||
"merlin",
|
"merlin",
|
||||||
"sha2 0.11.0-rc.0",
|
"sha2 0.11.0-rc.2",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3544,7 +3545,6 @@ name = "frost-schnorrkel"
|
|||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"dalek-ff-group 0.4.6",
|
|
||||||
"flexible-transcript",
|
"flexible-transcript",
|
||||||
"group",
|
"group",
|
||||||
"modular-frost",
|
"modular-frost",
|
||||||
@@ -3771,7 +3771,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "generalized-bulletproofs"
|
name = "generalized-bulletproofs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/monero-oxide/monero-oxide?rev=a6f8797007e768488568b821435cf5006517a962#a6f8797007e768488568b821435cf5006517a962"
|
source = "git+https://github.com/monero-oxide/monero-oxide?rev=7216a2e84c7671c167c3d81eafe0d2b1f418f102#7216a2e84c7671c167c3d81eafe0d2b1f418f102"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blake2 0.10.6",
|
"blake2 0.10.6",
|
||||||
"ciphersuite 0.4.99",
|
"ciphersuite 0.4.99",
|
||||||
@@ -3786,7 +3786,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "generalized-bulletproofs-circuit-abstraction"
|
name = "generalized-bulletproofs-circuit-abstraction"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/monero-oxide/monero-oxide?rev=a6f8797007e768488568b821435cf5006517a962#a6f8797007e768488568b821435cf5006517a962"
|
source = "git+https://github.com/monero-oxide/monero-oxide?rev=7216a2e84c7671c167c3d81eafe0d2b1f418f102#7216a2e84c7671c167c3d81eafe0d2b1f418f102"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ciphersuite 0.4.99",
|
"ciphersuite 0.4.99",
|
||||||
"generalized-bulletproofs",
|
"generalized-bulletproofs",
|
||||||
@@ -3797,7 +3797,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "generalized-bulletproofs-ec-gadgets"
|
name = "generalized-bulletproofs-ec-gadgets"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/monero-oxide/monero-oxide?rev=a6f8797007e768488568b821435cf5006517a962#a6f8797007e768488568b821435cf5006517a962"
|
source = "git+https://github.com/monero-oxide/monero-oxide?rev=7216a2e84c7671c167c3d81eafe0d2b1f418f102#7216a2e84c7671c167c3d81eafe0d2b1f418f102"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ciphersuite 0.4.99",
|
"ciphersuite 0.4.99",
|
||||||
"generalized-bulletproofs-circuit-abstraction",
|
"generalized-bulletproofs-circuit-abstraction",
|
||||||
@@ -4221,8 +4221,9 @@ checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hybrid-array"
|
name = "hybrid-array"
|
||||||
version = "0.3.1"
|
version = "0.4.0"
|
||||||
source = "git+https://github.com/kayabaNerve/hybrid-array?rev=8caa508976c93696a67f40734537c91be7cecd96#8caa508976c93696a67f40734537c91be7cecd96"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6fe39a812f039072707ce38020acbab2f769087952eddd9e2b890f37654b2349"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
@@ -6020,7 +6021,7 @@ dependencies = [
|
|||||||
"hex",
|
"hex",
|
||||||
"prime-field",
|
"prime-field",
|
||||||
"rand_core 0.6.4",
|
"rand_core 0.6.4",
|
||||||
"sha3 0.11.0-rc.0",
|
"sha3 0.11.0-rc.2",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -6079,11 +6080,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "modular-frost"
|
name = "modular-frost"
|
||||||
version = "0.10.1"
|
version = "0.11.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"ciphersuite-kp256",
|
"ciphersuite-kp256",
|
||||||
"dalek-ff-group 0.4.6",
|
"dalek-ff-group 0.5.0",
|
||||||
"dkg",
|
"dkg",
|
||||||
"dkg-dealer",
|
"dkg-dealer",
|
||||||
"dkg-recovery",
|
"dkg-recovery",
|
||||||
@@ -6105,7 +6106,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "monero-address"
|
name = "monero-address"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/monero-oxide/monero-oxide?rev=6966575e05fe09b77674c46984b21686ed9304ff#6966575e05fe09b77674c46984b21686ed9304ff"
|
source = "git+https://github.com/monero-oxide/monero-oxide?rev=7f37cc8f770858aa1739e0f56dbe447db86f4ba6#7f37cc8f770858aa1739e0f56dbe447db86f4ba6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"monero-base58",
|
"monero-base58",
|
||||||
@@ -6117,7 +6118,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "monero-base58"
|
name = "monero-base58"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/monero-oxide/monero-oxide?rev=6966575e05fe09b77674c46984b21686ed9304ff#6966575e05fe09b77674c46984b21686ed9304ff"
|
source = "git+https://github.com/monero-oxide/monero-oxide?rev=7f37cc8f770858aa1739e0f56dbe447db86f4ba6#7f37cc8f770858aa1739e0f56dbe447db86f4ba6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"monero-primitives",
|
"monero-primitives",
|
||||||
"std-shims",
|
"std-shims",
|
||||||
@@ -6126,7 +6127,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "monero-borromean"
|
name = "monero-borromean"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/monero-oxide/monero-oxide?rev=6966575e05fe09b77674c46984b21686ed9304ff#6966575e05fe09b77674c46984b21686ed9304ff"
|
source = "git+https://github.com/monero-oxide/monero-oxide?rev=7f37cc8f770858aa1739e0f56dbe447db86f4ba6#7f37cc8f770858aa1739e0f56dbe447db86f4ba6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"monero-generators",
|
"monero-generators",
|
||||||
@@ -6139,7 +6140,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "monero-bulletproofs"
|
name = "monero-bulletproofs"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/monero-oxide/monero-oxide?rev=6966575e05fe09b77674c46984b21686ed9304ff#6966575e05fe09b77674c46984b21686ed9304ff"
|
source = "git+https://github.com/monero-oxide/monero-oxide?rev=7f37cc8f770858aa1739e0f56dbe447db86f4ba6#7f37cc8f770858aa1739e0f56dbe447db86f4ba6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"monero-generators",
|
"monero-generators",
|
||||||
@@ -6154,10 +6155,10 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "monero-clsag"
|
name = "monero-clsag"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/monero-oxide/monero-oxide?rev=6966575e05fe09b77674c46984b21686ed9304ff#6966575e05fe09b77674c46984b21686ed9304ff"
|
source = "git+https://github.com/monero-oxide/monero-oxide?rev=7f37cc8f770858aa1739e0f56dbe447db86f4ba6#7f37cc8f770858aa1739e0f56dbe447db86f4ba6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"dalek-ff-group 0.4.99",
|
"dalek-ff-group 0.5.99",
|
||||||
"flexible-transcript",
|
"flexible-transcript",
|
||||||
"group",
|
"group",
|
||||||
"modular-frost",
|
"modular-frost",
|
||||||
@@ -6175,11 +6176,11 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "monero-generators"
|
name = "monero-generators"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "git+https://github.com/monero-oxide/monero-oxide?rev=6966575e05fe09b77674c46984b21686ed9304ff#6966575e05fe09b77674c46984b21686ed9304ff"
|
source = "git+https://github.com/monero-oxide/monero-oxide?rev=7f37cc8f770858aa1739e0f56dbe447db86f4ba6#7f37cc8f770858aa1739e0f56dbe447db86f4ba6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crypto-bigint 0.5.5",
|
"crypto-bigint 0.5.5",
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"dalek-ff-group 0.4.99",
|
"dalek-ff-group 0.5.99",
|
||||||
"group",
|
"group",
|
||||||
"monero-io",
|
"monero-io",
|
||||||
"sha3 0.10.8",
|
"sha3 0.10.8",
|
||||||
@@ -6190,16 +6191,17 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "monero-io"
|
name = "monero-io"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/monero-oxide/monero-oxide?rev=6966575e05fe09b77674c46984b21686ed9304ff#6966575e05fe09b77674c46984b21686ed9304ff"
|
source = "git+https://github.com/monero-oxide/monero-oxide?rev=7f37cc8f770858aa1739e0f56dbe447db86f4ba6#7f37cc8f770858aa1739e0f56dbe447db86f4ba6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"std-shims",
|
"std-shims",
|
||||||
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "monero-mlsag"
|
name = "monero-mlsag"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/monero-oxide/monero-oxide?rev=6966575e05fe09b77674c46984b21686ed9304ff#6966575e05fe09b77674c46984b21686ed9304ff"
|
source = "git+https://github.com/monero-oxide/monero-oxide?rev=7f37cc8f770858aa1739e0f56dbe447db86f4ba6#7f37cc8f770858aa1739e0f56dbe447db86f4ba6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"monero-generators",
|
"monero-generators",
|
||||||
@@ -6213,7 +6215,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "monero-oxide"
|
name = "monero-oxide"
|
||||||
version = "0.1.4-alpha"
|
version = "0.1.4-alpha"
|
||||||
source = "git+https://github.com/monero-oxide/monero-oxide?rev=6966575e05fe09b77674c46984b21686ed9304ff#6966575e05fe09b77674c46984b21686ed9304ff"
|
source = "git+https://github.com/monero-oxide/monero-oxide?rev=7f37cc8f770858aa1739e0f56dbe447db86f4ba6#7f37cc8f770858aa1739e0f56dbe447db86f4ba6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"hex-literal",
|
"hex-literal",
|
||||||
@@ -6231,7 +6233,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "monero-primitives"
|
name = "monero-primitives"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/monero-oxide/monero-oxide?rev=6966575e05fe09b77674c46984b21686ed9304ff#6966575e05fe09b77674c46984b21686ed9304ff"
|
source = "git+https://github.com/monero-oxide/monero-oxide?rev=7f37cc8f770858aa1739e0f56dbe447db86f4ba6#7f37cc8f770858aa1739e0f56dbe447db86f4ba6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"monero-generators",
|
"monero-generators",
|
||||||
@@ -6244,7 +6246,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "monero-rpc"
|
name = "monero-rpc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/monero-oxide/monero-oxide?rev=6966575e05fe09b77674c46984b21686ed9304ff#6966575e05fe09b77674c46984b21686ed9304ff"
|
source = "git+https://github.com/monero-oxide/monero-oxide?rev=7f37cc8f770858aa1739e0f56dbe447db86f4ba6#7f37cc8f770858aa1739e0f56dbe447db86f4ba6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"hex",
|
"hex",
|
||||||
@@ -6260,7 +6262,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "monero-simple-request-rpc"
|
name = "monero-simple-request-rpc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/monero-oxide/monero-oxide?rev=6966575e05fe09b77674c46984b21686ed9304ff#6966575e05fe09b77674c46984b21686ed9304ff"
|
source = "git+https://github.com/monero-oxide/monero-oxide?rev=7f37cc8f770858aa1739e0f56dbe447db86f4ba6#7f37cc8f770858aa1739e0f56dbe447db86f4ba6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"digest_auth",
|
"digest_auth",
|
||||||
"hex",
|
"hex",
|
||||||
@@ -6273,10 +6275,10 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "monero-wallet"
|
name = "monero-wallet"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/monero-oxide/monero-oxide?rev=6966575e05fe09b77674c46984b21686ed9304ff#6966575e05fe09b77674c46984b21686ed9304ff"
|
source = "git+https://github.com/monero-oxide/monero-oxide?rev=7f37cc8f770858aa1739e0f56dbe447db86f4ba6#7f37cc8f770858aa1739e0f56dbe447db86f4ba6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"dalek-ff-group 0.4.99",
|
"dalek-ff-group 0.5.99",
|
||||||
"flexible-transcript",
|
"flexible-transcript",
|
||||||
"hex",
|
"hex",
|
||||||
"modular-frost",
|
"modular-frost",
|
||||||
@@ -6327,7 +6329,7 @@ dependencies = [
|
|||||||
name = "multiexp"
|
name = "multiexp"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dalek-ff-group 0.4.6",
|
"dalek-ff-group 0.5.0",
|
||||||
"ff",
|
"ff",
|
||||||
"group",
|
"group",
|
||||||
"k256",
|
"k256",
|
||||||
@@ -6688,7 +6690,7 @@ version = "0.7.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d"
|
checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-crate 3.2.0",
|
"proc-macro-crate 1.3.1",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.106",
|
"syn 2.0.106",
|
||||||
@@ -9465,7 +9467,8 @@ name = "schnorr-signatures"
|
|||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"dalek-ff-group 0.4.6",
|
"dalek-ff-group 0.5.0",
|
||||||
|
"digest 0.11.0-rc.1",
|
||||||
"flexible-transcript",
|
"flexible-transcript",
|
||||||
"hex",
|
"hex",
|
||||||
"multiexp",
|
"multiexp",
|
||||||
@@ -9602,7 +9605,7 @@ dependencies = [
|
|||||||
"k256",
|
"k256",
|
||||||
"prime-field",
|
"prime-field",
|
||||||
"rand_core 0.6.4",
|
"rand_core 0.6.4",
|
||||||
"sha2 0.11.0-rc.0",
|
"sha2 0.11.0-rc.2",
|
||||||
"short-weierstrass",
|
"short-weierstrass",
|
||||||
"std-shims",
|
"std-shims",
|
||||||
]
|
]
|
||||||
@@ -9746,11 +9749,11 @@ dependencies = [
|
|||||||
"async-lock",
|
"async-lock",
|
||||||
"bitcoin",
|
"bitcoin",
|
||||||
"bitvec",
|
"bitvec",
|
||||||
"blake2 0.11.0-rc.0",
|
"blake2 0.11.0-rc.2",
|
||||||
"borsh",
|
"borsh",
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"ciphersuite-kp256",
|
"ciphersuite-kp256",
|
||||||
"dalek-ff-group 0.4.6",
|
"dalek-ff-group 0.5.0",
|
||||||
"dkg-musig",
|
"dkg-musig",
|
||||||
"dockertest",
|
"dockertest",
|
||||||
"frame-system",
|
"frame-system",
|
||||||
@@ -9808,20 +9811,18 @@ name = "serai-coordinator"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitvec",
|
"bitvec",
|
||||||
"blake2 0.11.0-rc.0",
|
"blake2 0.11.0-rc.2",
|
||||||
"borsh",
|
"borsh",
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"dalek-ff-group 0.4.6",
|
"dalek-ff-group 0.5.0",
|
||||||
"dkg-musig",
|
"dkg-musig",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"flexible-transcript",
|
|
||||||
"frost-schnorrkel",
|
"frost-schnorrkel",
|
||||||
"hex",
|
"hex",
|
||||||
"log",
|
"log",
|
||||||
"modular-frost",
|
"modular-frost",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"rand_core 0.6.4",
|
"rand_core 0.6.4",
|
||||||
"schnorr-signatures",
|
|
||||||
"schnorrkel",
|
"schnorrkel",
|
||||||
"serai-client",
|
"serai-client",
|
||||||
"serai-coordinator-libp2p-p2p",
|
"serai-coordinator-libp2p-p2p",
|
||||||
@@ -9845,7 +9846,7 @@ name = "serai-coordinator-libp2p-p2p"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"blake2 0.11.0-rc.0",
|
"blake2 0.11.0-rc.2",
|
||||||
"borsh",
|
"borsh",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"hex",
|
"hex",
|
||||||
@@ -9899,10 +9900,10 @@ dependencies = [
|
|||||||
name = "serai-coordinator-tributary"
|
name = "serai-coordinator-tributary"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blake2 0.11.0-rc.0",
|
"blake2 0.11.0-rc.2",
|
||||||
"borsh",
|
"borsh",
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"dalek-ff-group 0.4.6",
|
"dalek-ff-group 0.5.0",
|
||||||
"dkg",
|
"dkg",
|
||||||
"log",
|
"log",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
@@ -9922,7 +9923,7 @@ dependencies = [
|
|||||||
name = "serai-cosign"
|
name = "serai-cosign"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blake2 0.11.0-rc.0",
|
"blake2 0.11.0-rc.2",
|
||||||
"borsh",
|
"borsh",
|
||||||
"log",
|
"log",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
@@ -10166,7 +10167,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"borsh",
|
"borsh",
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"dalek-ff-group 0.4.6",
|
"dalek-ff-group 0.5.0",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"flexible-transcript",
|
"flexible-transcript",
|
||||||
"hex",
|
"hex",
|
||||||
@@ -10187,7 +10188,7 @@ name = "serai-message-queue-tests"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"dalek-ff-group 0.4.6",
|
"dalek-ff-group 0.5.0",
|
||||||
"dockertest",
|
"dockertest",
|
||||||
"hex",
|
"hex",
|
||||||
"rand_core 0.6.4",
|
"rand_core 0.6.4",
|
||||||
@@ -10204,7 +10205,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"borsh",
|
"borsh",
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"dalek-ff-group 0.4.6",
|
"dalek-ff-group 0.5.0",
|
||||||
"dkg-evrf",
|
"dkg-evrf",
|
||||||
"log",
|
"log",
|
||||||
"modular-frost",
|
"modular-frost",
|
||||||
@@ -10234,7 +10235,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitcoin-serai",
|
"bitcoin-serai",
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"dalek-ff-group 0.4.6",
|
"dalek-ff-group 0.5.0",
|
||||||
"dkg",
|
"dkg",
|
||||||
"dkg-evrf",
|
"dkg-evrf",
|
||||||
"embedwards25519",
|
"embedwards25519",
|
||||||
@@ -10256,7 +10257,7 @@ dependencies = [
|
|||||||
"ciphersuite-kp256",
|
"ciphersuite-kp256",
|
||||||
"clap",
|
"clap",
|
||||||
"curve25519-dalek",
|
"curve25519-dalek",
|
||||||
"dalek-ff-group 0.4.6",
|
"dalek-ff-group 0.5.0",
|
||||||
"embedwards25519",
|
"embedwards25519",
|
||||||
"frame-benchmarking",
|
"frame-benchmarking",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
@@ -10307,7 +10308,7 @@ name = "serai-orchestrator"
|
|||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"dalek-ff-group 0.4.6",
|
"dalek-ff-group 0.5.0",
|
||||||
"embedwards25519",
|
"embedwards25519",
|
||||||
"flexible-transcript",
|
"flexible-transcript",
|
||||||
"hex",
|
"hex",
|
||||||
@@ -10462,12 +10463,14 @@ dependencies = [
|
|||||||
name = "serai-processor-key-gen"
|
name = "serai-processor-key-gen"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blake2 0.11.0-rc.0",
|
"blake2 0.11.0-rc.2",
|
||||||
"borsh",
|
"borsh",
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"dkg-evrf",
|
"dkg-evrf",
|
||||||
|
"embedwards25519",
|
||||||
"flexible-transcript",
|
"flexible-transcript",
|
||||||
"log",
|
"log",
|
||||||
|
"modular-frost",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"rand_chacha 0.3.1",
|
"rand_chacha 0.3.1",
|
||||||
"rand_core 0.6.4",
|
"rand_core 0.6.4",
|
||||||
@@ -10510,7 +10513,7 @@ dependencies = [
|
|||||||
name = "serai-processor-scanner"
|
name = "serai-processor-scanner"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blake2 0.11.0-rc.0",
|
"blake2 0.11.0-rc.2",
|
||||||
"borsh",
|
"borsh",
|
||||||
"group",
|
"group",
|
||||||
"hex",
|
"hex",
|
||||||
@@ -10542,10 +10545,9 @@ dependencies = [
|
|||||||
name = "serai-processor-signers"
|
name = "serai-processor-signers"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blake2 0.11.0-rc.0",
|
"blake2 0.11.0-rc.2",
|
||||||
"borsh",
|
"borsh",
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"dalek-ff-group 0.4.6",
|
|
||||||
"frost-schnorrkel",
|
"frost-schnorrkel",
|
||||||
"log",
|
"log",
|
||||||
"modular-frost",
|
"modular-frost",
|
||||||
@@ -10723,7 +10725,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitvec",
|
"bitvec",
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"dalek-ff-group 0.4.6",
|
"dalek-ff-group 0.5.0",
|
||||||
"dkg-musig",
|
"dkg-musig",
|
||||||
"frame-support",
|
"frame-support",
|
||||||
"frame-system",
|
"frame-system",
|
||||||
@@ -10758,7 +10760,7 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"borsh",
|
"borsh",
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"dalek-ff-group 0.4.6",
|
"dalek-ff-group 0.5.0",
|
||||||
"dkg-musig",
|
"dkg-musig",
|
||||||
"parity-scale-codec",
|
"parity-scale-codec",
|
||||||
"scale-info",
|
"scale-info",
|
||||||
@@ -10943,13 +10945,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.11.0-rc.0"
|
version = "0.11.0-rc.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aa1d2e6b3cc4e43a8258a9a3b17aa5dfd2cc5186c7024bba8a64aa65b2c71a59"
|
checksum = "d1e3878ab0f98e35b2df35fe53201d088299b41a6bb63e3e34dada2ac4abd924"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
"digest 0.11.0-rc.0",
|
"digest 0.11.0-rc.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -10964,11 +10966,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha3"
|
name = "sha3"
|
||||||
version = "0.11.0-rc.0"
|
version = "0.11.0-rc.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b9e6a92fd180fd205defdc0b78288ce847c7309d329fd6647a814567e67db50e"
|
checksum = "b3c185ed8cff82204014bfaa7649b4c945ca565e03c0534eb33a8d2a01572932"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"digest 0.11.0-rc.0",
|
"digest 0.11.0-rc.1",
|
||||||
"keccak 0.2.0-pre.0",
|
"keccak 0.2.0-pre.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -12609,9 +12611,9 @@ dependencies = [
|
|||||||
name = "tributary-sdk"
|
name = "tributary-sdk"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blake2 0.11.0-rc.0",
|
"blake2 0.11.0-rc.2",
|
||||||
"ciphersuite 0.4.2",
|
"ciphersuite 0.4.2",
|
||||||
"dalek-ff-group 0.4.6",
|
"dalek-ff-group 0.5.0",
|
||||||
"flexible-transcript",
|
"flexible-transcript",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
|||||||
@@ -228,9 +228,6 @@ directories-next = { path = "patches/directories-next" }
|
|||||||
k256 = { git = "https://github.com/kayabaNerve/elliptic-curves", rev = "4994c9ab163781a88cd4a49beae812a89a44e8c3" }
|
k256 = { git = "https://github.com/kayabaNerve/elliptic-curves", rev = "4994c9ab163781a88cd4a49beae812a89a44e8c3" }
|
||||||
p256 = { 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]
|
[workspace.lints.clippy]
|
||||||
unwrap_or_default = "allow"
|
unwrap_or_default = "allow"
|
||||||
map_unwrap_or = "allow"
|
map_unwrap_or = "allow"
|
||||||
|
|||||||
@@ -24,10 +24,8 @@ rand_core = { version = "0.6", default-features = false, features = ["std"] }
|
|||||||
blake2 = { version = "0.11.0-rc.0", default-features = false, features = ["alloc"] }
|
blake2 = { version = "0.11.0-rc.0", default-features = false, features = ["alloc"] }
|
||||||
schnorrkel = { version = "0.11", default-features = false, features = ["std"] }
|
schnorrkel = { version = "0.11", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
transcript = { package = "flexible-transcript", path = "../crypto/transcript", default-features = false, features = ["std", "recommended"] }
|
|
||||||
dalek-ff-group = { path = "../crypto/dalek-ff-group", default-features = false, features = ["std"] }
|
dalek-ff-group = { path = "../crypto/dalek-ff-group", default-features = false, features = ["std"] }
|
||||||
ciphersuite = { path = "../crypto/ciphersuite", default-features = false, features = ["std"] }
|
ciphersuite = { path = "../crypto/ciphersuite", default-features = false, features = ["std"] }
|
||||||
schnorr = { package = "schnorr-signatures", path = "../crypto/schnorr", default-features = false, features = ["std", "aggregate"] }
|
|
||||||
dkg = { package = "dkg-musig", path = "../crypto/dkg/musig", default-features = false, features = ["std"] }
|
dkg = { package = "dkg-musig", path = "../crypto/dkg/musig", default-features = false, features = ["std"] }
|
||||||
frost = { package = "modular-frost", path = "../crypto/frost" }
|
frost = { package = "modular-frost", path = "../crypto/frost" }
|
||||||
frost-schnorrkel = { path = "../crypto/schnorrkel" }
|
frost-schnorrkel = { path = "../crypto/schnorrkel" }
|
||||||
|
|||||||
@@ -3,11 +3,10 @@ use std::{boxed::Box, collections::HashMap};
|
|||||||
|
|
||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
use rand_core::OsRng;
|
use rand_core::OsRng;
|
||||||
use ciphersuite::{group::GroupEncoding, Ciphersuite};
|
use ciphersuite::{group::GroupEncoding, *};
|
||||||
use dalek_ff_group::Ristretto;
|
|
||||||
use dkg::{Participant, musig};
|
use dkg::{Participant, musig};
|
||||||
use frost_schnorrkel::{
|
use frost_schnorrkel::{
|
||||||
frost::{FrostError, sign::*},
|
frost::{curve::Ristretto, FrostError, sign::*},
|
||||||
Schnorrkel,
|
Schnorrkel,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -31,7 +30,7 @@ fn schnorrkel() -> Schnorrkel {
|
|||||||
|
|
||||||
fn our_i(
|
fn our_i(
|
||||||
set: &NewSetInformation,
|
set: &NewSetInformation,
|
||||||
key: &Zeroizing<<Ristretto as Ciphersuite>::F>,
|
key: &Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
data: &HashMap<Participant, Vec<u8>>,
|
data: &HashMap<Participant, Vec<u8>>,
|
||||||
) -> Participant {
|
) -> Participant {
|
||||||
let public = SeraiAddress((Ristretto::generator() * key.deref()).to_bytes());
|
let public = SeraiAddress((Ristretto::generator() * key.deref()).to_bytes());
|
||||||
@@ -125,7 +124,7 @@ pub(crate) struct ConfirmDkgTask<CD: DbTrait, TD: DbTrait> {
|
|||||||
set: NewSetInformation,
|
set: NewSetInformation,
|
||||||
tributary_db: TD,
|
tributary_db: TD,
|
||||||
|
|
||||||
key: Zeroizing<<Ristretto as Ciphersuite>::F>,
|
key: Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
signer: Option<Signer>,
|
signer: Option<Signer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +133,7 @@ impl<CD: DbTrait, TD: DbTrait> ConfirmDkgTask<CD, TD> {
|
|||||||
db: CD,
|
db: CD,
|
||||||
set: NewSetInformation,
|
set: NewSetInformation,
|
||||||
tributary_db: TD,
|
tributary_db: TD,
|
||||||
key: Zeroizing<<Ristretto as Ciphersuite>::F>,
|
key: Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self { db, set, tributary_db, key, signer: None }
|
Self { db, set, tributary_db, key, signer: None }
|
||||||
}
|
}
|
||||||
@@ -153,7 +152,7 @@ impl<CD: DbTrait, TD: DbTrait> ConfirmDkgTask<CD, TD> {
|
|||||||
db: &mut CD,
|
db: &mut CD,
|
||||||
set: ExternalValidatorSet,
|
set: ExternalValidatorSet,
|
||||||
attempt: u32,
|
attempt: u32,
|
||||||
key: Zeroizing<<Ristretto as Ciphersuite>::F>,
|
key: Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
signer: &mut Option<Signer>,
|
signer: &mut Option<Signer>,
|
||||||
) {
|
) {
|
||||||
// Perform the preprocess
|
// Perform the preprocess
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use rand_core::{RngCore, OsRng};
|
|||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use ciphersuite::{
|
use ciphersuite::{
|
||||||
group::{ff::PrimeField, GroupEncoding},
|
group::{ff::PrimeField, GroupEncoding},
|
||||||
Ciphersuite,
|
*,
|
||||||
};
|
};
|
||||||
|
|
||||||
use borsh::BorshDeserialize;
|
use borsh::BorshDeserialize;
|
||||||
@@ -352,7 +352,7 @@ async fn main() {
|
|||||||
let mut key_bytes = [0; 32];
|
let mut key_bytes = [0; 32];
|
||||||
key_bytes.copy_from_slice(&key_vec);
|
key_bytes.copy_from_slice(&key_vec);
|
||||||
key_vec.zeroize();
|
key_vec.zeroize();
|
||||||
let key = Zeroizing::new(<Ristretto as Ciphersuite>::F::from_repr(key_bytes).unwrap());
|
let key = Zeroizing::new(<Ristretto as WrappedGroup>::F::from_repr(key_bytes).unwrap());
|
||||||
key_bytes.zeroize();
|
key_bytes.zeroize();
|
||||||
key
|
key
|
||||||
};
|
};
|
||||||
@@ -439,7 +439,7 @@ async fn main() {
|
|||||||
EphemeralEventStream::new(
|
EphemeralEventStream::new(
|
||||||
db.clone(),
|
db.clone(),
|
||||||
serai.clone(),
|
serai.clone(),
|
||||||
SeraiAddress((<Ristretto as Ciphersuite>::generator() * serai_key.deref()).to_bytes()),
|
SeraiAddress((<Ristretto as WrappedGroup>::generator() * serai_key.deref()).to_bytes()),
|
||||||
)
|
)
|
||||||
.continually_run(substrate_ephemeral_task_def, vec![substrate_task]),
|
.continually_run(substrate_ephemeral_task_def, vec![substrate_task]),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::*;
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
|
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
@@ -23,7 +23,7 @@ use serai_coordinator_p2p::P2p;
|
|||||||
use crate::{Db, KeySet};
|
use crate::{Db, KeySet};
|
||||||
|
|
||||||
pub(crate) struct SubstrateTask<P: P2p> {
|
pub(crate) struct SubstrateTask<P: P2p> {
|
||||||
pub(crate) serai_key: Zeroizing<<Ristretto as Ciphersuite>::F>,
|
pub(crate) serai_key: Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
pub(crate) db: Db,
|
pub(crate) db: Db,
|
||||||
pub(crate) message_queue: Arc<MessageQueue>,
|
pub(crate) message_queue: Arc<MessageQueue>,
|
||||||
pub(crate) p2p: P,
|
pub(crate) p2p: P,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use std::sync::Arc;
|
|||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
use rand_core::OsRng;
|
use rand_core::OsRng;
|
||||||
use blake2::{digest::typenum::U32, Digest, Blake2s};
|
use blake2::{digest::typenum::U32, Digest, Blake2s};
|
||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::*;
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
|
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
@@ -160,7 +160,7 @@ impl<CD: DbTrait, TD: DbTrait, P: P2p> ContinuallyRan
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
async fn add_signed_unsigned_transaction<TD: DbTrait, P: P2p>(
|
async fn add_signed_unsigned_transaction<TD: DbTrait, P: P2p>(
|
||||||
tributary: &Tributary<TD, Transaction, P>,
|
tributary: &Tributary<TD, Transaction, P>,
|
||||||
key: &Zeroizing<<Ristretto as Ciphersuite>::F>,
|
key: &Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
mut tx: Transaction,
|
mut tx: Transaction,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// If this is a signed transaction, sign it
|
// If this is a signed transaction, sign it
|
||||||
@@ -213,7 +213,7 @@ async fn add_with_recognition_check<TD: DbTrait, P: P2p>(
|
|||||||
set: ExternalValidatorSet,
|
set: ExternalValidatorSet,
|
||||||
tributary_db: &mut TD,
|
tributary_db: &mut TD,
|
||||||
tributary: &Tributary<TD, Transaction, P>,
|
tributary: &Tributary<TD, Transaction, P>,
|
||||||
key: &Zeroizing<<Ristretto as Ciphersuite>::F>,
|
key: &Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
tx: Transaction,
|
tx: Transaction,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let kind = tx.kind();
|
let kind = tx.kind();
|
||||||
@@ -252,7 +252,7 @@ pub(crate) struct AddTributaryTransactionsTask<CD: DbTrait, TD: DbTrait, P: P2p>
|
|||||||
tributary_db: TD,
|
tributary_db: TD,
|
||||||
tributary: Tributary<TD, Transaction, P>,
|
tributary: Tributary<TD, Transaction, P>,
|
||||||
set: NewSetInformation,
|
set: NewSetInformation,
|
||||||
key: Zeroizing<<Ristretto as Ciphersuite>::F>,
|
key: Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
}
|
}
|
||||||
impl<CD: DbTrait, TD: DbTrait, P: P2p> ContinuallyRan for AddTributaryTransactionsTask<CD, TD, P> {
|
impl<CD: DbTrait, TD: DbTrait, P: P2p> ContinuallyRan for AddTributaryTransactionsTask<CD, TD, P> {
|
||||||
type Error = DoesNotError;
|
type Error = DoesNotError;
|
||||||
@@ -382,7 +382,7 @@ pub(crate) struct SignSlashReportTask<CD: DbTrait, TD: DbTrait, P: P2p> {
|
|||||||
tributary_db: TD,
|
tributary_db: TD,
|
||||||
tributary: Tributary<TD, Transaction, P>,
|
tributary: Tributary<TD, Transaction, P>,
|
||||||
set: NewSetInformation,
|
set: NewSetInformation,
|
||||||
key: Zeroizing<<Ristretto as Ciphersuite>::F>,
|
key: Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
}
|
}
|
||||||
impl<CD: DbTrait, TD: DbTrait, P: P2p> ContinuallyRan for SignSlashReportTask<CD, TD, P> {
|
impl<CD: DbTrait, TD: DbTrait, P: P2p> ContinuallyRan for SignSlashReportTask<CD, TD, P> {
|
||||||
type Error = DoesNotError;
|
type Error = DoesNotError;
|
||||||
@@ -470,7 +470,7 @@ pub(crate) async fn spawn_tributary<P: P2p>(
|
|||||||
p2p: P,
|
p2p: P,
|
||||||
p2p_add_tributary: &mpsc::UnboundedSender<(ExternalValidatorSet, Tributary<Db, Transaction, P>)>,
|
p2p_add_tributary: &mpsc::UnboundedSender<(ExternalValidatorSet, Tributary<Db, Transaction, P>)>,
|
||||||
set: NewSetInformation,
|
set: NewSetInformation,
|
||||||
serai_key: Zeroizing<<Ristretto as Ciphersuite>::F>,
|
serai_key: Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
) {
|
) {
|
||||||
// Don't spawn retired Tributaries
|
// Don't spawn retired Tributaries
|
||||||
if crate::db::RetiredTributary::get(&db, set.set.network).map(|session| session.0) >=
|
if crate::db::RetiredTributary::get(&db, set.set.network).map(|session| session.0) >=
|
||||||
@@ -490,7 +490,7 @@ pub(crate) async fn spawn_tributary<P: P2p>(
|
|||||||
|
|
||||||
let mut tributary_validators = Vec::with_capacity(set.validators.len());
|
let mut tributary_validators = Vec::with_capacity(set.validators.len());
|
||||||
for (validator, weight) in set.validators.iter().copied() {
|
for (validator, weight) in set.validators.iter().copied() {
|
||||||
let validator_key = <Ristretto as Ciphersuite>::read_G(&mut validator.0.as_slice())
|
let validator_key = <Ristretto as GroupIo>::read_G(&mut validator.0.as_slice())
|
||||||
.expect("Serai validator had an invalid public key");
|
.expect("Serai validator had an invalid public key");
|
||||||
let weight = u64::from(weight);
|
let weight = u64::from(weight);
|
||||||
tributary_validators.push((validator_key, weight));
|
tributary_validators.push((validator_key, weight));
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::collections::{VecDeque, HashSet};
|
use std::collections::{VecDeque, HashSet};
|
||||||
|
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use ciphersuite::{group::GroupEncoding, Ciphersuite};
|
use ciphersuite::{group::GroupEncoding, *};
|
||||||
|
|
||||||
use serai_db::{Get, DbTxn, Db};
|
use serai_db::{Get, DbTxn, Db};
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ pub(crate) struct Blockchain<D: Db, T: TransactionTrait> {
|
|||||||
|
|
||||||
block_number: u64,
|
block_number: u64,
|
||||||
tip: [u8; 32],
|
tip: [u8; 32],
|
||||||
participants: HashSet<<Ristretto as Ciphersuite>::G>,
|
participants: HashSet<<Ristretto as WrappedGroup>::G>,
|
||||||
|
|
||||||
provided: ProvidedTransactions<D, T>,
|
provided: ProvidedTransactions<D, T>,
|
||||||
mempool: Mempool<D, T>,
|
mempool: Mempool<D, T>,
|
||||||
@@ -56,7 +56,7 @@ impl<D: Db, T: TransactionTrait> Blockchain<D, T> {
|
|||||||
}
|
}
|
||||||
fn next_nonce_key(
|
fn next_nonce_key(
|
||||||
genesis: &[u8; 32],
|
genesis: &[u8; 32],
|
||||||
signer: &<Ristretto as Ciphersuite>::G,
|
signer: &<Ristretto as WrappedGroup>::G,
|
||||||
order: &[u8],
|
order: &[u8],
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
D::key(
|
D::key(
|
||||||
@@ -69,7 +69,7 @@ impl<D: Db, T: TransactionTrait> Blockchain<D, T> {
|
|||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
db: D,
|
db: D,
|
||||||
genesis: [u8; 32],
|
genesis: [u8; 32],
|
||||||
participants: &[<Ristretto as Ciphersuite>::G],
|
participants: &[<Ristretto as WrappedGroup>::G],
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut res = Self {
|
let mut res = Self {
|
||||||
db: Some(db.clone()),
|
db: Some(db.clone()),
|
||||||
@@ -196,7 +196,7 @@ impl<D: Db, T: TransactionTrait> Blockchain<D, T> {
|
|||||||
|
|
||||||
pub(crate) fn next_nonce(
|
pub(crate) fn next_nonce(
|
||||||
&self,
|
&self,
|
||||||
signer: &<Ristretto as Ciphersuite>::G,
|
signer: &<Ristretto as WrappedGroup>::G,
|
||||||
order: &[u8],
|
order: &[u8],
|
||||||
) -> Option<u32> {
|
) -> Option<u32> {
|
||||||
if let Some(next_nonce) = self.mempool.next_nonce_in_mempool(signer, order.to_vec()) {
|
if let Some(next_nonce) = self.mempool.next_nonce_in_mempool(signer, order.to_vec()) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::{sync::Arc, io};
|
|||||||
|
|
||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::*;
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
|
|
||||||
use scale::Decode;
|
use scale::Decode;
|
||||||
@@ -162,8 +162,8 @@ impl<D: Db, T: TransactionTrait, P: P2p> Tributary<D, T, P> {
|
|||||||
db: D,
|
db: D,
|
||||||
genesis: [u8; 32],
|
genesis: [u8; 32],
|
||||||
start_time: u64,
|
start_time: u64,
|
||||||
key: Zeroizing<<Ristretto as Ciphersuite>::F>,
|
key: Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
validators: Vec<(<Ristretto as Ciphersuite>::G, u64)>,
|
validators: Vec<(<Ristretto as WrappedGroup>::G, u64)>,
|
||||||
p2p: P,
|
p2p: P,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
log::info!("new Tributary with genesis {}", hex::encode(genesis));
|
log::info!("new Tributary with genesis {}", hex::encode(genesis));
|
||||||
@@ -235,7 +235,7 @@ impl<D: Db, T: TransactionTrait, P: P2p> Tributary<D, T, P> {
|
|||||||
|
|
||||||
pub async fn next_nonce(
|
pub async fn next_nonce(
|
||||||
&self,
|
&self,
|
||||||
signer: &<Ristretto as Ciphersuite>::G,
|
signer: &<Ristretto as WrappedGroup>::G,
|
||||||
order: &[u8],
|
order: &[u8],
|
||||||
) -> Option<u32> {
|
) -> Option<u32> {
|
||||||
self.network.blockchain.read().await.next_nonce(signer, order)
|
self.network.blockchain.read().await.next_nonce(signer, order)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::*;
|
||||||
|
|
||||||
use serai_db::{DbTxn, Db};
|
use serai_db::{DbTxn, Db};
|
||||||
|
|
||||||
@@ -21,9 +21,9 @@ pub(crate) struct Mempool<D: Db, T: TransactionTrait> {
|
|||||||
db: D,
|
db: D,
|
||||||
genesis: [u8; 32],
|
genesis: [u8; 32],
|
||||||
|
|
||||||
last_nonce_in_mempool: HashMap<(<Ristretto as Ciphersuite>::G, Vec<u8>), u32>,
|
last_nonce_in_mempool: HashMap<(<Ristretto as WrappedGroup>::G, Vec<u8>), u32>,
|
||||||
txs: HashMap<[u8; 32], Transaction<T>>,
|
txs: HashMap<[u8; 32], Transaction<T>>,
|
||||||
txs_per_signer: HashMap<<Ristretto as Ciphersuite>::G, u32>,
|
txs_per_signer: HashMap<<Ristretto as WrappedGroup>::G, u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: Db, T: TransactionTrait> Mempool<D, T> {
|
impl<D: Db, T: TransactionTrait> Mempool<D, T> {
|
||||||
@@ -107,7 +107,7 @@ impl<D: Db, T: TransactionTrait> Mempool<D, T> {
|
|||||||
// Returns Ok(true) if new, Ok(false) if an already present unsigned, or the error.
|
// Returns Ok(true) if new, Ok(false) if an already present unsigned, or the error.
|
||||||
pub(crate) fn add<
|
pub(crate) fn add<
|
||||||
N: Network,
|
N: Network,
|
||||||
F: FnOnce(<Ristretto as Ciphersuite>::G, Vec<u8>) -> Option<u32>,
|
F: FnOnce(<Ristretto as WrappedGroup>::G, Vec<u8>) -> Option<u32>,
|
||||||
>(
|
>(
|
||||||
&mut self,
|
&mut self,
|
||||||
blockchain_next_nonce: F,
|
blockchain_next_nonce: F,
|
||||||
@@ -179,7 +179,7 @@ impl<D: Db, T: TransactionTrait> Mempool<D, T> {
|
|||||||
// Returns None if the mempool doesn't have a nonce tracked.
|
// Returns None if the mempool doesn't have a nonce tracked.
|
||||||
pub(crate) fn next_nonce_in_mempool(
|
pub(crate) fn next_nonce_in_mempool(
|
||||||
&self,
|
&self,
|
||||||
signer: &<Ristretto as Ciphersuite>::G,
|
signer: &<Ristretto as WrappedGroup>::G,
|
||||||
order: Vec<u8>,
|
order: Vec<u8>,
|
||||||
) -> Option<u32> {
|
) -> Option<u32> {
|
||||||
self.last_nonce_in_mempool.get(&(*signer, order)).copied().map(|nonce| nonce + 1)
|
self.last_nonce_in_mempool.get(&(*signer, order)).copied().map(|nonce| nonce + 1)
|
||||||
|
|||||||
@@ -10,11 +10,8 @@ use rand_chacha::ChaCha12Rng;
|
|||||||
use transcript::{Transcript, RecommendedTranscript};
|
use transcript::{Transcript, RecommendedTranscript};
|
||||||
|
|
||||||
use ciphersuite::{
|
use ciphersuite::{
|
||||||
group::{
|
group::{ff::PrimeField, GroupEncoding},
|
||||||
GroupEncoding,
|
*,
|
||||||
ff::{Field, PrimeField},
|
|
||||||
},
|
|
||||||
Ciphersuite,
|
|
||||||
};
|
};
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use schnorr::{
|
use schnorr::{
|
||||||
@@ -51,24 +48,26 @@ fn challenge(
|
|||||||
key: [u8; 32],
|
key: [u8; 32],
|
||||||
nonce: &[u8],
|
nonce: &[u8],
|
||||||
msg: &[u8],
|
msg: &[u8],
|
||||||
) -> <Ristretto as Ciphersuite>::F {
|
) -> <Ristretto as WrappedGroup>::F {
|
||||||
let mut transcript = RecommendedTranscript::new(b"Tributary Chain Tendermint Message");
|
let mut transcript = RecommendedTranscript::new(b"Tributary Chain Tendermint Message");
|
||||||
transcript.append_message(b"genesis", genesis);
|
transcript.append_message(b"genesis", genesis);
|
||||||
transcript.append_message(b"key", key);
|
transcript.append_message(b"key", key);
|
||||||
transcript.append_message(b"nonce", nonce);
|
transcript.append_message(b"nonce", nonce);
|
||||||
transcript.append_message(b"message", msg);
|
transcript.append_message(b"message", msg);
|
||||||
|
|
||||||
<Ristretto as Ciphersuite>::F::from_bytes_mod_order_wide(&transcript.challenge(b"schnorr").into())
|
<Ristretto as WrappedGroup>::F::from_bytes_mod_order_wide(
|
||||||
|
&transcript.challenge(b"schnorr").into(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct Signer {
|
pub struct Signer {
|
||||||
genesis: [u8; 32],
|
genesis: [u8; 32],
|
||||||
key: Zeroizing<<Ristretto as Ciphersuite>::F>,
|
key: Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Signer {
|
impl Signer {
|
||||||
pub(crate) fn new(genesis: [u8; 32], key: Zeroizing<<Ristretto as Ciphersuite>::F>) -> Signer {
|
pub(crate) fn new(genesis: [u8; 32], key: Zeroizing<<Ristretto as WrappedGroup>::F>) -> Signer {
|
||||||
Signer { genesis, key }
|
Signer { genesis, key }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,10 +100,10 @@ impl SignerTrait for Signer {
|
|||||||
assert_eq!(nonce_ref, [0; 64].as_ref());
|
assert_eq!(nonce_ref, [0; 64].as_ref());
|
||||||
|
|
||||||
let nonce =
|
let nonce =
|
||||||
Zeroizing::new(<Ristretto as Ciphersuite>::F::from_bytes_mod_order_wide(&nonce_arr));
|
Zeroizing::new(<Ristretto as WrappedGroup>::F::from_bytes_mod_order_wide(&nonce_arr));
|
||||||
nonce_arr.zeroize();
|
nonce_arr.zeroize();
|
||||||
|
|
||||||
assert!(!bool::from(nonce.ct_eq(&<Ristretto as Ciphersuite>::F::ZERO)));
|
assert!(!bool::from(nonce.ct_eq(&<Ristretto as WrappedGroup>::F::ZERO)));
|
||||||
|
|
||||||
let challenge = challenge(
|
let challenge = challenge(
|
||||||
self.genesis,
|
self.genesis,
|
||||||
@@ -133,7 +132,7 @@ pub struct Validators {
|
|||||||
impl Validators {
|
impl Validators {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
genesis: [u8; 32],
|
genesis: [u8; 32],
|
||||||
validators: Vec<(<Ristretto as Ciphersuite>::G, u64)>,
|
validators: Vec<(<Ristretto as WrappedGroup>::G, u64)>,
|
||||||
) -> Option<Validators> {
|
) -> Option<Validators> {
|
||||||
let mut total_weight = 0;
|
let mut total_weight = 0;
|
||||||
let mut weights = HashMap::new();
|
let mut weights = HashMap::new();
|
||||||
@@ -220,7 +219,7 @@ impl SignatureScheme for Validators {
|
|||||||
signers
|
signers
|
||||||
.iter()
|
.iter()
|
||||||
.zip(challenges)
|
.zip(challenges)
|
||||||
.map(|(s, c)| (<Ristretto as Ciphersuite>::read_G(&mut s.as_slice()).unwrap(), c))
|
.map(|(s, c)| (<Ristretto as GroupIo>::read_G(&mut s.as_slice()).unwrap(), c))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.as_slice(),
|
.as_slice(),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use scale::{Encode, Decode, IoReader};
|
|||||||
use blake2::{Digest, Blake2s256};
|
use blake2::{Digest, Blake2s256};
|
||||||
|
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
transaction::{Transaction, TransactionKind, TransactionError},
|
transaction::{Transaction, TransactionKind, TransactionError},
|
||||||
@@ -50,7 +50,7 @@ impl Transaction for TendermintTx {
|
|||||||
Blake2s256::digest(self.serialize()).into()
|
Blake2s256::digest(self.serialize()).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sig_hash(&self, _genesis: [u8; 32]) -> <Ristretto as Ciphersuite>::F {
|
fn sig_hash(&self, _genesis: [u8; 32]) -> <Ristretto as WrappedGroup>::F {
|
||||||
match self {
|
match self {
|
||||||
TendermintTx::SlashEvidence(_) => panic!("sig_hash called on slash evidence transaction"),
|
TendermintTx::SlashEvidence(_) => panic!("sig_hash called on slash evidence transaction"),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,7 @@ use std::{sync::Arc, io, collections::HashMap, fmt::Debug};
|
|||||||
use blake2::{Digest, Blake2s256};
|
use blake2::{Digest, Blake2s256};
|
||||||
|
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use ciphersuite::{
|
use ciphersuite::{group::Group, *};
|
||||||
group::{ff::Field, Group},
|
|
||||||
Ciphersuite,
|
|
||||||
};
|
|
||||||
use schnorr::SchnorrSignature;
|
use schnorr::SchnorrSignature;
|
||||||
|
|
||||||
use serai_db::MemDb;
|
use serai_db::MemDb;
|
||||||
@@ -32,11 +29,11 @@ impl NonceTransaction {
|
|||||||
nonce,
|
nonce,
|
||||||
distinguisher,
|
distinguisher,
|
||||||
Signed {
|
Signed {
|
||||||
signer: <Ristretto as Ciphersuite>::G::identity(),
|
signer: <Ristretto as WrappedGroup>::G::identity(),
|
||||||
nonce,
|
nonce,
|
||||||
signature: SchnorrSignature::<Ristretto> {
|
signature: SchnorrSignature::<Ristretto> {
|
||||||
R: <Ristretto as Ciphersuite>::G::identity(),
|
R: <Ristretto as WrappedGroup>::G::identity(),
|
||||||
s: <Ristretto as Ciphersuite>::F::ZERO,
|
s: <Ristretto as WrappedGroup>::F::ZERO,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use rand::rngs::OsRng;
|
|||||||
use blake2::{Digest, Blake2s256};
|
use blake2::{Digest, Blake2s256};
|
||||||
|
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use ciphersuite::{group::ff::Field, Ciphersuite};
|
use ciphersuite::*;
|
||||||
|
|
||||||
use serai_db::{DbTxn, Db, MemDb};
|
use serai_db::{DbTxn, Db, MemDb};
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ type N = TendermintNetwork<MemDb, SignedTransaction, DummyP2p>;
|
|||||||
|
|
||||||
fn new_blockchain<T: TransactionTrait>(
|
fn new_blockchain<T: TransactionTrait>(
|
||||||
genesis: [u8; 32],
|
genesis: [u8; 32],
|
||||||
participants: &[<Ristretto as Ciphersuite>::G],
|
participants: &[<Ristretto as WrappedGroup>::G],
|
||||||
) -> (MemDb, Blockchain<MemDb, T>) {
|
) -> (MemDb, Blockchain<MemDb, T>) {
|
||||||
let db = MemDb::new();
|
let db = MemDb::new();
|
||||||
let blockchain = Blockchain::new(db.clone(), genesis, participants);
|
let blockchain = Blockchain::new(db.clone(), genesis, participants);
|
||||||
@@ -82,7 +82,7 @@ fn invalid_block() {
|
|||||||
assert!(blockchain.verify_block::<N>(&block, &validators, false).is_err());
|
assert!(blockchain.verify_block::<N>(&block, &validators, false).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
let key = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng));
|
let key = Zeroizing::new(<Ristretto as WrappedGroup>::F::random(&mut OsRng));
|
||||||
let tx = crate::tests::signed_transaction(&mut OsRng, genesis, &key, 0);
|
let tx = crate::tests::signed_transaction(&mut OsRng, genesis, &key, 0);
|
||||||
|
|
||||||
// Not a participant
|
// Not a participant
|
||||||
@@ -134,7 +134,7 @@ fn invalid_block() {
|
|||||||
blockchain.verify_block::<N>(&block, &validators, false).unwrap();
|
blockchain.verify_block::<N>(&block, &validators, false).unwrap();
|
||||||
match &mut block.transactions[0] {
|
match &mut block.transactions[0] {
|
||||||
Transaction::Application(tx) => {
|
Transaction::Application(tx) => {
|
||||||
tx.1.signature.s += <Ristretto as Ciphersuite>::F::ONE;
|
tx.1.signature.s += <Ristretto as WrappedGroup>::F::ONE;
|
||||||
}
|
}
|
||||||
_ => panic!("non-signed tx found"),
|
_ => panic!("non-signed tx found"),
|
||||||
}
|
}
|
||||||
@@ -150,7 +150,7 @@ fn invalid_block() {
|
|||||||
fn signed_transaction() {
|
fn signed_transaction() {
|
||||||
let genesis = new_genesis();
|
let genesis = new_genesis();
|
||||||
let validators = Arc::new(Validators::new(genesis, vec![]).unwrap());
|
let validators = Arc::new(Validators::new(genesis, vec![]).unwrap());
|
||||||
let key = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng));
|
let key = Zeroizing::new(<Ristretto as WrappedGroup>::F::random(&mut OsRng));
|
||||||
let tx = crate::tests::signed_transaction(&mut OsRng, genesis, &key, 0);
|
let tx = crate::tests::signed_transaction(&mut OsRng, genesis, &key, 0);
|
||||||
let signer = tx.1.signer;
|
let signer = tx.1.signer;
|
||||||
|
|
||||||
@@ -339,7 +339,7 @@ fn provided_transaction() {
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn tendermint_evidence_tx() {
|
async fn tendermint_evidence_tx() {
|
||||||
let genesis = new_genesis();
|
let genesis = new_genesis();
|
||||||
let key = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng));
|
let key = Zeroizing::new(<Ristretto as WrappedGroup>::F::random(&mut OsRng));
|
||||||
let signer = Signer::new(genesis, key.clone());
|
let signer = Signer::new(genesis, key.clone());
|
||||||
let signer_id = Ristretto::generator() * key.deref();
|
let signer_id = Ristretto::generator() * key.deref();
|
||||||
let validators = Arc::new(Validators::new(genesis, vec![(signer_id, 1)]).unwrap());
|
let validators = Arc::new(Validators::new(genesis, vec![(signer_id, 1)]).unwrap());
|
||||||
@@ -379,7 +379,7 @@ async fn tendermint_evidence_tx() {
|
|||||||
let mut mempool: Vec<Transaction<SignedTransaction>> = vec![];
|
let mut mempool: Vec<Transaction<SignedTransaction>> = vec![];
|
||||||
let mut signers = vec![];
|
let mut signers = vec![];
|
||||||
for _ in 0 .. 5 {
|
for _ in 0 .. 5 {
|
||||||
let key = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng));
|
let key = Zeroizing::new(<Ristretto as WrappedGroup>::F::random(&mut OsRng));
|
||||||
let signer = Signer::new(genesis, key.clone());
|
let signer = Signer::new(genesis, key.clone());
|
||||||
let signer_id = Ristretto::generator() * key.deref();
|
let signer_id = Ristretto::generator() * key.deref();
|
||||||
signers.push((signer_id, 1));
|
signers.push((signer_id, 1));
|
||||||
@@ -446,7 +446,7 @@ async fn block_tx_ordering() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let genesis = new_genesis();
|
let genesis = new_genesis();
|
||||||
let key = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng));
|
let key = Zeroizing::new(<Ristretto as WrappedGroup>::F::random(&mut OsRng));
|
||||||
|
|
||||||
// signer
|
// signer
|
||||||
let signer = crate::tests::signed_transaction(&mut OsRng, genesis, &key, 0).1.signer;
|
let signer = crate::tests::signed_transaction(&mut OsRng, genesis, &key, 0).1.signer;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use zeroize::Zeroizing;
|
|||||||
use rand::{RngCore, rngs::OsRng};
|
use rand::{RngCore, rngs::OsRng};
|
||||||
|
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use ciphersuite::{group::ff::Field, Ciphersuite};
|
use ciphersuite::*;
|
||||||
|
|
||||||
use tendermint::ext::Commit;
|
use tendermint::ext::Commit;
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ async fn mempool_addition() {
|
|||||||
Some(Commit::<Arc<Validators>> { end_time: 0, validators: vec![], signature: vec![] })
|
Some(Commit::<Arc<Validators>> { end_time: 0, validators: vec![], signature: vec![] })
|
||||||
};
|
};
|
||||||
let unsigned_in_chain = |_: [u8; 32]| false;
|
let unsigned_in_chain = |_: [u8; 32]| false;
|
||||||
let key = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng));
|
let key = Zeroizing::new(<Ristretto as WrappedGroup>::F::random(&mut OsRng));
|
||||||
|
|
||||||
let first_tx = signed_transaction(&mut OsRng, genesis, &key, 0);
|
let first_tx = signed_transaction(&mut OsRng, genesis, &key, 0);
|
||||||
let signer = first_tx.1.signer;
|
let signer = first_tx.1.signer;
|
||||||
@@ -125,7 +125,7 @@ async fn mempool_addition() {
|
|||||||
|
|
||||||
// If the mempool doesn't have a nonce for an account, it should successfully use the
|
// If the mempool doesn't have a nonce for an account, it should successfully use the
|
||||||
// blockchain's
|
// blockchain's
|
||||||
let second_key = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng));
|
let second_key = Zeroizing::new(<Ristretto as WrappedGroup>::F::random(&mut OsRng));
|
||||||
let tx = signed_transaction(&mut OsRng, genesis, &second_key, 2);
|
let tx = signed_transaction(&mut OsRng, genesis, &second_key, 2);
|
||||||
let second_signer = tx.1.signer;
|
let second_signer = tx.1.signer;
|
||||||
assert_eq!(mempool.next_nonce_in_mempool(&second_signer, vec![]), None);
|
assert_eq!(mempool.next_nonce_in_mempool(&second_signer, vec![]), None);
|
||||||
@@ -165,7 +165,7 @@ fn too_many_mempool() {
|
|||||||
Some(Commit::<Arc<Validators>> { end_time: 0, validators: vec![], signature: vec![] })
|
Some(Commit::<Arc<Validators>> { end_time: 0, validators: vec![], signature: vec![] })
|
||||||
};
|
};
|
||||||
let unsigned_in_chain = |_: [u8; 32]| false;
|
let unsigned_in_chain = |_: [u8; 32]| false;
|
||||||
let key = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng));
|
let key = Zeroizing::new(<Ristretto as WrappedGroup>::F::random(&mut OsRng));
|
||||||
|
|
||||||
// We should be able to add transactions up to the limit
|
// We should be able to add transactions up to the limit
|
||||||
for i in 0 .. ACCOUNT_MEMPOOL_LIMIT {
|
for i in 0 .. ACCOUNT_MEMPOOL_LIMIT {
|
||||||
|
|||||||
@@ -7,10 +7,7 @@ use rand::{RngCore, CryptoRng, rngs::OsRng};
|
|||||||
use blake2::{Digest, Blake2s256};
|
use blake2::{Digest, Blake2s256};
|
||||||
|
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use ciphersuite::{
|
use ciphersuite::{group::Group, *};
|
||||||
group::{ff::Field, Group},
|
|
||||||
Ciphersuite,
|
|
||||||
};
|
|
||||||
use schnorr::SchnorrSignature;
|
use schnorr::SchnorrSignature;
|
||||||
|
|
||||||
use scale::Encode;
|
use scale::Encode;
|
||||||
@@ -34,11 +31,11 @@ mod tendermint;
|
|||||||
|
|
||||||
pub fn random_signed<R: RngCore + CryptoRng>(rng: &mut R) -> Signed {
|
pub fn random_signed<R: RngCore + CryptoRng>(rng: &mut R) -> Signed {
|
||||||
Signed {
|
Signed {
|
||||||
signer: <Ristretto as Ciphersuite>::G::random(&mut *rng),
|
signer: <Ristretto as WrappedGroup>::G::random(&mut *rng),
|
||||||
nonce: u32::try_from(rng.next_u64() >> 32 >> 1).unwrap(),
|
nonce: u32::try_from(rng.next_u64() >> 32 >> 1).unwrap(),
|
||||||
signature: SchnorrSignature::<Ristretto> {
|
signature: SchnorrSignature::<Ristretto> {
|
||||||
R: <Ristretto as Ciphersuite>::G::random(&mut *rng),
|
R: <Ristretto as WrappedGroup>::G::random(&mut *rng),
|
||||||
s: <Ristretto as Ciphersuite>::F::random(rng),
|
s: <Ristretto as WrappedGroup>::F::random(rng),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,18 +134,18 @@ impl Transaction for SignedTransaction {
|
|||||||
pub fn signed_transaction<R: RngCore + CryptoRng>(
|
pub fn signed_transaction<R: RngCore + CryptoRng>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
genesis: [u8; 32],
|
genesis: [u8; 32],
|
||||||
key: &Zeroizing<<Ristretto as Ciphersuite>::F>,
|
key: &Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
nonce: u32,
|
nonce: u32,
|
||||||
) -> SignedTransaction {
|
) -> SignedTransaction {
|
||||||
let mut data = vec![0; 512];
|
let mut data = vec![0; 512];
|
||||||
rng.fill_bytes(&mut data);
|
rng.fill_bytes(&mut data);
|
||||||
|
|
||||||
let signer = <Ristretto as Ciphersuite>::generator() * **key;
|
let signer = <Ristretto as WrappedGroup>::generator() * **key;
|
||||||
|
|
||||||
let mut tx =
|
let mut tx =
|
||||||
SignedTransaction(data, Signed { signer, nonce, signature: random_signed(rng).signature });
|
SignedTransaction(data, Signed { signer, nonce, signature: random_signed(rng).signature });
|
||||||
|
|
||||||
let sig_nonce = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(rng));
|
let sig_nonce = Zeroizing::new(<Ristretto as WrappedGroup>::F::random(rng));
|
||||||
tx.1.signature.R = Ristretto::generator() * sig_nonce.deref();
|
tx.1.signature.R = Ristretto::generator() * sig_nonce.deref();
|
||||||
tx.1.signature = SchnorrSignature::sign(key, sig_nonce, tx.sig_hash(genesis));
|
tx.1.signature = SchnorrSignature::sign(key, sig_nonce, tx.sig_hash(genesis));
|
||||||
|
|
||||||
@@ -163,7 +160,7 @@ pub fn random_signed_transaction<R: RngCore + CryptoRng>(
|
|||||||
let mut genesis = [0; 32];
|
let mut genesis = [0; 32];
|
||||||
rng.fill_bytes(&mut genesis);
|
rng.fill_bytes(&mut genesis);
|
||||||
|
|
||||||
let key = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut *rng));
|
let key = Zeroizing::new(<Ristretto as WrappedGroup>::F::random(&mut *rng));
|
||||||
// Shift over an additional bit to ensure it won't overflow when incremented
|
// Shift over an additional bit to ensure it won't overflow when incremented
|
||||||
let nonce = u32::try_from(rng.next_u64() >> 32 >> 1).unwrap();
|
let nonce = u32::try_from(rng.next_u64() >> 32 >> 1).unwrap();
|
||||||
|
|
||||||
@@ -180,12 +177,11 @@ pub async fn tendermint_meta() -> ([u8; 32], Signer, [u8; 32], Arc<Validators>)
|
|||||||
// signer
|
// signer
|
||||||
let genesis = new_genesis();
|
let genesis = new_genesis();
|
||||||
let signer =
|
let signer =
|
||||||
Signer::new(genesis, Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng)));
|
Signer::new(genesis, Zeroizing::new(<Ristretto as WrappedGroup>::F::random(&mut OsRng)));
|
||||||
let validator_id = signer.validator_id().await.unwrap();
|
let validator_id = signer.validator_id().await.unwrap();
|
||||||
|
|
||||||
// schema
|
// schema
|
||||||
let signer_pub =
|
let signer_pub = <Ristretto as GroupIo>::read_G::<&[u8]>(&mut validator_id.as_slice()).unwrap();
|
||||||
<Ristretto as Ciphersuite>::read_G::<&[u8]>(&mut validator_id.as_slice()).unwrap();
|
|
||||||
let validators = Arc::new(Validators::new(genesis, vec![(signer_pub, 1)]).unwrap());
|
let validators = Arc::new(Validators::new(genesis, vec![(signer_pub, 1)]).unwrap());
|
||||||
|
|
||||||
(genesis, signer, validator_id, validators)
|
(genesis, signer, validator_id, validators)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use rand::rngs::OsRng;
|
|||||||
use blake2::{Digest, Blake2s256};
|
use blake2::{Digest, Blake2s256};
|
||||||
|
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use ciphersuite::{group::ff::Field, Ciphersuite};
|
use ciphersuite::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ReadWrite,
|
ReadWrite,
|
||||||
@@ -69,7 +69,7 @@ fn signed_transaction() {
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
let mut tx = tx.clone();
|
let mut tx = tx.clone();
|
||||||
tx.1.signature.s += <Ristretto as Ciphersuite>::F::ONE;
|
tx.1.signature.s += <Ristretto as WrappedGroup>::F::ONE;
|
||||||
assert!(verify_transaction(&tx, genesis, &mut |_, _| Some(tx.1.nonce)).is_err());
|
assert!(verify_transaction(&tx, genesis, &mut |_, _| Some(tx.1.nonce)).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use zeroize::Zeroizing;
|
|||||||
use rand::{RngCore, rngs::OsRng};
|
use rand::{RngCore, rngs::OsRng};
|
||||||
|
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use ciphersuite::{Ciphersuite, group::ff::Field};
|
use ciphersuite::*;
|
||||||
|
|
||||||
use scale::Encode;
|
use scale::Encode;
|
||||||
|
|
||||||
@@ -261,7 +261,7 @@ async fn conflicting_msgs_evidence_tx() {
|
|||||||
let signed_1 = signed_for_b_r(0, 0, Data::Proposal(None, TendermintBlock(vec![0x11]))).await;
|
let signed_1 = signed_for_b_r(0, 0, Data::Proposal(None, TendermintBlock(vec![0x11]))).await;
|
||||||
|
|
||||||
let signer_2 =
|
let signer_2 =
|
||||||
Signer::new(genesis, Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng)));
|
Signer::new(genesis, Zeroizing::new(<Ristretto as WrappedGroup>::F::random(&mut OsRng)));
|
||||||
let signed_id_2 = signer_2.validator_id().await.unwrap();
|
let signed_id_2 = signer_2.validator_id().await.unwrap();
|
||||||
let signed_2 = signed_from_data::<N>(
|
let signed_2 = signed_from_data::<N>(
|
||||||
signer_2.into(),
|
signer_2.into(),
|
||||||
@@ -278,10 +278,9 @@ async fn conflicting_msgs_evidence_tx() {
|
|||||||
));
|
));
|
||||||
|
|
||||||
// update schema so that we don't fail due to invalid signature
|
// update schema so that we don't fail due to invalid signature
|
||||||
let signer_pub =
|
let signer_pub = <Ristretto as GroupIo>::read_G::<&[u8]>(&mut signer_id.as_slice()).unwrap();
|
||||||
<Ristretto as Ciphersuite>::read_G::<&[u8]>(&mut signer_id.as_slice()).unwrap();
|
|
||||||
let signer_pub_2 =
|
let signer_pub_2 =
|
||||||
<Ristretto as Ciphersuite>::read_G::<&[u8]>(&mut signed_id_2.as_slice()).unwrap();
|
<Ristretto as GroupIo>::read_G::<&[u8]>(&mut signed_id_2.as_slice()).unwrap();
|
||||||
let validators =
|
let validators =
|
||||||
Arc::new(Validators::new(genesis, vec![(signer_pub, 1), (signer_pub_2, 1)]).unwrap());
|
Arc::new(Validators::new(genesis, vec![(signer_pub, 1), (signer_pub_2, 1)]).unwrap());
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use blake2::{Digest, Blake2b512};
|
|||||||
|
|
||||||
use ciphersuite::{
|
use ciphersuite::{
|
||||||
group::{Group, GroupEncoding},
|
group::{Group, GroupEncoding},
|
||||||
Ciphersuite,
|
*,
|
||||||
};
|
};
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use schnorr::SchnorrSignature;
|
use schnorr::SchnorrSignature;
|
||||||
@@ -43,7 +43,7 @@ pub enum TransactionError {
|
|||||||
/// Data for a signed transaction.
|
/// Data for a signed transaction.
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct Signed {
|
pub struct Signed {
|
||||||
pub signer: <Ristretto as Ciphersuite>::G,
|
pub signer: <Ristretto as WrappedGroup>::G,
|
||||||
pub nonce: u32,
|
pub nonce: u32,
|
||||||
pub signature: SchnorrSignature<Ristretto>,
|
pub signature: SchnorrSignature<Ristretto>,
|
||||||
}
|
}
|
||||||
@@ -160,10 +160,10 @@ pub trait Transaction: 'static + Send + Sync + Clone + Eq + Debug + ReadWrite {
|
|||||||
/// Do not override this unless you know what you're doing.
|
/// Do not override this unless you know what you're doing.
|
||||||
///
|
///
|
||||||
/// Panics if called on non-signed transactions.
|
/// Panics if called on non-signed transactions.
|
||||||
fn sig_hash(&self, genesis: [u8; 32]) -> <Ristretto as Ciphersuite>::F {
|
fn sig_hash(&self, genesis: [u8; 32]) -> <Ristretto as WrappedGroup>::F {
|
||||||
match self.kind() {
|
match self.kind() {
|
||||||
TransactionKind::Signed(order, Signed { signature, .. }) => {
|
TransactionKind::Signed(order, Signed { signature, .. }) => {
|
||||||
<Ristretto as Ciphersuite>::F::from_bytes_mod_order_wide(
|
<Ristretto as WrappedGroup>::F::from_bytes_mod_order_wide(
|
||||||
&Blake2b512::digest(
|
&Blake2b512::digest(
|
||||||
[
|
[
|
||||||
b"Tributary Signed Transaction",
|
b"Tributary Signed Transaction",
|
||||||
@@ -182,8 +182,8 @@ pub trait Transaction: 'static + Send + Sync + Clone + Eq + Debug + ReadWrite {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait GAIN: FnMut(&<Ristretto as Ciphersuite>::G, &[u8]) -> Option<u32> {}
|
pub trait GAIN: FnMut(&<Ristretto as WrappedGroup>::G, &[u8]) -> Option<u32> {}
|
||||||
impl<F: FnMut(&<Ristretto as Ciphersuite>::G, &[u8]) -> Option<u32>> GAIN for F {}
|
impl<F: FnMut(&<Ristretto as WrappedGroup>::G, &[u8]) -> Option<u32>> GAIN for F {}
|
||||||
|
|
||||||
pub(crate) fn verify_transaction<F: GAIN, T: Transaction>(
|
pub(crate) fn verify_transaction<F: GAIN, T: Transaction>(
|
||||||
tx: &T,
|
tx: &T,
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ use rand_core::{RngCore, CryptoRng};
|
|||||||
|
|
||||||
use blake2::{digest::typenum::U32, Digest, Blake2b};
|
use blake2::{digest::typenum::U32, Digest, Blake2b};
|
||||||
use ciphersuite::{
|
use ciphersuite::{
|
||||||
group::{ff::Field, Group, GroupEncoding},
|
group::{Group, GroupEncoding},
|
||||||
Ciphersuite,
|
*,
|
||||||
};
|
};
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use schnorr::SchnorrSignature;
|
use schnorr::SchnorrSignature;
|
||||||
@@ -52,7 +52,7 @@ impl SigningProtocolRound {
|
|||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
pub struct Signed {
|
pub struct Signed {
|
||||||
/// The signer.
|
/// The signer.
|
||||||
signer: <Ristretto as Ciphersuite>::G,
|
signer: <Ristretto as WrappedGroup>::G,
|
||||||
/// The signature.
|
/// The signature.
|
||||||
signature: SchnorrSignature<Ristretto>,
|
signature: SchnorrSignature<Ristretto>,
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,7 @@ impl BorshDeserialize for Signed {
|
|||||||
|
|
||||||
impl Signed {
|
impl Signed {
|
||||||
/// Fetch the signer.
|
/// Fetch the signer.
|
||||||
pub(crate) fn signer(&self) -> <Ristretto as Ciphersuite>::G {
|
pub(crate) fn signer(&self) -> <Ristretto as WrappedGroup>::G {
|
||||||
self.signer
|
self.signer
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,10 +86,10 @@ impl Signed {
|
|||||||
impl Default for Signed {
|
impl Default for Signed {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
signer: <Ristretto as Ciphersuite>::G::identity(),
|
signer: <Ristretto as WrappedGroup>::G::identity(),
|
||||||
signature: SchnorrSignature {
|
signature: SchnorrSignature {
|
||||||
R: <Ristretto as Ciphersuite>::G::identity(),
|
R: <Ristretto as WrappedGroup>::G::identity(),
|
||||||
s: <Ristretto as Ciphersuite>::F::ZERO,
|
s: <Ristretto as WrappedGroup>::F::ZERO,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,7 +356,7 @@ impl Transaction {
|
|||||||
&mut self,
|
&mut self,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
genesis: [u8; 32],
|
genesis: [u8; 32],
|
||||||
key: &Zeroizing<<Ristretto as Ciphersuite>::F>,
|
key: &Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
) {
|
) {
|
||||||
fn signed(tx: &mut Transaction) -> &mut Signed {
|
fn signed(tx: &mut Transaction) -> &mut Signed {
|
||||||
#[allow(clippy::match_same_arms)] // This doesn't make semantic sense here
|
#[allow(clippy::match_same_arms)] // This doesn't make semantic sense here
|
||||||
@@ -380,13 +380,13 @@ impl Transaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Decide the nonce to sign with
|
// Decide the nonce to sign with
|
||||||
let sig_nonce = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(rng));
|
let sig_nonce = Zeroizing::new(<Ristretto as WrappedGroup>::F::random(rng));
|
||||||
|
|
||||||
{
|
{
|
||||||
// Set the signer and the nonce
|
// Set the signer and the nonce
|
||||||
let signed = signed(self);
|
let signed = signed(self);
|
||||||
signed.signer = Ristretto::generator() * key.deref();
|
signed.signer = Ristretto::generator() * key.deref();
|
||||||
signed.signature.R = <Ristretto as Ciphersuite>::generator() * sig_nonce.deref();
|
signed.signature.R = <Ristretto as WrappedGroup>::generator() * sig_nonce.deref();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the signature hash (which now includes `R || A` making it valid as the challenge)
|
// Get the signature hash (which now includes `R || A` making it valid as the challenge)
|
||||||
|
|||||||
@@ -17,15 +17,12 @@ rustdoc-args = ["--cfg", "docsrs"]
|
|||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
std-shims = { path = "../../common/std-shims", version = "^0.1.1", default-features = false, optional = true }
|
std-shims = { path = "../../common/std-shims", version = "0.1.4", default-features = false, optional = true }
|
||||||
|
|
||||||
rand_core = { version = "0.6", default-features = false }
|
|
||||||
|
|
||||||
zeroize = { version = "^1.5", default-features = false, features = ["derive"] }
|
zeroize = { version = "^1.5", default-features = false, features = ["derive"] }
|
||||||
subtle = { version = "^2.4", default-features = false }
|
subtle = { version = "^2.4", default-features = false }
|
||||||
|
|
||||||
digest = { version = "0.11.0-rc.0", default-features = false, features = ["block-api"] }
|
digest = { version = "0.11.0-rc.1", default-features = false }
|
||||||
transcript = { package = "flexible-transcript", path = "../transcript", version = "^0.3.2", default-features = false }
|
|
||||||
|
|
||||||
ff = { version = "0.13", default-features = false, features = ["bits"] }
|
ff = { version = "0.13", default-features = false, features = ["bits"] }
|
||||||
group = { version = "0.13", default-features = false }
|
group = { version = "0.13", default-features = false }
|
||||||
@@ -33,24 +30,18 @@ group = { version = "0.13", default-features = false }
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
hex = { version = "0.4", default-features = false, features = ["std"] }
|
hex = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
rand_core = { version = "0.6", default-features = false, features = ["std"] }
|
|
||||||
|
|
||||||
ff-group-tests = { version = "0.13", path = "../ff-group-tests" }
|
ff-group-tests = { version = "0.13", path = "../ff-group-tests" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
alloc = ["std-shims", "digest/alloc", "ff/alloc"]
|
alloc = ["std-shims", "zeroize/alloc", "digest/alloc", "ff/alloc"]
|
||||||
std = [
|
std = [
|
||||||
"alloc",
|
"alloc",
|
||||||
|
|
||||||
"std-shims/std",
|
"std-shims/std",
|
||||||
|
|
||||||
"rand_core/std",
|
|
||||||
|
|
||||||
"zeroize/std",
|
"zeroize/std",
|
||||||
"subtle/std",
|
"subtle/std",
|
||||||
|
|
||||||
"transcript/std",
|
|
||||||
|
|
||||||
"ff/std",
|
"ff/std",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ rand_core = { version = "0.6", default-features = false }
|
|||||||
|
|
||||||
zeroize = { version = "^1.5", default-features = false, features = ["derive"] }
|
zeroize = { version = "^1.5", default-features = false, features = ["derive"] }
|
||||||
|
|
||||||
sha2 = { version = "0.11.0-rc.0", default-features = false }
|
sha2 = { version = "0.11.0-rc.2", default-features = false }
|
||||||
|
|
||||||
p256 = { version = "^0.13.1", default-features = false, features = ["arithmetic", "bits", "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"] }
|
k256 = { version = "^0.13.1", default-features = false, features = ["arithmetic", "bits", "hash2curve"] }
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use zeroize::Zeroize;
|
|||||||
|
|
||||||
use sha2::Sha512;
|
use sha2::Sha512;
|
||||||
|
|
||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::{WrappedGroup, Id, WithPreferredHash, GroupCanonicalEncoding};
|
||||||
|
|
||||||
pub use k256;
|
pub use k256;
|
||||||
pub use p256;
|
pub use p256;
|
||||||
@@ -18,17 +18,20 @@ macro_rules! kp_curve {
|
|||||||
$Ciphersuite: ident,
|
$Ciphersuite: ident,
|
||||||
$ID: literal
|
$ID: literal
|
||||||
) => {
|
) => {
|
||||||
impl Ciphersuite for $Ciphersuite {
|
impl WrappedGroup for $Ciphersuite {
|
||||||
type F = $lib::Scalar;
|
type F = $lib::Scalar;
|
||||||
type G = $lib::ProjectivePoint;
|
type G = $lib::ProjectivePoint;
|
||||||
type H = Sha512;
|
|
||||||
|
|
||||||
const ID: &'static [u8] = $ID;
|
|
||||||
|
|
||||||
fn generator() -> Self::G {
|
fn generator() -> Self::G {
|
||||||
$lib::ProjectivePoint::GENERATOR
|
$lib::ProjectivePoint::GENERATOR
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Id for $Ciphersuite {
|
||||||
|
const ID: &'static [u8] = $ID;
|
||||||
|
}
|
||||||
|
impl WithPreferredHash for $Ciphersuite {
|
||||||
|
type H = Sha512;
|
||||||
|
}
|
||||||
|
impl GroupCanonicalEncoding for $Ciphersuite {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,22 +9,18 @@ use std_shims::prelude::*;
|
|||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
use std_shims::io::{self, Read};
|
use std_shims::io::{self, Read};
|
||||||
|
|
||||||
use rand_core::{RngCore, CryptoRng};
|
use subtle::{CtOption, ConstantTimeEq, ConditionallySelectable};
|
||||||
|
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
use subtle::ConstantTimeEq;
|
|
||||||
|
|
||||||
pub use digest;
|
pub use digest;
|
||||||
use digest::{array::ArraySize, block_api::BlockSizeUser, OutputSizeUser, Digest, HashMarker};
|
use digest::{array::ArraySize, OutputSizeUser, Digest, HashMarker};
|
||||||
use transcript::SecureDigest;
|
|
||||||
|
|
||||||
pub use group;
|
pub use group;
|
||||||
use group::{
|
use group::{
|
||||||
ff::{Field, PrimeField, PrimeFieldBits},
|
ff::{PrimeField, PrimeFieldBits},
|
||||||
Group, GroupOps,
|
Group, GroupOps,
|
||||||
prime::PrimeGroup,
|
prime::PrimeGroup,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
use group::GroupEncoding;
|
use group::GroupEncoding;
|
||||||
|
|
||||||
pub trait FromUniformBytes<T> {
|
pub trait FromUniformBytes<T> {
|
||||||
@@ -36,74 +32,118 @@ impl<const N: usize, F: group::ff::FromUniformBytes<N>> FromUniformBytes<[u8; N]
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unified trait defining a ciphersuite around an elliptic curve.
|
/// A marker trait for fields which fleshes them out a bit more.
|
||||||
pub trait Ciphersuite:
|
pub trait F: PrimeField + PrimeFieldBits + Zeroize {}
|
||||||
|
impl<Fi: PrimeField + PrimeFieldBits + Zeroize> F for Fi {}
|
||||||
|
/// A marker trait for groups which fleshes them out a bit more.
|
||||||
|
pub trait G:
|
||||||
|
Group + GroupOps + GroupEncoding + PrimeGroup + ConstantTimeEq + ConditionallySelectable + Zeroize
|
||||||
|
{
|
||||||
|
}
|
||||||
|
impl<
|
||||||
|
Gr: Group
|
||||||
|
+ GroupOps
|
||||||
|
+ GroupEncoding
|
||||||
|
+ PrimeGroup
|
||||||
|
+ ConstantTimeEq
|
||||||
|
+ ConditionallySelectable
|
||||||
|
+ Zeroize,
|
||||||
|
> G for Gr
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `Group` type which has been wrapped into the current type.
|
||||||
|
///
|
||||||
|
/// This avoids having to re-implement all of the `Group` traits on the wrapper.
|
||||||
|
// TODO: Remove these bounds
|
||||||
|
pub trait WrappedGroup:
|
||||||
'static + Send + Sync + Clone + Copy + PartialEq + Eq + Debug + Zeroize
|
'static + Send + Sync + Clone + Copy + PartialEq + Eq + Debug + Zeroize
|
||||||
{
|
{
|
||||||
/// Scalar field element type.
|
/// Scalar field element type.
|
||||||
// This is available via G::Scalar yet `C::G::Scalar` is ambiguous, forcing horrific accesses
|
// This is available via `G::Scalar` yet `WG::G::Scalar` is ambiguous, forcing horrific accesses
|
||||||
type F: PrimeField
|
type F: F;
|
||||||
+ PrimeFieldBits
|
|
||||||
+ Zeroize
|
|
||||||
+ FromUniformBytes<<<Self::H as OutputSizeUser>::OutputSize as ArraySize>::ArrayType<u8>>;
|
|
||||||
/// Group element type.
|
/// Group element type.
|
||||||
type G: Group<Scalar = Self::F> + GroupOps + PrimeGroup + Zeroize + ConstantTimeEq;
|
type G: Group<Scalar = Self::F> + G;
|
||||||
/// Hash algorithm used with this curve.
|
|
||||||
// Requires BlockSizeUser so it can be used within Hkdf which requires that.
|
|
||||||
type H: Send + Clone + BlockSizeUser + Digest + HashMarker + SecureDigest;
|
|
||||||
|
|
||||||
/// ID for this curve.
|
|
||||||
const ID: &'static [u8];
|
|
||||||
|
|
||||||
/// Generator for the group.
|
/// Generator for the group.
|
||||||
// While group does provide this in its API, privacy coins may want to use a custom basepoint
|
|
||||||
fn generator() -> Self::G;
|
fn generator() -> Self::G;
|
||||||
|
}
|
||||||
|
impl<Gr: G<Scalar: F>> WrappedGroup for Gr {
|
||||||
|
type F = <Gr as Group>::Scalar;
|
||||||
|
type G = Gr;
|
||||||
|
fn generator() -> Self::G {
|
||||||
|
<Self::G as Group>::generator()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An ID for an object.
|
||||||
|
pub trait Id {
|
||||||
|
// The ID.
|
||||||
|
const ID: &'static [u8];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A group with a preferred hash function.
|
||||||
|
pub trait WithPreferredHash:
|
||||||
|
WrappedGroup<
|
||||||
|
F: FromUniformBytes<<<Self::H as OutputSizeUser>::OutputSize as ArraySize>::ArrayType<u8>>,
|
||||||
|
>
|
||||||
|
{
|
||||||
|
type H: Send + Clone + Digest + HashMarker;
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn hash_to_F(data: &[u8]) -> Self::F {
|
fn hash_to_F(data: &[u8]) -> Self::F {
|
||||||
Self::F::from_uniform_bytes(&Self::H::digest(data).into())
|
Self::F::from_uniform_bytes(&Self::H::digest(data).into())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate a random non-zero scalar.
|
/// A group which always encodes points canonically and supports decoding points while checking
|
||||||
#[allow(non_snake_case)]
|
/// they have a canonical encoding.
|
||||||
fn random_nonzero_F<R: RngCore + CryptoRng>(rng: &mut R) -> Self::F {
|
pub trait GroupCanonicalEncoding: WrappedGroup {
|
||||||
let mut res;
|
/// Decode a point from its canonical encoding.
|
||||||
while {
|
|
||||||
res = Self::F::random(&mut *rng);
|
|
||||||
res.ct_eq(&Self::F::ZERO).into()
|
|
||||||
} {}
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read a canonical scalar from something implementing std::io::Read.
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
fn read_F<R: Read>(reader: &mut R) -> io::Result<Self::F> {
|
|
||||||
let mut encoding = <Self::F as PrimeField>::Repr::default();
|
|
||||||
reader.read_exact(encoding.as_mut())?;
|
|
||||||
|
|
||||||
// ff mandates this is canonical
|
|
||||||
let res = Option::<Self::F>::from(Self::F::from_repr(encoding))
|
|
||||||
.ok_or_else(|| io::Error::other("non-canonical scalar"));
|
|
||||||
encoding.as_mut().zeroize();
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read a canonical point from something implementing std::io::Read.
|
|
||||||
///
|
///
|
||||||
/// The provided implementation is safe so long as `GroupEncoding::to_bytes` always returns a
|
/// Returns `None` if the point was invalid or not the encoding wasn't canonical.
|
||||||
/// canonical serialization.
|
///
|
||||||
|
/// If `<Self::G as GroupEncoding>::from_bytes` already only accepts canonical encodings, this
|
||||||
|
/// SHOULD be overriden with `<Self::G as GroupEncoding>::from_bytes(bytes)`.
|
||||||
|
fn from_canonical_bytes(bytes: &<Self::G as GroupEncoding>::Repr) -> CtOption<Self::G> {
|
||||||
|
let res = Self::G::from_bytes(bytes).unwrap_or(Self::generator());
|
||||||
|
// Safe due to the bound points are always encoded canonically
|
||||||
|
let canonical = res.to_bytes().as_ref().ct_eq(bytes.as_ref());
|
||||||
|
CtOption::new(res, canonical)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `std::io` extensions for `GroupCanonicalEncoding.`
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub trait GroupIo: GroupCanonicalEncoding {
|
||||||
|
/// Read a canonical field element from something implementing `std::io::Read`.
|
||||||
|
fn read_F<R: Read>(reader: &mut R) -> io::Result<Self::F> {
|
||||||
|
let mut bytes = <Self::F as PrimeField>::Repr::default();
|
||||||
|
reader.read_exact(bytes.as_mut())?;
|
||||||
|
|
||||||
|
// `ff` mandates this is canonical
|
||||||
|
let res = Option::<Self::F>::from(Self::F::from_repr(bytes))
|
||||||
|
.ok_or_else(|| io::Error::other("non-canonical scalar"));
|
||||||
|
bytes.as_mut().zeroize();
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read a canonical point from something implementing `std::io::Read`.
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn read_G<R: Read>(reader: &mut R) -> io::Result<Self::G> {
|
fn read_G<R: Read>(reader: &mut R) -> io::Result<Self::G> {
|
||||||
let mut encoding = <Self::G as GroupEncoding>::Repr::default();
|
let mut bytes = <Self::G as GroupEncoding>::Repr::default();
|
||||||
reader.read_exact(encoding.as_mut())?;
|
reader.read_exact(bytes.as_mut())?;
|
||||||
|
|
||||||
let point = Option::<Self::G>::from(Self::G::from_bytes(&encoding))
|
let res = Option::<Self::G>::from(Self::from_canonical_bytes(&bytes))
|
||||||
.ok_or_else(|| io::Error::other("invalid point"))?;
|
.ok_or_else(|| io::Error::other("invalid point"))?;
|
||||||
if point.to_bytes().as_ref() != encoding.as_ref() {
|
bytes.as_mut().zeroize();
|
||||||
Err(io::Error::other("non-canonical point"))?;
|
|
||||||
}
|
Ok(res)
|
||||||
Ok(point)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<Gr: GroupCanonicalEncoding> GroupIo for Gr {}
|
||||||
|
|
||||||
|
/// Unified trait defining a ciphersuite around an elliptic curve.
|
||||||
|
pub trait Ciphersuite: Id + WithPreferredHash + GroupCanonicalEncoding {}
|
||||||
|
impl<C: Id + WithPreferredHash + GroupCanonicalEncoding> Ciphersuite for C {}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "dalek-ff-group"
|
name = "dalek-ff-group"
|
||||||
version = "0.4.6"
|
version = "0.5.0"
|
||||||
description = "ff/group bindings around curve25519-dalek"
|
description = "ff/group bindings around curve25519-dalek"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/serai-dex/serai/tree/develop/crypto/dalek-ff-group"
|
repository = "https://github.com/serai-dex/serai/tree/develop/crypto/dalek-ff-group"
|
||||||
@@ -22,15 +22,13 @@ subtle = { version = "^2.4", default-features = false }
|
|||||||
|
|
||||||
rand_core = { version = "0.6", default-features = false }
|
rand_core = { version = "0.6", default-features = false }
|
||||||
|
|
||||||
digest = { version = "0.10", default-features = false }
|
sha2 = { version = "0.11.0-rc.2", default-features = false, features = ["zeroize"] }
|
||||||
sha2 = { version = "0.11.0-rc.0", default-features = false }
|
blake2 = { version = "0.11.0-rc.2", default-features = false, features = ["zeroize"] }
|
||||||
|
|
||||||
prime-field = { path = "../prime-field", default-features = false }
|
prime-field = { path = "../prime-field", default-features = false }
|
||||||
ciphersuite = { version = "0.4.2", path = "../ciphersuite", default-features = false }
|
ciphersuite = { version = "0.4.2", path = "../ciphersuite", default-features = false }
|
||||||
|
|
||||||
crypto-bigint = { version = "0.6", default-features = false, features = ["zeroize"] }
|
curve25519-dalek = { version = ">= 4.0, < 4.2", default-features = false, features = ["zeroize", "digest", "group-bits", "precomputed-tables"] }
|
||||||
|
|
||||||
curve25519-dalek = { version = ">= 4.0, < 4.2", default-features = false, features = ["zeroize", "digest", "group", "precomputed-tables"] }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
@@ -38,6 +36,6 @@ rand_core = { version = "0.6", default-features = false, features = ["std"] }
|
|||||||
ff-group-tests = { path = "../ff-group-tests" }
|
ff-group-tests = { path = "../ff-group-tests" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
alloc = ["zeroize/alloc", "digest/alloc", "prime-field/alloc", "ciphersuite/alloc", "crypto-bigint/alloc", "curve25519-dalek/alloc"]
|
alloc = ["zeroize/alloc", "prime-field/alloc", "ciphersuite/alloc", "curve25519-dalek/alloc"]
|
||||||
std = ["alloc", "zeroize/std", "subtle/std", "rand_core/std", "digest/std", "prime-field/std", "ciphersuite/std"]
|
std = ["alloc", "zeroize/std", "subtle/std", "rand_core/std", "prime-field/std", "ciphersuite/std"]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|||||||
@@ -1,49 +1,48 @@
|
|||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
use sha2::Sha512;
|
use sha2::Sha512;
|
||||||
|
use blake2::Blake2b512;
|
||||||
|
|
||||||
use ciphersuite::{group::Group, Ciphersuite};
|
use ::ciphersuite::{group::Group, *};
|
||||||
|
|
||||||
use crate::Scalar;
|
use crate::*;
|
||||||
|
|
||||||
macro_rules! dalek_curve {
|
|
||||||
(
|
|
||||||
$feature: literal,
|
|
||||||
|
|
||||||
$Ciphersuite: ident,
|
|
||||||
$Point: ident,
|
|
||||||
$ID: literal
|
|
||||||
) => {
|
|
||||||
use crate::$Point;
|
|
||||||
|
|
||||||
impl Ciphersuite for $Ciphersuite {
|
|
||||||
type F = Scalar;
|
|
||||||
type G = $Point;
|
|
||||||
type H = Sha512;
|
|
||||||
|
|
||||||
const ID: &'static [u8] = $ID;
|
|
||||||
|
|
||||||
fn generator() -> Self::G {
|
|
||||||
$Point::generator()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Ciphersuite for Ristretto.
|
/// Ciphersuite for Ristretto.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
|
||||||
pub struct Ristretto;
|
pub struct Ristretto;
|
||||||
dalek_curve!("ristretto", Ristretto, RistrettoPoint, b"ristretto");
|
impl WrappedGroup for Ristretto {
|
||||||
#[test]
|
type F = Scalar;
|
||||||
fn test_ristretto() {
|
type G = RistrettoPoint;
|
||||||
ff_group_tests::group::test_prime_group_bits::<_, RistrettoPoint>(&mut rand_core::OsRng);
|
fn generator() -> Self::G {
|
||||||
|
<RistrettoPoint as Group>::generator()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Id for Ristretto {
|
||||||
|
const ID: &[u8] = b"ristretto";
|
||||||
|
}
|
||||||
|
impl WithPreferredHash for Ristretto {
|
||||||
|
type H = Blake2b512;
|
||||||
|
}
|
||||||
|
impl GroupCanonicalEncoding for Ristretto {
|
||||||
|
fn from_canonical_bytes(bytes: &<Self::G as GroupEncoding>::Repr) -> CtOption<Self::G> {
|
||||||
|
Self::G::from_bytes(bytes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ciphersuite for Ed25519, inspired by RFC-8032.
|
/// Ciphersuite for Ed25519.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
|
||||||
pub struct Ed25519;
|
pub struct Ed25519;
|
||||||
dalek_curve!("ed25519", Ed25519, EdwardsPoint, b"edwards25519");
|
impl WrappedGroup for Ed25519 {
|
||||||
#[test]
|
type F = Scalar;
|
||||||
fn test_ed25519() {
|
type G = EdwardsPoint;
|
||||||
ff_group_tests::group::test_prime_group_bits::<_, EdwardsPoint>(&mut rand_core::OsRng);
|
fn generator() -> Self::G {
|
||||||
|
<EdwardsPoint as Group>::generator()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
impl Id for Ed25519 {
|
||||||
|
const ID: &[u8] = b"ed25519";
|
||||||
|
}
|
||||||
|
impl WithPreferredHash for Ed25519 {
|
||||||
|
type H = Sha512;
|
||||||
|
}
|
||||||
|
impl GroupCanonicalEncoding for Ed25519 {}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
use core::{
|
use core::{
|
||||||
borrow::Borrow,
|
borrow::Borrow,
|
||||||
ops::{Deref, Add, AddAssign, Sub, SubAssign, Neg, Mul, MulAssign},
|
ops::{Deref, Add, AddAssign, Sub, SubAssign, Neg, Mul, MulAssign},
|
||||||
iter::{Iterator, Sum, Product},
|
iter::{Iterator, Sum},
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -15,25 +15,16 @@ use zeroize::Zeroize;
|
|||||||
use subtle::{ConstantTimeEq, ConditionallySelectable};
|
use subtle::{ConstantTimeEq, ConditionallySelectable};
|
||||||
|
|
||||||
use rand_core::RngCore;
|
use rand_core::RngCore;
|
||||||
use digest::{consts::U64, Digest, HashMarker};
|
|
||||||
|
|
||||||
use subtle::{Choice, CtOption};
|
use subtle::{Choice, CtOption};
|
||||||
|
|
||||||
pub use curve25519_dalek as dalek;
|
use curve25519_dalek::{
|
||||||
|
edwards::{EdwardsPoint as DEdwardsPoint, CompressedEdwardsY},
|
||||||
use dalek::{
|
ristretto::{RistrettoPoint as DRistrettoPoint, CompressedRistretto},
|
||||||
constants::{self, BASEPOINT_ORDER},
|
|
||||||
scalar::Scalar as DScalar,
|
|
||||||
edwards::{EdwardsPoint as DEdwardsPoint, EdwardsBasepointTable, CompressedEdwardsY},
|
|
||||||
ristretto::{RistrettoPoint as DRistrettoPoint, RistrettoBasepointTable, CompressedRistretto},
|
|
||||||
};
|
};
|
||||||
pub use constants::{ED25519_BASEPOINT_TABLE, RISTRETTO_BASEPOINT_TABLE};
|
pub use curve25519_dalek::Scalar;
|
||||||
|
|
||||||
use ::ciphersuite::group::{
|
use ::ciphersuite::group::{Group, GroupEncoding, prime::PrimeGroup};
|
||||||
ff::{Field, PrimeField, FieldBits, PrimeFieldBits, FromUniformBytes},
|
|
||||||
Group, GroupEncoding,
|
|
||||||
prime::PrimeGroup,
|
|
||||||
};
|
|
||||||
|
|
||||||
mod ciphersuite;
|
mod ciphersuite;
|
||||||
pub use crate::ciphersuite::{Ed25519, Ristretto};
|
pub use crate::ciphersuite::{Ed25519, Ristretto};
|
||||||
@@ -97,7 +88,41 @@ macro_rules! constant_time {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub(crate) use constant_time;
|
|
||||||
|
macro_rules! math_op_without_wrapping {
|
||||||
|
(
|
||||||
|
$Value: ident,
|
||||||
|
$Other: ident,
|
||||||
|
$Op: ident,
|
||||||
|
$op_fn: ident,
|
||||||
|
$Assign: ident,
|
||||||
|
$assign_fn: ident,
|
||||||
|
$function: expr
|
||||||
|
) => {
|
||||||
|
impl $Op<$Other> for $Value {
|
||||||
|
type Output = $Value;
|
||||||
|
fn $op_fn(self, other: $Other) -> Self::Output {
|
||||||
|
Self($function(self.0, other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl $Assign<$Other> for $Value {
|
||||||
|
fn $assign_fn(&mut self, other: $Other) {
|
||||||
|
self.0 = $function(self.0, other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> $Op<&'a $Other> for $Value {
|
||||||
|
type Output = $Value;
|
||||||
|
fn $op_fn(self, other: &'a $Other) -> Self::Output {
|
||||||
|
Self($function(self.0, other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> $Assign<&'a $Other> for $Value {
|
||||||
|
fn $assign_fn(&mut self, other: &'a $Other) {
|
||||||
|
self.0 = $function(self.0, other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! math_op {
|
macro_rules! math_op {
|
||||||
(
|
(
|
||||||
@@ -133,20 +158,12 @@ macro_rules! math_op {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub(crate) use math_op;
|
|
||||||
|
|
||||||
macro_rules! math {
|
|
||||||
($Value: ident, $Factor: ident, $add: expr, $sub: expr, $mul: expr) => {
|
|
||||||
math_op!($Value, $Value, Add, add, AddAssign, add_assign, $add);
|
|
||||||
math_op!($Value, $Value, Sub, sub, SubAssign, sub_assign, $sub);
|
|
||||||
math_op!($Value, $Factor, Mul, mul, MulAssign, mul_assign, $mul);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
pub(crate) use math;
|
|
||||||
|
|
||||||
macro_rules! math_neg {
|
macro_rules! math_neg {
|
||||||
($Value: ident, $Factor: ident, $add: expr, $sub: expr, $mul: expr) => {
|
($Value: ident, $Factor: ident, $add: expr, $sub: expr, $mul: expr) => {
|
||||||
math!($Value, $Factor, $add, $sub, $mul);
|
math_op!($Value, $Value, Add, add, AddAssign, add_assign, $add);
|
||||||
|
math_op!($Value, $Value, Sub, sub, SubAssign, sub_assign, $sub);
|
||||||
|
math_op_without_wrapping!($Value, $Factor, Mul, mul, MulAssign, mul_assign, $mul);
|
||||||
|
|
||||||
impl Neg for $Value {
|
impl Neg for $Value {
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
@@ -157,187 +174,6 @@ macro_rules! math_neg {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper around the dalek Scalar type.
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Default, Debug, Zeroize)]
|
|
||||||
pub struct Scalar(pub DScalar);
|
|
||||||
deref_borrow!(Scalar, DScalar);
|
|
||||||
constant_time!(Scalar, DScalar);
|
|
||||||
math_neg!(Scalar, Scalar, DScalar::add, DScalar::sub, DScalar::mul);
|
|
||||||
|
|
||||||
macro_rules! from_wrapper {
|
|
||||||
($uint: ident) => {
|
|
||||||
impl From<$uint> for Scalar {
|
|
||||||
fn from(a: $uint) -> Scalar {
|
|
||||||
Scalar(DScalar::from(a))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
from_wrapper!(u8);
|
|
||||||
from_wrapper!(u16);
|
|
||||||
from_wrapper!(u32);
|
|
||||||
from_wrapper!(u64);
|
|
||||||
from_wrapper!(u128);
|
|
||||||
|
|
||||||
impl Scalar {
|
|
||||||
pub fn pow(&self, other: Scalar) -> Scalar {
|
|
||||||
let mut table = [Scalar::ONE; 16];
|
|
||||||
table[1] = *self;
|
|
||||||
for i in 2 .. 16 {
|
|
||||||
table[i] = table[i - 1] * self;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut res = Scalar::ONE;
|
|
||||||
let mut bits = 0;
|
|
||||||
for (i, mut bit) in other.to_le_bits().iter_mut().rev().enumerate() {
|
|
||||||
bits <<= 1;
|
|
||||||
let mut bit = u8_from_bool(&mut bit);
|
|
||||||
bits |= bit;
|
|
||||||
bit.zeroize();
|
|
||||||
|
|
||||||
if ((i + 1) % 4) == 0 {
|
|
||||||
if i != 3 {
|
|
||||||
for _ in 0 .. 4 {
|
|
||||||
res *= res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut scale_by = Scalar::ONE;
|
|
||||||
#[allow(clippy::needless_range_loop)]
|
|
||||||
for i in 0 .. 16 {
|
|
||||||
#[allow(clippy::cast_possible_truncation)] // Safe since 0 .. 16
|
|
||||||
{
|
|
||||||
scale_by = <_>::conditional_select(&scale_by, &table[i], bits.ct_eq(&(i as u8)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res *= scale_by;
|
|
||||||
bits = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Perform wide reduction on a 64-byte array to create a Scalar without bias.
|
|
||||||
pub fn from_bytes_mod_order_wide(bytes: &[u8; 64]) -> Scalar {
|
|
||||||
Self(DScalar::from_bytes_mod_order_wide(bytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Derive a Scalar without bias from a digest via wide reduction.
|
|
||||||
pub fn from_hash<D: Digest<OutputSize = U64> + HashMarker>(hash: D) -> Scalar {
|
|
||||||
let mut output = [0u8; 64];
|
|
||||||
output.copy_from_slice(&hash.finalize());
|
|
||||||
let res = Scalar(DScalar::from_bytes_mod_order_wide(&output));
|
|
||||||
output.zeroize();
|
|
||||||
res
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Field for Scalar {
|
|
||||||
const ZERO: Scalar = Scalar(DScalar::ZERO);
|
|
||||||
const ONE: Scalar = Scalar(DScalar::ONE);
|
|
||||||
|
|
||||||
fn random(rng: impl RngCore) -> Self {
|
|
||||||
Self(<DScalar as Field>::random(rng))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn square(&self) -> Self {
|
|
||||||
Self(self.0.square())
|
|
||||||
}
|
|
||||||
fn double(&self) -> Self {
|
|
||||||
Self(self.0.double())
|
|
||||||
}
|
|
||||||
fn invert(&self) -> CtOption<Self> {
|
|
||||||
<DScalar as Field>::invert(&self.0).map(Self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sqrt(&self) -> CtOption<Self> {
|
|
||||||
self.0.sqrt().map(Self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
|
|
||||||
let (choice, res) = DScalar::sqrt_ratio(num, div);
|
|
||||||
(choice, Self(res))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PrimeField for Scalar {
|
|
||||||
type Repr = [u8; 32];
|
|
||||||
|
|
||||||
const MODULUS: &'static str = <DScalar as PrimeField>::MODULUS;
|
|
||||||
|
|
||||||
const NUM_BITS: u32 = <DScalar as PrimeField>::NUM_BITS;
|
|
||||||
const CAPACITY: u32 = <DScalar as PrimeField>::CAPACITY;
|
|
||||||
|
|
||||||
const TWO_INV: Scalar = Scalar(<DScalar as PrimeField>::TWO_INV);
|
|
||||||
|
|
||||||
const MULTIPLICATIVE_GENERATOR: Scalar =
|
|
||||||
Scalar(<DScalar as PrimeField>::MULTIPLICATIVE_GENERATOR);
|
|
||||||
const S: u32 = <DScalar as PrimeField>::S;
|
|
||||||
|
|
||||||
const ROOT_OF_UNITY: Scalar = Scalar(<DScalar as PrimeField>::ROOT_OF_UNITY);
|
|
||||||
const ROOT_OF_UNITY_INV: Scalar = Scalar(<DScalar as PrimeField>::ROOT_OF_UNITY_INV);
|
|
||||||
|
|
||||||
const DELTA: Scalar = Scalar(<DScalar as PrimeField>::DELTA);
|
|
||||||
|
|
||||||
fn from_repr(bytes: [u8; 32]) -> CtOption<Self> {
|
|
||||||
<DScalar as PrimeField>::from_repr(bytes).map(Scalar)
|
|
||||||
}
|
|
||||||
fn to_repr(&self) -> [u8; 32] {
|
|
||||||
self.0.to_repr()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_odd(&self) -> Choice {
|
|
||||||
self.0.is_odd()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_u128(num: u128) -> Self {
|
|
||||||
Scalar(DScalar::from_u128(num))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PrimeFieldBits for Scalar {
|
|
||||||
type ReprBits = [u8; 32];
|
|
||||||
|
|
||||||
fn to_le_bits(&self) -> FieldBits<Self::ReprBits> {
|
|
||||||
self.to_repr().into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn char_le_bits() -> FieldBits<Self::ReprBits> {
|
|
||||||
BASEPOINT_ORDER.to_bytes().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromUniformBytes<64> for Scalar {
|
|
||||||
fn from_uniform_bytes(bytes: &[u8; 64]) -> Self {
|
|
||||||
Self::from_bytes_mod_order_wide(bytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Sum<Scalar> for Scalar {
|
|
||||||
fn sum<I: Iterator<Item = Scalar>>(iter: I) -> Scalar {
|
|
||||||
Self(DScalar::sum(iter))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Sum<&'a Scalar> for Scalar {
|
|
||||||
fn sum<I: Iterator<Item = &'a Scalar>>(iter: I) -> Scalar {
|
|
||||||
Self(DScalar::sum(iter))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Product<Scalar> for Scalar {
|
|
||||||
fn product<I: Iterator<Item = Scalar>>(iter: I) -> Scalar {
|
|
||||||
Self(DScalar::product(iter))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Product<&'a Scalar> for Scalar {
|
|
||||||
fn product<I: Iterator<Item = &'a Scalar>>(iter: I) -> Scalar {
|
|
||||||
Self(DScalar::product(iter))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! dalek_group {
|
macro_rules! dalek_group {
|
||||||
(
|
(
|
||||||
$Point: ident,
|
$Point: ident,
|
||||||
@@ -347,9 +183,6 @@ macro_rules! dalek_group {
|
|||||||
$Table: ident,
|
$Table: ident,
|
||||||
|
|
||||||
$DCompressed: ident,
|
$DCompressed: ident,
|
||||||
|
|
||||||
$BASEPOINT_POINT: ident,
|
|
||||||
$BASEPOINT_TABLE: ident
|
|
||||||
) => {
|
) => {
|
||||||
/// Wrapper around the dalek Point type.
|
/// Wrapper around the dalek Point type.
|
||||||
///
|
///
|
||||||
@@ -363,9 +196,6 @@ macro_rules! dalek_group {
|
|||||||
constant_time!($Point, $DPoint);
|
constant_time!($Point, $DPoint);
|
||||||
math_neg!($Point, Scalar, $DPoint::add, $DPoint::sub, $DPoint::mul);
|
math_neg!($Point, Scalar, $DPoint::add, $DPoint::sub, $DPoint::mul);
|
||||||
|
|
||||||
/// The basepoint for this curve.
|
|
||||||
pub const $BASEPOINT_POINT: $Point = $Point(constants::$BASEPOINT_POINT);
|
|
||||||
|
|
||||||
impl Sum<$Point> for $Point {
|
impl Sum<$Point> for $Point {
|
||||||
fn sum<I: Iterator<Item = $Point>>(iter: I) -> $Point {
|
fn sum<I: Iterator<Item = $Point>>(iter: I) -> $Point {
|
||||||
Self($DPoint::sum(iter))
|
Self($DPoint::sum(iter))
|
||||||
@@ -396,7 +226,7 @@ macro_rules! dalek_group {
|
|||||||
Self($DPoint::identity())
|
Self($DPoint::identity())
|
||||||
}
|
}
|
||||||
fn generator() -> Self {
|
fn generator() -> Self {
|
||||||
$BASEPOINT_POINT
|
Self(<$DPoint as Group>::generator())
|
||||||
}
|
}
|
||||||
fn is_identity(&self) -> Choice {
|
fn is_identity(&self) -> Choice {
|
||||||
self.0.ct_eq(&$DPoint::identity())
|
self.0.ct_eq(&$DPoint::identity())
|
||||||
@@ -430,13 +260,6 @@ macro_rules! dalek_group {
|
|||||||
|
|
||||||
impl PrimeGroup for $Point {}
|
impl PrimeGroup for $Point {}
|
||||||
|
|
||||||
impl Mul<Scalar> for &$Table {
|
|
||||||
type Output = $Point;
|
|
||||||
fn mul(self, b: Scalar) -> $Point {
|
|
||||||
$Point(&b.0 * self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Support being used as a key in a table
|
// Support being used as a key in a table
|
||||||
// While it is expensive as a key, due to the field operations required, there's frequently
|
// While it is expensive as a key, due to the field operations required, there's frequently
|
||||||
// use cases for public key -> value lookups
|
// use cases for public key -> value lookups
|
||||||
@@ -456,24 +279,14 @@ dalek_group!(
|
|||||||
|point: DEdwardsPoint| point.is_torsion_free(),
|
|point: DEdwardsPoint| point.is_torsion_free(),
|
||||||
EdwardsBasepointTable,
|
EdwardsBasepointTable,
|
||||||
CompressedEdwardsY,
|
CompressedEdwardsY,
|
||||||
ED25519_BASEPOINT_POINT,
|
|
||||||
ED25519_BASEPOINT_TABLE
|
|
||||||
);
|
);
|
||||||
|
|
||||||
impl EdwardsPoint {
|
|
||||||
pub fn mul_by_cofactor(&self) -> EdwardsPoint {
|
|
||||||
EdwardsPoint(self.0.mul_by_cofactor())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dalek_group!(
|
dalek_group!(
|
||||||
RistrettoPoint,
|
RistrettoPoint,
|
||||||
DRistrettoPoint,
|
DRistrettoPoint,
|
||||||
|_| true,
|
|_| true,
|
||||||
RistrettoBasepointTable,
|
RistrettoBasepointTable,
|
||||||
CompressedRistretto,
|
CompressedRistretto,
|
||||||
RISTRETTO_BASEPOINT_POINT,
|
|
||||||
RISTRETTO_BASEPOINT_TABLE
|
|
||||||
);
|
);
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ use rand_core::{RngCore, CryptoRng};
|
|||||||
|
|
||||||
use ciphersuite::{
|
use ciphersuite::{
|
||||||
group::ff::{Field, PrimeField},
|
group::ff::{Field, PrimeField},
|
||||||
Ciphersuite,
|
GroupIo, Id,
|
||||||
};
|
};
|
||||||
pub use dkg::*;
|
pub use dkg::*;
|
||||||
|
|
||||||
/// Create a key via a dealer key generation protocol.
|
/// Create a key via a dealer key generation protocol.
|
||||||
pub fn key_gen<R: RngCore + CryptoRng, C: Ciphersuite>(
|
pub fn key_gen<R: RngCore + CryptoRng, C: GroupIo + Id>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
threshold: u16,
|
threshold: u16,
|
||||||
participants: u16,
|
participants: u16,
|
||||||
|
|||||||
@@ -31,13 +31,13 @@ ciphersuite = { path = "../../ciphersuite", version = "^0.4.1", default-features
|
|||||||
multiexp = { path = "../../multiexp", version = "0.4", default-features = false }
|
multiexp = { path = "../../multiexp", version = "0.4", default-features = false }
|
||||||
|
|
||||||
generic-array = { version = "1", default-features = false, features = ["alloc"] }
|
generic-array = { version = "1", default-features = false, features = ["alloc"] }
|
||||||
blake2 = { version = "0.11.0-rc.0", default-features = false }
|
blake2 = { version = "0.11.0-rc.2", default-features = false }
|
||||||
rand_chacha = { version = "0.3", default-features = false }
|
rand_chacha = { version = "0.3", default-features = false }
|
||||||
|
|
||||||
generalized-bulletproofs = { git = "https://github.com/monero-oxide/monero-oxide", rev = "a6f8797007e768488568b821435cf5006517a962", default-features = false }
|
generalized-bulletproofs = { git = "https://github.com/monero-oxide/monero-oxide", rev = "7216a2e84c7671c167c3d81eafe0d2b1f418f102", default-features = false }
|
||||||
ec-divisors = { git = "https://github.com/monero-oxide/monero-oxide", rev = "a6f8797007e768488568b821435cf5006517a962", default-features = false }
|
ec-divisors = { git = "https://github.com/monero-oxide/monero-oxide", rev = "7216a2e84c7671c167c3d81eafe0d2b1f418f102", default-features = false }
|
||||||
generalized-bulletproofs-circuit-abstraction = { git = "https://github.com/monero-oxide/monero-oxide", rev = "a6f8797007e768488568b821435cf5006517a962", default-features = false }
|
generalized-bulletproofs-circuit-abstraction = { git = "https://github.com/monero-oxide/monero-oxide", rev = "7216a2e84c7671c167c3d81eafe0d2b1f418f102", default-features = false }
|
||||||
generalized-bulletproofs-ec-gadgets = { git = "https://github.com/monero-oxide/monero-oxide", rev = "a6f8797007e768488568b821435cf5006517a962", default-features = false }
|
generalized-bulletproofs-ec-gadgets = { git = "https://github.com/monero-oxide/monero-oxide", rev = "7216a2e84c7671c167c3d81eafe0d2b1f418f102", default-features = false }
|
||||||
|
|
||||||
dkg = { path = "..", default-features = false }
|
dkg = { path = "..", default-features = false }
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ rand = { version = "0.8", default-features = false, features = ["std"] }
|
|||||||
ciphersuite = { path = "../../ciphersuite", default-features = false, features = ["std"] }
|
ciphersuite = { path = "../../ciphersuite", default-features = false, features = ["std"] }
|
||||||
embedwards25519 = { path = "../../embedwards25519", default-features = false, features = ["std"] }
|
embedwards25519 = { path = "../../embedwards25519", default-features = false, features = ["std"] }
|
||||||
dalek-ff-group = { path = "../../dalek-ff-group", default-features = false, features = ["std"] }
|
dalek-ff-group = { path = "../../dalek-ff-group", default-features = false, features = ["std"] }
|
||||||
generalized-bulletproofs = { git = "https://github.com/monero-oxide/monero-oxide", rev = "a6f8797007e768488568b821435cf5006517a962", features = ["tests"] }
|
generalized-bulletproofs = { git = "https://github.com/monero-oxide/monero-oxide", rev = "7216a2e84c7671c167c3d81eafe0d2b1f418f102", features = ["tests"] }
|
||||||
dkg-recovery = { path = "../recovery" }
|
dkg-recovery = { path = "../recovery" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
@@ -86,6 +86,5 @@ std = [
|
|||||||
]
|
]
|
||||||
secp256k1 = ["ciphersuite-kp256", "secq256k1"]
|
secp256k1 = ["ciphersuite-kp256", "secq256k1"]
|
||||||
ed25519 = ["dalek-ff-group", "embedwards25519"]
|
ed25519 = ["dalek-ff-group", "embedwards25519"]
|
||||||
ristretto = ["dalek-ff-group", "embedwards25519"]
|
|
||||||
tests = ["rand_core/getrandom"]
|
tests = ["rand_core/getrandom"]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ type Blake2s256Keyed = Blake2sMac<U32>;
|
|||||||
|
|
||||||
use ciphersuite::{
|
use ciphersuite::{
|
||||||
group::{ff::FromUniformBytes, GroupEncoding},
|
group::{ff::FromUniformBytes, GroupEncoding},
|
||||||
Ciphersuite,
|
WrappedGroup, Id, GroupIo,
|
||||||
};
|
};
|
||||||
|
|
||||||
use ec_divisors::DivisorCurve;
|
use ec_divisors::DivisorCurve;
|
||||||
@@ -27,10 +27,10 @@ use generalized_bulletproofs_ec_gadgets::*;
|
|||||||
/// A pair of curves to perform the eVRF with.
|
/// A pair of curves to perform the eVRF with.
|
||||||
pub trait Curves {
|
pub trait Curves {
|
||||||
/// The towering curve, for which the resulting key is on.
|
/// The towering curve, for which the resulting key is on.
|
||||||
type ToweringCurve: Ciphersuite<F: FromUniformBytes<64>>;
|
type ToweringCurve: Id + GroupIo<F: FromUniformBytes<64>>;
|
||||||
/// The embedded curve which participants represent their public keys over.
|
/// The embedded curve which participants represent their public keys over.
|
||||||
type EmbeddedCurve: Ciphersuite<
|
type EmbeddedCurve: GroupIo<
|
||||||
G: DivisorCurve<FieldElement = <Self::ToweringCurve as Ciphersuite>::F>,
|
G: DivisorCurve<FieldElement = <Self::ToweringCurve as WrappedGroup>::F>,
|
||||||
>;
|
>;
|
||||||
/// The parameters to use the embedded curve with the discrete-log gadget.
|
/// The parameters to use the embedded curve with the discrete-log gadget.
|
||||||
type EmbeddedCurveParameters: DiscreteLogParameters;
|
type EmbeddedCurveParameters: DiscreteLogParameters;
|
||||||
@@ -49,14 +49,14 @@ impl<C: Curves> Generators<C> {
|
|||||||
pub fn new(max_threshold: u16, max_participants: u16) -> Generators<C> {
|
pub fn new(max_threshold: u16, max_participants: u16) -> Generators<C> {
|
||||||
let entropy = <Blake2s256Keyed as KeyInit>::new(&{
|
let entropy = <Blake2s256Keyed as KeyInit>::new(&{
|
||||||
let mut key = Array::<u8, <Blake2s256Keyed as KeySizeUser>::KeySize>::default();
|
let mut key = Array::<u8, <Blake2s256Keyed as KeySizeUser>::KeySize>::default();
|
||||||
let key_len = key.len().min(<C::ToweringCurve as Ciphersuite>::ID.len());
|
let key_len = key.len().min(<C::ToweringCurve as Id>::ID.len());
|
||||||
{
|
{
|
||||||
let key: &mut [u8] = key.as_mut();
|
let key: &mut [u8] = key.as_mut();
|
||||||
key[.. key_len].copy_from_slice(&<C::ToweringCurve as Ciphersuite>::ID[.. key_len])
|
key[.. key_len].copy_from_slice(&<C::ToweringCurve as Id>::ID[.. key_len])
|
||||||
}
|
}
|
||||||
key
|
key
|
||||||
})
|
})
|
||||||
.chain_update(<C::ToweringCurve as Ciphersuite>::generator().to_bytes())
|
.chain_update(<C::ToweringCurve as WrappedGroup>::generator().to_bytes())
|
||||||
.finalize()
|
.finalize()
|
||||||
.into_bytes();
|
.into_bytes();
|
||||||
let mut rng = ChaCha20Rng::from_seed(entropy.into());
|
let mut rng = ChaCha20Rng::from_seed(entropy.into());
|
||||||
@@ -71,7 +71,8 @@ impl<C: Curves> Generators<C> {
|
|||||||
h_bold.push(crate::sample_point::<C::ToweringCurve>(&mut rng));
|
h_bold.push(crate::sample_point::<C::ToweringCurve>(&mut rng));
|
||||||
}
|
}
|
||||||
Self(
|
Self(
|
||||||
BpGenerators::new(<C::ToweringCurve as Ciphersuite>::generator(), h, g_bold, h_bold).unwrap(),
|
BpGenerators::new(<C::ToweringCurve as WrappedGroup>::generator(), h, g_bold, h_bold)
|
||||||
|
.unwrap(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,13 +96,3 @@ impl Curves for Ed25519 {
|
|||||||
type EmbeddedCurve = embedwards25519::Embedwards25519;
|
type EmbeddedCurve = embedwards25519::Embedwards25519;
|
||||||
type EmbeddedCurveParameters = embedwards25519::Embedwards25519;
|
type EmbeddedCurveParameters = embedwards25519::Embedwards25519;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ristretto, and an elliptic curve defined over its scalar field (embedwards25519).
|
|
||||||
#[cfg(any(test, feature = "ristretto"))]
|
|
||||||
pub struct Ristretto;
|
|
||||||
#[cfg(any(test, feature = "ristretto"))]
|
|
||||||
impl Curves for Ristretto {
|
|
||||||
type ToweringCurve = dalek_ff_group::Ristretto;
|
|
||||||
type EmbeddedCurve = embedwards25519::Embedwards25519;
|
|
||||||
type EmbeddedCurveParameters = embedwards25519::Embedwards25519;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use ciphersuite::{
|
|||||||
ff::{Field, PrimeField},
|
ff::{Field, PrimeField},
|
||||||
Group, GroupEncoding,
|
Group, GroupEncoding,
|
||||||
},
|
},
|
||||||
Ciphersuite,
|
WrappedGroup, GroupIo,
|
||||||
};
|
};
|
||||||
use multiexp::multiexp_vartime;
|
use multiexp::multiexp_vartime;
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ mod tests;
|
|||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct Participation<C: Curves> {
|
pub struct Participation<C: Curves> {
|
||||||
proof: Vec<u8>,
|
proof: Vec<u8>,
|
||||||
encrypted_secret_shares: HashMap<Participant, <C::ToweringCurve as Ciphersuite>::F>,
|
encrypted_secret_shares: HashMap<Participant, <C::ToweringCurve as WrappedGroup>::F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Curves> Participation<C> {
|
impl<C: Curves> Participation<C> {
|
||||||
@@ -79,7 +79,7 @@ impl<C: Curves> Participation<C> {
|
|||||||
|
|
||||||
let mut encrypted_secret_shares = HashMap::with_capacity(usize::from(n));
|
let mut encrypted_secret_shares = HashMap::with_capacity(usize::from(n));
|
||||||
for i in Participant::iter().take(usize::from(n)) {
|
for i in Participant::iter().take(usize::from(n)) {
|
||||||
encrypted_secret_shares.insert(i, <C::ToweringCurve as Ciphersuite>::read_F(reader)?);
|
encrypted_secret_shares.insert(i, <C::ToweringCurve as GroupIo>::read_F(reader)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self { proof, encrypted_secret_shares })
|
Ok(Self { proof, encrypted_secret_shares })
|
||||||
@@ -151,14 +151,14 @@ pub enum VerifyResult<C: Curves> {
|
|||||||
pub struct Dkg<C: Curves> {
|
pub struct Dkg<C: Curves> {
|
||||||
t: u16,
|
t: u16,
|
||||||
n: u16,
|
n: u16,
|
||||||
evrf_public_keys: Vec<<C::EmbeddedCurve as Ciphersuite>::G>,
|
evrf_public_keys: Vec<<C::EmbeddedCurve as WrappedGroup>::G>,
|
||||||
verification_shares: HashMap<Participant, <C::ToweringCurve as Ciphersuite>::G>,
|
verification_shares: HashMap<Participant, <C::ToweringCurve as WrappedGroup>::G>,
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
encrypted_secret_shares: HashMap<
|
encrypted_secret_shares: HashMap<
|
||||||
Participant,
|
Participant,
|
||||||
HashMap<
|
HashMap<
|
||||||
Participant,
|
Participant,
|
||||||
([<C::EmbeddedCurve as Ciphersuite>::G; 2], <C::ToweringCurve as Ciphersuite>::F),
|
([<C::EmbeddedCurve as WrappedGroup>::G; 2], <C::ToweringCurve as WrappedGroup>::F),
|
||||||
>,
|
>,
|
||||||
>,
|
>,
|
||||||
}
|
}
|
||||||
@@ -167,7 +167,7 @@ impl<C: Curves> Dkg<C> {
|
|||||||
// Form the initial transcript for the proofs.
|
// Form the initial transcript for the proofs.
|
||||||
fn initial_transcript(
|
fn initial_transcript(
|
||||||
invocation: [u8; 32],
|
invocation: [u8; 32],
|
||||||
evrf_public_keys: &[<C::EmbeddedCurve as Ciphersuite>::G],
|
evrf_public_keys: &[<C::EmbeddedCurve as WrappedGroup>::G],
|
||||||
t: u16,
|
t: u16,
|
||||||
) -> [u8; 32] {
|
) -> [u8; 32] {
|
||||||
let mut transcript = Blake2s256::new();
|
let mut transcript = Blake2s256::new();
|
||||||
@@ -188,8 +188,8 @@ impl<C: Curves> Dkg<C> {
|
|||||||
generators: &Generators<C>,
|
generators: &Generators<C>,
|
||||||
context: [u8; 32],
|
context: [u8; 32],
|
||||||
t: u16,
|
t: u16,
|
||||||
evrf_public_keys: &[<C::EmbeddedCurve as Ciphersuite>::G],
|
evrf_public_keys: &[<C::EmbeddedCurve as WrappedGroup>::G],
|
||||||
evrf_private_key: &Zeroizing<<C::EmbeddedCurve as Ciphersuite>::F>,
|
evrf_private_key: &Zeroizing<<C::EmbeddedCurve as WrappedGroup>::F>,
|
||||||
) -> Result<Participation<C>, Error> {
|
) -> Result<Participation<C>, Error> {
|
||||||
let Ok(n) = u16::try_from(evrf_public_keys.len()) else {
|
let Ok(n) = u16::try_from(evrf_public_keys.len()) else {
|
||||||
Err(Error::TooManyParticipants { provided: evrf_public_keys.len() })?
|
Err(Error::TooManyParticipants { provided: evrf_public_keys.len() })?
|
||||||
@@ -202,7 +202,8 @@ impl<C: Curves> Dkg<C> {
|
|||||||
};
|
};
|
||||||
// This also ensures the private key is not 0, due to the prior check the identity point wasn't
|
// This also ensures the private key is not 0, due to the prior check the identity point wasn't
|
||||||
// present
|
// present
|
||||||
let evrf_public_key = <C::EmbeddedCurve as Ciphersuite>::generator() * evrf_private_key.deref();
|
let evrf_public_key =
|
||||||
|
<C::EmbeddedCurve as WrappedGroup>::generator() * evrf_private_key.deref();
|
||||||
if !evrf_public_keys.contains(&evrf_public_key) {
|
if !evrf_public_keys.contains(&evrf_public_key) {
|
||||||
Err(Error::NotAParticipant)?;
|
Err(Error::NotAParticipant)?;
|
||||||
};
|
};
|
||||||
@@ -231,7 +232,7 @@ impl<C: Curves> Dkg<C> {
|
|||||||
|
|
||||||
let mut encrypted_secret_shares = HashMap::with_capacity(usize::from(n));
|
let mut encrypted_secret_shares = HashMap::with_capacity(usize::from(n));
|
||||||
for (l, encryption_key) in Participant::iter().take(usize::from(n)).zip(encryption_keys) {
|
for (l, encryption_key) in Participant::iter().take(usize::from(n)).zip(encryption_keys) {
|
||||||
let share = polynomial::<<C::ToweringCurve as Ciphersuite>::F>(&coefficients, l);
|
let share = polynomial::<<C::ToweringCurve as WrappedGroup>::F>(&coefficients, l);
|
||||||
encrypted_secret_shares.insert(l, *share + *encryption_key);
|
encrypted_secret_shares.insert(l, *share + *encryption_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,26 +244,26 @@ impl<C: Curves> Dkg<C> {
|
|||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
fn verifiable_encryption_statements<C: Curves>(
|
fn verifiable_encryption_statements<C: Curves>(
|
||||||
rng: &mut (impl RngCore + CryptoRng),
|
rng: &mut (impl RngCore + CryptoRng),
|
||||||
coefficients: &[<C::ToweringCurve as Ciphersuite>::G],
|
coefficients: &[<C::ToweringCurve as WrappedGroup>::G],
|
||||||
encryption_key_commitments: &[<C::ToweringCurve as Ciphersuite>::G],
|
encryption_key_commitments: &[<C::ToweringCurve as WrappedGroup>::G],
|
||||||
encrypted_secret_shares: &HashMap<Participant, <C::ToweringCurve as Ciphersuite>::F>,
|
encrypted_secret_shares: &HashMap<Participant, <C::ToweringCurve as WrappedGroup>::F>,
|
||||||
) -> (
|
) -> (
|
||||||
<C::ToweringCurve as Ciphersuite>::F,
|
<C::ToweringCurve as WrappedGroup>::F,
|
||||||
Vec<(<C::ToweringCurve as Ciphersuite>::F, <C::ToweringCurve as Ciphersuite>::G)>,
|
Vec<(<C::ToweringCurve as WrappedGroup>::F, <C::ToweringCurve as WrappedGroup>::G)>,
|
||||||
) {
|
) {
|
||||||
let mut g_scalar = <C::ToweringCurve as Ciphersuite>::F::ZERO;
|
let mut g_scalar = <C::ToweringCurve as WrappedGroup>::F::ZERO;
|
||||||
let mut pairs = Vec::with_capacity(coefficients.len() + encryption_key_commitments.len());
|
let mut pairs = Vec::with_capacity(coefficients.len() + encryption_key_commitments.len());
|
||||||
|
|
||||||
// Push on the commitments to the polynomial being secret-shared
|
// Push on the commitments to the polynomial being secret-shared
|
||||||
for coefficient in coefficients {
|
for coefficient in coefficients {
|
||||||
// This uses `0` as we'll add to it later, given its fixed position
|
// This uses `0` as we'll add to it later, given its fixed position
|
||||||
pairs.push((<C::ToweringCurve as Ciphersuite>::F::ZERO, *coefficient));
|
pairs.push((<C::ToweringCurve as WrappedGroup>::F::ZERO, *coefficient));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i, encrypted_secret_share) in encrypted_secret_shares {
|
for (i, encrypted_secret_share) in encrypted_secret_shares {
|
||||||
let encryption_key_commitment = encryption_key_commitments[usize::from(u16::from(*i)) - 1];
|
let encryption_key_commitment = encryption_key_commitments[usize::from(u16::from(*i)) - 1];
|
||||||
|
|
||||||
let weight = <C::ToweringCurve as Ciphersuite>::F::random(&mut *rng);
|
let weight = <C::ToweringCurve as WrappedGroup>::F::random(&mut *rng);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The encrypted secret share scaling `G`, minus the encryption key commitment, minus the
|
The encrypted secret share scaling `G`, minus the encryption key commitment, minus the
|
||||||
@@ -274,7 +275,7 @@ fn verifiable_encryption_statements<C: Curves>(
|
|||||||
pairs.push((weight, encryption_key_commitment));
|
pairs.push((weight, encryption_key_commitment));
|
||||||
// Calculate the commitment to the secret share via the commitments to the polynomial
|
// Calculate the commitment to the secret share via the commitments to the polynomial
|
||||||
{
|
{
|
||||||
let i = <C::ToweringCurve as Ciphersuite>::F::from(u64::from(u16::from(*i)));
|
let i = <C::ToweringCurve as WrappedGroup>::F::from(u64::from(u16::from(*i)));
|
||||||
(0 .. coefficients.len()).fold(weight, |exp, j| {
|
(0 .. coefficients.len()).fold(weight, |exp, j| {
|
||||||
pairs[j].0 += exp;
|
pairs[j].0 += exp;
|
||||||
exp * i
|
exp * i
|
||||||
@@ -300,7 +301,7 @@ impl<C: Curves> Dkg<C> {
|
|||||||
generators: &Generators<C>,
|
generators: &Generators<C>,
|
||||||
context: [u8; 32],
|
context: [u8; 32],
|
||||||
t: u16,
|
t: u16,
|
||||||
evrf_public_keys: &[<C::EmbeddedCurve as Ciphersuite>::G],
|
evrf_public_keys: &[<C::EmbeddedCurve as WrappedGroup>::G],
|
||||||
participations: &HashMap<Participant, Participation<C>>,
|
participations: &HashMap<Participant, Participation<C>>,
|
||||||
) -> Result<VerifyResult<C>, Error> {
|
) -> Result<VerifyResult<C>, Error> {
|
||||||
let Ok(n) = u16::try_from(evrf_public_keys.len()) else {
|
let Ok(n) = u16::try_from(evrf_public_keys.len()) else {
|
||||||
@@ -386,7 +387,7 @@ impl<C: Curves> Dkg<C> {
|
|||||||
{
|
{
|
||||||
let mut share_verification_statements_actual = HashMap::with_capacity(valid.len());
|
let mut share_verification_statements_actual = HashMap::with_capacity(valid.len());
|
||||||
if !{
|
if !{
|
||||||
let mut g_scalar = <C::ToweringCurve as Ciphersuite>::F::ZERO;
|
let mut g_scalar = <C::ToweringCurve as WrappedGroup>::F::ZERO;
|
||||||
let mut pairs = Vec::with_capacity(valid.len() * (usize::from(t) + evrf_public_keys.len()));
|
let mut pairs = Vec::with_capacity(valid.len() * (usize::from(t) + evrf_public_keys.len()));
|
||||||
for (i, (encrypted_secret_shares, data)) in &valid {
|
for (i, (encrypted_secret_shares, data)) in &valid {
|
||||||
let (this_g_scalar, mut these_pairs) = verifiable_encryption_statements::<C>(
|
let (this_g_scalar, mut these_pairs) = verifiable_encryption_statements::<C>(
|
||||||
@@ -417,9 +418,11 @@ impl<C: Curves> Dkg<C> {
|
|||||||
let sum_encrypted_secret_share = sum_encrypted_secret_shares
|
let sum_encrypted_secret_share = sum_encrypted_secret_shares
|
||||||
.get(j)
|
.get(j)
|
||||||
.copied()
|
.copied()
|
||||||
.unwrap_or(<C::ToweringCurve as Ciphersuite>::F::ZERO);
|
.unwrap_or(<C::ToweringCurve as WrappedGroup>::F::ZERO);
|
||||||
let sum_mask =
|
let sum_mask = sum_masks
|
||||||
sum_masks.get(j).copied().unwrap_or(<C::ToweringCurve as Ciphersuite>::G::identity());
|
.get(j)
|
||||||
|
.copied()
|
||||||
|
.unwrap_or(<C::ToweringCurve as WrappedGroup>::G::identity());
|
||||||
sum_encrypted_secret_shares.insert(*j, sum_encrypted_secret_share + enc_share);
|
sum_encrypted_secret_shares.insert(*j, sum_encrypted_secret_share + enc_share);
|
||||||
|
|
||||||
let j_index = usize::from(u16::from(*j)) - 1;
|
let j_index = usize::from(u16::from(*j)) - 1;
|
||||||
@@ -487,7 +490,7 @@ impl<C: Curves> Dkg<C> {
|
|||||||
for i in Participant::iter().take(usize::from(n)) {
|
for i in Participant::iter().take(usize::from(n)) {
|
||||||
verification_shares.insert(
|
verification_shares.insert(
|
||||||
i,
|
i,
|
||||||
(<C::ToweringCurve as Ciphersuite>::generator() * sum_encrypted_secret_shares[&i]) -
|
(<C::ToweringCurve as WrappedGroup>::generator() * sum_encrypted_secret_shares[&i]) -
|
||||||
sum_masks[&i],
|
sum_masks[&i],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -506,9 +509,10 @@ impl<C: Curves> Dkg<C> {
|
|||||||
/// This will return _all_ keys belong to the participant.
|
/// This will return _all_ keys belong to the participant.
|
||||||
pub fn keys(
|
pub fn keys(
|
||||||
&self,
|
&self,
|
||||||
evrf_private_key: &Zeroizing<<C::EmbeddedCurve as Ciphersuite>::F>,
|
evrf_private_key: &Zeroizing<<C::EmbeddedCurve as WrappedGroup>::F>,
|
||||||
) -> Vec<ThresholdKeys<C::ToweringCurve>> {
|
) -> Vec<ThresholdKeys<C::ToweringCurve>> {
|
||||||
let evrf_public_key = <C::EmbeddedCurve as Ciphersuite>::generator() * evrf_private_key.deref();
|
let evrf_public_key =
|
||||||
|
<C::EmbeddedCurve as WrappedGroup>::generator() * evrf_private_key.deref();
|
||||||
let mut is = Vec::with_capacity(1);
|
let mut is = Vec::with_capacity(1);
|
||||||
for (i, evrf_key) in Participant::iter().zip(self.evrf_public_keys.iter()) {
|
for (i, evrf_key) in Participant::iter().zip(self.evrf_public_keys.iter()) {
|
||||||
if *evrf_key == evrf_public_key {
|
if *evrf_key == evrf_public_key {
|
||||||
@@ -518,14 +522,14 @@ impl<C: Curves> Dkg<C> {
|
|||||||
|
|
||||||
let mut res = Vec::with_capacity(is.len());
|
let mut res = Vec::with_capacity(is.len());
|
||||||
for i in is {
|
for i in is {
|
||||||
let mut secret_share = Zeroizing::new(<C::ToweringCurve as Ciphersuite>::F::ZERO);
|
let mut secret_share = Zeroizing::new(<C::ToweringCurve as WrappedGroup>::F::ZERO);
|
||||||
for shares in self.encrypted_secret_shares.values() {
|
for shares in self.encrypted_secret_shares.values() {
|
||||||
let (ecdh_commitments, encrypted_secret_share) = shares[&i];
|
let (ecdh_commitments, encrypted_secret_share) = shares[&i];
|
||||||
|
|
||||||
let mut ecdh = Zeroizing::new(<C::ToweringCurve as Ciphersuite>::F::ZERO);
|
let mut ecdh = Zeroizing::new(<C::ToweringCurve as WrappedGroup>::F::ZERO);
|
||||||
for point in ecdh_commitments {
|
for point in ecdh_commitments {
|
||||||
let (mut x, mut y) =
|
let (mut x, mut y) =
|
||||||
<C::EmbeddedCurve as Ciphersuite>::G::to_xy(point * evrf_private_key.deref()).unwrap();
|
<C::EmbeddedCurve as WrappedGroup>::G::to_xy(point * evrf_private_key.deref()).unwrap();
|
||||||
*ecdh += x;
|
*ecdh += x;
|
||||||
x.zeroize();
|
x.zeroize();
|
||||||
y.zeroize();
|
y.zeroize();
|
||||||
@@ -534,7 +538,7 @@ impl<C: Curves> Dkg<C> {
|
|||||||
}
|
}
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
self.verification_shares[&i],
|
self.verification_shares[&i],
|
||||||
<C::ToweringCurve as Ciphersuite>::G::generator() * secret_share.deref()
|
<C::ToweringCurve as WrappedGroup>::generator() * secret_share.deref()
|
||||||
);
|
);
|
||||||
|
|
||||||
res.push(
|
res.push(
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use zeroize::Zeroizing;
|
|||||||
use rand_core::{RngCore, CryptoRng, SeedableRng};
|
use rand_core::{RngCore, CryptoRng, SeedableRng};
|
||||||
use rand_chacha::ChaCha20Rng;
|
use rand_chacha::ChaCha20Rng;
|
||||||
|
|
||||||
use ciphersuite::{group::ff::Field, Ciphersuite};
|
use ciphersuite::{group::ff::Field, WrappedGroup};
|
||||||
|
|
||||||
use generalized_bulletproofs::{
|
use generalized_bulletproofs::{
|
||||||
Generators, BatchVerifier, PedersenCommitment, PedersenVectorCommitment,
|
Generators, BatchVerifier, PedersenCommitment, PedersenVectorCommitment,
|
||||||
@@ -28,8 +28,8 @@ mod tape;
|
|||||||
use tape::*;
|
use tape::*;
|
||||||
|
|
||||||
type EmbeddedPoint<C> = (
|
type EmbeddedPoint<C> = (
|
||||||
<<<C as Curves>::EmbeddedCurve as Ciphersuite>::G as DivisorCurve>::FieldElement,
|
<<<C as Curves>::EmbeddedCurve as WrappedGroup>::G as DivisorCurve>::FieldElement,
|
||||||
<<<C as Curves>::EmbeddedCurve as Ciphersuite>::G as DivisorCurve>::FieldElement,
|
<<<C as Curves>::EmbeddedCurve as WrappedGroup>::G as DivisorCurve>::FieldElement,
|
||||||
);
|
);
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
@@ -37,14 +37,15 @@ struct Circuit<
|
|||||||
'a,
|
'a,
|
||||||
C: Curves,
|
C: Curves,
|
||||||
CG: Iterator<
|
CG: Iterator<
|
||||||
Item = ChallengedGenerator<<C::ToweringCurve as Ciphersuite>::F, C::EmbeddedCurveParameters>,
|
Item = ChallengedGenerator<<C::ToweringCurve as WrappedGroup>::F, C::EmbeddedCurveParameters>,
|
||||||
>,
|
>,
|
||||||
> {
|
> {
|
||||||
curve_spec: &'a CurveSpec<<<C::EmbeddedCurve as Ciphersuite>::G as DivisorCurve>::FieldElement>,
|
curve_spec: &'a CurveSpec<<<C::EmbeddedCurve as WrappedGroup>::G as DivisorCurve>::FieldElement>,
|
||||||
circuit: &'a mut BpCircuit<C::ToweringCurve>,
|
circuit: &'a mut BpCircuit<C::ToweringCurve>,
|
||||||
challenge: DiscreteLogChallenge<<C::ToweringCurve as Ciphersuite>::F, C::EmbeddedCurveParameters>,
|
challenge:
|
||||||
|
DiscreteLogChallenge<<C::ToweringCurve as WrappedGroup>::F, C::EmbeddedCurveParameters>,
|
||||||
challenged_G:
|
challenged_G:
|
||||||
ChallengedGenerator<<C::ToweringCurve as Ciphersuite>::F, C::EmbeddedCurveParameters>,
|
ChallengedGenerator<<C::ToweringCurve as WrappedGroup>::F, C::EmbeddedCurveParameters>,
|
||||||
challenged_generators: &'a mut CG,
|
challenged_generators: &'a mut CG,
|
||||||
tape: Tape,
|
tape: Tape,
|
||||||
pedersen_commitment_tape: PedersenCommitmentTape,
|
pedersen_commitment_tape: PedersenCommitmentTape,
|
||||||
@@ -54,7 +55,7 @@ impl<
|
|||||||
'a,
|
'a,
|
||||||
C: Curves,
|
C: Curves,
|
||||||
CG: Iterator<
|
CG: Iterator<
|
||||||
Item = ChallengedGenerator<<C::ToweringCurve as Ciphersuite>::F, C::EmbeddedCurveParameters>,
|
Item = ChallengedGenerator<<C::ToweringCurve as WrappedGroup>::F, C::EmbeddedCurveParameters>,
|
||||||
>,
|
>,
|
||||||
> Circuit<'a, C, CG>
|
> Circuit<'a, C, CG>
|
||||||
{
|
{
|
||||||
@@ -92,7 +93,7 @@ impl<
|
|||||||
&self.challenge,
|
&self.challenge,
|
||||||
&challenged_generator,
|
&challenged_generator,
|
||||||
);
|
);
|
||||||
lincomb = lincomb.term(<C::ToweringCurve as Ciphersuite>::F::ONE, point.x());
|
lincomb = lincomb.term(<C::ToweringCurve as WrappedGroup>::F::ONE, point.x());
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
Constrain the sum of the two `x` coordinates to be equal to the value committed to in a
|
Constrain the sum of the two `x` coordinates to be equal to the value committed to in a
|
||||||
@@ -137,7 +138,7 @@ impl<
|
|||||||
&self.challenge,
|
&self.challenge,
|
||||||
&challenged_public_key,
|
&challenged_public_key,
|
||||||
);
|
);
|
||||||
lincomb = lincomb.term(<C::ToweringCurve as Ciphersuite>::F::ONE, point.x());
|
lincomb = lincomb.term(<C::ToweringCurve as WrappedGroup>::F::ONE, point.x());
|
||||||
debug_assert!(point_with_dlogs.next().is_none());
|
debug_assert!(point_with_dlogs.next().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,20 +153,20 @@ impl<
|
|||||||
/// The result of proving.
|
/// The result of proving.
|
||||||
pub(super) struct ProveResult<C: Curves> {
|
pub(super) struct ProveResult<C: Curves> {
|
||||||
/// The coefficients for use in the DKG.
|
/// The coefficients for use in the DKG.
|
||||||
pub(super) coefficients: Vec<Zeroizing<<C::ToweringCurve as Ciphersuite>::F>>,
|
pub(super) coefficients: Vec<Zeroizing<<C::ToweringCurve as WrappedGroup>::F>>,
|
||||||
/// The masks to encrypt secret shares with.
|
/// The masks to encrypt secret shares with.
|
||||||
pub(super) encryption_keys: Vec<Zeroizing<<C::ToweringCurve as Ciphersuite>::F>>,
|
pub(super) encryption_keys: Vec<Zeroizing<<C::ToweringCurve as WrappedGroup>::F>>,
|
||||||
/// The proof itself.
|
/// The proof itself.
|
||||||
pub(super) proof: Vec<u8>,
|
pub(super) proof: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct Verified<C: Curves> {
|
pub(super) struct Verified<C: Curves> {
|
||||||
/// The commitments to the coefficients used within the DKG.
|
/// The commitments to the coefficients used within the DKG.
|
||||||
pub(super) coefficients: Vec<<C::ToweringCurve as Ciphersuite>::G>,
|
pub(super) coefficients: Vec<<C::ToweringCurve as WrappedGroup>::G>,
|
||||||
/// The ephemeral public keys to perform ECDHs with
|
/// The ephemeral public keys to perform ECDHs with
|
||||||
pub(super) ecdh_commitments: Vec<[<C::EmbeddedCurve as Ciphersuite>::G; 2]>,
|
pub(super) ecdh_commitments: Vec<[<C::EmbeddedCurve as WrappedGroup>::G; 2]>,
|
||||||
/// The commitments to the masks used to encrypt secret shares with.
|
/// The commitments to the masks used to encrypt secret shares with.
|
||||||
pub(super) encryption_key_commitments: Vec<<C::ToweringCurve as Ciphersuite>::G>,
|
pub(super) encryption_key_commitments: Vec<<C::ToweringCurve as WrappedGroup>::G>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Curves> fmt::Debug for Verified<C> {
|
impl<C: Curves> fmt::Debug for Verified<C> {
|
||||||
@@ -175,7 +176,7 @@ impl<C: Curves> fmt::Debug for Verified<C> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GeneratorTable<C> = generalized_bulletproofs_ec_gadgets::GeneratorTable<
|
type GeneratorTable<C> = generalized_bulletproofs_ec_gadgets::GeneratorTable<
|
||||||
<<<C as Curves>::EmbeddedCurve as Ciphersuite>::G as DivisorCurve>::FieldElement,
|
<<<C as Curves>::EmbeddedCurve as WrappedGroup>::G as DivisorCurve>::FieldElement,
|
||||||
<C as Curves>::EmbeddedCurveParameters,
|
<C as Curves>::EmbeddedCurveParameters,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
@@ -219,7 +220,7 @@ impl<C: Curves> Proof<C> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn circuit(
|
fn circuit(
|
||||||
curve_spec: &CurveSpec<<<C::EmbeddedCurve as Ciphersuite>::G as DivisorCurve>::FieldElement>,
|
curve_spec: &CurveSpec<<<C::EmbeddedCurve as WrappedGroup>::G as DivisorCurve>::FieldElement>,
|
||||||
evrf_public_key: EmbeddedPoint<C>,
|
evrf_public_key: EmbeddedPoint<C>,
|
||||||
coefficients: usize,
|
coefficients: usize,
|
||||||
ecdh_commitments: &[[EmbeddedPoint<C>; 2]],
|
ecdh_commitments: &[[EmbeddedPoint<C>; 2]],
|
||||||
@@ -281,7 +282,7 @@ impl<C: Curves> Proof<C> {
|
|||||||
fn sample_coefficients_evrf_points(
|
fn sample_coefficients_evrf_points(
|
||||||
seed: [u8; 32],
|
seed: [u8; 32],
|
||||||
coefficients: usize,
|
coefficients: usize,
|
||||||
) -> Vec<<C::EmbeddedCurve as Ciphersuite>::G> {
|
) -> Vec<<C::EmbeddedCurve as WrappedGroup>::G> {
|
||||||
let mut rng = ChaCha20Rng::from_seed(seed);
|
let mut rng = ChaCha20Rng::from_seed(seed);
|
||||||
let quantity = 2 * coefficients;
|
let quantity = 2 * coefficients;
|
||||||
let mut res = Vec::with_capacity(quantity);
|
let mut res = Vec::with_capacity(quantity);
|
||||||
@@ -293,28 +294,29 @@ impl<C: Curves> Proof<C> {
|
|||||||
|
|
||||||
/// Create the required tables for the generators.
|
/// Create the required tables for the generators.
|
||||||
fn generator_tables(
|
fn generator_tables(
|
||||||
coefficients_evrf_points: &[<C::EmbeddedCurve as Ciphersuite>::G],
|
coefficients_evrf_points: &[<C::EmbeddedCurve as WrappedGroup>::G],
|
||||||
participants: &[<<C as Curves>::EmbeddedCurve as Ciphersuite>::G],
|
participants: &[<<C as Curves>::EmbeddedCurve as WrappedGroup>::G],
|
||||||
) -> Vec<GeneratorTable<C>> {
|
) -> Vec<GeneratorTable<C>> {
|
||||||
let curve_spec = CurveSpec {
|
let curve_spec = CurveSpec {
|
||||||
a: <<C as Curves>::EmbeddedCurve as Ciphersuite>::G::a(),
|
a: <<C as Curves>::EmbeddedCurve as WrappedGroup>::G::a(),
|
||||||
b: <<C as Curves>::EmbeddedCurve as Ciphersuite>::G::b(),
|
b: <<C as Curves>::EmbeddedCurve as WrappedGroup>::G::b(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut generator_tables =
|
let mut generator_tables =
|
||||||
Vec::with_capacity(1 + coefficients_evrf_points.len() + participants.len());
|
Vec::with_capacity(1 + coefficients_evrf_points.len() + participants.len());
|
||||||
{
|
{
|
||||||
let (x, y) =
|
let (x, y) = <C::EmbeddedCurve as WrappedGroup>::G::to_xy(
|
||||||
<C::EmbeddedCurve as Ciphersuite>::G::to_xy(<C::EmbeddedCurve as Ciphersuite>::generator())
|
<C::EmbeddedCurve as WrappedGroup>::generator(),
|
||||||
.unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
generator_tables.push(GeneratorTable::<C>::new(&curve_spec, x, y));
|
generator_tables.push(GeneratorTable::<C>::new(&curve_spec, x, y));
|
||||||
}
|
}
|
||||||
for generator in coefficients_evrf_points {
|
for generator in coefficients_evrf_points {
|
||||||
let (x, y) = <C::EmbeddedCurve as Ciphersuite>::G::to_xy(*generator).unwrap();
|
let (x, y) = <C::EmbeddedCurve as WrappedGroup>::G::to_xy(*generator).unwrap();
|
||||||
generator_tables.push(GeneratorTable::<C>::new(&curve_spec, x, y));
|
generator_tables.push(GeneratorTable::<C>::new(&curve_spec, x, y));
|
||||||
}
|
}
|
||||||
for generator in participants {
|
for generator in participants {
|
||||||
let (x, y) = <C::EmbeddedCurve as Ciphersuite>::G::to_xy(*generator).unwrap();
|
let (x, y) = <C::EmbeddedCurve as WrappedGroup>::G::to_xy(*generator).unwrap();
|
||||||
generator_tables.push(GeneratorTable::<C>::new(&curve_spec, x, y));
|
generator_tables.push(GeneratorTable::<C>::new(&curve_spec, x, y));
|
||||||
}
|
}
|
||||||
generator_tables
|
generator_tables
|
||||||
@@ -325,12 +327,12 @@ impl<C: Curves> Proof<C> {
|
|||||||
generators: &Generators<C::ToweringCurve>,
|
generators: &Generators<C::ToweringCurve>,
|
||||||
transcript: [u8; 32],
|
transcript: [u8; 32],
|
||||||
coefficients: usize,
|
coefficients: usize,
|
||||||
participant_public_keys: &[<<C as Curves>::EmbeddedCurve as Ciphersuite>::G],
|
participant_public_keys: &[<<C as Curves>::EmbeddedCurve as WrappedGroup>::G],
|
||||||
evrf_private_key: &Zeroizing<<<C as Curves>::EmbeddedCurve as Ciphersuite>::F>,
|
evrf_private_key: &Zeroizing<<<C as Curves>::EmbeddedCurve as WrappedGroup>::F>,
|
||||||
) -> Result<ProveResult<C>, AcProveError> {
|
) -> Result<ProveResult<C>, AcProveError> {
|
||||||
let curve_spec = CurveSpec {
|
let curve_spec = CurveSpec {
|
||||||
a: <<C as Curves>::EmbeddedCurve as Ciphersuite>::G::a(),
|
a: <<C as Curves>::EmbeddedCurve as WrappedGroup>::G::a(),
|
||||||
b: <<C as Curves>::EmbeddedCurve as Ciphersuite>::G::b(),
|
b: <<C as Curves>::EmbeddedCurve as WrappedGroup>::G::b(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let coefficients_evrf_points = Self::sample_coefficients_evrf_points(transcript, coefficients);
|
let coefficients_evrf_points = Self::sample_coefficients_evrf_points(transcript, coefficients);
|
||||||
@@ -340,7 +342,7 @@ impl<C: Curves> Proof<C> {
|
|||||||
// Push a discrete logarithm onto the tape
|
// Push a discrete logarithm onto the tape
|
||||||
let discrete_log =
|
let discrete_log =
|
||||||
|vector_commitment_tape: &mut Vec<_>,
|
|vector_commitment_tape: &mut Vec<_>,
|
||||||
dlog: &ScalarDecomposition<<<C as Curves>::EmbeddedCurve as Ciphersuite>::F>| {
|
dlog: &ScalarDecomposition<<<C as Curves>::EmbeddedCurve as WrappedGroup>::F>| {
|
||||||
for coefficient in dlog.decomposition() {
|
for coefficient in dlog.decomposition() {
|
||||||
vector_commitment_tape.push(<_>::from(*coefficient));
|
vector_commitment_tape.push(<_>::from(*coefficient));
|
||||||
}
|
}
|
||||||
@@ -351,8 +353,8 @@ impl<C: Curves> Proof<C> {
|
|||||||
// Returns the point for which the claim was made.
|
// Returns the point for which the claim was made.
|
||||||
let discrete_log_claim =
|
let discrete_log_claim =
|
||||||
|vector_commitment_tape: &mut Vec<_>,
|
|vector_commitment_tape: &mut Vec<_>,
|
||||||
dlog: &ScalarDecomposition<<<C as Curves>::EmbeddedCurve as Ciphersuite>::F>,
|
dlog: &ScalarDecomposition<<<C as Curves>::EmbeddedCurve as WrappedGroup>::F>,
|
||||||
generator: <<C as Curves>::EmbeddedCurve as Ciphersuite>::G| {
|
generator: <<C as Curves>::EmbeddedCurve as WrappedGroup>::G| {
|
||||||
{
|
{
|
||||||
let divisor =
|
let divisor =
|
||||||
Zeroizing::new(dlog.scalar_mul_divisor(generator).normalize_x_coefficient());
|
Zeroizing::new(dlog.scalar_mul_divisor(generator).normalize_x_coefficient());
|
||||||
@@ -368,12 +370,12 @@ impl<C: Curves> Proof<C> {
|
|||||||
.y_coefficients
|
.y_coefficients
|
||||||
.first()
|
.first()
|
||||||
.copied()
|
.copied()
|
||||||
.unwrap_or(<C::ToweringCurve as Ciphersuite>::F::ZERO),
|
.unwrap_or(<C::ToweringCurve as WrappedGroup>::F::ZERO),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let dh = generator * dlog.scalar();
|
let dh = generator * dlog.scalar();
|
||||||
let (x, y) = <C::EmbeddedCurve as Ciphersuite>::G::to_xy(dh).unwrap();
|
let (x, y) = <C::EmbeddedCurve as WrappedGroup>::G::to_xy(dh).unwrap();
|
||||||
vector_commitment_tape.push(x);
|
vector_commitment_tape.push(x);
|
||||||
vector_commitment_tape.push(y);
|
vector_commitment_tape.push(y);
|
||||||
(dh, (x, y))
|
(dh, (x, y))
|
||||||
@@ -387,7 +389,7 @@ impl<C: Curves> Proof<C> {
|
|||||||
let mut coefficients = Vec::with_capacity(coefficients);
|
let mut coefficients = Vec::with_capacity(coefficients);
|
||||||
let evrf_public_key = {
|
let evrf_public_key = {
|
||||||
let evrf_private_key =
|
let evrf_private_key =
|
||||||
ScalarDecomposition::<<C::EmbeddedCurve as Ciphersuite>::F>::new(**evrf_private_key)
|
ScalarDecomposition::<<C::EmbeddedCurve as WrappedGroup>::F>::new(**evrf_private_key)
|
||||||
.expect("eVRF private key was zero");
|
.expect("eVRF private key was zero");
|
||||||
|
|
||||||
discrete_log(&mut vector_commitment_tape, &evrf_private_key);
|
discrete_log(&mut vector_commitment_tape, &evrf_private_key);
|
||||||
@@ -396,12 +398,12 @@ impl<C: Curves> Proof<C> {
|
|||||||
let (_, evrf_public_key) = discrete_log_claim(
|
let (_, evrf_public_key) = discrete_log_claim(
|
||||||
&mut vector_commitment_tape,
|
&mut vector_commitment_tape,
|
||||||
&evrf_private_key,
|
&evrf_private_key,
|
||||||
<<C as Curves>::EmbeddedCurve as Ciphersuite>::generator(),
|
<<C as Curves>::EmbeddedCurve as WrappedGroup>::generator(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Push the divisor for each point we use in the eVRF
|
// Push the divisor for each point we use in the eVRF
|
||||||
for pair in coefficients_evrf_points.chunks(2) {
|
for pair in coefficients_evrf_points.chunks(2) {
|
||||||
let mut coefficient = Zeroizing::new(<C::ToweringCurve as Ciphersuite>::F::ZERO);
|
let mut coefficient = Zeroizing::new(<C::ToweringCurve as WrappedGroup>::F::ZERO);
|
||||||
for point in pair {
|
for point in pair {
|
||||||
let (_, (dh_x, _)) =
|
let (_, (dh_x, _)) =
|
||||||
discrete_log_claim(&mut vector_commitment_tape, &evrf_private_key, *point);
|
discrete_log_claim(&mut vector_commitment_tape, &evrf_private_key, *point);
|
||||||
@@ -418,15 +420,16 @@ impl<C: Curves> Proof<C> {
|
|||||||
let mut ecdh_commitments = Vec::with_capacity(2 * participant_public_keys.len());
|
let mut ecdh_commitments = Vec::with_capacity(2 * participant_public_keys.len());
|
||||||
let mut ecdh_commitments_xy = Vec::with_capacity(participant_public_keys.len());
|
let mut ecdh_commitments_xy = Vec::with_capacity(participant_public_keys.len());
|
||||||
for participant_public_key in participant_public_keys {
|
for participant_public_key in participant_public_keys {
|
||||||
let mut ecdh_commitments_xy_i =
|
let mut ecdh_commitments_xy_i = [(
|
||||||
[(<C::ToweringCurve as Ciphersuite>::F::ZERO, <C::ToweringCurve as Ciphersuite>::F::ZERO);
|
<C::ToweringCurve as WrappedGroup>::F::ZERO,
|
||||||
2];
|
<C::ToweringCurve as WrappedGroup>::F::ZERO,
|
||||||
let mut encryption_key = Zeroizing::new(<C::ToweringCurve as Ciphersuite>::F::ZERO);
|
); 2];
|
||||||
|
let mut encryption_key = Zeroizing::new(<C::ToweringCurve as WrappedGroup>::F::ZERO);
|
||||||
for ecdh_commitments_xy_i_j_dest in &mut ecdh_commitments_xy_i {
|
for ecdh_commitments_xy_i_j_dest in &mut ecdh_commitments_xy_i {
|
||||||
let mut ecdh_ephemeral_secret;
|
let mut ecdh_ephemeral_secret;
|
||||||
loop {
|
loop {
|
||||||
ecdh_ephemeral_secret =
|
ecdh_ephemeral_secret =
|
||||||
Zeroizing::new(<C::EmbeddedCurve as Ciphersuite>::F::random(&mut *rng));
|
Zeroizing::new(<C::EmbeddedCurve as WrappedGroup>::F::random(&mut *rng));
|
||||||
// 0 would produce the identity, which isn't representable within the discrete-log proof.
|
// 0 would produce the identity, which isn't representable within the discrete-log proof.
|
||||||
if bool::from(!ecdh_ephemeral_secret.is_zero()) {
|
if bool::from(!ecdh_ephemeral_secret.is_zero()) {
|
||||||
break;
|
break;
|
||||||
@@ -434,7 +437,7 @@ impl<C: Curves> Proof<C> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let ecdh_ephemeral_secret =
|
let ecdh_ephemeral_secret =
|
||||||
ScalarDecomposition::<<C::EmbeddedCurve as Ciphersuite>::F>::new(*ecdh_ephemeral_secret)
|
ScalarDecomposition::<<C::EmbeddedCurve as WrappedGroup>::F>::new(*ecdh_ephemeral_secret)
|
||||||
.expect("ECDH ephemeral secret zero");
|
.expect("ECDH ephemeral secret zero");
|
||||||
discrete_log(&mut vector_commitment_tape, &ecdh_ephemeral_secret);
|
discrete_log(&mut vector_commitment_tape, &ecdh_ephemeral_secret);
|
||||||
|
|
||||||
@@ -442,7 +445,7 @@ impl<C: Curves> Proof<C> {
|
|||||||
let (ecdh_commitment, ecdh_commitment_xy_i_j) = discrete_log_claim(
|
let (ecdh_commitment, ecdh_commitment_xy_i_j) = discrete_log_claim(
|
||||||
&mut vector_commitment_tape,
|
&mut vector_commitment_tape,
|
||||||
&ecdh_ephemeral_secret,
|
&ecdh_ephemeral_secret,
|
||||||
<<C as Curves>::EmbeddedCurve as Ciphersuite>::generator(),
|
<<C as Curves>::EmbeddedCurve as WrappedGroup>::generator(),
|
||||||
);
|
);
|
||||||
ecdh_commitments.push(ecdh_commitment);
|
ecdh_commitments.push(ecdh_commitment);
|
||||||
*ecdh_commitments_xy_i_j_dest = ecdh_commitment_xy_i_j;
|
*ecdh_commitments_xy_i_j_dest = ecdh_commitment_xy_i_j;
|
||||||
@@ -470,7 +473,7 @@ impl<C: Curves> Proof<C> {
|
|||||||
for chunk in vector_commitment_tape.chunks(generators_to_use) {
|
for chunk in vector_commitment_tape.chunks(generators_to_use) {
|
||||||
vector_commitments.push(PedersenVectorCommitment {
|
vector_commitments.push(PedersenVectorCommitment {
|
||||||
g_values: chunk.into(),
|
g_values: chunk.into(),
|
||||||
mask: <C::ToweringCurve as Ciphersuite>::F::random(&mut *rng),
|
mask: <C::ToweringCurve as WrappedGroup>::F::random(&mut *rng),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,13 +482,13 @@ impl<C: Curves> Proof<C> {
|
|||||||
for coefficient in &coefficients {
|
for coefficient in &coefficients {
|
||||||
commitments.push(PedersenCommitment {
|
commitments.push(PedersenCommitment {
|
||||||
value: **coefficient,
|
value: **coefficient,
|
||||||
mask: <C::ToweringCurve as Ciphersuite>::F::random(&mut *rng),
|
mask: <C::ToweringCurve as WrappedGroup>::F::random(&mut *rng),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
for enc_mask in &encryption_keys {
|
for enc_mask in &encryption_keys {
|
||||||
commitments.push(PedersenCommitment {
|
commitments.push(PedersenCommitment {
|
||||||
value: **enc_mask,
|
value: **enc_mask,
|
||||||
mask: <C::ToweringCurve as Ciphersuite>::F::random(&mut *rng),
|
mask: <C::ToweringCurve as WrappedGroup>::F::random(&mut *rng),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,13 +539,13 @@ impl<C: Curves> Proof<C> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Prove the openings of the commitments were correct
|
// Prove the openings of the commitments were correct
|
||||||
let mut x = Zeroizing::new(<C::ToweringCurve as Ciphersuite>::F::ZERO);
|
let mut x = Zeroizing::new(<C::ToweringCurve as WrappedGroup>::F::ZERO);
|
||||||
for commitment in commitments {
|
for commitment in commitments {
|
||||||
*x += commitment.mask * transcript.challenge::<C::ToweringCurve>();
|
*x += commitment.mask * transcript.challenge::<C::ToweringCurve>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Produce a Schnorr PoK for the weighted-sum of the Pedersen commitments' blinding factors
|
// Produce a Schnorr PoK for the weighted-sum of the Pedersen commitments' blinding factors
|
||||||
let r = Zeroizing::new(<C::ToweringCurve as Ciphersuite>::F::random(&mut *rng));
|
let r = Zeroizing::new(<C::ToweringCurve as WrappedGroup>::F::random(&mut *rng));
|
||||||
transcript.push_point(&(generators.h() * r.deref()));
|
transcript.push_point(&(generators.h() * r.deref()));
|
||||||
let c = transcript.challenge::<C::ToweringCurve>();
|
let c = transcript.challenge::<C::ToweringCurve>();
|
||||||
transcript.push_scalar((c * x.deref()) + r.deref());
|
transcript.push_scalar((c * x.deref()) + r.deref());
|
||||||
@@ -557,14 +560,14 @@ impl<C: Curves> Proof<C> {
|
|||||||
verifier: &mut BatchVerifier<C::ToweringCurve>,
|
verifier: &mut BatchVerifier<C::ToweringCurve>,
|
||||||
transcript: [u8; 32],
|
transcript: [u8; 32],
|
||||||
coefficients: usize,
|
coefficients: usize,
|
||||||
participant_public_keys: &[<<C as Curves>::EmbeddedCurve as Ciphersuite>::G],
|
participant_public_keys: &[<<C as Curves>::EmbeddedCurve as WrappedGroup>::G],
|
||||||
evrf_public_key: <<C as Curves>::EmbeddedCurve as Ciphersuite>::G,
|
evrf_public_key: <<C as Curves>::EmbeddedCurve as WrappedGroup>::G,
|
||||||
proof: &[u8],
|
proof: &[u8],
|
||||||
) -> Result<Verified<C>, ()> {
|
) -> Result<Verified<C>, ()> {
|
||||||
let (mut transcript, ecdh_commitments, pedersen_commitments) = {
|
let (mut transcript, ecdh_commitments, pedersen_commitments) = {
|
||||||
let curve_spec = CurveSpec {
|
let curve_spec = CurveSpec {
|
||||||
a: <<C as Curves>::EmbeddedCurve as Ciphersuite>::G::a(),
|
a: <<C as Curves>::EmbeddedCurve as WrappedGroup>::G::a(),
|
||||||
b: <<C as Curves>::EmbeddedCurve as Ciphersuite>::G::b(),
|
b: <<C as Curves>::EmbeddedCurve as WrappedGroup>::G::b(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let coefficients_evrf_points =
|
let coefficients_evrf_points =
|
||||||
@@ -600,9 +603,9 @@ impl<C: Curves> Proof<C> {
|
|||||||
ecdh_commitments.push(ecdh_commitments_i);
|
ecdh_commitments.push(ecdh_commitments_i);
|
||||||
// This inherently bans using the identity point, as it won't have an affine representation
|
// This inherently bans using the identity point, as it won't have an affine representation
|
||||||
ecdh_commitments_xy.push([
|
ecdh_commitments_xy.push([
|
||||||
<<C::EmbeddedCurve as Ciphersuite>::G as DivisorCurve>::to_xy(ecdh_commitments_i[0])
|
<<C::EmbeddedCurve as WrappedGroup>::G as DivisorCurve>::to_xy(ecdh_commitments_i[0])
|
||||||
.ok_or(())?,
|
.ok_or(())?,
|
||||||
<<C::EmbeddedCurve as Ciphersuite>::G as DivisorCurve>::to_xy(ecdh_commitments_i[1])
|
<<C::EmbeddedCurve as WrappedGroup>::G as DivisorCurve>::to_xy(ecdh_commitments_i[1])
|
||||||
.ok_or(())?,
|
.ok_or(())?,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -610,7 +613,7 @@ impl<C: Curves> Proof<C> {
|
|||||||
let mut circuit = BpCircuit::verify();
|
let mut circuit = BpCircuit::verify();
|
||||||
Self::circuit(
|
Self::circuit(
|
||||||
&curve_spec,
|
&curve_spec,
|
||||||
<C::EmbeddedCurve as Ciphersuite>::G::to_xy(evrf_public_key).ok_or(())?,
|
<C::EmbeddedCurve as WrappedGroup>::G::to_xy(evrf_public_key).ok_or(())?,
|
||||||
coefficients,
|
coefficients,
|
||||||
&ecdh_commitments_xy,
|
&ecdh_commitments_xy,
|
||||||
&generator_tables.iter().collect::<Vec<_>>(),
|
&generator_tables.iter().collect::<Vec<_>>(),
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ use zeroize::Zeroizing;
|
|||||||
use rand_core::OsRng;
|
use rand_core::OsRng;
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
|
|
||||||
use ciphersuite::{group::ff::Field, Ciphersuite};
|
use ciphersuite::{group::ff::Field, WrappedGroup};
|
||||||
use embedwards25519::Embedwards25519;
|
use embedwards25519::Embedwards25519;
|
||||||
|
|
||||||
use dkg_recovery::recover_key;
|
use dkg_recovery::recover_key;
|
||||||
use crate::{Participant, Curves, Generators, VerifyResult, Dkg, Ristretto};
|
use crate::{Participant, Curves, Generators, VerifyResult, Dkg, Ed25519};
|
||||||
|
|
||||||
mod proof;
|
mod proof;
|
||||||
|
|
||||||
@@ -17,14 +17,14 @@ const PARTICIPANTS: u16 = 5;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dkg() {
|
fn dkg() {
|
||||||
let generators = Generators::<Ristretto>::new(THRESHOLD, PARTICIPANTS);
|
let generators = Generators::<Ed25519>::new(THRESHOLD, PARTICIPANTS);
|
||||||
let context = [0; 32];
|
let context = [0; 32];
|
||||||
|
|
||||||
let mut priv_keys = vec![];
|
let mut priv_keys = vec![];
|
||||||
let mut pub_keys = vec![];
|
let mut pub_keys = vec![];
|
||||||
for i in 0 .. PARTICIPANTS {
|
for i in 0 .. PARTICIPANTS {
|
||||||
let priv_key = <Embedwards25519 as Ciphersuite>::F::random(&mut OsRng);
|
let priv_key = <Embedwards25519 as WrappedGroup>::F::random(&mut OsRng);
|
||||||
pub_keys.push(<Embedwards25519 as Ciphersuite>::generator() * priv_key);
|
pub_keys.push(<Embedwards25519 as WrappedGroup>::generator() * priv_key);
|
||||||
priv_keys.push((Participant::new(1 + i).unwrap(), Zeroizing::new(priv_key)));
|
priv_keys.push((Participant::new(1 + i).unwrap(), Zeroizing::new(priv_key)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,27 +34,15 @@ fn dkg() {
|
|||||||
for (i, priv_key) in priv_keys.iter().take(usize::from(THRESHOLD)) {
|
for (i, priv_key) in priv_keys.iter().take(usize::from(THRESHOLD)) {
|
||||||
participations.insert(
|
participations.insert(
|
||||||
*i,
|
*i,
|
||||||
Dkg::<Ristretto>::participate(
|
Dkg::<Ed25519>::participate(&mut OsRng, &generators, context, THRESHOLD, &pub_keys, priv_key)
|
||||||
&mut OsRng,
|
.unwrap(),
|
||||||
&generators,
|
|
||||||
context,
|
|
||||||
THRESHOLD,
|
|
||||||
&pub_keys,
|
|
||||||
priv_key,
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let VerifyResult::Valid(dkg) = Dkg::<Ristretto>::verify(
|
let VerifyResult::Valid(dkg) =
|
||||||
&mut OsRng,
|
Dkg::<Ed25519>::verify(&mut OsRng, &generators, context, THRESHOLD, &pub_keys, &participations)
|
||||||
&generators,
|
.unwrap()
|
||||||
context,
|
else {
|
||||||
THRESHOLD,
|
|
||||||
&pub_keys,
|
|
||||||
&participations,
|
|
||||||
)
|
|
||||||
.unwrap() else {
|
|
||||||
panic!("verify didn't return VerifyResult::Valid")
|
panic!("verify didn't return VerifyResult::Valid")
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -80,7 +68,7 @@ fn dkg() {
|
|||||||
|
|
||||||
// TODO: Test for all possible combinations of keys
|
// TODO: Test for all possible combinations of keys
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
<<Ristretto as Curves>::ToweringCurve as Ciphersuite>::generator() *
|
<<Ed25519 as Curves>::ToweringCurve as WrappedGroup>::generator() *
|
||||||
*recover_key(&all_keys.values().cloned().collect::<Vec<_>>()).unwrap(),
|
*recover_key(&all_keys.values().cloned().collect::<Vec<_>>()).unwrap(),
|
||||||
group_key.unwrap()
|
group_key.unwrap()
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ use zeroize::Zeroizing;
|
|||||||
|
|
||||||
use ciphersuite::{
|
use ciphersuite::{
|
||||||
group::{ff::Field, Group},
|
group::{ff::Field, Group},
|
||||||
Ciphersuite,
|
WrappedGroup,
|
||||||
};
|
};
|
||||||
|
|
||||||
use generalized_bulletproofs::{Generators, tests::insecure_test_generators};
|
use generalized_bulletproofs::{Generators, tests::insecure_test_generators};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Curves, Ristretto,
|
Curves, Ed25519,
|
||||||
proof::*,
|
proof::*,
|
||||||
tests::{THRESHOLD, PARTICIPANTS},
|
tests::{THRESHOLD, PARTICIPANTS},
|
||||||
};
|
};
|
||||||
@@ -20,9 +20,9 @@ use crate::{
|
|||||||
fn proof<C: Curves>() {
|
fn proof<C: Curves>() {
|
||||||
let generators = insecure_test_generators(&mut OsRng, 2048).unwrap();
|
let generators = insecure_test_generators(&mut OsRng, 2048).unwrap();
|
||||||
let embedded_private_key =
|
let embedded_private_key =
|
||||||
Zeroizing::new(<C::EmbeddedCurve as Ciphersuite>::F::random(&mut OsRng));
|
Zeroizing::new(<C::EmbeddedCurve as WrappedGroup>::F::random(&mut OsRng));
|
||||||
let ecdh_public_keys: [_; PARTICIPANTS as usize] =
|
let ecdh_public_keys: [_; PARTICIPANTS as usize] =
|
||||||
core::array::from_fn(|_| <C::EmbeddedCurve as Ciphersuite>::G::random(&mut OsRng));
|
core::array::from_fn(|_| <C::EmbeddedCurve as WrappedGroup>::G::random(&mut OsRng));
|
||||||
let time = Instant::now();
|
let time = Instant::now();
|
||||||
let res = Proof::<C>::prove(
|
let res = Proof::<C>::prove(
|
||||||
&mut OsRng,
|
&mut OsRng,
|
||||||
@@ -54,5 +54,5 @@ fn proof<C: Curves>() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ristretto_proof() {
|
fn ristretto_proof() {
|
||||||
proof::<Ristretto>();
|
proof::<Ed25519>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use rand_core::{RngCore, CryptoRng};
|
|||||||
|
|
||||||
use ciphersuite::{
|
use ciphersuite::{
|
||||||
group::{ff::PrimeField, Group, GroupEncoding},
|
group::{ff::PrimeField, Group, GroupEncoding},
|
||||||
Ciphersuite,
|
GroupIo,
|
||||||
};
|
};
|
||||||
|
|
||||||
use dkg::Participant;
|
use dkg::Participant;
|
||||||
@@ -13,7 +13,7 @@ use dkg::Participant;
|
|||||||
/// Sample a random, unbiased point on the elliptic curve with an unknown discrete logarithm.
|
/// Sample a random, unbiased point on the elliptic curve with an unknown discrete logarithm.
|
||||||
///
|
///
|
||||||
/// This keeps it simple by using rejection sampling.
|
/// This keeps it simple by using rejection sampling.
|
||||||
pub(crate) fn sample_point<C: Ciphersuite>(rng: &mut (impl RngCore + CryptoRng)) -> C::G {
|
pub(crate) fn sample_point<C: GroupIo>(rng: &mut (impl RngCore + CryptoRng)) -> C::G {
|
||||||
let mut repr = <C::G as GroupEncoding>::Repr::default();
|
let mut repr = <C::G as GroupEncoding>::Repr::default();
|
||||||
loop {
|
loop {
|
||||||
rng.fill_bytes(repr.as_mut());
|
rng.fill_bytes(repr.as_mut());
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use zeroize::Zeroizing;
|
|||||||
use rand_core::OsRng;
|
use rand_core::OsRng;
|
||||||
|
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use ciphersuite::{group::ff::Field, Ciphersuite};
|
use ciphersuite::WrappedGroup;
|
||||||
|
|
||||||
use dkg_recovery::recover_key;
|
use dkg_recovery::recover_key;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
@@ -17,21 +17,21 @@ pub fn test_musig() {
|
|||||||
let mut keys = vec![];
|
let mut keys = vec![];
|
||||||
let mut pub_keys = vec![];
|
let mut pub_keys = vec![];
|
||||||
for _ in 0 .. PARTICIPANTS {
|
for _ in 0 .. PARTICIPANTS {
|
||||||
let key = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng));
|
let key = Zeroizing::new(<Ristretto as WrappedGroup>::F::random(&mut OsRng));
|
||||||
pub_keys.push(<Ristretto as Ciphersuite>::generator() * *key);
|
pub_keys.push(<Ristretto as WrappedGroup>::generator() * *key);
|
||||||
keys.push(key);
|
keys.push(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
const CONTEXT: [u8; 32] = *b"MuSig Test ";
|
const CONTEXT: [u8; 32] = *b"MuSig Test ";
|
||||||
|
|
||||||
// Empty signing set
|
// Empty signing set
|
||||||
musig::<Ristretto>(CONTEXT, Zeroizing::new(<Ristretto as Ciphersuite>::F::ZERO), &[])
|
musig::<Ristretto>(CONTEXT, Zeroizing::new(<Ristretto as WrappedGroup>::F::ZERO), &[])
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
// Signing set we're not part of
|
// Signing set we're not part of
|
||||||
musig::<Ristretto>(
|
musig::<Ristretto>(
|
||||||
CONTEXT,
|
CONTEXT,
|
||||||
Zeroizing::new(<Ristretto as Ciphersuite>::F::ZERO),
|
Zeroizing::new(<Ristretto as WrappedGroup>::F::ZERO),
|
||||||
&[<Ristretto as Ciphersuite>::generator()],
|
&[<Ristretto as WrappedGroup>::generator()],
|
||||||
)
|
)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ pub fn test_musig() {
|
|||||||
|
|
||||||
verification_shares.insert(
|
verification_shares.insert(
|
||||||
these_keys.params().i(),
|
these_keys.params().i(),
|
||||||
<Ristretto as Ciphersuite>::generator() * **these_keys.original_secret_share(),
|
<Ristretto as WrappedGroup>::generator() * **these_keys.original_secret_share(),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(these_keys.group_key(), group_key);
|
assert_eq!(these_keys.group_key(), group_key);
|
||||||
@@ -63,7 +63,7 @@ pub fn test_musig() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
<Ristretto as Ciphersuite>::generator() *
|
<Ristretto as WrappedGroup>::generator() *
|
||||||
*recover_key(&created_keys.values().cloned().collect::<Vec<_>>()).unwrap(),
|
*recover_key(&created_keys.values().cloned().collect::<Vec<_>>()).unwrap(),
|
||||||
group_key
|
group_key
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use alloc::vec::Vec;
|
|||||||
|
|
||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::{GroupIo, Id};
|
||||||
|
|
||||||
pub use dkg::*;
|
pub use dkg::*;
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ pub enum RecoveryError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Recover a shared secret from a collection of `dkg::ThresholdKeys`.
|
/// Recover a shared secret from a collection of `dkg::ThresholdKeys`.
|
||||||
pub fn recover_key<C: Ciphersuite>(
|
pub fn recover_key<C: GroupIo + Id>(
|
||||||
keys: &[ThresholdKeys<C>],
|
keys: &[ThresholdKeys<C>],
|
||||||
) -> Result<Zeroizing<C::F>, RecoveryError> {
|
) -> Result<Zeroizing<C::F>, RecoveryError> {
|
||||||
let included = keys.iter().map(|keys| keys.params().i()).collect::<Vec<_>>();
|
let included = keys.iter().map(|keys| keys.params().i()).collect::<Vec<_>>();
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ use ciphersuite::{
|
|||||||
ff::{Field, PrimeField},
|
ff::{Field, PrimeField},
|
||||||
GroupEncoding,
|
GroupEncoding,
|
||||||
},
|
},
|
||||||
Ciphersuite,
|
GroupIo, Id,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The ID of a participant, defined as a non-zero u16.
|
/// The ID of a participant, defined as a non-zero u16.
|
||||||
@@ -268,7 +268,7 @@ impl<F: Zeroize + PrimeField> Interpolation<F> {
|
|||||||
/// heap-allocated pointer to minimize copies on the stack (`ThresholdKeys`, the publicly exposed
|
/// heap-allocated pointer to minimize copies on the stack (`ThresholdKeys`, the publicly exposed
|
||||||
/// type).
|
/// type).
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
struct ThresholdCore<C: Ciphersuite> {
|
struct ThresholdCore<C: GroupIo + Id> {
|
||||||
params: ThresholdParams,
|
params: ThresholdParams,
|
||||||
group_key: C::G,
|
group_key: C::G,
|
||||||
verification_shares: HashMap<Participant, C::G>,
|
verification_shares: HashMap<Participant, C::G>,
|
||||||
@@ -276,7 +276,7 @@ struct ThresholdCore<C: Ciphersuite> {
|
|||||||
secret_share: Zeroizing<C::F>,
|
secret_share: Zeroizing<C::F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Ciphersuite> fmt::Debug for ThresholdCore<C> {
|
impl<C: GroupIo + Id> fmt::Debug for ThresholdCore<C> {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
fmt
|
fmt
|
||||||
.debug_struct("ThresholdCore")
|
.debug_struct("ThresholdCore")
|
||||||
@@ -288,7 +288,7 @@ impl<C: Ciphersuite> fmt::Debug for ThresholdCore<C> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Ciphersuite> Zeroize for ThresholdCore<C> {
|
impl<C: GroupIo + Id> Zeroize for ThresholdCore<C> {
|
||||||
fn zeroize(&mut self) {
|
fn zeroize(&mut self) {
|
||||||
self.params.zeroize();
|
self.params.zeroize();
|
||||||
self.group_key.zeroize();
|
self.group_key.zeroize();
|
||||||
@@ -302,7 +302,7 @@ impl<C: Ciphersuite> Zeroize for ThresholdCore<C> {
|
|||||||
|
|
||||||
/// Threshold keys usable for signing.
|
/// Threshold keys usable for signing.
|
||||||
#[derive(Clone, Debug, Zeroize)]
|
#[derive(Clone, Debug, Zeroize)]
|
||||||
pub struct ThresholdKeys<C: Ciphersuite> {
|
pub struct ThresholdKeys<C: GroupIo + Id> {
|
||||||
// Core keys.
|
// Core keys.
|
||||||
#[zeroize(skip)]
|
#[zeroize(skip)]
|
||||||
core: Arc<Zeroizing<ThresholdCore<C>>>,
|
core: Arc<Zeroizing<ThresholdCore<C>>>,
|
||||||
@@ -315,7 +315,7 @@ pub struct ThresholdKeys<C: Ciphersuite> {
|
|||||||
|
|
||||||
/// View of keys, interpolated and with the expected linear combination taken for usage.
|
/// View of keys, interpolated and with the expected linear combination taken for usage.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ThresholdView<C: Ciphersuite> {
|
pub struct ThresholdView<C: GroupIo + Id> {
|
||||||
interpolation: Interpolation<C::F>,
|
interpolation: Interpolation<C::F>,
|
||||||
scalar: C::F,
|
scalar: C::F,
|
||||||
offset: C::F,
|
offset: C::F,
|
||||||
@@ -326,7 +326,7 @@ pub struct ThresholdView<C: Ciphersuite> {
|
|||||||
verification_shares: HashMap<Participant, C::G>,
|
verification_shares: HashMap<Participant, C::G>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Ciphersuite> fmt::Debug for ThresholdView<C> {
|
impl<C: GroupIo + Id> fmt::Debug for ThresholdView<C> {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
fmt
|
fmt
|
||||||
.debug_struct("ThresholdView")
|
.debug_struct("ThresholdView")
|
||||||
@@ -341,7 +341,7 @@ impl<C: Ciphersuite> fmt::Debug for ThresholdView<C> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Ciphersuite> Zeroize for ThresholdView<C> {
|
impl<C: GroupIo + Id> Zeroize for ThresholdView<C> {
|
||||||
fn zeroize(&mut self) {
|
fn zeroize(&mut self) {
|
||||||
self.scalar.zeroize();
|
self.scalar.zeroize();
|
||||||
self.offset.zeroize();
|
self.offset.zeroize();
|
||||||
@@ -357,7 +357,7 @@ impl<C: Ciphersuite> Zeroize for ThresholdView<C> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Ciphersuite> ThresholdKeys<C> {
|
impl<C: GroupIo + Id> ThresholdKeys<C> {
|
||||||
/// Create a new set of ThresholdKeys.
|
/// Create a new set of ThresholdKeys.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
params: ThresholdParams,
|
params: ThresholdParams,
|
||||||
@@ -632,7 +632,7 @@ impl<C: Ciphersuite> ThresholdKeys<C> {
|
|||||||
|
|
||||||
let mut verification_shares = HashMap::new();
|
let mut verification_shares = HashMap::new();
|
||||||
for l in (1 ..= n).map(Participant) {
|
for l in (1 ..= n).map(Participant) {
|
||||||
verification_shares.insert(l, <C as Ciphersuite>::read_G(reader)?);
|
verification_shares.insert(l, C::read_G(reader)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
ThresholdKeys::new(
|
ThresholdKeys::new(
|
||||||
@@ -645,7 +645,7 @@ impl<C: Ciphersuite> ThresholdKeys<C> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Ciphersuite> ThresholdView<C> {
|
impl<C: GroupIo + Id> ThresholdView<C> {
|
||||||
/// Return the scalar applied to this view.
|
/// Return the scalar applied to this view.
|
||||||
pub fn scalar(&self) -> C::F {
|
pub fn scalar(&self) -> C::F {
|
||||||
self.scalar
|
self.scalar
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] }
|
zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] }
|
||||||
|
|
||||||
sha3 = { version = "0.11.0-rc.0", default-features = false }
|
sha3 = { version = "0.11.0-rc.2", default-features = false }
|
||||||
|
|
||||||
crypto-bigint = { version = "0.6", default-features = false, features = ["zeroize"] }
|
crypto-bigint = { version = "0.6", default-features = false, features = ["zeroize"] }
|
||||||
prime-field = { path = "../prime-field", default-features = false }
|
prime-field = { path = "../prime-field", default-features = false }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use zeroize::Zeroize;
|
use prime_field::subtle::CtOption;
|
||||||
|
|
||||||
use sha3::{
|
use sha3::{
|
||||||
digest::{
|
digest::{
|
||||||
@@ -8,9 +8,9 @@ use sha3::{
|
|||||||
Shake256,
|
Shake256,
|
||||||
};
|
};
|
||||||
|
|
||||||
use ciphersuite::{group::Group, Ciphersuite};
|
use ciphersuite::{group::GroupEncoding, Id, WithPreferredHash, GroupCanonicalEncoding};
|
||||||
|
|
||||||
use crate::{Scalar, Point};
|
use crate::Point;
|
||||||
|
|
||||||
/// Shake256, fixed to a 114-byte output, as used by Ed448.
|
/// Shake256, fixed to a 114-byte output, as used by Ed448.
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
@@ -49,21 +49,14 @@ impl FixedOutput for Shake256_114 {
|
|||||||
}
|
}
|
||||||
impl HashMarker for Shake256_114 {}
|
impl HashMarker for Shake256_114 {}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
|
impl Id for Point {
|
||||||
pub struct Ed448;
|
const ID: &[u8] = b"ed448";
|
||||||
impl Ciphersuite for Ed448 {
|
}
|
||||||
type F = Scalar;
|
impl WithPreferredHash for Point {
|
||||||
type G = Point;
|
|
||||||
type H = Shake256_114;
|
type H = Shake256_114;
|
||||||
|
}
|
||||||
const ID: &'static [u8] = b"ed448";
|
impl GroupCanonicalEncoding for Point {
|
||||||
|
fn from_canonical_bytes(bytes: &<Self::G as GroupEncoding>::Repr) -> CtOption<Self::G> {
|
||||||
fn generator() -> Self::G {
|
Self::G::from_bytes(bytes)
|
||||||
Point::generator()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_ed448() {
|
|
||||||
ff_group_tests::group::test_prime_group_bits::<_, Point>(&mut rand_core::OsRng);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ mod point;
|
|||||||
pub use point::Point;
|
pub use point::Point;
|
||||||
|
|
||||||
mod ciphersuite;
|
mod ciphersuite;
|
||||||
pub use crate::ciphersuite::Ed448;
|
|
||||||
|
|
||||||
pub(crate) fn u8_from_bool(bit_ref: &mut bool) -> u8 {
|
pub(crate) fn u8_from_bool(bit_ref: &mut bool) -> u8 {
|
||||||
use core::hint::black_box;
|
use core::hint::black_box;
|
||||||
|
|||||||
@@ -25,12 +25,11 @@ typenum = { version = "1", default-features = false }
|
|||||||
prime-field = { path = "../prime-field", default-features = false }
|
prime-field = { path = "../prime-field", default-features = false }
|
||||||
short-weierstrass = { path = "../short-weierstrass", default-features = false }
|
short-weierstrass = { path = "../short-weierstrass", default-features = false }
|
||||||
curve25519-dalek = { version = "4", default-features = false, features = ["legacy_compatibility"] }
|
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.11.0-rc.0", default-features = false }
|
blake2 = { version = "0.11.0-rc.2", default-features = false }
|
||||||
ciphersuite = { path = "../ciphersuite", version = "0.4", 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 }
|
generalized-bulletproofs-ec-gadgets = { git = "https://github.com/monero-oxide/monero-oxide", rev = "7216a2e84c7671c167c3d81eafe0d2b1f418f102", default-features = false, optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
|
|||||||
@@ -5,17 +5,14 @@
|
|||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use std_shims::prelude::*;
|
use std_shims::prelude::*;
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
use std_shims::io::{self, Read};
|
|
||||||
|
|
||||||
use prime_field::{subtle::Choice, zeroize::Zeroize};
|
use prime_field::{
|
||||||
use ciphersuite::group::{
|
subtle::{Choice, CtOption},
|
||||||
ff::{Field, PrimeField},
|
zeroize::Zeroize,
|
||||||
Group,
|
|
||||||
};
|
};
|
||||||
|
use ciphersuite::group::{ff::PrimeField, Group, GroupEncoding};
|
||||||
|
|
||||||
use curve25519_dalek::Scalar as DalekScalar;
|
pub use curve25519_dalek::Scalar as FieldElement;
|
||||||
pub use dalek_ff_group::Scalar as FieldElement;
|
|
||||||
|
|
||||||
use short_weierstrass::{ShortWeierstrass, Affine, Projective};
|
use short_weierstrass::{ShortWeierstrass, Affine, Projective};
|
||||||
|
|
||||||
@@ -32,18 +29,18 @@ pub struct Embedwards25519;
|
|||||||
#[allow(deprecated)] // No other way to construct arbitrary `FieldElement` at compile-time :/
|
#[allow(deprecated)] // No other way to construct arbitrary `FieldElement` at compile-time :/
|
||||||
impl ShortWeierstrass for Embedwards25519 {
|
impl ShortWeierstrass for Embedwards25519 {
|
||||||
type FieldElement = FieldElement;
|
type FieldElement = FieldElement;
|
||||||
const A: FieldElement = FieldElement(DalekScalar::from_bits(hex_literal::hex!(
|
const A: FieldElement = FieldElement::from_bits(hex_literal::hex!(
|
||||||
"ead3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010"
|
"ead3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010"
|
||||||
)));
|
));
|
||||||
const B: FieldElement = FieldElement(DalekScalar::from_bits(hex_literal::hex!(
|
const B: FieldElement = FieldElement::from_bits(hex_literal::hex!(
|
||||||
"5f07603a853f20370b682036210d463e64903a23ea669d07ca26cfc13f594209"
|
"5f07603a853f20370b682036210d463e64903a23ea669d07ca26cfc13f594209"
|
||||||
)));
|
));
|
||||||
const PRIME_ORDER: bool = true;
|
const PRIME_ORDER: bool = true;
|
||||||
const GENERATOR: Affine<Self> = Affine::from_xy_unchecked(
|
const GENERATOR: Affine<Self> = Affine::from_xy_unchecked(
|
||||||
FieldElement::ONE,
|
FieldElement::ONE,
|
||||||
FieldElement(DalekScalar::from_bits(hex_literal::hex!(
|
FieldElement::from_bits(hex_literal::hex!(
|
||||||
"2e4118080a484a3dfbafe2199a0e36b7193581d676c0dadfa376b0265616020c"
|
"2e4118080a484a3dfbafe2199a0e36b7193581d676c0dadfa376b0265616020c"
|
||||||
))),
|
)),
|
||||||
);
|
);
|
||||||
type Scalar = Scalar;
|
type Scalar = Scalar;
|
||||||
|
|
||||||
@@ -80,30 +77,23 @@ impl ShortWeierstrass for Embedwards25519 {
|
|||||||
|
|
||||||
pub type Point = Projective<Embedwards25519>;
|
pub type Point = Projective<Embedwards25519>;
|
||||||
|
|
||||||
impl ciphersuite::Ciphersuite for Embedwards25519 {
|
impl ciphersuite::WrappedGroup for Embedwards25519 {
|
||||||
type F = Scalar;
|
type F = Scalar;
|
||||||
type G = Point;
|
type G = Point;
|
||||||
type H = blake2::Blake2b512;
|
|
||||||
|
|
||||||
const ID: &'static [u8] = b"embedwards25519";
|
|
||||||
|
|
||||||
fn generator() -> Self::G {
|
fn generator() -> Self::G {
|
||||||
Point::generator()
|
<Point as Group>::generator()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// We override the provided impl, which compares against the reserialization, because
|
impl ciphersuite::Id for Embedwards25519 {
|
||||||
// we already require canonicity
|
const ID: &[u8] = b"embedwards25519";
|
||||||
#[cfg(feature = "alloc")]
|
}
|
||||||
#[allow(non_snake_case)]
|
impl ciphersuite::WithPreferredHash for Embedwards25519 {
|
||||||
fn read_G<R: Read>(reader: &mut R) -> io::Result<Self::G> {
|
type H = blake2::Blake2b512;
|
||||||
use ciphersuite::group::GroupEncoding;
|
}
|
||||||
|
impl ciphersuite::GroupCanonicalEncoding for Embedwards25519 {
|
||||||
let mut encoding = <Self::G as GroupEncoding>::Repr::default();
|
fn from_canonical_bytes(bytes: &<Self::G as GroupEncoding>::Repr) -> CtOption<Self::G> {
|
||||||
reader.read_exact(encoding.as_mut())?;
|
Self::G::from_bytes(bytes)
|
||||||
|
|
||||||
let point = Option::<Self::G>::from(Self::G::from_bytes(&encoding))
|
|
||||||
.ok_or_else(|| io::Error::other("invalid point"))?;
|
|
||||||
Ok(point)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,9 +109,8 @@ fn test_curve() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn generator() {
|
fn generator() {
|
||||||
use ciphersuite::group::{Group, GroupEncoding};
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Point::generator(),
|
<Point as Group>::generator(),
|
||||||
Point::from_bytes(&hex_literal::hex!(
|
Point::from_bytes(&hex_literal::hex!(
|
||||||
"0100000000000000000000000000000000000000000000000000000000000000"
|
"0100000000000000000000000000000000000000000000000000000000000000"
|
||||||
))
|
))
|
||||||
@@ -139,6 +128,5 @@ fn zero_x_is_off_curve() {
|
|||||||
// Checks random won't infinitely loop
|
// Checks random won't infinitely loop
|
||||||
#[test]
|
#[test]
|
||||||
fn random() {
|
fn random() {
|
||||||
use ciphersuite::group::Group;
|
|
||||||
Point::random(&mut rand_core::OsRng);
|
Point::random(&mut rand_core::OsRng);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "modular-frost"
|
name = "modular-frost"
|
||||||
version = "0.10.1"
|
version = "0.11.0"
|
||||||
description = "Modular implementation of FROST over ff/group"
|
description = "Modular implementation of FROST over ff/group"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/serai-dex/serai/tree/develop/crypto/frost"
|
repository = "https://github.com/serai-dex/serai/tree/develop/crypto/frost"
|
||||||
@@ -29,7 +29,7 @@ hex = { version = "0.4", default-features = false, features = ["std"], optional
|
|||||||
|
|
||||||
transcript = { package = "flexible-transcript", path = "../transcript", version = "^0.3.2", default-features = false, features = ["std", "recommended"] }
|
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 }
|
dalek-ff-group = { path = "../dalek-ff-group", version = "0.5", default-features = false, features = ["std"], optional = true }
|
||||||
minimal-ed448 = { path = "../ed448", 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"] }
|
ciphersuite = { path = "../ciphersuite", version = "^0.4.1", default-features = false, features = ["std"] }
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
use ciphersuite::{digest::Digest, FromUniformBytes, Ciphersuite};
|
use subtle::CtOption;
|
||||||
|
use zeroize::Zeroize;
|
||||||
|
use ciphersuite::{
|
||||||
|
digest::Digest, group::GroupEncoding, FromUniformBytes, WrappedGroup, WithPreferredHash,
|
||||||
|
};
|
||||||
use dalek_ff_group::Scalar;
|
use dalek_ff_group::Scalar;
|
||||||
|
|
||||||
use crate::{curve::Curve, algorithm::Hram};
|
use crate::{curve::Curve, algorithm::Hram};
|
||||||
|
|
||||||
macro_rules! dalek_curve {
|
macro_rules! dalek_curve {
|
||||||
(
|
(
|
||||||
$feature: literal,
|
|
||||||
|
|
||||||
$Curve: ident,
|
$Curve: ident,
|
||||||
$Hram: ident,
|
$Hram: ident,
|
||||||
|
|
||||||
$CONTEXT: literal,
|
$CONTEXT: literal,
|
||||||
$chal: literal
|
$chal: literal
|
||||||
) => {
|
) => {
|
||||||
pub use dalek_ff_group::$Curve;
|
|
||||||
|
|
||||||
impl Curve for $Curve {
|
impl Curve for $Curve {
|
||||||
const CONTEXT: &'static [u8] = $CONTEXT;
|
const CONTEXT: &'static [u8] = $CONTEXT;
|
||||||
fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F {
|
fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F {
|
||||||
let mut digest = <Self as Ciphersuite>::H::new();
|
let mut digest = <Self as WithPreferredHash>::H::new();
|
||||||
digest.update(Self::CONTEXT);
|
digest.update(Self::CONTEXT);
|
||||||
digest.update(dst);
|
digest.update(dst);
|
||||||
digest.update(msg);
|
digest.update(msg);
|
||||||
@@ -31,8 +31,12 @@ macro_rules! dalek_curve {
|
|||||||
pub struct $Hram;
|
pub struct $Hram;
|
||||||
impl Hram<$Curve> for $Hram {
|
impl Hram<$Curve> for $Hram {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn hram(R: &<$Curve as Ciphersuite>::G, A: &<$Curve as Ciphersuite>::G, m: &[u8]) -> Scalar {
|
fn hram(
|
||||||
let mut hash = <$Curve as Ciphersuite>::H::new();
|
R: &<$Curve as WrappedGroup>::G,
|
||||||
|
A: &<$Curve as WrappedGroup>::G,
|
||||||
|
m: &[u8],
|
||||||
|
) -> Scalar {
|
||||||
|
let mut hash = <$Curve as WithPreferredHash>::H::new();
|
||||||
if $chal.len() != 0 {
|
if $chal.len() != 0 {
|
||||||
hash.update($CONTEXT);
|
hash.update($CONTEXT);
|
||||||
hash.update($chal);
|
hash.update($chal);
|
||||||
@@ -46,8 +50,31 @@ macro_rules! dalek_curve {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ristretto")]
|
/*
|
||||||
dalek_curve!("ristretto", Ristretto, IetfRistrettoHram, b"FROST-RISTRETTO255-SHA512-v1", b"chal");
|
FROST defined Ristretto as using SHA2-512, while Blake2b512 is considered "preferred" by
|
||||||
|
`dalek-ff-group`. We define our own ciphersuite for it accordingly.
|
||||||
|
*/
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
|
||||||
|
pub struct Ristretto;
|
||||||
|
impl WrappedGroup for Ristretto {
|
||||||
|
type F = Scalar;
|
||||||
|
type G = dalek_ff_group::RistrettoPoint;
|
||||||
|
fn generator() -> Self::G {
|
||||||
|
dalek_ff_group::Ristretto::generator()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ciphersuite::Id for Ristretto {
|
||||||
|
const ID: &[u8] = b"FROST-RISTRETTO255";
|
||||||
|
}
|
||||||
|
impl WithPreferredHash for Ristretto {
|
||||||
|
type H = <Ed25519 as WithPreferredHash>::H;
|
||||||
|
}
|
||||||
|
impl ciphersuite::GroupCanonicalEncoding for Ristretto {
|
||||||
|
fn from_canonical_bytes(bytes: &<Self::G as GroupEncoding>::Repr) -> CtOption<Self::G> {
|
||||||
|
dalek_ff_group::Ristretto::from_canonical_bytes(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dalek_curve!(Ristretto, IetfRistrettoHram, b"FROST-RISTRETTO255-SHA512-v1", b"chal");
|
||||||
|
|
||||||
#[cfg(feature = "ed25519")]
|
pub use dalek_ff_group::Ed25519;
|
||||||
dalek_curve!("ed25519", Ed25519, IetfEd25519Hram, b"FROST-ED25519-SHA512-v1", b"");
|
dalek_curve!(Ed25519, IetfEd25519Hram, b"FROST-ED25519-SHA512-v1", b"");
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
pub use ciphersuite::{digest::Digest, group::GroupEncoding, FromUniformBytes, Ciphersuite};
|
pub use ciphersuite::{digest::Digest, group::GroupEncoding, FromUniformBytes, WithPreferredHash};
|
||||||
use minimal_ed448::{Scalar, Point};
|
use minimal_ed448::Scalar;
|
||||||
pub use minimal_ed448::Ed448;
|
pub use minimal_ed448::Point as Ed448;
|
||||||
|
|
||||||
use crate::{curve::Curve, algorithm::Hram};
|
use crate::{curve::Curve, algorithm::Hram};
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ const CONTEXT: &[u8] = b"FROST-ED448-SHAKE256-v1";
|
|||||||
impl Curve for Ed448 {
|
impl Curve for Ed448 {
|
||||||
const CONTEXT: &'static [u8] = CONTEXT;
|
const CONTEXT: &'static [u8] = CONTEXT;
|
||||||
fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F {
|
fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F {
|
||||||
let mut digest = <Self as Ciphersuite>::H::new();
|
let mut digest = <Self as WithPreferredHash>::H::new();
|
||||||
digest.update(Self::CONTEXT);
|
digest.update(Self::CONTEXT);
|
||||||
digest.update(dst);
|
digest.update(dst);
|
||||||
digest.update(msg);
|
digest.update(msg);
|
||||||
@@ -22,8 +22,8 @@ impl Curve for Ed448 {
|
|||||||
pub(crate) struct Ietf8032Ed448Hram;
|
pub(crate) struct Ietf8032Ed448Hram;
|
||||||
impl Ietf8032Ed448Hram {
|
impl Ietf8032Ed448Hram {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub(crate) fn hram(context: &[u8], R: &Point, A: &Point, m: &[u8]) -> Scalar {
|
pub(crate) fn hram(context: &[u8], R: &Ed448, A: &Ed448, m: &[u8]) -> Scalar {
|
||||||
let mut digest = <Ed448 as Ciphersuite>::H::new();
|
let mut digest = <Ed448 as WithPreferredHash>::H::new();
|
||||||
digest.update(b"SigEd448");
|
digest.update(b"SigEd448");
|
||||||
digest.update([0, u8::try_from(context.len()).unwrap()]);
|
digest.update([0, u8::try_from(context.len()).unwrap()]);
|
||||||
digest.update(context);
|
digest.update(context);
|
||||||
@@ -39,7 +39,7 @@ impl Ietf8032Ed448Hram {
|
|||||||
pub struct IetfEd448Hram;
|
pub struct IetfEd448Hram;
|
||||||
impl Hram<Ed448> for IetfEd448Hram {
|
impl Hram<Ed448> for IetfEd448Hram {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn hram(R: &Point, A: &Point, m: &[u8]) -> Scalar {
|
fn hram(R: &Ed448, A: &Ed448, m: &[u8]) -> Scalar {
|
||||||
Ietf8032Ed448Hram::hram(&[], R, A, m)
|
Ietf8032Ed448Hram::hram(&[], R, A, m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use ciphersuite::{
|
|||||||
ff::{Field, PrimeField},
|
ff::{Field, PrimeField},
|
||||||
GroupEncoding,
|
GroupEncoding,
|
||||||
},
|
},
|
||||||
Ciphersuite,
|
WrappedGroup,
|
||||||
};
|
};
|
||||||
|
|
||||||
use elliptic_curve::{
|
use elliptic_curve::{
|
||||||
@@ -20,7 +20,7 @@ use elliptic_curve::{
|
|||||||
use crate::{curve::Curve, algorithm::Hram};
|
use crate::{curve::Curve, algorithm::Hram};
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn hash_to_F<C: Ciphersuite<F: PrimeField<Repr = GenericArray<u8, U32>>>>(
|
fn hash_to_F<C: WrappedGroup<F: PrimeField<Repr = GenericArray<u8, U32>>>>(
|
||||||
dst: &[u8],
|
dst: &[u8],
|
||||||
msg: &[u8],
|
msg: &[u8],
|
||||||
) -> C::F {
|
) -> C::F {
|
||||||
@@ -112,10 +112,10 @@ macro_rules! kp_curve {
|
|||||||
impl Hram<$Curve> for $Hram {
|
impl Hram<$Curve> for $Hram {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn hram(
|
fn hram(
|
||||||
R: &<$Curve as Ciphersuite>::G,
|
R: &<$Curve as WrappedGroup>::G,
|
||||||
A: &<$Curve as Ciphersuite>::G,
|
A: &<$Curve as WrappedGroup>::G,
|
||||||
m: &[u8],
|
m: &[u8],
|
||||||
) -> <$Curve as Ciphersuite>::F {
|
) -> <$Curve as WrappedGroup>::F {
|
||||||
<$Curve as Curve>::hash_to_F(
|
<$Curve as Curve>::hash_to_F(
|
||||||
b"chal",
|
b"chal",
|
||||||
&[R.to_bytes().as_ref(), A.to_bytes().as_ref(), m].concat(),
|
&[R.to_bytes().as_ref(), A.to_bytes().as_ref(), m].concat(),
|
||||||
@@ -132,7 +132,7 @@ kp_curve!("p256", P256, IetfP256Hram, b"FROST-P256-SHA256-v1");
|
|||||||
kp_curve!("secp256k1", Secp256k1, IetfSecp256k1Hram, b"FROST-secp256k1-SHA256-v1");
|
kp_curve!("secp256k1", Secp256k1, IetfSecp256k1Hram, b"FROST-secp256k1-SHA256-v1");
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn test_oversize_dst<C: Ciphersuite<F: PrimeField<Repr = GenericArray<u8, U32>>>>() {
|
fn test_oversize_dst<C: WrappedGroup<F: PrimeField<Repr = GenericArray<u8, U32>>>>() {
|
||||||
use sha2::Digest;
|
use sha2::Digest;
|
||||||
|
|
||||||
// The draft specifies DSTs >255 bytes should be hashed into a 32-byte DST
|
// The draft specifies DSTs >255 bytes should be hashed into a 32-byte DST
|
||||||
|
|||||||
@@ -6,21 +6,16 @@ use rand_core::{RngCore, CryptoRng};
|
|||||||
use zeroize::{Zeroize, Zeroizing};
|
use zeroize::{Zeroize, Zeroizing};
|
||||||
use subtle::ConstantTimeEq;
|
use subtle::ConstantTimeEq;
|
||||||
|
|
||||||
pub use ciphersuite::{
|
use ciphersuite::group::{
|
||||||
digest::Digest,
|
ff::{Field, PrimeField},
|
||||||
group::{
|
Group,
|
||||||
ff::{Field, PrimeField},
|
|
||||||
Group,
|
|
||||||
},
|
|
||||||
Ciphersuite,
|
|
||||||
};
|
};
|
||||||
|
pub use ciphersuite::{digest::Digest, WrappedGroup, GroupIo, Ciphersuite};
|
||||||
|
|
||||||
#[cfg(any(feature = "ristretto", feature = "ed25519"))]
|
#[cfg(any(feature = "ristretto", feature = "ed25519"))]
|
||||||
mod dalek;
|
mod dalek;
|
||||||
#[cfg(feature = "ristretto")]
|
#[cfg(any(feature = "ristretto", feature = "ed25519"))]
|
||||||
pub use dalek::{Ristretto, IetfRistrettoHram};
|
pub use dalek::*;
|
||||||
#[cfg(feature = "ed25519")]
|
|
||||||
pub use dalek::{Ed25519, IetfEd25519Hram};
|
|
||||||
|
|
||||||
#[cfg(any(feature = "secp256k1", feature = "p256"))]
|
#[cfg(any(feature = "secp256k1", feature = "p256"))]
|
||||||
mod kp256;
|
mod kp256;
|
||||||
@@ -38,11 +33,11 @@ pub(crate) use ed448::Ietf8032Ed448Hram;
|
|||||||
|
|
||||||
/// FROST Ciphersuite.
|
/// FROST Ciphersuite.
|
||||||
///
|
///
|
||||||
/// This exclude the signing algorithm specific H2, making this solely the curve, its associated
|
/// This excludes the signing algorithm specific H2, making this solely the curve, its associated
|
||||||
/// hash function, and the functions derived from it.
|
/// hash function, and the functions derived from it.
|
||||||
pub trait Curve: Ciphersuite {
|
pub trait Curve: GroupIo + Ciphersuite {
|
||||||
/// Context string for this curve.
|
/// Context string for this curve.
|
||||||
const CONTEXT: &'static [u8];
|
const CONTEXT: &[u8];
|
||||||
|
|
||||||
/// Hash the given dst and data to a byte vector. Used to instantiate H4 and H5.
|
/// Hash the given dst and data to a byte vector. Used to instantiate H4 and H5.
|
||||||
fn hash(dst: &[u8], data: &[u8]) -> impl AsRef<[u8]> {
|
fn hash(dst: &[u8], data: &[u8]) -> impl AsRef<[u8]> {
|
||||||
@@ -121,7 +116,7 @@ pub trait Curve: Ciphersuite {
|
|||||||
/// Read a point from a reader, rejecting identity.
|
/// Read a point from a reader, rejecting identity.
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn read_G<R: Read>(reader: &mut R) -> io::Result<Self::G> {
|
fn read_G<R: Read>(reader: &mut R) -> io::Result<Self::G> {
|
||||||
let res = <Self as Ciphersuite>::read_G(reader)?;
|
let res = <Self as GroupIo>::read_G(reader)?;
|
||||||
if res.is_identity().into() {
|
if res.is_identity().into() {
|
||||||
Err(io::Error::other("identity point"))?;
|
Err(io::Error::other("identity point"))?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,9 @@ use zeroize::{Zeroize, Zeroizing};
|
|||||||
|
|
||||||
use transcript::Transcript;
|
use transcript::Transcript;
|
||||||
|
|
||||||
use ciphersuite::group::{
|
use ciphersuite::group::{ff::PrimeField, GroupEncoding};
|
||||||
ff::{Field, PrimeField},
|
#[cfg(any(test, feature = "tests"))]
|
||||||
GroupEncoding,
|
use ciphersuite::group::ff::Field;
|
||||||
};
|
|
||||||
use multiexp::BatchVerifier;
|
use multiexp::BatchVerifier;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use rand_core::OsRng;
|
use rand_core::OsRng;
|
||||||
|
|
||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::GroupIo;
|
||||||
|
|
||||||
use schnorr::SchnorrSignature;
|
use schnorr::SchnorrSignature;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use rand_core::{RngCore, CryptoRng};
|
use rand_core::{RngCore, CryptoRng};
|
||||||
|
|
||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::{GroupIo, Id};
|
||||||
pub use dkg_recovery::recover_key;
|
pub use dkg_recovery::recover_key;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -28,7 +28,7 @@ pub const PARTICIPANTS: u16 = 5;
|
|||||||
pub const THRESHOLD: u16 = ((PARTICIPANTS * 2) / 3) + 1;
|
pub const THRESHOLD: u16 = ((PARTICIPANTS * 2) / 3) + 1;
|
||||||
|
|
||||||
/// Create a key, for testing purposes.
|
/// Create a key, for testing purposes.
|
||||||
pub fn key_gen<R: RngCore + CryptoRng, C: Ciphersuite>(
|
pub fn key_gen<R: RngCore + CryptoRng, C: GroupIo + Id>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> HashMap<Participant, ThresholdKeys<C>> {
|
) -> HashMap<Participant, ThresholdKeys<C>> {
|
||||||
let res = dkg_dealer::key_gen::<R, C>(rng, THRESHOLD, PARTICIPANTS).unwrap();
|
let res = dkg_dealer::key_gen::<R, C>(rng, THRESHOLD, PARTICIPANTS).unwrap();
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ std-shims = { path = "../../common/std-shims", version = "^0.1.1", default-featu
|
|||||||
rand_core = { version = "0.6", default-features = false }
|
rand_core = { version = "0.6", default-features = false }
|
||||||
|
|
||||||
zeroize = { version = "^1.5", default-features = false, features = ["zeroize_derive"] }
|
zeroize = { version = "^1.5", default-features = false, features = ["zeroize_derive"] }
|
||||||
|
digest = { version = "0.11.0-rc.1", default-features = false, features = ["block-api"] }
|
||||||
|
|
||||||
transcript = { package = "flexible-transcript", path = "../transcript", version = "^0.3.2", default-features = false, optional = true }
|
transcript = { package = "flexible-transcript", path = "../transcript", version = "^0.3.2", default-features = false, optional = true }
|
||||||
|
|
||||||
|
|||||||
@@ -5,74 +5,34 @@ use std_shims::{
|
|||||||
|
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
use transcript::{Transcript, SecureDigest, DigestTranscript};
|
use transcript::{Transcript, DigestTranscript};
|
||||||
|
|
||||||
use ciphersuite::{
|
use ciphersuite::{
|
||||||
group::{
|
group::{
|
||||||
ff::{Field, PrimeField},
|
ff::{Field, PrimeField},
|
||||||
Group, GroupEncoding,
|
Group, GroupEncoding,
|
||||||
},
|
},
|
||||||
Ciphersuite,
|
FromUniformBytes, GroupIo, WithPreferredHash,
|
||||||
};
|
};
|
||||||
use multiexp::multiexp_vartime;
|
use multiexp::multiexp_vartime;
|
||||||
|
|
||||||
use crate::SchnorrSignature;
|
use crate::SchnorrSignature;
|
||||||
|
|
||||||
// Returns a unbiased scalar weight to use on a signature in order to prevent malleability
|
// Returns a unbiased scalar weight to use on a signature in order to prevent malleability
|
||||||
fn weight<D: Send + Clone + SecureDigest, F: PrimeField>(digest: &mut DigestTranscript<D>) -> F {
|
fn weight<C: WithPreferredHash>(digest: &mut DigestTranscript<C::H>) -> C::F {
|
||||||
let mut bytes = digest.challenge(b"aggregation_weight");
|
let bytes = digest.challenge(b"aggregation_weight");
|
||||||
debug_assert_eq!(bytes.len() % 8, 0);
|
C::F::from_uniform_bytes(&bytes.into())
|
||||||
// This should be guaranteed thanks to SecureDigest
|
|
||||||
debug_assert!(bytes.len() >= 32);
|
|
||||||
|
|
||||||
let mut res = F::ZERO;
|
|
||||||
let mut i = 0;
|
|
||||||
|
|
||||||
// Derive a scalar from enough bits of entropy that bias is < 2^128
|
|
||||||
// This can't be const due to its usage of a generic
|
|
||||||
// Also due to the usize::try_from, yet that could be replaced with an `as`
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
let BYTES: usize = usize::try_from((F::NUM_BITS + 128).div_ceil(8)).unwrap();
|
|
||||||
|
|
||||||
let mut remaining = BYTES;
|
|
||||||
|
|
||||||
// We load bits in as u64s
|
|
||||||
const WORD_LEN_IN_BITS: usize = 64;
|
|
||||||
const WORD_LEN_IN_BYTES: usize = WORD_LEN_IN_BITS / 8;
|
|
||||||
|
|
||||||
let mut first = true;
|
|
||||||
while i < remaining {
|
|
||||||
// Shift over the already loaded bits
|
|
||||||
if !first {
|
|
||||||
for _ in 0 .. WORD_LEN_IN_BITS {
|
|
||||||
res += res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
first = false;
|
|
||||||
|
|
||||||
// Add the next 64 bits
|
|
||||||
res += F::from(u64::from_be_bytes(bytes[i .. (i + WORD_LEN_IN_BYTES)].try_into().unwrap()));
|
|
||||||
i += WORD_LEN_IN_BYTES;
|
|
||||||
|
|
||||||
// If we've exhausted this challenge, get another
|
|
||||||
if i == bytes.len() {
|
|
||||||
bytes = digest.challenge(b"aggregation_weight_continued");
|
|
||||||
remaining -= i;
|
|
||||||
i = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Aggregate Schnorr signature as defined in <https://eprint.iacr.org/2021/350>.
|
/// Aggregate Schnorr signature as defined in <https://eprint.iacr.org/2021/350>.
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[derive(Clone, PartialEq, Eq, Debug, Zeroize)]
|
#[derive(Clone, PartialEq, Eq, Debug, Zeroize)]
|
||||||
pub struct SchnorrAggregate<C: Ciphersuite> {
|
pub struct SchnorrAggregate<C: GroupIo + WithPreferredHash> {
|
||||||
Rs: Vec<C::G>,
|
Rs: Vec<C::G>,
|
||||||
s: C::F,
|
s: C::F,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Ciphersuite> SchnorrAggregate<C> {
|
impl<C: GroupIo + WithPreferredHash> SchnorrAggregate<C> {
|
||||||
/// Read a SchnorrAggregate from something implementing Read.
|
/// Read a SchnorrAggregate from something implementing Read.
|
||||||
pub fn read<R: Read>(reader: &mut R) -> io::Result<Self> {
|
pub fn read<R: Read>(reader: &mut R) -> io::Result<Self> {
|
||||||
let mut len = [0; 4];
|
let mut len = [0; 4];
|
||||||
@@ -137,7 +97,7 @@ impl<C: Ciphersuite> SchnorrAggregate<C> {
|
|||||||
|
|
||||||
let mut pairs = Vec::with_capacity((2 * keys_and_challenges.len()) + 1);
|
let mut pairs = Vec::with_capacity((2 * keys_and_challenges.len()) + 1);
|
||||||
for (i, (key, challenge)) in keys_and_challenges.iter().enumerate() {
|
for (i, (key, challenge)) in keys_and_challenges.iter().enumerate() {
|
||||||
let z = weight(&mut digest);
|
let z = weight::<C>(&mut digest);
|
||||||
pairs.push((z, self.Rs[i]));
|
pairs.push((z, self.Rs[i]));
|
||||||
pairs.push((z * challenge, *key));
|
pairs.push((z * challenge, *key));
|
||||||
}
|
}
|
||||||
@@ -148,13 +108,22 @@ impl<C: Ciphersuite> SchnorrAggregate<C> {
|
|||||||
|
|
||||||
/// A signature aggregator capable of consuming signatures in order to produce an aggregate.
|
/// A signature aggregator capable of consuming signatures in order to produce an aggregate.
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[derive(Clone, Debug, Zeroize)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SchnorrAggregator<C: Ciphersuite> {
|
pub struct SchnorrAggregator<C: GroupIo + WithPreferredHash> {
|
||||||
digest: DigestTranscript<C::H>,
|
digest: DigestTranscript<C::H>,
|
||||||
sigs: Vec<SchnorrSignature<C>>,
|
sigs: Vec<SchnorrSignature<C>>,
|
||||||
}
|
}
|
||||||
|
impl<C: GroupIo + WithPreferredHash> Zeroize for SchnorrAggregator<C>
|
||||||
|
where
|
||||||
|
C::H: digest::block_api::BlockSizeUser,
|
||||||
|
{
|
||||||
|
fn zeroize(&mut self) {
|
||||||
|
self.digest.zeroize();
|
||||||
|
self.sigs.zeroize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<C: Ciphersuite> SchnorrAggregator<C> {
|
impl<C: GroupIo + WithPreferredHash> SchnorrAggregator<C> {
|
||||||
/// Create a new aggregator.
|
/// Create a new aggregator.
|
||||||
///
|
///
|
||||||
/// The DST used here must prevent a collision with whatever hash function produced the
|
/// The DST used here must prevent a collision with whatever hash function produced the
|
||||||
@@ -180,7 +149,7 @@ impl<C: Ciphersuite> SchnorrAggregator<C> {
|
|||||||
let mut aggregate = SchnorrAggregate { Rs: Vec::with_capacity(self.sigs.len()), s: C::F::ZERO };
|
let mut aggregate = SchnorrAggregate { Rs: Vec::with_capacity(self.sigs.len()), s: C::F::ZERO };
|
||||||
for i in 0 .. self.sigs.len() {
|
for i in 0 .. self.sigs.len() {
|
||||||
aggregate.Rs.push(self.sigs[i].R);
|
aggregate.Rs.push(self.sigs[i].R);
|
||||||
aggregate.s += self.sigs[i].s * weight::<_, C::F>(&mut self.digest);
|
aggregate.s += self.sigs[i].s * weight::<C>(&mut self.digest);
|
||||||
}
|
}
|
||||||
Some(aggregate)
|
Some(aggregate)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ use ciphersuite::{
|
|||||||
ff::{Field, PrimeField},
|
ff::{Field, PrimeField},
|
||||||
Group, GroupEncoding,
|
Group, GroupEncoding,
|
||||||
},
|
},
|
||||||
Ciphersuite,
|
GroupIo,
|
||||||
};
|
};
|
||||||
use multiexp::{multiexp_vartime, BatchVerifier};
|
use multiexp::{multiexp_vartime, BatchVerifier};
|
||||||
|
|
||||||
@@ -33,20 +33,20 @@ mod tests;
|
|||||||
|
|
||||||
/// A Schnorr signature of the form (R, s) where s = r + cx.
|
/// A Schnorr signature of the form (R, s) where s = r + cx.
|
||||||
///
|
///
|
||||||
/// These are intended to be strict. It is generic over Ciphersuite which is for PrimeGroups,
|
/// These are intended to be strict. It is generic over `GroupIo` which is for `PrimeGroup`s,
|
||||||
/// and mandates canonical encodings in its read function.
|
/// and mandates canonical encodings in its read function.
|
||||||
///
|
///
|
||||||
/// RFC 8032 has an alternative verification formula, 8R = 8s - 8cX, which is intended to handle
|
/// RFC 8032 has an alternative verification formula for Ed25519, `8R = 8s - 8cX`, which is
|
||||||
/// torsioned nonces/public keys. Due to this library's strict requirements, such signatures will
|
/// intended to handle torsioned nonces/public keys. Due to this library's strict requirements,
|
||||||
/// not be verifiable with this library.
|
/// such signatures will not be verifiable with this library.
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
|
||||||
pub struct SchnorrSignature<C: Ciphersuite> {
|
pub struct SchnorrSignature<C: GroupIo> {
|
||||||
pub R: C::G,
|
pub R: C::G,
|
||||||
pub s: C::F,
|
pub s: C::F,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Ciphersuite> SchnorrSignature<C> {
|
impl<C: GroupIo> SchnorrSignature<C> {
|
||||||
/// Read a SchnorrSignature from something implementing Read.
|
/// Read a SchnorrSignature from something implementing Read.
|
||||||
pub fn read<R: Read>(reader: &mut R) -> io::Result<Self> {
|
pub fn read<R: Read>(reader: &mut R) -> io::Result<Self> {
|
||||||
Ok(SchnorrSignature { R: C::read_G(reader)?, s: C::read_F(reader)? })
|
Ok(SchnorrSignature { R: C::read_G(reader)?, s: C::read_F(reader)? })
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use rand_core::OsRng;
|
|||||||
use dalek_ff_group::Ed25519;
|
use dalek_ff_group::Ed25519;
|
||||||
use ciphersuite::{
|
use ciphersuite::{
|
||||||
group::{ff::Field, Group},
|
group::{ff::Field, Group},
|
||||||
Ciphersuite,
|
GroupIo, WithPreferredHash,
|
||||||
};
|
};
|
||||||
use multiexp::BatchVerifier;
|
use multiexp::BatchVerifier;
|
||||||
|
|
||||||
@@ -16,10 +16,10 @@ use crate::aggregate::{SchnorrAggregator, SchnorrAggregate};
|
|||||||
|
|
||||||
mod rfc8032;
|
mod rfc8032;
|
||||||
|
|
||||||
pub(crate) fn sign<C: Ciphersuite>() {
|
pub(crate) fn sign<C: GroupIo>() {
|
||||||
let private_key = Zeroizing::new(C::random_nonzero_F(&mut OsRng));
|
let private_key = Zeroizing::new(C::F::random(&mut OsRng));
|
||||||
let nonce = Zeroizing::new(C::random_nonzero_F(&mut OsRng));
|
let nonce = Zeroizing::new(C::F::random(&mut OsRng));
|
||||||
let challenge = C::random_nonzero_F(&mut OsRng); // Doesn't bother to craft an HRAm
|
let challenge = C::F::random(&mut OsRng); // Doesn't bother to craft an HRAm
|
||||||
assert!(SchnorrSignature::<C>::sign(&private_key, nonce, challenge)
|
assert!(SchnorrSignature::<C>::sign(&private_key, nonce, challenge)
|
||||||
.verify(C::generator() * private_key.deref(), challenge));
|
.verify(C::generator() * private_key.deref(), challenge));
|
||||||
}
|
}
|
||||||
@@ -27,22 +27,22 @@ pub(crate) fn sign<C: Ciphersuite>() {
|
|||||||
// The above sign function verifies signing works
|
// The above sign function verifies signing works
|
||||||
// This verifies invalid signatures don't pass, using zero signatures, which should effectively be
|
// This verifies invalid signatures don't pass, using zero signatures, which should effectively be
|
||||||
// random
|
// random
|
||||||
pub(crate) fn verify<C: Ciphersuite>() {
|
pub(crate) fn verify<C: GroupIo>() {
|
||||||
assert!(!SchnorrSignature::<C> { R: C::G::identity(), s: C::F::ZERO }
|
assert!(!SchnorrSignature::<C> { R: C::G::identity(), s: C::F::ZERO }
|
||||||
.verify(C::generator() * C::random_nonzero_F(&mut OsRng), C::random_nonzero_F(&mut OsRng)));
|
.verify(C::generator() * C::F::random(&mut OsRng), C::F::random(&mut OsRng)));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn batch_verify<C: Ciphersuite>() {
|
pub(crate) fn batch_verify<C: GroupIo>() {
|
||||||
// Create 5 signatures
|
// Create 5 signatures
|
||||||
let mut keys = vec![];
|
let mut keys = vec![];
|
||||||
let mut challenges = vec![];
|
let mut challenges = vec![];
|
||||||
let mut sigs = vec![];
|
let mut sigs = vec![];
|
||||||
for i in 0 .. 5 {
|
for i in 0 .. 5 {
|
||||||
keys.push(Zeroizing::new(C::random_nonzero_F(&mut OsRng)));
|
keys.push(Zeroizing::new(C::F::random(&mut OsRng)));
|
||||||
challenges.push(C::random_nonzero_F(&mut OsRng));
|
challenges.push(C::F::random(&mut OsRng));
|
||||||
sigs.push(SchnorrSignature::<C>::sign(
|
sigs.push(SchnorrSignature::<C>::sign(
|
||||||
&keys[i],
|
&keys[i],
|
||||||
Zeroizing::new(C::random_nonzero_F(&mut OsRng)),
|
Zeroizing::new(C::F::random(&mut OsRng)),
|
||||||
challenges[i],
|
challenges[i],
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -78,7 +78,7 @@ pub(crate) fn batch_verify<C: Ciphersuite>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "aggregate")]
|
#[cfg(feature = "aggregate")]
|
||||||
pub(crate) fn aggregate<C: Ciphersuite>() {
|
pub(crate) fn aggregate<C: GroupIo + WithPreferredHash>() {
|
||||||
const DST: &[u8] = b"Schnorr Aggregator Test";
|
const DST: &[u8] = b"Schnorr Aggregator Test";
|
||||||
|
|
||||||
// Create 5 signatures
|
// Create 5 signatures
|
||||||
@@ -86,14 +86,14 @@ pub(crate) fn aggregate<C: Ciphersuite>() {
|
|||||||
let mut challenges = vec![];
|
let mut challenges = vec![];
|
||||||
let mut aggregator = SchnorrAggregator::<C>::new(DST);
|
let mut aggregator = SchnorrAggregator::<C>::new(DST);
|
||||||
for i in 0 .. 5 {
|
for i in 0 .. 5 {
|
||||||
keys.push(Zeroizing::new(C::random_nonzero_F(&mut OsRng)));
|
keys.push(Zeroizing::new(C::F::random(&mut OsRng)));
|
||||||
// In practice, this MUST be a secure challenge binding to the nonce, key, and any message
|
// In practice, this MUST be a secure challenge binding to the nonce, key, and any message
|
||||||
challenges.push(C::random_nonzero_F(&mut OsRng));
|
challenges.push(C::F::random(&mut OsRng));
|
||||||
aggregator.aggregate(
|
aggregator.aggregate(
|
||||||
challenges[i],
|
challenges[i],
|
||||||
SchnorrSignature::<C>::sign(
|
SchnorrSignature::<C>::sign(
|
||||||
&keys[i],
|
&keys[i],
|
||||||
Zeroizing::new(C::random_nonzero_F(&mut OsRng)),
|
Zeroizing::new(C::F::random(&mut OsRng)),
|
||||||
challenges[i],
|
challenges[i],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
use sha2::{Digest, Sha512};
|
use sha2::{Digest, Sha512};
|
||||||
|
|
||||||
use dalek_ff_group::{Scalar, Ed25519};
|
use dalek_ff_group::{Scalar, Ed25519};
|
||||||
use ciphersuite::{group::GroupEncoding, Ciphersuite};
|
use ciphersuite::{group::GroupEncoding, GroupIo};
|
||||||
|
|
||||||
use crate::SchnorrSignature;
|
use crate::SchnorrSignature;
|
||||||
|
|
||||||
|
|||||||
@@ -24,10 +24,9 @@ transcript = { package = "flexible-transcript", path = "../transcript", version
|
|||||||
|
|
||||||
group = "0.13"
|
group = "0.13"
|
||||||
|
|
||||||
dalek-ff-group = { path = "../dalek-ff-group" }
|
|
||||||
ciphersuite = { path = "../ciphersuite", version = "^0.4.1", features = ["std"] }
|
ciphersuite = { path = "../ciphersuite", version = "^0.4.1", features = ["std"] }
|
||||||
schnorr = { package = "schnorr-signatures", path = "../schnorr", version = "^0.5.1" }
|
schnorr = { package = "schnorr-signatures", path = "../schnorr", version = "^0.5.1" }
|
||||||
frost = { path = "../frost", package = "modular-frost", version = "^0.10.0", features = ["ristretto"] }
|
frost = { path = "../frost", package = "modular-frost", version = "0.11.0", features = ["ristretto"] }
|
||||||
|
|
||||||
schnorrkel = { version = "0.11" }
|
schnorrkel = { version = "0.11" }
|
||||||
|
|
||||||
|
|||||||
@@ -9,16 +9,16 @@ use zeroize::Zeroizing;
|
|||||||
|
|
||||||
use transcript::{Transcript, MerlinTranscript};
|
use transcript::{Transcript, MerlinTranscript};
|
||||||
|
|
||||||
use dalek_ff_group::Ristretto;
|
|
||||||
use ciphersuite::{
|
use ciphersuite::{
|
||||||
group::{ff::PrimeField, GroupEncoding},
|
group::{ff::PrimeField, GroupEncoding},
|
||||||
Ciphersuite,
|
WrappedGroup,
|
||||||
};
|
};
|
||||||
use schnorr::SchnorrSignature;
|
use schnorr::SchnorrSignature;
|
||||||
|
|
||||||
use ::frost::{
|
use ::frost::{
|
||||||
Participant, ThresholdKeys, ThresholdView, FrostError,
|
Participant, ThresholdKeys, ThresholdView, FrostError,
|
||||||
algorithm::{Hram, Algorithm, Schnorr},
|
algorithm::{Hram, Algorithm, Schnorr},
|
||||||
|
curve::Ristretto,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The [modular-frost](https://docs.rs/modular-frost) library.
|
/// The [modular-frost](https://docs.rs/modular-frost) library.
|
||||||
@@ -28,8 +28,8 @@ pub mod frost {
|
|||||||
|
|
||||||
use schnorrkel::{PublicKey, Signature, context::SigningTranscript, signing_context};
|
use schnorrkel::{PublicKey, Signature, context::SigningTranscript, signing_context};
|
||||||
|
|
||||||
type RistrettoPoint = <Ristretto as Ciphersuite>::G;
|
type RistrettoPoint = <Ristretto as WrappedGroup>::G;
|
||||||
type Scalar = <Ristretto as Ciphersuite>::F;
|
type Scalar = <Ristretto as WrappedGroup>::F;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
@@ -83,7 +83,7 @@ impl Algorithm<Ristretto> for Schnorrkel {
|
|||||||
self.schnorr.transcript()
|
self.schnorr.transcript()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nonces(&self) -> Vec<Vec<<Ristretto as Ciphersuite>::G>> {
|
fn nonces(&self) -> Vec<Vec<<Ristretto as WrappedGroup>::G>> {
|
||||||
self.schnorr.nonces()
|
self.schnorr.nonces()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ hex-literal = { version = "0.4", default-features = false }
|
|||||||
|
|
||||||
std-shims = { version = "0.1", path = "../../common/std-shims", default-features = false, optional = true }
|
std-shims = { version = "0.1", path = "../../common/std-shims", default-features = false, optional = true }
|
||||||
|
|
||||||
k256 = { version = "0.13", default-features = false, features = ["arithmetic"] }
|
sha2 = { version = "0.11.0-rc.0", default-features = false }
|
||||||
|
k256 = { version = "0.13", default-features = false, features = ["arithmetic", "expose-field"] }
|
||||||
prime-field = { path = "../prime-field", default-features = false }
|
prime-field = { path = "../prime-field", default-features = false }
|
||||||
short-weierstrass = { path = "../short-weierstrass", default-features = false }
|
short-weierstrass = { path = "../short-weierstrass", default-features = false }
|
||||||
|
|
||||||
sha2 = { version = "0.11.0-rc.0", default-features = false }
|
|
||||||
ciphersuite = { path = "../ciphersuite", version = "0.4", 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 }
|
generalized-bulletproofs-ec-gadgets = { git = "https://github.com/monero-oxide/monero-oxide", rev = "7216a2e84c7671c167c3d81eafe0d2b1f418f102", default-features = false, optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
|
|||||||
@@ -5,17 +5,12 @@
|
|||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use std_shims::prelude::*;
|
use std_shims::prelude::*;
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
use std_shims::io::{self, Read};
|
|
||||||
|
|
||||||
use sha2::{
|
use sha2::digest::array::{typenum::U33, Array};
|
||||||
digest::array::{typenum::U33, Array},
|
|
||||||
Sha512,
|
|
||||||
};
|
|
||||||
use k256::elliptic_curve::{
|
use k256::elliptic_curve::{
|
||||||
subtle::{Choice, ConstantTimeEq, ConditionallySelectable},
|
subtle::{Choice, CtOption, ConstantTimeEq, ConditionallySelectable},
|
||||||
zeroize::Zeroize,
|
zeroize::Zeroize,
|
||||||
group::{ff::PrimeField, Group},
|
group::{ff::PrimeField, Group, GroupEncoding},
|
||||||
sec1::Tag,
|
sec1::Tag,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -109,32 +104,25 @@ impl ShortWeierstrass for Secq256k1 {
|
|||||||
|
|
||||||
pub type Point = Projective<Secq256k1>;
|
pub type Point = Projective<Secq256k1>;
|
||||||
|
|
||||||
impl ciphersuite::Ciphersuite for Secq256k1 {
|
impl ciphersuite::WrappedGroup for Secq256k1 {
|
||||||
type F = Scalar;
|
type F = Scalar;
|
||||||
type G = Point;
|
type G = Point;
|
||||||
type H = Sha512;
|
|
||||||
|
|
||||||
const ID: &'static [u8] = b"secq256k1";
|
|
||||||
|
|
||||||
fn generator() -> Self::G {
|
fn generator() -> Self::G {
|
||||||
Point::generator()
|
<Point as Group>::generator()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// We override the provided impl, which compares against the reserialization, because
|
impl ciphersuite::Id for Secq256k1 {
|
||||||
// we already require canonicity
|
const ID: &[u8] = b"secq256k1";
|
||||||
#[cfg(feature = "alloc")]
|
}
|
||||||
#[allow(non_snake_case)]
|
impl ciphersuite::GroupCanonicalEncoding for Secq256k1 {
|
||||||
fn read_G<R: Read>(reader: &mut R) -> io::Result<Self::G> {
|
fn from_canonical_bytes(bytes: &<Self::G as GroupEncoding>::Repr) -> CtOption<Self::G> {
|
||||||
use ciphersuite::group::GroupEncoding;
|
Self::G::from_bytes(bytes)
|
||||||
|
|
||||||
let mut encoding = <Self::G as GroupEncoding>::Repr::default();
|
|
||||||
reader.read_exact(encoding.as_mut())?;
|
|
||||||
|
|
||||||
let point = Option::<Self::G>::from(Self::G::from_bytes(&encoding))
|
|
||||||
.ok_or_else(|| io::Error::other("invalid point"))?;
|
|
||||||
Ok(point)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl ciphersuite::WithPreferredHash for Secq256k1 {
|
||||||
|
type H = sha2::Sha512;
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
impl generalized_bulletproofs_ec_gadgets::DiscreteLogParameter for Secq256k1 {
|
impl generalized_bulletproofs_ec_gadgets::DiscreteLogParameter for Secq256k1 {
|
||||||
@@ -150,7 +138,7 @@ fn test_curve() {
|
|||||||
fn generator() {
|
fn generator() {
|
||||||
use ciphersuite::group::GroupEncoding;
|
use ciphersuite::group::GroupEncoding;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Point::generator(),
|
<Point as Group>::generator(),
|
||||||
Point::from_bytes(&Array(hex_literal::hex!(
|
Point::from_bytes(&Array(hex_literal::hex!(
|
||||||
"020000000000000000000000000000000000000000000000000000000000000001"
|
"020000000000000000000000000000000000000000000000000000000000000001"
|
||||||
)))
|
)))
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ rand_core = { version = "0.6", default-features = false }
|
|||||||
ff = { version = "0.13", default-features = false, features = ["bits"] }
|
ff = { version = "0.13", default-features = false, features = ["bits"] }
|
||||||
group = { version = "0.13", default-features = false }
|
group = { version = "0.13", default-features = false }
|
||||||
|
|
||||||
ec-divisors = { git = "https://github.com/monero-oxide/monero-oxide", rev = "a6f8797007e768488568b821435cf5006517a962", default-features = false, optional = true }
|
ec-divisors = { git = "https://github.com/monero-oxide/monero-oxide", rev = "7216a2e84c7671c167c3d81eafe0d2b1f418f102", default-features = false, optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
alloc = ["zeroize/alloc", "rand_core/alloc", "ff/alloc", "group/alloc", "ec-divisors"]
|
alloc = ["zeroize/alloc", "rand_core/alloc", "ff/alloc", "group/alloc", "ec-divisors"]
|
||||||
|
|||||||
@@ -413,7 +413,6 @@ impl<C: ShortWeierstrass<Scalar: PrimeFieldBits>> PrimeGroup for Projective<C> {
|
|||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
mod alloc {
|
mod alloc {
|
||||||
use core::borrow::Borrow;
|
|
||||||
use ff::{PrimeField, PrimeFieldBits};
|
use ff::{PrimeField, PrimeFieldBits};
|
||||||
use crate::{ShortWeierstrass, Affine, Projective};
|
use crate::{ShortWeierstrass, Affine, Projective};
|
||||||
|
|
||||||
@@ -421,7 +420,8 @@ mod alloc {
|
|||||||
type FieldElement = C::FieldElement;
|
type FieldElement = C::FieldElement;
|
||||||
type XyPoint = ec_divisors::Projective<Self>;
|
type XyPoint = ec_divisors::Projective<Self>;
|
||||||
|
|
||||||
fn interpolator_for_scalar_mul() -> impl Borrow<ec_divisors::Interpolator<C::FieldElement>> {
|
type BorrowedInterpolator = ec_divisors::Interpolator<C::FieldElement>;
|
||||||
|
fn interpolator_for_scalar_mul() -> Self::BorrowedInterpolator {
|
||||||
ec_divisors::Interpolator::new((<C::Scalar as PrimeField>::NUM_BITS as usize).div_ceil(2) + 2)
|
ec_divisors::Interpolator::new((<C::Scalar as PrimeField>::NUM_BITS as usize).div_ceil(2) + 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,14 +19,14 @@ workspace = true
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
zeroize = { version = "^1.5", default-features = false }
|
zeroize = { version = "^1.5", default-features = false }
|
||||||
|
|
||||||
digest = { version = "0.11.0-rc.0", default-features = false, features = ["block-api"] }
|
digest = { version = "0.11.0-rc.1", default-features = false, features = ["block-api"] }
|
||||||
|
|
||||||
blake2 = { version = "0.11.0-rc.0", default-features = false, optional = true }
|
blake2 = { version = "0.11.0-rc.2", default-features = false, optional = true }
|
||||||
merlin = { version = "3", default-features = false, optional = true }
|
merlin = { version = "3", default-features = false, optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
sha2 = { version = "0.11.0-rc.0", default-features = false }
|
sha2 = { version = "0.11.0-rc.2", default-features = false }
|
||||||
blake2 = { version = "0.11.0-rc.0", default-features = false }
|
blake2 = { version = "0.11.0-rc.2", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
std = ["zeroize/std", "merlin?/std"]
|
std = ["zeroize/std", "merlin?/std"]
|
||||||
|
|||||||
@@ -4,13 +4,7 @@
|
|||||||
|
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
use digest::{
|
use digest::{block_api::BlockSizeUser, Digest, Output, HashMarker};
|
||||||
typenum::{
|
|
||||||
consts::U32, marker_traits::NonZero, type_operators::IsGreaterOrEqual, operator_aliases::GrEq,
|
|
||||||
},
|
|
||||||
block_api::BlockSizeUser,
|
|
||||||
Digest, Output, HashMarker,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "merlin")]
|
#[cfg(feature = "merlin")]
|
||||||
mod merlin;
|
mod merlin;
|
||||||
@@ -75,24 +69,11 @@ impl DigestTranscriptMember {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait defining cryptographic Digests with at least a 256-bit output size, assuming at least a
|
|
||||||
/// 128-bit level of security accordingly.
|
|
||||||
pub trait SecureDigest: Digest + HashMarker {}
|
|
||||||
impl<D: Digest + HashMarker> SecureDigest for D
|
|
||||||
where
|
|
||||||
// This just lets us perform the comparison
|
|
||||||
D::OutputSize: IsGreaterOrEqual<U32>,
|
|
||||||
// Perform the comparison and make sure it's true (not zero), meaning D::OutputSize is >= U32
|
|
||||||
// This should be U32 as it's length in bytes, not bits
|
|
||||||
GrEq<D::OutputSize, U32>: NonZero,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A simple transcript format constructed around the specified hash algorithm.
|
/// A simple transcript format constructed around the specified hash algorithm.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DigestTranscript<D: Send + Clone + SecureDigest>(D);
|
pub struct DigestTranscript<D: Send + Clone + Digest + HashMarker>(D);
|
||||||
|
|
||||||
impl<D: Send + Clone + SecureDigest> DigestTranscript<D> {
|
impl<D: Send + Clone + Digest + HashMarker> DigestTranscript<D> {
|
||||||
fn append(&mut self, kind: DigestTranscriptMember, value: &[u8]) {
|
fn append(&mut self, kind: DigestTranscriptMember, value: &[u8]) {
|
||||||
self.0.update([kind.as_u8()]);
|
self.0.update([kind.as_u8()]);
|
||||||
// Assumes messages don't exceed 16 exabytes
|
// Assumes messages don't exceed 16 exabytes
|
||||||
@@ -101,7 +82,7 @@ impl<D: Send + Clone + SecureDigest> DigestTranscript<D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: Send + Clone + SecureDigest> Transcript for DigestTranscript<D> {
|
impl<D: Send + Clone + Digest + HashMarker> Transcript for DigestTranscript<D> {
|
||||||
type Challenge = Output<D>;
|
type Challenge = Output<D>;
|
||||||
|
|
||||||
fn new(name: &'static [u8]) -> Self {
|
fn new(name: &'static [u8]) -> Self {
|
||||||
@@ -140,7 +121,7 @@ impl<D: Send + Clone + SecureDigest> Transcript for DigestTranscript<D> {
|
|||||||
// Digest doesn't implement Zeroize
|
// Digest doesn't implement Zeroize
|
||||||
// Implement Zeroize for DigestTranscript by writing twice the block size to the digest in an
|
// Implement Zeroize for DigestTranscript by writing twice the block size to the digest in an
|
||||||
// attempt to overwrite the internal hash state/any leftover bytes
|
// attempt to overwrite the internal hash state/any leftover bytes
|
||||||
impl<D: Send + Clone + SecureDigest> Zeroize for DigestTranscript<D>
|
impl<D: Send + Clone + Digest + HashMarker> Zeroize for DigestTranscript<D>
|
||||||
where
|
where
|
||||||
D: BlockSizeUser,
|
D: BlockSizeUser,
|
||||||
{
|
{
|
||||||
@@ -159,7 +140,7 @@ where
|
|||||||
// These writes may be optimized out if they're never read
|
// These writes may be optimized out if they're never read
|
||||||
// Attempt to get them marked as read
|
// Attempt to get them marked as read
|
||||||
|
|
||||||
fn mark_read<D: Send + Clone + SecureDigest>(transcript: &DigestTranscript<D>) {
|
fn mark_read<D: Send + Clone + Digest + HashMarker>(transcript: &DigestTranscript<D>) {
|
||||||
// Just get a challenge from the state
|
// Just get a challenge from the state
|
||||||
let mut challenge = core::hint::black_box(transcript.0.clone().finalize());
|
let mut challenge = core::hint::black_box(transcript.0.clone().finalize());
|
||||||
challenge.as_mut().zeroize();
|
challenge.as_mut().zeroize();
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ zeroize = { version = "1", default-features = false, features = ["std"] }
|
|||||||
rand_core = { version = "0.6", default-features = false, features = ["std"] }
|
rand_core = { version = "0.6", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
# Cryptography
|
# Cryptography
|
||||||
transcript = { package = "flexible-transcript", path = "../crypto/transcript", default-features = false, features = ["std", "recommended"] }
|
transcript = { package = "flexible-transcript", path = "../crypto/transcript", default-features = false, features = ["std"] }
|
||||||
dalek-ff-group = { path = "../crypto/dalek-ff-group", default-features = false, features = ["std"] }
|
dalek-ff-group = { path = "../crypto/dalek-ff-group", default-features = false, features = ["std"] }
|
||||||
ciphersuite = { path = "../crypto/ciphersuite", default-features = false, features = ["std"] }
|
ciphersuite = { path = "../crypto/ciphersuite", default-features = false, features = ["std"] }
|
||||||
schnorr-signatures = { path = "../crypto/schnorr", default-features = false, features = ["std"] }
|
schnorr-signatures = { path = "../crypto/schnorr", default-features = false, features = ["std"] }
|
||||||
|
|||||||
@@ -4,10 +4,7 @@ use zeroize::{Zeroize, Zeroizing};
|
|||||||
use rand_core::OsRng;
|
use rand_core::OsRng;
|
||||||
|
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use ciphersuite::{
|
use ciphersuite::{group::ff::PrimeField, WrappedGroup};
|
||||||
group::ff::{Field, PrimeField},
|
|
||||||
Ciphersuite,
|
|
||||||
};
|
|
||||||
use schnorr_signatures::SchnorrSignature;
|
use schnorr_signatures::SchnorrSignature;
|
||||||
|
|
||||||
use tokio::{
|
use tokio::{
|
||||||
@@ -22,8 +19,8 @@ use crate::{Service, Metadata, QueuedMessage, MessageQueueRequest, message_chall
|
|||||||
|
|
||||||
pub struct MessageQueue {
|
pub struct MessageQueue {
|
||||||
pub service: Service,
|
pub service: Service,
|
||||||
priv_key: Zeroizing<<Ristretto as Ciphersuite>::F>,
|
priv_key: Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
pub_key: <Ristretto as Ciphersuite>::G,
|
pub_key: <Ristretto as WrappedGroup>::G,
|
||||||
url: String,
|
url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +28,7 @@ impl MessageQueue {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
service: Service,
|
service: Service,
|
||||||
mut url: String,
|
mut url: String,
|
||||||
priv_key: Zeroizing<<Ristretto as Ciphersuite>::F>,
|
priv_key: Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
) -> MessageQueue {
|
) -> MessageQueue {
|
||||||
// Allow MESSAGE_QUEUE_RPC to either be a full URL or just a hostname
|
// Allow MESSAGE_QUEUE_RPC to either be a full URL or just a hostname
|
||||||
// While we could stitch together multiple variables, our control over this service makes this
|
// While we could stitch together multiple variables, our control over this service makes this
|
||||||
@@ -46,16 +43,16 @@ impl MessageQueue {
|
|||||||
pub fn from_env(service: Service) -> MessageQueue {
|
pub fn from_env(service: Service) -> MessageQueue {
|
||||||
let url = env::var("MESSAGE_QUEUE_RPC").expect("message-queue RPC wasn't specified");
|
let url = env::var("MESSAGE_QUEUE_RPC").expect("message-queue RPC wasn't specified");
|
||||||
|
|
||||||
let priv_key: Zeroizing<<Ristretto as Ciphersuite>::F> = {
|
let priv_key: Zeroizing<<Ristretto as WrappedGroup>::F> = {
|
||||||
let key_str =
|
let key_str =
|
||||||
Zeroizing::new(env::var("MESSAGE_QUEUE_KEY").expect("message-queue key wasn't specified"));
|
Zeroizing::new(env::var("MESSAGE_QUEUE_KEY").expect("message-queue key wasn't specified"));
|
||||||
let key_bytes = Zeroizing::new(
|
let key_bytes = Zeroizing::new(
|
||||||
hex::decode(&key_str).expect("invalid message-queue key specified (wasn't hex)"),
|
hex::decode(&key_str).expect("invalid message-queue key specified (wasn't hex)"),
|
||||||
);
|
);
|
||||||
let mut bytes = <<Ristretto as Ciphersuite>::F as PrimeField>::Repr::default();
|
let mut bytes = <<Ristretto as WrappedGroup>::F as PrimeField>::Repr::default();
|
||||||
bytes.copy_from_slice(&key_bytes);
|
bytes.copy_from_slice(&key_bytes);
|
||||||
let key = Zeroizing::new(
|
let key = Zeroizing::new(
|
||||||
Option::from(<<Ristretto as Ciphersuite>::F as PrimeField>::from_repr(bytes))
|
Option::from(<<Ristretto as WrappedGroup>::F as PrimeField>::from_repr(bytes))
|
||||||
.expect("invalid message-queue key specified"),
|
.expect("invalid message-queue key specified"),
|
||||||
);
|
);
|
||||||
bytes.zeroize();
|
bytes.zeroize();
|
||||||
@@ -79,7 +76,7 @@ impl MessageQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn queue(&self, metadata: Metadata, msg: Vec<u8>) -> Result<(), String> {
|
pub async fn queue(&self, metadata: Metadata, msg: Vec<u8>) -> Result<(), String> {
|
||||||
let nonce = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng));
|
let nonce = Zeroizing::new(<Ristretto as WrappedGroup>::F::random(&mut OsRng));
|
||||||
let nonce_pub = Ristretto::generator() * nonce.deref();
|
let nonce_pub = Ristretto::generator() * nonce.deref();
|
||||||
let sig = SchnorrSignature::<Ristretto>::sign(
|
let sig = SchnorrSignature::<Ristretto>::sign(
|
||||||
&self.priv_key,
|
&self.priv_key,
|
||||||
@@ -215,7 +212,7 @@ impl MessageQueue {
|
|||||||
|
|
||||||
pub async fn ack(&self, from: Service, id: u64) {
|
pub async fn ack(&self, from: Service, id: u64) {
|
||||||
// TODO: Should this use OsRng? Deterministic or deterministic + random may be better.
|
// TODO: Should this use OsRng? Deterministic or deterministic + random may be better.
|
||||||
let nonce = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut OsRng));
|
let nonce = Zeroizing::new(<Ristretto as WrappedGroup>::F::random(&mut OsRng));
|
||||||
let nonce_pub = Ristretto::generator() * nonce.deref();
|
let nonce_pub = Ristretto::generator() * nonce.deref();
|
||||||
let sig = SchnorrSignature::<Ristretto>::sign(
|
let sig = SchnorrSignature::<Ristretto>::sign(
|
||||||
&self.priv_key,
|
&self.priv_key,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ pub(crate) use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
pub(crate) use ciphersuite::{group::GroupEncoding, Ciphersuite};
|
pub(crate) use ciphersuite::{group::GroupEncoding, WrappedGroup, GroupCanonicalEncoding};
|
||||||
pub(crate) use schnorr_signatures::SchnorrSignature;
|
pub(crate) use schnorr_signatures::SchnorrSignature;
|
||||||
|
|
||||||
pub(crate) use serai_primitives::ExternalNetworkId;
|
pub(crate) use serai_primitives::ExternalNetworkId;
|
||||||
@@ -29,7 +29,7 @@ pub(crate) type Db = serai_db::RocksDB;
|
|||||||
mod clippy {
|
mod clippy {
|
||||||
use super::*;
|
use super::*;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
pub(crate) static KEYS: Lazy<Arc<RwLock<HashMap<Service, <Ristretto as Ciphersuite>::G>>>> =
|
pub(crate) static KEYS: Lazy<Arc<RwLock<HashMap<Service, <Ristretto as WrappedGroup>::G>>>> =
|
||||||
Lazy::new(|| Arc::new(RwLock::new(HashMap::new())));
|
Lazy::new(|| Arc::new(RwLock::new(HashMap::new())));
|
||||||
pub(crate) static QUEUES: Lazy<Arc<RwLock<HashMap<(Service, Service), RwLock<Queue<Db>>>>>> =
|
pub(crate) static QUEUES: Lazy<Arc<RwLock<HashMap<(Service, Service), RwLock<Queue<Db>>>>>> =
|
||||||
Lazy::new(|| Arc::new(RwLock::new(HashMap::new())));
|
Lazy::new(|| Arc::new(RwLock::new(HashMap::new())));
|
||||||
@@ -189,9 +189,9 @@ async fn main() {
|
|||||||
let read_key = |str| {
|
let read_key = |str| {
|
||||||
let key = serai_env::var(str)?;
|
let key = serai_env::var(str)?;
|
||||||
|
|
||||||
let mut repr = <<Ristretto as Ciphersuite>::G as GroupEncoding>::Repr::default();
|
let mut repr = <<Ristretto as WrappedGroup>::G as GroupEncoding>::Repr::default();
|
||||||
repr.as_mut().copy_from_slice(&hex::decode(key).unwrap());
|
repr.as_mut().copy_from_slice(&hex::decode(key).unwrap());
|
||||||
Some(<Ristretto as Ciphersuite>::G::from_bytes(&repr).unwrap())
|
Some(<Ristretto as GroupCanonicalEncoding>::from_canonical_bytes(&repr).unwrap())
|
||||||
};
|
};
|
||||||
|
|
||||||
let register_service = |service, key| {
|
let register_service = |service, key| {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use transcript::{Transcript, RecommendedTranscript};
|
use transcript::{Transcript, DigestTranscript};
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use ciphersuite::{group::GroupEncoding, Ciphersuite};
|
use ciphersuite::{group::GroupEncoding, FromUniformBytes, WrappedGroup, WithPreferredHash};
|
||||||
|
|
||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
|
|
||||||
@@ -36,13 +36,15 @@ pub enum MessageQueueRequest {
|
|||||||
|
|
||||||
pub fn message_challenge(
|
pub fn message_challenge(
|
||||||
from: Service,
|
from: Service,
|
||||||
from_key: <Ristretto as Ciphersuite>::G,
|
from_key: <Ristretto as WrappedGroup>::G,
|
||||||
to: Service,
|
to: Service,
|
||||||
intent: &[u8],
|
intent: &[u8],
|
||||||
msg: &[u8],
|
msg: &[u8],
|
||||||
nonce: <Ristretto as Ciphersuite>::G,
|
nonce: <Ristretto as WrappedGroup>::G,
|
||||||
) -> <Ristretto as Ciphersuite>::F {
|
) -> <Ristretto as WrappedGroup>::F {
|
||||||
let mut transcript = RecommendedTranscript::new(b"Serai Message Queue v0.1 Message");
|
let mut transcript = DigestTranscript::<<Ristretto as WithPreferredHash>::H>::new(
|
||||||
|
b"Serai Message Queue v0.1 Message",
|
||||||
|
);
|
||||||
transcript.domain_separate(b"metadata");
|
transcript.domain_separate(b"metadata");
|
||||||
transcript.append_message(b"from", borsh::to_vec(&from).unwrap());
|
transcript.append_message(b"from", borsh::to_vec(&from).unwrap());
|
||||||
transcript.append_message(b"from_key", from_key.to_bytes());
|
transcript.append_message(b"from_key", from_key.to_bytes());
|
||||||
@@ -52,17 +54,19 @@ pub fn message_challenge(
|
|||||||
transcript.append_message(b"msg", msg);
|
transcript.append_message(b"msg", msg);
|
||||||
transcript.domain_separate(b"signature");
|
transcript.domain_separate(b"signature");
|
||||||
transcript.append_message(b"nonce", nonce.to_bytes());
|
transcript.append_message(b"nonce", nonce.to_bytes());
|
||||||
<Ristretto as Ciphersuite>::hash_to_F(&transcript.challenge(b"challenge"))
|
<Ristretto as WrappedGroup>::F::from_uniform_bytes(&transcript.challenge(b"challenge").into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ack_challenge(
|
pub fn ack_challenge(
|
||||||
to: Service,
|
to: Service,
|
||||||
to_key: <Ristretto as Ciphersuite>::G,
|
to_key: <Ristretto as WrappedGroup>::G,
|
||||||
from: Service,
|
from: Service,
|
||||||
id: u64,
|
id: u64,
|
||||||
nonce: <Ristretto as Ciphersuite>::G,
|
nonce: <Ristretto as WrappedGroup>::G,
|
||||||
) -> <Ristretto as Ciphersuite>::F {
|
) -> <Ristretto as WrappedGroup>::F {
|
||||||
let mut transcript = RecommendedTranscript::new(b"Serai Message Queue v0.1 Acknowledgement");
|
let mut transcript = DigestTranscript::<<Ristretto as WithPreferredHash>::H>::new(
|
||||||
|
b"Serai Message Queue v0.1 Acknowledgement",
|
||||||
|
);
|
||||||
transcript.domain_separate(b"metadata");
|
transcript.domain_separate(b"metadata");
|
||||||
transcript.append_message(b"to", borsh::to_vec(&to).unwrap());
|
transcript.append_message(b"to", borsh::to_vec(&to).unwrap());
|
||||||
transcript.append_message(b"to_key", to_key.to_bytes());
|
transcript.append_message(b"to_key", to_key.to_bytes());
|
||||||
@@ -71,5 +75,5 @@ pub fn ack_challenge(
|
|||||||
transcript.append_message(b"id", id.to_le_bytes());
|
transcript.append_message(b"id", id.to_le_bytes());
|
||||||
transcript.domain_separate(b"signature");
|
transcript.domain_separate(b"signature");
|
||||||
transcript.append_message(b"nonce", nonce.to_bytes());
|
transcript.append_message(b"nonce", nonce.to_bytes());
|
||||||
<Ristretto as Ciphersuite>::hash_to_F(&transcript.challenge(b"challenge"))
|
<Ristretto as WrappedGroup>::F::from_uniform_bytes(&transcript.challenge(b"challenge").into())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ rand_core = { version = "0.6", default-features = false }
|
|||||||
bitcoin = { version = "0.32", default-features = false }
|
bitcoin = { version = "0.32", default-features = false }
|
||||||
|
|
||||||
k256 = { version = "^0.13.1", default-features = false, features = ["arithmetic", "bits"] }
|
k256 = { version = "^0.13.1", default-features = false, features = ["arithmetic", "bits"] }
|
||||||
frost = { package = "modular-frost", path = "../../crypto/frost", version = "0.10", default-features = false, features = ["secp256k1"], optional = true }
|
frost = { package = "modular-frost", path = "../../crypto/frost", version = "0.11", default-features = false, features = ["secp256k1"], optional = true }
|
||||||
|
|
||||||
hex = { version = "0.4", default-features = false, optional = true }
|
hex = { version = "0.4", default-features = false, optional = true }
|
||||||
serde = { version = "1", default-features = false, features = ["derive"], optional = true }
|
serde = { version = "1", default-features = false, features = ["derive"], optional = true }
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ mod frost_crypto {
|
|||||||
use k256::{elliptic_curve::ops::Reduce, U256, Scalar};
|
use k256::{elliptic_curve::ops::Reduce, U256, Scalar};
|
||||||
|
|
||||||
use frost::{
|
use frost::{
|
||||||
curve::{Ciphersuite, Secp256k1},
|
curve::{WrappedGroup, Secp256k1},
|
||||||
Participant, ThresholdKeys, ThresholdView, FrostError,
|
Participant, ThresholdKeys, ThresholdView, FrostError,
|
||||||
algorithm::{Hram as HramTrait, Algorithm, IetfSchnorr as FrostSchnorr},
|
algorithm::{Hram as HramTrait, Algorithm, IetfSchnorr as FrostSchnorr},
|
||||||
};
|
};
|
||||||
@@ -128,10 +128,10 @@ mod frost_crypto {
|
|||||||
fn sign_share(
|
fn sign_share(
|
||||||
&mut self,
|
&mut self,
|
||||||
params: &ThresholdView<Secp256k1>,
|
params: &ThresholdView<Secp256k1>,
|
||||||
nonce_sums: &[Vec<<Secp256k1 as Ciphersuite>::G>],
|
nonce_sums: &[Vec<<Secp256k1 as WrappedGroup>::G>],
|
||||||
nonces: Vec<Zeroizing<<Secp256k1 as Ciphersuite>::F>>,
|
nonces: Vec<Zeroizing<<Secp256k1 as WrappedGroup>::F>>,
|
||||||
msg: &[u8],
|
msg: &[u8],
|
||||||
) -> <Secp256k1 as Ciphersuite>::F {
|
) -> <Secp256k1 as WrappedGroup>::F {
|
||||||
self.0.sign_share(params, nonce_sums, nonces, msg)
|
self.0.sign_share(params, nonce_sums, nonces, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use k256::{
|
|||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use frost::{
|
use frost::{
|
||||||
curve::{Ciphersuite, Secp256k1},
|
curve::{WrappedGroup, GroupIo, Secp256k1},
|
||||||
ThresholdKeys,
|
ThresholdKeys,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ pub fn tweak_keys(keys: ThresholdKeys<Secp256k1>) -> ThresholdKeys<Secp256k1> {
|
|||||||
would be unusable due to a check the script path hash is less than the order. That doesn't
|
would be unusable due to a check the script path hash is less than the order. That doesn't
|
||||||
impact us as we don't want the script path to be usable.
|
impact us as we don't want the script path to be usable.
|
||||||
*/
|
*/
|
||||||
keys.offset(<Secp256k1 as Ciphersuite>::F::reduce(U256::from_be_bytes(
|
keys.offset(<Secp256k1 as WrappedGroup>::F::reduce(U256::from_be_bytes(
|
||||||
*tweak_hash.to_raw_hash().as_ref(),
|
*tweak_hash.to_raw_hash().as_ref(),
|
||||||
)))
|
)))
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::path::Path;
|
|||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use ciphersuite::{group::ff::PrimeField, Ciphersuite};
|
use ciphersuite::{group::ff::PrimeField, WrappedGroup};
|
||||||
|
|
||||||
use crate::{Network, Os, mimalloc, os, build_serai_service, write_dockerfile};
|
use crate::{Network, Os, mimalloc, os, build_serai_service, write_dockerfile};
|
||||||
|
|
||||||
@@ -11,8 +11,8 @@ use crate::{Network, Os, mimalloc, os, build_serai_service, write_dockerfile};
|
|||||||
pub fn coordinator(
|
pub fn coordinator(
|
||||||
orchestration_path: &Path,
|
orchestration_path: &Path,
|
||||||
network: Network,
|
network: Network,
|
||||||
coordinator_key: Zeroizing<<Ristretto as Ciphersuite>::F>,
|
coordinator_key: Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
serai_key: &Zeroizing<<Ristretto as Ciphersuite>::F>,
|
serai_key: &Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
) {
|
) {
|
||||||
let db = network.db();
|
let db = network.db();
|
||||||
let longer_reattempts = if network == Network::Dev { "longer-reattempts" } else { "" };
|
let longer_reattempts = if network == Network::Dev { "longer-reattempts" } else { "" };
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ use ciphersuite::{
|
|||||||
ff::{Field, PrimeField},
|
ff::{Field, PrimeField},
|
||||||
GroupEncoding,
|
GroupEncoding,
|
||||||
},
|
},
|
||||||
Ciphersuite,
|
WrappedGroup,
|
||||||
};
|
};
|
||||||
use embedwards25519::Embedwards25519;
|
use embedwards25519::Embedwards25519;
|
||||||
use secq256k1::Secq256k1;
|
use secq256k1::Secq256k1;
|
||||||
@@ -221,8 +221,10 @@ fn orchestration_path(network: Network) -> PathBuf {
|
|||||||
orchestration_path
|
orchestration_path
|
||||||
}
|
}
|
||||||
|
|
||||||
type InfrastructureKeys =
|
type InfrastructureKeys = HashMap<
|
||||||
HashMap<&'static str, (Zeroizing<<Ristretto as Ciphersuite>::F>, <Ristretto as Ciphersuite>::G)>;
|
&'static str,
|
||||||
|
(Zeroizing<<Ristretto as WrappedGroup>::F>, <Ristretto as WrappedGroup>::G),
|
||||||
|
>;
|
||||||
fn infrastructure_keys(network: Network) -> InfrastructureKeys {
|
fn infrastructure_keys(network: Network) -> InfrastructureKeys {
|
||||||
// Generate entropy for the infrastructure keys
|
// Generate entropy for the infrastructure keys
|
||||||
|
|
||||||
@@ -257,7 +259,7 @@ fn infrastructure_keys(network: Network) -> InfrastructureKeys {
|
|||||||
let mut rng = ChaCha20Rng::from_seed(transcript.rng_seed(b"infrastructure_keys"));
|
let mut rng = ChaCha20Rng::from_seed(transcript.rng_seed(b"infrastructure_keys"));
|
||||||
|
|
||||||
let mut key_pair = || {
|
let mut key_pair = || {
|
||||||
let key = Zeroizing::new(<Ristretto as Ciphersuite>::F::random(&mut rng));
|
let key = Zeroizing::new(<Ristretto as WrappedGroup>::F::random(&mut rng));
|
||||||
let public = Ristretto::generator() * key.deref();
|
let public = Ristretto::generator() * key.deref();
|
||||||
(key, public)
|
(key, public)
|
||||||
};
|
};
|
||||||
@@ -307,12 +309,12 @@ fn embedded_curve_keys(network: Network) -> EmbeddedCurveKeys {
|
|||||||
|
|
||||||
EmbeddedCurveKeys {
|
EmbeddedCurveKeys {
|
||||||
embedwards25519: {
|
embedwards25519: {
|
||||||
let key = Zeroizing::new(<Embedwards25519 as Ciphersuite>::F::random(&mut rng));
|
let key = Zeroizing::new(<Embedwards25519 as WrappedGroup>::F::random(&mut rng));
|
||||||
let pub_key = Embedwards25519::generator() * key.deref();
|
let pub_key = Embedwards25519::generator() * key.deref();
|
||||||
(Zeroizing::new(key.to_repr().as_ref().to_vec()), pub_key.to_bytes().to_vec())
|
(Zeroizing::new(key.to_repr().as_ref().to_vec()), pub_key.to_bytes().to_vec())
|
||||||
},
|
},
|
||||||
secq256k1: {
|
secq256k1: {
|
||||||
let key = Zeroizing::new(<Secq256k1 as Ciphersuite>::F::random(&mut rng));
|
let key = Zeroizing::new(<Secq256k1 as WrappedGroup>::F::random(&mut rng));
|
||||||
let pub_key = Secq256k1::generator() * key.deref();
|
let pub_key = Secq256k1::generator() * key.deref();
|
||||||
(Zeroizing::new(key.to_repr().as_ref().to_vec()), pub_key.to_bytes().to_vec())
|
(Zeroizing::new(key.to_repr().as_ref().to_vec()), pub_key.to_bytes().to_vec())
|
||||||
},
|
},
|
||||||
@@ -381,9 +383,9 @@ fn dockerfiles(network: Network) {
|
|||||||
.expect("couldn't read key for this network"),
|
.expect("couldn't read key for this network"),
|
||||||
);
|
);
|
||||||
let mut serai_key_repr =
|
let mut serai_key_repr =
|
||||||
Zeroizing::new(<<Ristretto as Ciphersuite>::F as PrimeField>::Repr::default());
|
Zeroizing::new(<<Ristretto as WrappedGroup>::F as PrimeField>::Repr::default());
|
||||||
serai_key_repr.as_mut().copy_from_slice(serai_key.as_ref());
|
serai_key_repr.as_mut().copy_from_slice(serai_key.as_ref());
|
||||||
Zeroizing::new(<Ristretto as Ciphersuite>::F::from_repr(*serai_key_repr).unwrap())
|
Zeroizing::new(<Ristretto as WrappedGroup>::F::from_repr(*serai_key_repr).unwrap())
|
||||||
};
|
};
|
||||||
|
|
||||||
coordinator(&orchestration_path, network, coordinator_key.0, &serai_key);
|
coordinator(&orchestration_path, network, coordinator_key.0, &serai_key);
|
||||||
@@ -399,7 +401,7 @@ fn key_gen(network: Network) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let key = <Ristretto as Ciphersuite>::F::random(&mut OsRng);
|
let key = <Ristretto as WrappedGroup>::F::random(&mut OsRng);
|
||||||
|
|
||||||
let _ = fs::create_dir_all(&serai_dir);
|
let _ = fs::create_dir_all(&serai_dir);
|
||||||
fs::write(key_file, key.to_repr()).expect("couldn't write key");
|
fs::write(key_file, key.to_repr()).expect("couldn't write key");
|
||||||
@@ -407,7 +409,7 @@ fn key_gen(network: Network) {
|
|||||||
// TODO: Move embedded curve key gen here, and print them
|
// TODO: Move embedded curve key gen here, and print them
|
||||||
println!(
|
println!(
|
||||||
"Public Key: {}",
|
"Public Key: {}",
|
||||||
hex::encode((<Ristretto as Ciphersuite>::generator() * key).to_bytes())
|
hex::encode((<Ristretto as WrappedGroup>::generator() * key).to_bytes())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use ciphersuite::{group::GroupEncoding, Ciphersuite};
|
use ciphersuite::{group::GroupEncoding, WrappedGroup};
|
||||||
|
|
||||||
use crate::{Network, Os, mimalloc, os, build_serai_service, write_dockerfile};
|
use crate::{Network, Os, mimalloc, os, build_serai_service, write_dockerfile};
|
||||||
|
|
||||||
pub fn message_queue(
|
pub fn message_queue(
|
||||||
orchestration_path: &Path,
|
orchestration_path: &Path,
|
||||||
network: Network,
|
network: Network,
|
||||||
coordinator_key: <Ristretto as Ciphersuite>::G,
|
coordinator_key: <Ristretto as WrappedGroup>::G,
|
||||||
bitcoin_key: <Ristretto as Ciphersuite>::G,
|
bitcoin_key: <Ristretto as WrappedGroup>::G,
|
||||||
ethereum_key: <Ristretto as Ciphersuite>::G,
|
ethereum_key: <Ristretto as WrappedGroup>::G,
|
||||||
monero_key: <Ristretto as Ciphersuite>::G,
|
monero_key: <Ristretto as WrappedGroup>::G,
|
||||||
) {
|
) {
|
||||||
let setup = mimalloc(Os::Debian).to_string() +
|
let setup = mimalloc(Os::Debian).to_string() +
|
||||||
&build_serai_service("", network.release(), network.db(), "serai-message-queue");
|
&build_serai_service("", network.release(), network.db(), "serai-message-queue");
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::path::Path;
|
|||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use ciphersuite::{group::ff::PrimeField, Ciphersuite};
|
use ciphersuite::{group::ff::PrimeField, WrappedGroup};
|
||||||
|
|
||||||
use crate::{Network, Os, mimalloc, os, build_serai_service, write_dockerfile};
|
use crate::{Network, Os, mimalloc, os, build_serai_service, write_dockerfile};
|
||||||
|
|
||||||
@@ -12,8 +12,8 @@ pub fn processor(
|
|||||||
orchestration_path: &Path,
|
orchestration_path: &Path,
|
||||||
network: Network,
|
network: Network,
|
||||||
coin: &'static str,
|
coin: &'static str,
|
||||||
_coordinator_key: <Ristretto as Ciphersuite>::G,
|
_coordinator_key: <Ristretto as WrappedGroup>::G,
|
||||||
processor_key: Zeroizing<<Ristretto as Ciphersuite>::F>,
|
processor_key: Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
substrate_evrf_key: Zeroizing<Vec<u8>>,
|
substrate_evrf_key: Zeroizing<Vec<u8>>,
|
||||||
network_evrf_key: Zeroizing<Vec<u8>>,
|
network_evrf_key: Zeroizing<Vec<u8>>,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ use std::path::Path;
|
|||||||
|
|
||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
use dalek_ff_group::Ristretto;
|
use dalek_ff_group::Ristretto;
|
||||||
use ciphersuite::{group::ff::PrimeField, Ciphersuite};
|
use ciphersuite::{group::ff::PrimeField, WrappedGroup};
|
||||||
|
|
||||||
use crate::{Network, Os, mimalloc, os, build_serai_service, write_dockerfile};
|
use crate::{Network, Os, mimalloc, os, build_serai_service, write_dockerfile};
|
||||||
|
|
||||||
pub fn serai(
|
pub fn serai(
|
||||||
orchestration_path: &Path,
|
orchestration_path: &Path,
|
||||||
network: Network,
|
network: Network,
|
||||||
serai_key: &Zeroizing<<Ristretto as Ciphersuite>::F>,
|
serai_key: &Zeroizing<<Ristretto as WrappedGroup>::F>,
|
||||||
) {
|
) {
|
||||||
// Always builds in release for performance reasons
|
// Always builds in release for performance reasons
|
||||||
let setup = mimalloc(Os::Debian).to_string() + &build_serai_service("", true, "", "serai-node");
|
let setup = mimalloc(Os::Debian).to_string() + &build_serai_service("", true, "", "serai-node");
|
||||||
|
|||||||
@@ -16,13 +16,19 @@ rustdoc-args = ["--cfg", "docsrs"]
|
|||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
std-shims = { path = "../../common/std-shims", version = "0.1.4", default-features = false, optional = true }
|
||||||
|
|
||||||
|
zeroize = { version = "1", default-features = false }
|
||||||
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false }
|
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false }
|
||||||
|
|
||||||
dalek-ff-group = { path = "../../crypto/dalek-ff-group", default-features = false, optional = true }
|
dalek-ff-group = { path = "../../crypto/dalek-ff-group", default-features = false, optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
alloc = ["ciphersuite/alloc"]
|
alloc = ["std-shims", "zeroize/alloc", "ciphersuite/alloc", "dalek-ff-group/alloc"]
|
||||||
std = [
|
std = [
|
||||||
"alloc",
|
"alloc",
|
||||||
|
"std-shims/std",
|
||||||
|
"zeroize/std",
|
||||||
"ciphersuite/std",
|
"ciphersuite/std",
|
||||||
"dalek-ff-group?/std",
|
"dalek-ff-group?/std",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,5 +1,33 @@
|
|||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
pub use ciphersuite::*;
|
use std_shims::io;
|
||||||
|
|
||||||
|
use zeroize::Zeroize;
|
||||||
|
pub use ciphersuite::group;
|
||||||
|
use group::{*, ff::*, prime::PrimeGroup};
|
||||||
|
|
||||||
|
pub trait Ciphersuite: 'static + Send + Sync {
|
||||||
|
type F: PrimeField + PrimeFieldBits + Zeroize;
|
||||||
|
type G: Group<Scalar = Self::F> + GroupOps + PrimeGroup + Zeroize;
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn read_F<R: io::Read>(reader: &mut R) -> io::Result<Self::F>;
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn read_G<R: io::Read>(reader: &mut R) -> io::Result<Self::G>;
|
||||||
|
}
|
||||||
|
impl<C: ciphersuite::GroupIo> Ciphersuite for C {
|
||||||
|
type F = <C as ciphersuite::WrappedGroup>::F;
|
||||||
|
type G = <C as ciphersuite::WrappedGroup>::G;
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
fn read_F<R: io::Read>(reader: &mut R) -> io::Result<Self::F> {
|
||||||
|
<C as ciphersuite::GroupIo>::read_F(reader)
|
||||||
|
}
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
fn read_G<R: io::Read>(reader: &mut R) -> io::Result<Self::G> {
|
||||||
|
<C as ciphersuite::GroupIo>::read_G(reader)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ed25519")]
|
#[cfg(feature = "ed25519")]
|
||||||
pub use dalek_ff_group::Ed25519;
|
pub use dalek_ff_group::Ed25519;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "dalek-ff-group"
|
name = "dalek-ff-group"
|
||||||
version = "0.4.99"
|
version = "0.5.99"
|
||||||
description = "ff/group bindings around curve25519-dalek"
|
description = "ff/group bindings around curve25519-dalek"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://github.com/serai-dex/serai/tree/develop/crypto/dalek-ff-group"
|
repository = "https://github.com/serai-dex/serai/tree/develop/crypto/dalek-ff-group"
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ scale = { package = "parity-scale-codec", version = "3", default-features = fals
|
|||||||
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] }
|
||||||
|
|
||||||
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["std"] }
|
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["std"] }
|
||||||
dkg = { package = "dkg-evrf", path = "../../crypto/dkg/evrf", default-features = false, features = ["std", "ristretto"] }
|
dkg = { package = "dkg-evrf", path = "../../crypto/dkg/evrf", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
serai-client = { path = "../../substrate/client", default-features = false }
|
serai-client = { path = "../../substrate/client", default-features = false }
|
||||||
serai-cosign = { path = "../../coordinator/cosign" }
|
serai-cosign = { path = "../../coordinator/cosign" }
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ use zeroize::{Zeroize, Zeroizing};
|
|||||||
|
|
||||||
use ciphersuite::{
|
use ciphersuite::{
|
||||||
group::{ff::PrimeField, GroupEncoding},
|
group::{ff::PrimeField, GroupEncoding},
|
||||||
Ciphersuite,
|
*,
|
||||||
};
|
};
|
||||||
use dkg::{Curves, Ristretto};
|
use dkg::Curves;
|
||||||
|
|
||||||
use serai_client::validator_sets::primitives::Session;
|
use serai_client::validator_sets::primitives::Session;
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ use serai_env as env;
|
|||||||
use serai_db::{Get, DbTxn, Db as DbTrait, create_db, db_channel};
|
use serai_db::{Get, DbTxn, Db as DbTrait, create_db, db_channel};
|
||||||
|
|
||||||
use primitives::EncodableG;
|
use primitives::EncodableG;
|
||||||
use ::key_gen::{KeyGenParams, KeyGen};
|
use ::key_gen::{Ristretto, KeyGenParams, KeyGen};
|
||||||
use scheduler::{SignableTransaction, TransactionFor};
|
use scheduler::{SignableTransaction, TransactionFor};
|
||||||
use scanner::{ScannerFeed, Scanner, KeyFor, Scheduler};
|
use scanner::{ScannerFeed, Scanner, KeyFor, Scheduler};
|
||||||
use signers::{TransactionPublisher, Signers};
|
use signers::{TransactionPublisher, Signers};
|
||||||
@@ -80,7 +80,7 @@ pub fn url() -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn key_gen<K: KeyGenParams>() -> KeyGen<K> {
|
fn key_gen<K: KeyGenParams>() -> KeyGen<K> {
|
||||||
fn read_key_from_env<C: Ciphersuite>(label: &'static str) -> Zeroizing<C::F> {
|
fn read_key_from_env<C: WrappedGroup>(label: &'static str) -> Zeroizing<C::F> {
|
||||||
let key_hex =
|
let key_hex =
|
||||||
Zeroizing::new(env::var(label).unwrap_or_else(|| panic!("{label} wasn't provided")));
|
Zeroizing::new(env::var(label).unwrap_or_else(|| panic!("{label} wasn't provided")));
|
||||||
let bytes = Zeroizing::new(
|
let bytes = Zeroizing::new(
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use ciphersuite::{group::GroupEncoding, Ciphersuite};
|
use ciphersuite::{group::GroupEncoding, *};
|
||||||
use dkg::{ThresholdKeys, Curves, Secp256k1};
|
use dkg::{ThresholdKeys, Curves, Secp256k1};
|
||||||
|
|
||||||
use crate::{primitives::x_coord_to_even_point, scan::scanner};
|
use crate::{primitives::x_coord_to_even_point, scan::scanner};
|
||||||
@@ -18,7 +18,7 @@ impl key_gen::KeyGenParams for KeyGenParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn encode_key(
|
fn encode_key(
|
||||||
key: <<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as Ciphersuite>::G,
|
key: <<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as WrappedGroup>::G,
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
let key = key.to_bytes();
|
let key = key.to_bytes();
|
||||||
let key: &[u8] = key.as_ref();
|
let key: &[u8] = key.as_ref();
|
||||||
@@ -28,7 +28,7 @@ impl key_gen::KeyGenParams for KeyGenParams {
|
|||||||
|
|
||||||
fn decode_key(
|
fn decode_key(
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Option<<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as Ciphersuite>::G> {
|
) -> Option<<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as WrappedGroup>::G> {
|
||||||
x_coord_to_even_point(key)
|
x_coord_to_even_point(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use core::fmt;
|
use core::fmt;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::*;
|
||||||
use ciphersuite_kp256::Secp256k1;
|
use ciphersuite_kp256::Secp256k1;
|
||||||
|
|
||||||
use bitcoin_serai::bitcoin::block::{Header, Block as BBlock};
|
use bitcoin_serai::bitcoin::block::{Header, Block as BBlock};
|
||||||
@@ -35,7 +35,7 @@ impl<D: Db> fmt::Debug for Block<D> {
|
|||||||
impl<D: Db> primitives::Block for Block<D> {
|
impl<D: Db> primitives::Block for Block<D> {
|
||||||
type Header = BlockHeader;
|
type Header = BlockHeader;
|
||||||
|
|
||||||
type Key = <Secp256k1 as Ciphersuite>::G;
|
type Key = <Secp256k1 as WrappedGroup>::G;
|
||||||
type Address = Address;
|
type Address = Address;
|
||||||
type Output = Output;
|
type Output = Output;
|
||||||
type Eventuality = Eventuality;
|
type Eventuality = Eventuality;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::*;
|
||||||
use ciphersuite_kp256::Secp256k1;
|
use ciphersuite_kp256::Secp256k1;
|
||||||
|
|
||||||
use bitcoin_serai::bitcoin::key::{Parity, XOnlyPublicKey};
|
use bitcoin_serai::bitcoin::key::{Parity, XOnlyPublicKey};
|
||||||
@@ -7,7 +7,7 @@ pub(crate) mod output;
|
|||||||
pub(crate) mod transaction;
|
pub(crate) mod transaction;
|
||||||
pub(crate) mod block;
|
pub(crate) mod block;
|
||||||
|
|
||||||
pub(crate) fn x_coord_to_even_point(key: &[u8]) -> Option<<Secp256k1 as Ciphersuite>::G> {
|
pub(crate) fn x_coord_to_even_point(key: &[u8]) -> Option<<Secp256k1 as WrappedGroup>::G> {
|
||||||
if key.len() != 32 {
|
if key.len() != 32 {
|
||||||
None?
|
None?
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::*;
|
||||||
use ciphersuite_kp256::Secp256k1;
|
use ciphersuite_kp256::Secp256k1;
|
||||||
|
|
||||||
use bitcoin_serai::{
|
use bitcoin_serai::{
|
||||||
@@ -55,7 +55,7 @@ pub(crate) struct Output {
|
|||||||
impl Output {
|
impl Output {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
getter: &impl Get,
|
getter: &impl Get,
|
||||||
key: <Secp256k1 as Ciphersuite>::G,
|
key: <Secp256k1 as WrappedGroup>::G,
|
||||||
tx: &Transaction,
|
tx: &Transaction,
|
||||||
output: WalletOutput,
|
output: WalletOutput,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@@ -71,7 +71,7 @@ impl Output {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new_with_presumed_origin(
|
pub(crate) fn new_with_presumed_origin(
|
||||||
key: <Secp256k1 as Ciphersuite>::G,
|
key: <Secp256k1 as WrappedGroup>::G,
|
||||||
tx: &Transaction,
|
tx: &Transaction,
|
||||||
presumed_origin: Option<Address>,
|
presumed_origin: Option<Address>,
|
||||||
output: WalletOutput,
|
output: WalletOutput,
|
||||||
@@ -88,7 +88,7 @@ impl Output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReceivedOutput<<Secp256k1 as Ciphersuite>::G, Address> for Output {
|
impl ReceivedOutput<<Secp256k1 as WrappedGroup>::G, Address> for Output {
|
||||||
type Id = OutputId;
|
type Id = OutputId;
|
||||||
type TransactionId = [u8; 32];
|
type TransactionId = [u8; 32];
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ impl ReceivedOutput<<Secp256k1 as Ciphersuite>::G, Address> for Output {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn key(&self) -> <Secp256k1 as Ciphersuite>::G {
|
fn key(&self) -> <Secp256k1 as WrappedGroup>::G {
|
||||||
// We read the key from the script pubkey so we don't have to independently store it
|
// We read the key from the script pubkey so we don't have to independently store it
|
||||||
let script = &self.output.output().script_pubkey;
|
let script = &self.output.output().script_pubkey;
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ impl ReceivedOutput<<Secp256k1 as Ciphersuite>::G, Address> for Output {
|
|||||||
.expect("last item in scanned v1 Taproot script wasn't a valid x-only public key");
|
.expect("last item in scanned v1 Taproot script wasn't a valid x-only public key");
|
||||||
|
|
||||||
// The output's key minus the output's offset is the root key
|
// The output's key minus the output's offset is the root key
|
||||||
key - (<Secp256k1 as Ciphersuite>::G::GENERATOR * self.output.offset())
|
key - (<Secp256k1 as WrappedGroup>::G::GENERATOR * self.output.offset())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn presumed_origin(&self) -> Option<Address> {
|
fn presumed_origin(&self) -> Option<Address> {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::{sync::LazyLock, collections::HashMap};
|
use std::{sync::LazyLock, collections::HashMap};
|
||||||
|
|
||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::*;
|
||||||
use ciphersuite_kp256::Secp256k1;
|
use ciphersuite_kp256::Secp256k1;
|
||||||
|
|
||||||
use bitcoin_serai::{
|
use bitcoin_serai::{
|
||||||
@@ -20,20 +20,20 @@ use primitives::OutputType;
|
|||||||
use crate::hash_bytes;
|
use crate::hash_bytes;
|
||||||
|
|
||||||
// TODO: Bitcoin HD derivation, instead of these bespoke labels?
|
// TODO: Bitcoin HD derivation, instead of these bespoke labels?
|
||||||
static BRANCH_BASE_OFFSET: LazyLock<<Secp256k1 as Ciphersuite>::F> =
|
static BRANCH_BASE_OFFSET: LazyLock<<Secp256k1 as WrappedGroup>::F> =
|
||||||
LazyLock::new(|| Secp256k1::hash_to_F(b"branch"));
|
LazyLock::new(|| Secp256k1::hash_to_F(b"branch"));
|
||||||
static CHANGE_BASE_OFFSET: LazyLock<<Secp256k1 as Ciphersuite>::F> =
|
static CHANGE_BASE_OFFSET: LazyLock<<Secp256k1 as WrappedGroup>::F> =
|
||||||
LazyLock::new(|| Secp256k1::hash_to_F(b"change"));
|
LazyLock::new(|| Secp256k1::hash_to_F(b"change"));
|
||||||
static FORWARD_BASE_OFFSET: LazyLock<<Secp256k1 as Ciphersuite>::F> =
|
static FORWARD_BASE_OFFSET: LazyLock<<Secp256k1 as WrappedGroup>::F> =
|
||||||
LazyLock::new(|| Secp256k1::hash_to_F(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
|
// 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
|
// even. While we could tweak the key until all derivations are even, that'd require significantly
|
||||||
// more tweaking. This algorithmic complexity is preferred.
|
// more tweaking. This algorithmic complexity is preferred.
|
||||||
pub(crate) fn offsets_for_key(
|
pub(crate) fn offsets_for_key(
|
||||||
key: <Secp256k1 as Ciphersuite>::G,
|
key: <Secp256k1 as WrappedGroup>::G,
|
||||||
) -> HashMap<OutputType, <Secp256k1 as Ciphersuite>::F> {
|
) -> HashMap<OutputType, <Secp256k1 as WrappedGroup>::F> {
|
||||||
let mut offsets = HashMap::from([(OutputType::External, <Secp256k1 as Ciphersuite>::F::ZERO)]);
|
let mut offsets = HashMap::from([(OutputType::External, <Secp256k1 as WrappedGroup>::F::ZERO)]);
|
||||||
|
|
||||||
// We create an actual Bitcoin scanner as upon adding an offset, it yields the tweaked offset
|
// We create an actual Bitcoin scanner as upon adding an offset, it yields the tweaked offset
|
||||||
// actually used
|
// actually used
|
||||||
@@ -50,7 +50,7 @@ pub(crate) fn offsets_for_key(
|
|||||||
offsets
|
offsets
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn scanner(key: <Secp256k1 as Ciphersuite>::G) -> Scanner {
|
pub(crate) fn scanner(key: <Secp256k1 as WrappedGroup>::G) -> Scanner {
|
||||||
let mut scanner = Scanner::new(key).unwrap();
|
let mut scanner = Scanner::new(key).unwrap();
|
||||||
for (_, offset) in offsets_for_key(key) {
|
for (_, offset) in offsets_for_key(key) {
|
||||||
let tweaked_offset = scanner.register_offset(offset).unwrap();
|
let tweaked_offset = scanner.register_offset(offset).unwrap();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use core::future::Future;
|
use core::future::Future;
|
||||||
|
|
||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::*;
|
||||||
use ciphersuite_kp256::Secp256k1;
|
use ciphersuite_kp256::Secp256k1;
|
||||||
|
|
||||||
use bitcoin_serai::{
|
use bitcoin_serai::{
|
||||||
@@ -26,8 +26,8 @@ use crate::{
|
|||||||
rpc::Rpc,
|
rpc::Rpc,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn address_from_serai_key(key: <Secp256k1 as Ciphersuite>::G, kind: OutputType) -> Address {
|
fn address_from_serai_key(key: <Secp256k1 as WrappedGroup>::G, kind: OutputType) -> Address {
|
||||||
let offset = <Secp256k1 as Ciphersuite>::G::GENERATOR * offsets_for_key(key)[&kind];
|
let offset = <Secp256k1 as WrappedGroup>::G::GENERATOR * offsets_for_key(key)[&kind];
|
||||||
Address::new(
|
Address::new(
|
||||||
p2tr_script_buf(key + offset)
|
p2tr_script_buf(key + offset)
|
||||||
.expect("creating address from Serai key which wasn't properly tweaked"),
|
.expect("creating address from Serai key which wasn't properly tweaked"),
|
||||||
@@ -72,7 +72,7 @@ fn signable_transaction<D: Db>(
|
|||||||
*/
|
*/
|
||||||
payments.push((
|
payments.push((
|
||||||
// The generator is even so this is valid
|
// The generator is even so this is valid
|
||||||
p2tr_script_buf(<Secp256k1 as Ciphersuite>::G::GENERATOR).unwrap(),
|
p2tr_script_buf(<Secp256k1 as WrappedGroup>::G::GENERATOR).unwrap(),
|
||||||
// This uses the minimum output value allowed, as defined as a constant in bitcoin-serai
|
// This uses the minimum output value allowed, as defined as a constant in bitcoin-serai
|
||||||
// TODO: Add a test for this comparing to bitcoin's `minimal_non_dust`
|
// TODO: Add a test for this comparing to bitcoin's `minimal_non_dust`
|
||||||
bitcoin_serai::wallet::DUST,
|
bitcoin_serai::wallet::DUST,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::*;
|
||||||
use dkg::{ThresholdKeys, Curves, Secp256k1};
|
use dkg::{ThresholdKeys, Curves, Secp256k1};
|
||||||
|
|
||||||
use ethereum_schnorr::PublicKey;
|
use ethereum_schnorr::PublicKey;
|
||||||
@@ -13,19 +13,19 @@ impl key_gen::KeyGenParams for KeyGenParams {
|
|||||||
keys: &mut ThresholdKeys<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve>,
|
keys: &mut ThresholdKeys<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve>,
|
||||||
) {
|
) {
|
||||||
while PublicKey::new(keys.group_key()).is_none() {
|
while PublicKey::new(keys.group_key()).is_none() {
|
||||||
*keys = keys.clone().offset(<<Secp256k1 as Curves>::ToweringCurve as Ciphersuite>::F::ONE);
|
*keys = keys.clone().offset(<<Secp256k1 as Curves>::ToweringCurve as WrappedGroup>::F::ONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_key(
|
fn encode_key(
|
||||||
key: <<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as Ciphersuite>::G,
|
key: <<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as WrappedGroup>::G,
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
PublicKey::new(key).unwrap().eth_repr().to_vec()
|
PublicKey::new(key).unwrap().eth_repr().to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_key(
|
fn decode_key(
|
||||||
key: &[u8],
|
key: &[u8],
|
||||||
) -> Option<<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as Ciphersuite>::G> {
|
) -> Option<<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as WrappedGroup>::G> {
|
||||||
PublicKey::from_eth_repr(key.try_into().ok()?).map(|key| key.point())
|
PublicKey::from_eth_repr(key.try_into().ok()?).map(|key| key.point())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::*;
|
||||||
use ciphersuite_kp256::Secp256k1;
|
use ciphersuite_kp256::Secp256k1;
|
||||||
|
|
||||||
use serai_client::networks::ethereum::Address;
|
use serai_client::networks::ethereum::Address;
|
||||||
@@ -41,7 +41,7 @@ pub(crate) struct FullEpoch {
|
|||||||
impl primitives::Block for FullEpoch {
|
impl primitives::Block for FullEpoch {
|
||||||
type Header = Epoch;
|
type Header = Epoch;
|
||||||
|
|
||||||
type Key = <Secp256k1 as Ciphersuite>::G;
|
type Key = <Secp256k1 as WrappedGroup>::G;
|
||||||
type Address = Address;
|
type Address = Address;
|
||||||
type Output = Output;
|
type Output = Output;
|
||||||
type Eventuality = Eventuality;
|
type Eventuality = Eventuality;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::{io, collections::HashMap};
|
|||||||
|
|
||||||
use rand_core::{RngCore, CryptoRng};
|
use rand_core::{RngCore, CryptoRng};
|
||||||
|
|
||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::*;
|
||||||
use ciphersuite_kp256::Secp256k1;
|
use ciphersuite_kp256::Secp256k1;
|
||||||
use frost::{
|
use frost::{
|
||||||
dkg::{Participant, ThresholdKeys},
|
dkg::{Participant, ThresholdKeys},
|
||||||
@@ -24,10 +24,10 @@ pub struct EthereumHram;
|
|||||||
impl Hram<Secp256k1> for EthereumHram {
|
impl Hram<Secp256k1> for EthereumHram {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn hram(
|
fn hram(
|
||||||
R: &<Secp256k1 as Ciphersuite>::G,
|
R: &<Secp256k1 as WrappedGroup>::G,
|
||||||
A: &<Secp256k1 as Ciphersuite>::G,
|
A: &<Secp256k1 as WrappedGroup>::G,
|
||||||
m: &[u8],
|
m: &[u8],
|
||||||
) -> <Secp256k1 as Ciphersuite>::F {
|
) -> <Secp256k1 as WrappedGroup>::F {
|
||||||
Signature::challenge(*R, &PublicKey::new(*A).unwrap(), m)
|
Signature::challenge(*R, &PublicKey::new(*A).unwrap(), m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use ciphersuite::{group::GroupEncoding, Ciphersuite};
|
use ciphersuite::{group::GroupEncoding, *};
|
||||||
use ciphersuite_kp256::Secp256k1;
|
use ciphersuite_kp256::Secp256k1;
|
||||||
|
|
||||||
use alloy_core::primitives::U256;
|
use alloy_core::primitives::U256;
|
||||||
@@ -61,10 +61,10 @@ impl AsMut<[u8]> for OutputId {
|
|||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub(crate) enum Output {
|
pub(crate) enum Output {
|
||||||
Output { key: <Secp256k1 as Ciphersuite>::G, instruction: EthereumInInstruction },
|
Output { key: <Secp256k1 as WrappedGroup>::G, instruction: EthereumInInstruction },
|
||||||
Eventuality { key: <Secp256k1 as Ciphersuite>::G, nonce: u64 },
|
Eventuality { key: <Secp256k1 as WrappedGroup>::G, nonce: u64 },
|
||||||
}
|
}
|
||||||
impl ReceivedOutput<<Secp256k1 as Ciphersuite>::G, Address> for Output {
|
impl ReceivedOutput<<Secp256k1 as WrappedGroup>::G, Address> for Output {
|
||||||
type Id = OutputId;
|
type Id = OutputId;
|
||||||
type TransactionId = [u8; 32];
|
type TransactionId = [u8; 32];
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ impl ReceivedOutput<<Secp256k1 as Ciphersuite>::G, Address> for Output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn key(&self) -> <Secp256k1 as Ciphersuite>::G {
|
fn key(&self) -> <Secp256k1 as WrappedGroup>::G {
|
||||||
match self {
|
match self {
|
||||||
Output::Output { key, .. } | Output::Eventuality { key, .. } => *key,
|
Output::Output { key, .. } | Output::Eventuality { key, .. } => *key,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,9 @@ rand_chacha = { version = "0.3", default-features = false, features = ["std"] }
|
|||||||
blake2 = { version = "0.11.0-rc.0", default-features = false, features = ["alloc"] }
|
blake2 = { version = "0.11.0-rc.0", default-features = false, features = ["alloc"] }
|
||||||
transcript = { package = "flexible-transcript", path = "../../crypto/transcript", default-features = false, features = ["std"] }
|
transcript = { package = "flexible-transcript", path = "../../crypto/transcript", default-features = false, features = ["std"] }
|
||||||
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["std"] }
|
ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["std"] }
|
||||||
dkg = { package = "dkg-evrf", path = "../../crypto/dkg/evrf", default-features = false, features = ["std", "ristretto"] }
|
embedwards25519 = { path = "../../crypto/embedwards25519", default-features = false, features = ["std"] }
|
||||||
|
dkg = { package = "dkg-evrf", path = "../../crypto/dkg/evrf", default-features = false, features = ["std"] }
|
||||||
|
frost = { package = "modular-frost", path = "../../crypto/frost", default-features = false, features = ["ristretto"] }
|
||||||
|
|
||||||
# Substrate
|
# Substrate
|
||||||
serai-validator-sets-primitives = { path = "../../substrate/validator-sets/primitives", default-features = false, features = ["std"] }
|
serai-validator-sets-primitives = { path = "../../substrate/validator-sets/primitives", default-features = false, features = ["std"] }
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
use ciphersuite::{group::GroupEncoding, Ciphersuite};
|
use ciphersuite::{group::GroupEncoding, *};
|
||||||
use dkg::*;
|
use dkg::*;
|
||||||
|
|
||||||
use serai_validator_sets_primitives::Session;
|
use serai_validator_sets_primitives::Session;
|
||||||
@@ -11,15 +11,15 @@ use serai_validator_sets_primitives::Session;
|
|||||||
use borsh::{BorshSerialize, BorshDeserialize};
|
use borsh::{BorshSerialize, BorshDeserialize};
|
||||||
use serai_db::{Get, DbTxn};
|
use serai_db::{Get, DbTxn};
|
||||||
|
|
||||||
use crate::KeyGenParams;
|
use crate::{Ristretto, KeyGenParams};
|
||||||
|
|
||||||
pub(crate) struct Params<P: KeyGenParams> {
|
pub(crate) struct Params<P: KeyGenParams> {
|
||||||
pub(crate) t: u16,
|
pub(crate) t: u16,
|
||||||
pub(crate) n: u16,
|
pub(crate) n: u16,
|
||||||
pub(crate) substrate_evrf_public_keys:
|
pub(crate) substrate_evrf_public_keys:
|
||||||
Vec<<<Ristretto as Curves>::EmbeddedCurve as Ciphersuite>::G>,
|
Vec<<<Ristretto as Curves>::EmbeddedCurve as WrappedGroup>::G>,
|
||||||
pub(crate) network_evrf_public_keys:
|
pub(crate) network_evrf_public_keys:
|
||||||
Vec<<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as Ciphersuite>::G>,
|
Vec<<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as WrappedGroup>::G>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(BorshSerialize, BorshDeserialize)]
|
#[derive(BorshSerialize, BorshDeserialize)]
|
||||||
@@ -85,17 +85,16 @@ impl<P: KeyGenParams> KeyGenDb<P> {
|
|||||||
.substrate_evrf_public_keys
|
.substrate_evrf_public_keys
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|key| {
|
.map(|key| {
|
||||||
<<Ristretto as Curves>::EmbeddedCurve as Ciphersuite>::read_G(&mut key.as_slice())
|
<<Ristretto as Curves>::EmbeddedCurve as GroupIo>::read_G(&mut key.as_slice()).unwrap()
|
||||||
.unwrap()
|
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
network_evrf_public_keys: params
|
network_evrf_public_keys: params
|
||||||
.network_evrf_public_keys
|
.network_evrf_public_keys
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|key| {
|
.map(|key| {
|
||||||
<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as Ciphersuite>::read_G::<
|
<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as GroupIo>::read_G::<&[u8]>(
|
||||||
&[u8],
|
&mut key.as_ref(),
|
||||||
>(&mut key.as_ref())
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use blake2::{Digest, Blake2s256};
|
|||||||
use transcript::{Transcript, RecommendedTranscript};
|
use transcript::{Transcript, RecommendedTranscript};
|
||||||
use ciphersuite::{
|
use ciphersuite::{
|
||||||
group::{Group, GroupEncoding},
|
group::{Group, GroupEncoding},
|
||||||
Ciphersuite,
|
*,
|
||||||
};
|
};
|
||||||
use dkg::*;
|
use dkg::*;
|
||||||
|
|
||||||
@@ -28,6 +28,14 @@ use generators::generators;
|
|||||||
mod db;
|
mod db;
|
||||||
use db::{Params, Participations, KeyGenDb};
|
use db::{Params, Participations, KeyGenDb};
|
||||||
|
|
||||||
|
/// Ristretto, and an elliptic curve defined over its scalar field (embedwards25519).
|
||||||
|
pub struct Ristretto;
|
||||||
|
impl Curves for Ristretto {
|
||||||
|
type ToweringCurve = frost::curve::Ristretto;
|
||||||
|
type EmbeddedCurve = embedwards25519::Embedwards25519;
|
||||||
|
type EmbeddedCurveParameters = embedwards25519::Embedwards25519;
|
||||||
|
}
|
||||||
|
|
||||||
/// Parameters for a key generation.
|
/// Parameters for a key generation.
|
||||||
pub trait KeyGenParams {
|
pub trait KeyGenParams {
|
||||||
/// The ID for this instantiation.
|
/// The ID for this instantiation.
|
||||||
@@ -49,7 +57,7 @@ pub trait KeyGenParams {
|
|||||||
///
|
///
|
||||||
/// A default implementation is provided which calls the traditional `to_bytes`.
|
/// A default implementation is provided which calls the traditional `to_bytes`.
|
||||||
fn encode_key(
|
fn encode_key(
|
||||||
key: <<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as Ciphersuite>::G,
|
key: <<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as WrappedGroup>::G,
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
key.to_bytes().as_ref().to_vec()
|
key.to_bytes().as_ref().to_vec()
|
||||||
}
|
}
|
||||||
@@ -59,11 +67,10 @@ pub trait KeyGenParams {
|
|||||||
/// A default implementation is provided which calls the traditional `from_bytes`.
|
/// A default implementation is provided which calls the traditional `from_bytes`.
|
||||||
fn decode_key(
|
fn decode_key(
|
||||||
mut key: &[u8],
|
mut key: &[u8],
|
||||||
) -> Option<<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as Ciphersuite>::G> {
|
) -> Option<<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as WrappedGroup>::G> {
|
||||||
let res = <<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as Ciphersuite>::read_G(
|
let res =
|
||||||
&mut key,
|
<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as GroupIo>::read_G(&mut key)
|
||||||
)
|
.ok()?;
|
||||||
.ok()?;
|
|
||||||
if !key.is_empty() {
|
if !key.is_empty() {
|
||||||
None?;
|
None?;
|
||||||
}
|
}
|
||||||
@@ -101,14 +108,14 @@ pub trait KeyGenParams {
|
|||||||
*/
|
*/
|
||||||
fn coerce_keys<C: 'static + Curves>(
|
fn coerce_keys<C: 'static + Curves>(
|
||||||
key_bytes: &[impl AsRef<[u8]>],
|
key_bytes: &[impl AsRef<[u8]>],
|
||||||
) -> (Vec<<C::EmbeddedCurve as Ciphersuite>::G>, Vec<Participant>) {
|
) -> (Vec<<C::EmbeddedCurve as WrappedGroup>::G>, Vec<Participant>) {
|
||||||
fn evrf_key<C: 'static + Curves>(key: &[u8]) -> Option<<C::EmbeddedCurve as Ciphersuite>::G> {
|
fn evrf_key<C: 'static + Curves>(key: &[u8]) -> Option<<C::EmbeddedCurve as WrappedGroup>::G> {
|
||||||
let mut repr = <<C::EmbeddedCurve as Ciphersuite>::G as GroupEncoding>::Repr::default();
|
let mut repr = <<C::EmbeddedCurve as WrappedGroup>::G as GroupEncoding>::Repr::default();
|
||||||
if repr.as_ref().len() != key.len() {
|
if repr.as_ref().len() != key.len() {
|
||||||
None?;
|
None?;
|
||||||
}
|
}
|
||||||
repr.as_mut().copy_from_slice(key);
|
repr.as_mut().copy_from_slice(key);
|
||||||
let point = Option::<<C::EmbeddedCurve as Ciphersuite>::G>::from(<_>::from_bytes(&repr))?;
|
let point = Option::<<C::EmbeddedCurve as WrappedGroup>::G>::from(<_>::from_bytes(&repr))?;
|
||||||
if bool::from(point.is_identity()) {
|
if bool::from(point.is_identity()) {
|
||||||
None?;
|
None?;
|
||||||
}
|
}
|
||||||
@@ -131,10 +138,10 @@ fn coerce_keys<C: 'static + Curves>(
|
|||||||
// Generate a random key
|
// Generate a random key
|
||||||
let mut rng = ChaCha20Rng::from_seed(Blake2s256::digest(key).into());
|
let mut rng = ChaCha20Rng::from_seed(Blake2s256::digest(key).into());
|
||||||
loop {
|
loop {
|
||||||
let mut repr = <<C::EmbeddedCurve as Ciphersuite>::G as GroupEncoding>::Repr::default();
|
let mut repr = <<C::EmbeddedCurve as WrappedGroup>::G as GroupEncoding>::Repr::default();
|
||||||
rng.fill_bytes(repr.as_mut());
|
rng.fill_bytes(repr.as_mut());
|
||||||
if let Some(key) =
|
if let Some(key) =
|
||||||
Option::<<C::EmbeddedCurve as Ciphersuite>::G>::from(<_>::from_bytes(&repr))
|
Option::<<C::EmbeddedCurve as WrappedGroup>::G>::from(<_>::from_bytes(&repr))
|
||||||
{
|
{
|
||||||
break key;
|
break key;
|
||||||
}
|
}
|
||||||
@@ -149,18 +156,20 @@ fn coerce_keys<C: 'static + Curves>(
|
|||||||
/// An instance of the Serai key generation protocol.
|
/// An instance of the Serai key generation protocol.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct KeyGen<P: KeyGenParams> {
|
pub struct KeyGen<P: KeyGenParams> {
|
||||||
substrate_evrf_private_key: Zeroizing<<<Ristretto as Curves>::EmbeddedCurve as Ciphersuite>::F>,
|
substrate_evrf_private_key: Zeroizing<<<Ristretto as Curves>::EmbeddedCurve as WrappedGroup>::F>,
|
||||||
network_evrf_private_key:
|
network_evrf_private_key:
|
||||||
Zeroizing<<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as Ciphersuite>::F>,
|
Zeroizing<<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as WrappedGroup>::F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: KeyGenParams> KeyGen<P> {
|
impl<P: KeyGenParams> KeyGen<P> {
|
||||||
/// Create a new key generation instance.
|
/// Create a new key generation instance.
|
||||||
#[allow(clippy::new_ret_no_self)]
|
#[allow(clippy::new_ret_no_self)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
substrate_evrf_private_key: Zeroizing<<<Ristretto as Curves>::EmbeddedCurve as Ciphersuite>::F>,
|
substrate_evrf_private_key: Zeroizing<
|
||||||
|
<<Ristretto as Curves>::EmbeddedCurve as WrappedGroup>::F,
|
||||||
|
>,
|
||||||
network_evrf_private_key: Zeroizing<
|
network_evrf_private_key: Zeroizing<
|
||||||
<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as Ciphersuite>::F,
|
<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as WrappedGroup>::F,
|
||||||
>,
|
>,
|
||||||
) -> KeyGen<P> {
|
) -> KeyGen<P> {
|
||||||
KeyGen { substrate_evrf_private_key, network_evrf_private_key }
|
KeyGen { substrate_evrf_private_key, network_evrf_private_key }
|
||||||
@@ -214,8 +223,8 @@ impl<P: KeyGenParams> KeyGen<P> {
|
|||||||
fn participate<C: 'static + Curves>(
|
fn participate<C: 'static + Curves>(
|
||||||
context: [u8; 32],
|
context: [u8; 32],
|
||||||
threshold: u16,
|
threshold: u16,
|
||||||
evrf_public_keys: &[<C::EmbeddedCurve as Ciphersuite>::G],
|
evrf_public_keys: &[<C::EmbeddedCurve as WrappedGroup>::G],
|
||||||
evrf_private_key: &Zeroizing<<C::EmbeddedCurve as Ciphersuite>::F>,
|
evrf_private_key: &Zeroizing<<C::EmbeddedCurve as WrappedGroup>::F>,
|
||||||
output: &mut impl io::Write,
|
output: &mut impl io::Write,
|
||||||
) {
|
) {
|
||||||
let participation = Dkg::<C>::participate(
|
let participation = Dkg::<C>::participate(
|
||||||
@@ -411,7 +420,7 @@ impl<P: KeyGenParams> KeyGen<P> {
|
|||||||
session: Session,
|
session: Session,
|
||||||
true_if_substrate_false_if_network: bool,
|
true_if_substrate_false_if_network: bool,
|
||||||
threshold: u16,
|
threshold: u16,
|
||||||
evrf_public_keys: &[<C::EmbeddedCurve as Ciphersuite>::G],
|
evrf_public_keys: &[<C::EmbeddedCurve as WrappedGroup>::G],
|
||||||
substrate_participations: &mut HashMap<Participant, Vec<u8>>,
|
substrate_participations: &mut HashMap<Participant, Vec<u8>>,
|
||||||
network_participations: &mut HashMap<Participant, Vec<u8>>,
|
network_participations: &mut HashMap<Participant, Vec<u8>>,
|
||||||
) -> Result<Dkg<C>, Vec<ProcessorMessage>> {
|
) -> Result<Dkg<C>, Vec<ProcessorMessage>> {
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ dalek-ff-group = { path = "../../crypto/dalek-ff-group", default-features = fals
|
|||||||
dkg = { package = "dkg-evrf", path = "../../crypto/dkg/evrf", default-features = false, features = ["std", "ed25519"] }
|
dkg = { package = "dkg-evrf", path = "../../crypto/dkg/evrf", default-features = false, features = ["std", "ed25519"] }
|
||||||
frost = { package = "modular-frost", path = "../../crypto/frost", default-features = false }
|
frost = { package = "modular-frost", path = "../../crypto/frost", default-features = false }
|
||||||
|
|
||||||
monero-wallet = { git = "https://github.com/monero-oxide/monero-oxide", rev = "6966575e05fe09b77674c46984b21686ed9304ff", default-features = false, features = ["std", "multisig"] }
|
monero-wallet = { git = "https://github.com/monero-oxide/monero-oxide", rev = "7f37cc8f770858aa1739e0f56dbe447db86f4ba6", default-features = false, features = ["std", "multisig"] }
|
||||||
monero-simple-request-rpc = { git = "https://github.com/monero-oxide/monero-oxide", rev = "6966575e05fe09b77674c46984b21686ed9304ff", default-features = false }
|
monero-simple-request-rpc = { git = "https://github.com/monero-oxide/monero-oxide", rev = "7f37cc8f770858aa1739e0f56dbe447db86f4ba6", default-features = false }
|
||||||
|
|
||||||
serai-client = { path = "../../substrate/client", default-features = false, features = ["monero"] }
|
serai-client = { path = "../../substrate/client", default-features = false, features = ["monero"] }
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::*;
|
||||||
use dalek_ff_group::Ed25519;
|
use dalek_ff_group::Ed25519;
|
||||||
|
|
||||||
use monero_wallet::{
|
use monero_wallet::{
|
||||||
@@ -32,7 +32,7 @@ pub(crate) struct Block(pub(crate) MScannableBlock);
|
|||||||
impl primitives::Block for Block {
|
impl primitives::Block for Block {
|
||||||
type Header = BlockHeader;
|
type Header = BlockHeader;
|
||||||
|
|
||||||
type Key = <Ed25519 as Ciphersuite>::G;
|
type Key = <Ed25519 as WrappedGroup>::G;
|
||||||
type Address = Address;
|
type Address = Address;
|
||||||
type Output = Output;
|
type Output = Output;
|
||||||
type Eventuality = Eventuality;
|
type Eventuality = Eventuality;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::*;
|
||||||
use dalek_ff_group::Ed25519;
|
use dalek_ff_group::Ed25519;
|
||||||
|
|
||||||
use monero_wallet::{address::SubaddressIndex, ViewPairError, GuaranteedViewPair};
|
use monero_wallet::{address::SubaddressIndex, ViewPairError, GuaranteedViewPair};
|
||||||
@@ -28,8 +28,8 @@ pub(crate) const FORWARDED_SUBADDRESS: SubaddressIndex = match SubaddressIndex::
|
|||||||
None => panic!("SubaddressIndex for FORWARDED_SUBADDRESS was None"),
|
None => panic!("SubaddressIndex for FORWARDED_SUBADDRESS was None"),
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn view_pair(key: <Ed25519 as Ciphersuite>::G) -> GuaranteedViewPair {
|
pub(crate) fn view_pair(key: <Ed25519 as WrappedGroup>::G) -> GuaranteedViewPair {
|
||||||
match GuaranteedViewPair::new(key.0, Zeroizing::new(*view_key::<Ed25519>(0))) {
|
match GuaranteedViewPair::new(key.0, Zeroizing::new(view_key::<Ed25519>(0))) {
|
||||||
Ok(view_pair) => view_pair,
|
Ok(view_pair) => view_pair,
|
||||||
Err(ViewPairError::TorsionedSpendKey) => {
|
Err(ViewPairError::TorsionedSpendKey) => {
|
||||||
unreachable!("dalek_ff_group::EdwardsPoint had torsion")
|
unreachable!("dalek_ff_group::EdwardsPoint had torsion")
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use ciphersuite::{group::Group, Ciphersuite};
|
use ciphersuite::WrappedGroup;
|
||||||
use dalek_ff_group::Ed25519;
|
use dalek_ff_group::Ed25519;
|
||||||
|
|
||||||
use monero_wallet::WalletOutput;
|
use monero_wallet::WalletOutput;
|
||||||
@@ -35,7 +35,7 @@ impl AsMut<[u8]> for OutputId {
|
|||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub(crate) struct Output(pub(crate) WalletOutput);
|
pub(crate) struct Output(pub(crate) WalletOutput);
|
||||||
impl ReceivedOutput<<Ed25519 as Ciphersuite>::G, Address> for Output {
|
impl ReceivedOutput<<Ed25519 as WrappedGroup>::G, Address> for Output {
|
||||||
type Id = OutputId;
|
type Id = OutputId;
|
||||||
type TransactionId = [u8; 32];
|
type TransactionId = [u8; 32];
|
||||||
|
|
||||||
@@ -64,12 +64,12 @@ impl ReceivedOutput<<Ed25519 as Ciphersuite>::G, Address> for Output {
|
|||||||
self.0.transaction()
|
self.0.transaction()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn key(&self) -> <Ed25519 as Ciphersuite>::G {
|
fn key(&self) -> <Ed25519 as WrappedGroup>::G {
|
||||||
// The spend key will be a key we generated, so it'll be in the prime-order subgroup
|
// The spend key will be a key we generated, so it'll be in the prime-order subgroup
|
||||||
// The output's key is the spend key + (key_offset * G), so it's in the prime-order subgroup if
|
// The output's key is the spend key + (key_offset * G), so it's in the prime-order subgroup if
|
||||||
// the spend key is
|
// the spend key is
|
||||||
dalek_ff_group::EdwardsPoint(
|
dalek_ff_group::EdwardsPoint(
|
||||||
self.0.key() - (*<Ed25519 as Ciphersuite>::G::generator() * self.0.key_offset()),
|
self.0.key() - (*<Ed25519 as WrappedGroup>::generator() * self.0.key_offset()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use zeroize::Zeroizing;
|
|||||||
use rand_core::SeedableRng;
|
use rand_core::SeedableRng;
|
||||||
use rand_chacha::ChaCha20Rng;
|
use rand_chacha::ChaCha20Rng;
|
||||||
|
|
||||||
use ciphersuite::Ciphersuite;
|
use ciphersuite::*;
|
||||||
use dalek_ff_group::Ed25519;
|
use dalek_ff_group::Ed25519;
|
||||||
|
|
||||||
use monero_wallet::rpc::{FeeRate, RpcError};
|
use monero_wallet::rpc::{FeeRate, RpcError};
|
||||||
@@ -33,7 +33,7 @@ use crate::{
|
|||||||
rpc::Rpc,
|
rpc::Rpc,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn address_from_serai_key(key: <Ed25519 as Ciphersuite>::G, kind: OutputType) -> Address {
|
fn address_from_serai_key(key: <Ed25519 as WrappedGroup>::G, kind: OutputType) -> Address {
|
||||||
view_pair(key)
|
view_pair(key)
|
||||||
.address(
|
.address(
|
||||||
Network::Mainnet,
|
Network::Mainnet,
|
||||||
@@ -118,8 +118,8 @@ async fn signable_transaction(
|
|||||||
MoneroAddress::new(
|
MoneroAddress::new(
|
||||||
Network::Mainnet,
|
Network::Mainnet,
|
||||||
AddressType::Legacy,
|
AddressType::Legacy,
|
||||||
<Ed25519 as Ciphersuite>::generator().0,
|
<Ed25519 as WrappedGroup>::generator().0,
|
||||||
<Ed25519 as Ciphersuite>::generator().0,
|
<Ed25519 as WrappedGroup>::generator().0,
|
||||||
),
|
),
|
||||||
0,
|
0,
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use ciphersuite::{group::GroupEncoding, Ciphersuite};
|
use ciphersuite::{group::GroupEncoding, *};
|
||||||
use frost::{dkg::ThresholdKeys, sign::PreprocessMachine};
|
use frost::{dkg::ThresholdKeys, sign::PreprocessMachine};
|
||||||
|
|
||||||
use serai_db::DbTxn;
|
use serai_db::DbTxn;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user