From 7a790f3a209aed9237c9abdde0b87cadd07f095d Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Sat, 23 Aug 2025 11:00:05 -0400 Subject: [PATCH 01/15] ff/alloc when ciphersuite/alloc --- crypto/ciphersuite/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/ciphersuite/Cargo.toml b/crypto/ciphersuite/Cargo.toml index f86155aa..5e69b454 100644 --- a/crypto/ciphersuite/Cargo.toml +++ b/crypto/ciphersuite/Cargo.toml @@ -38,7 +38,7 @@ rand_core = { version = "0.6", default-features = false, features = ["std"] } ff-group-tests = { version = "0.13", path = "../ff-group-tests" } [features] -alloc = ["std-shims"] +alloc = ["std-shims", "ff/alloc"] std = [ "std-shims/std", From f8adfb56ad30d736e918746ad4eaf0a914e3273d Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Tue, 26 Aug 2025 23:15:58 -0400 Subject: [PATCH 02/15] Remove unwrap within debug assertion --- crypto/dkg/musig/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/dkg/musig/src/lib.rs b/crypto/dkg/musig/src/lib.rs index 36f4fd31..93f5fad8 100644 --- a/crypto/dkg/musig/src/lib.rs +++ b/crypto/dkg/musig/src/lib.rs @@ -150,7 +150,7 @@ pub fn musig( } let group_key = multiexp::multiexp(&multiexp); debug_assert_eq!(our_pub_key, verification_shares[¶ms.i()]); - debug_assert_eq!(musig_key_vartime::(context, keys).unwrap(), group_key); + debug_assert_eq!(musig_key_vartime::(context, keys), Some(group_key)); ThresholdKeys::new( params, From 98b9cc82a7b962bf1327c3958089987834ebd52b Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Mon, 1 Sep 2025 15:42:47 -0400 Subject: [PATCH 03/15] Fix Some(_) which should be Ok(_) --- crypto/dkg/musig/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/dkg/musig/src/lib.rs b/crypto/dkg/musig/src/lib.rs index 93f5fad8..7a3cebde 100644 --- a/crypto/dkg/musig/src/lib.rs +++ b/crypto/dkg/musig/src/lib.rs @@ -150,7 +150,7 @@ pub fn musig( } let group_key = multiexp::multiexp(&multiexp); debug_assert_eq!(our_pub_key, verification_shares[¶ms.i()]); - debug_assert_eq!(musig_key_vartime::(context, keys), Some(group_key)); + debug_assert_eq!(musig_key_vartime::(context, keys), Ok(group_key)); ThresholdKeys::new( params, From 251996c1b0796b18695f94e84d52fa78ec1134c6 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Mon, 1 Sep 2025 15:46:04 -0400 Subject: [PATCH 04/15] Use `solc 0.8.26` `next` already does, and it's annoying to have to consistently switch between the two branches. --- .github/actions/build-dependencies/action.yml | 4 ++-- networks/ethereum/build.rs | 2 +- orchestration/src/processor.rs | 4 ++-- spec/Getting Started.md | 10 +--------- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/.github/actions/build-dependencies/action.yml b/.github/actions/build-dependencies/action.yml index c50ce6cf..bfc02a4c 100644 --- a/.github/actions/build-dependencies/action.yml +++ b/.github/actions/build-dependencies/action.yml @@ -44,8 +44,8 @@ runs: shell: bash run: | cargo +1.89 install svm-rs --version =0.5.18 - svm install 0.8.25 - svm use 0.8.25 + svm install 0.8.26 + svm use 0.8.26 - name: Remove preinstalled Docker shell: bash diff --git a/networks/ethereum/build.rs b/networks/ethereum/build.rs index 38fcfe00..435131be 100644 --- a/networks/ethereum/build.rs +++ b/networks/ethereum/build.rs @@ -10,7 +10,7 @@ fn main() { { if let Some(version) = line.strip_prefix("Version: ") { let version = version.split('+').next().unwrap(); - assert_eq!(version, "0.8.25"); + assert_eq!(version, "0.8.26"); } } diff --git a/orchestration/src/processor.rs b/orchestration/src/processor.rs index a16cd1fc..6375f27a 100644 --- a/orchestration/src/processor.rs +++ b/orchestration/src/processor.rs @@ -21,8 +21,8 @@ pub fn processor( if coin == "ethereum" { r#" RUN cargo install svm-rs -RUN svm install 0.8.25 -RUN svm use 0.8.25 +RUN svm install 0.8.26 +RUN svm use 0.8.26 "# } else { "" diff --git a/spec/Getting Started.md b/spec/Getting Started.md index 06a5cfb7..01d1e757 100644 --- a/spec/Getting Started.md +++ b/spec/Getting Started.md @@ -32,15 +32,7 @@ rustup toolchain install nightly rustup target add wasm32v1-none --toolchain nightly ``` -### Install Solidity - -``` -cargo install svm-rs -svm install 0.8.25 -svm use 0.8.25 -``` - -### Install Solidity Compiler Version Manager +### Install Solidity with `svm` ``` cargo install svm-rs From eaa9a0e5a63398f45256b6da7926ca166552e2d3 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Sat, 30 Aug 2025 15:48:56 -0400 Subject: [PATCH 05/15] Pin actions in the pages workflow --- .github/workflows/pages.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 069517c8..72691f20 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -46,16 +46,16 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac - name: Setup Ruby - uses: ruby/setup-ruby@v1 + uses: ruby/setup-ruby@44511735964dcb71245e7e55f72539531f7bc0eb with: bundler-cache: true cache-version: 0 working-directory: "${{ github.workspace }}/docs" - name: Setup Pages id: pages - uses: actions/configure-pages@v3 + uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b - name: Build with Jekyll run: cd ${{ github.workspace }}/docs && bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}" env: @@ -74,7 +74,7 @@ jobs: mv target/doc docs/_site/rust - name: Upload artifact - uses: actions/upload-pages-artifact@v3 + uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b with: path: "docs/_site/" @@ -88,4 +88,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e From 2a02a8dc5903e5526c114ab12fb868649af2f3d4 Mon Sep 17 00:00:00 2001 From: Mohan <86064887+binarybaron@users.noreply.github.com> Date: Mon, 1 Sep 2025 21:57:19 +0200 Subject: [PATCH 06/15] fix(spec): svm version mismatch in docs; document foundryup (#665) * fix(spec): Change svm version in docs to 0.8.26 * fix(spec): add instructions for using foundryup --- spec/Getting Started.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/spec/Getting Started.md b/spec/Getting Started.md index 06a5cfb7..92897b70 100644 --- a/spec/Getting Started.md +++ b/spec/Getting Started.md @@ -36,8 +36,8 @@ rustup target add wasm32v1-none --toolchain nightly ``` cargo install svm-rs -svm install 0.8.25 -svm use 0.8.25 +svm install 0.8.26 +svm use 0.8.26 ``` ### Install Solidity Compiler Version Manager @@ -51,7 +51,8 @@ svm use 0.8.25 ### Install foundry (for tests) ``` -cargo install --git https://github.com/foundry-rs/foundry --profile local --locked forge cast chisel anvil +curl -L https://foundry.paradigm.xyz | bash +foundryup ``` ### Clone and Build Serai From 568324f631f18189caf4efe2510cb860cce92c46 Mon Sep 17 00:00:00 2001 From: Mohan <86064887+binarybaron@users.noreply.github.com> Date: Mon, 1 Sep 2025 21:57:19 +0200 Subject: [PATCH 07/15] fix(spec): svm version mismatch in docs; document foundryup (#665) * fix(spec): Change svm version in docs to 0.8.26 * fix(spec): add instructions for using foundryup --- spec/Getting Started.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/spec/Getting Started.md b/spec/Getting Started.md index 01d1e757..a2716582 100644 --- a/spec/Getting Started.md +++ b/spec/Getting Started.md @@ -36,14 +36,15 @@ rustup target add wasm32v1-none --toolchain nightly ``` cargo install svm-rs -svm install 0.8.25 -svm use 0.8.25 +svm install 0.8.26 +svm use 0.8.26 ``` ### Install foundry (for tests) ``` -cargo install --git https://github.com/foundry-rs/foundry --profile local --locked forge cast chisel anvil +curl -L https://foundry.paradigm.xyz | bash +foundryup ``` ### Clone and Build Serai From 7d54c02ec6182b6ddf3fa09c48961f12e2f08658 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Mon, 1 Sep 2025 16:48:34 -0400 Subject: [PATCH 08/15] Update to latest nightly Replaces #671 due to a lint being triggered. --- .github/nightly-version | 2 +- processor/src/main.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/nightly-version b/.github/nightly-version index 45e51c4c..10423e5c 100644 --- a/.github/nightly-version +++ b/.github/nightly-version @@ -1 +1 @@ -nightly-2025-08-01 +nightly-2025-09-01 diff --git a/processor/src/main.rs b/processor/src/main.rs index 98b09a06..6f4ca953 100644 --- a/processor/src/main.rs +++ b/processor/src/main.rs @@ -755,7 +755,7 @@ async fn main() { ExternalNetworkId::Ethereum => { let relayer_hostname = env::var("ETHEREUM_RELAYER_HOSTNAME") .expect("ethereum relayer hostname wasn't specified") - .to_string(); + .clone(); let relayer_port = env::var("ETHEREUM_RELAYER_PORT").expect("ethereum relayer port wasn't specified"); let relayer_url = relayer_hostname + ":" + &relayer_port; From 0066b94d38c34be3f407ee050e4f9340eb186258 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Mon, 1 Sep 2025 20:52:11 -0400 Subject: [PATCH 09/15] Update `substrate-wasm-builder` from `serai/polkadot-sdk` to `serai/patch-polkadot-sdk` Steps towards allowing us to delete the `serai/polkadot-sdk` repository. --- Cargo.lock | 58 ++++++++++++++++++------------------ deny.toml | 2 +- substrate/runtime/Cargo.toml | 2 +- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4e3bec66..48360d40 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2229,7 +2229,7 @@ dependencies = [ "borsh", "ciphersuite", "std-shims", - "thiserror 2.0.14", + "thiserror 2.0.16", "zeroize", ] @@ -2255,7 +2255,7 @@ dependencies = [ "multiexp", "rand_core", "std-shims", - "thiserror 2.0.14", + "thiserror 2.0.16", "zeroize", ] @@ -2272,7 +2272,7 @@ dependencies = [ "multiexp", "rand_core", "schnorr-signatures", - "thiserror 2.0.14", + "thiserror 2.0.16", "zeroize", ] @@ -2287,7 +2287,7 @@ dependencies = [ "dleq", "flexible-transcript", "rand_core", - "thiserror 2.0.14", + "thiserror 2.0.16", "zeroize", ] @@ -2297,7 +2297,7 @@ version = "0.6.0" dependencies = [ "ciphersuite", "dkg", - "thiserror 2.0.14", + "thiserror 2.0.16", "zeroize", ] @@ -2316,7 +2316,7 @@ dependencies = [ "multiexp", "rand_core", "rustversion", - "thiserror 2.0.14", + "thiserror 2.0.16", "zeroize", ] @@ -3494,7 +3494,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.10", + "socket2 0.5.7", "tokio", "tower-service", "tracing", @@ -4041,7 +4041,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -4918,7 +4918,7 @@ dependencies = [ "schnorr-signatures", "serde_json", "subtle", - "thiserror 2.0.14", + "thiserror 2.0.16", "zeroize", ] @@ -4930,7 +4930,7 @@ dependencies = [ "curve25519-dalek", "monero-base58", "monero-io", - "thiserror 2.0.14", + "thiserror 2.0.16", "zeroize", ] @@ -4966,7 +4966,7 @@ dependencies = [ "monero-primitives", "rand_core", "std-shims", - "thiserror 2.0.14", + "thiserror 2.0.16", "zeroize", ] @@ -4987,7 +4987,7 @@ dependencies = [ "rand_core", "std-shims", "subtle", - "thiserror 2.0.14", + "thiserror 2.0.16", "zeroize", ] @@ -5025,7 +5025,7 @@ dependencies = [ "monero-io", "monero-primitives", "std-shims", - "thiserror 2.0.14", + "thiserror 2.0.16", "zeroize", ] @@ -5072,7 +5072,7 @@ dependencies = [ "serde", "serde_json", "std-shims", - "thiserror 2.0.14", + "thiserror 2.0.16", "zeroize", ] @@ -5108,7 +5108,7 @@ dependencies = [ "rand_core", "rand_distr", "std-shims", - "thiserror 2.0.14", + "thiserror 2.0.16", "zeroize", ] @@ -9368,10 +9368,10 @@ dependencies = [ [[package]] name = "sp-maybe-compressed-blob" version = "11.0.0" -source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#ebfc5f338a9752403fa07e88dd072b1d6de7acfc" +source = "git+https://github.com/serai-dex/patch-polkadot-sdk?rev=19c487d6aa9893b6b09a21ce0ab8aefb1c299186#19c487d6aa9893b6b09a21ce0ab8aefb1c299186" dependencies = [ - "thiserror 2.0.14", - "zstd 0.13.2", + "thiserror 2.0.16", + "zstd 0.13.3", ] [[package]] @@ -9878,8 +9878,8 @@ dependencies = [ [[package]] name = "substrate-wasm-builder" -version = "25.0.0" -source = "git+https://github.com/serai-dex/polkadot-sdk?branch=serai-next#ebfc5f338a9752403fa07e88dd072b1d6de7acfc" +version = "26.0.1" +source = "git+https://github.com/serai-dex/patch-polkadot-sdk?rev=19c487d6aa9893b6b09a21ce0ab8aefb1c299186#19c487d6aa9893b6b09a21ce0ab8aefb1c299186" dependencies = [ "build-helper", "cargo_metadata", @@ -10053,11 +10053,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.14" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b0949c3a6c842cbde3f1686d6eea5a010516deb7085f79db747562d4102f41e" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" dependencies = [ - "thiserror-impl 2.0.14", + "thiserror-impl 2.0.16", ] [[package]] @@ -10073,9 +10073,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.14" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5b44b4ab9c2fdd0e0512e6bece8388e214c0749f5862b114cc5b7a25daf227" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" dependencies = [ "proc-macro2", "quote", @@ -11221,7 +11221,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -11584,7 +11584,7 @@ dependencies = [ name = "zstd" version = "0.11.2+zstd.1.5.2" dependencies = [ - "zstd 0.13.2", + "zstd 0.13.3", ] [[package]] @@ -11598,9 +11598,9 @@ dependencies = [ [[package]] name = "zstd" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" dependencies = [ "zstd-safe 7.2.1", ] diff --git a/deny.toml b/deny.toml index cc2f2c3d..f997a732 100644 --- a/deny.toml +++ b/deny.toml @@ -106,5 +106,5 @@ allow-git = [ "https://github.com/monero-oxide/monero-oxide", "https://github.com/serai-dex/substrate-bip39", "https://github.com/serai-dex/substrate", - "https://github.com/serai-dex/polkadot-sdk", + "https://github.com/serai-dex/patch-polkadot-sdk", ] diff --git a/substrate/runtime/Cargo.toml b/substrate/runtime/Cargo.toml index 97e7d42c..861402d6 100644 --- a/substrate/runtime/Cargo.toml +++ b/substrate/runtime/Cargo.toml @@ -76,7 +76,7 @@ frame-system-rpc-runtime-api = { git = "https://github.com/serai-dex/substrate", pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/serai-dex/substrate", default-features = false } [build-dependencies] -substrate-wasm-builder = { git = "https://github.com/serai-dex/polkadot-sdk", branch = "serai-next" } +substrate-wasm-builder = { git = "https://github.com/serai-dex/patch-polkadot-sdk", rev = "19c487d6aa9893b6b09a21ce0ab8aefb1c299186" } [features] std = [ From 47ef24a7ccecf49c3b353385bb6690b4a8831bda Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Sat, 30 Aug 2025 16:20:29 -0400 Subject: [PATCH 10/15] Remove unused patch for parking_lot_core --- Cargo.lock | 13 +++---------- Cargo.toml | 2 -- patches/parking_lot_core/Cargo.toml | 16 ---------------- patches/parking_lot_core/src/lib.rs | 1 - 4 files changed, 3 insertions(+), 29 deletions(-) delete mode 100644 patches/parking_lot_core/Cargo.toml delete mode 100644 patches/parking_lot_core/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 01f73bb4..f878b590 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2515,7 +2515,7 @@ dependencies = [ "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core 0.9.11", + "parking_lot_core", ] [[package]] @@ -6993,14 +6993,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", - "parking_lot_core 0.9.11", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -dependencies = [ - "parking_lot_core 0.9.11", + "parking_lot_core", ] [[package]] @@ -11835,7 +11828,7 @@ dependencies = [ "cfg_aliases 0.2.1", "libc", "parking_lot 0.12.4", - "parking_lot_core 0.9.11", + "parking_lot_core", "static_init_macro", "winapi", ] diff --git a/Cargo.toml b/Cargo.toml index 052343cc..067e9d06 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,6 @@ resolver = "2" members = [ # Version patches - "patches/parking_lot_core", "patches/parking_lot", "patches/zstd", "patches/rocksdb", @@ -204,7 +203,6 @@ modular-frost = { path = "crypto/frost" } # https://github.com/rust-lang-nursery/lazy-static.rs/issues/201 lazy_static = { git = "https://github.com/rust-lang-nursery/lazy-static.rs", rev = "5735630d46572f1e5377c8f2ba0f79d18f53b10c" } -parking_lot_core = { path = "patches/parking_lot_core" } parking_lot = { path = "patches/parking_lot" } # wasmtime pulls in an old version for this zstd = { path = "patches/zstd" } diff --git a/patches/parking_lot_core/Cargo.toml b/patches/parking_lot_core/Cargo.toml deleted file mode 100644 index cafd432b..00000000 --- a/patches/parking_lot_core/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "parking_lot_core" -version = "0.8.6" -description = "parking_lot_core which patches to the latest update" -license = "MIT" -repository = "https://github.com/serai-dex/serai/tree/develop/patches/parking_lot_core" -authors = ["Luke Parker "] -keywords = [] -edition = "2021" - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs"] - -[dependencies] -parking_lot_core = "0.9" diff --git a/patches/parking_lot_core/src/lib.rs b/patches/parking_lot_core/src/lib.rs deleted file mode 100644 index bfecbfd8..00000000 --- a/patches/parking_lot_core/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ -pub use parking_lot_core::*; From 974bc823878c8957b9a13cc4bf08bf5fe1f5d6d2 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Sat, 30 Aug 2025 18:08:08 -0400 Subject: [PATCH 11/15] Remove unnecessary `to_string` for `clone` --- networks/ethereum/schnorr/build.rs | 2 +- processor/ethereum/deployer/build.rs | 2 +- processor/ethereum/router/build.rs | 3 +-- processor/ethereum/src/main.rs | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/networks/ethereum/schnorr/build.rs b/networks/ethereum/schnorr/build.rs index cf12f948..97acb1a5 100644 --- a/networks/ethereum/schnorr/build.rs +++ b/networks/ethereum/schnorr/build.rs @@ -1,4 +1,4 @@ fn main() { - let artifacts_path = std::env::var("OUT_DIR").unwrap().to_string() + "/ethereum-schnorr-contract"; + let artifacts_path = std::env::var("OUT_DIR").unwrap().clone() + "/ethereum-schnorr-contract"; build_solidity_contracts::build(&[], "contracts", &artifacts_path).unwrap(); } diff --git a/processor/ethereum/deployer/build.rs b/processor/ethereum/deployer/build.rs index 1906f1df..94f0c7fe 100644 --- a/processor/ethereum/deployer/build.rs +++ b/processor/ethereum/deployer/build.rs @@ -1,5 +1,5 @@ fn main() { let artifacts_path = - std::env::var("OUT_DIR").unwrap().to_string() + "/serai-processor-ethereum-deployer"; + std::env::var("OUT_DIR").unwrap().clone() + "/serai-processor-ethereum-deployer"; build_solidity_contracts::build(&[], "contracts", &artifacts_path).unwrap(); } diff --git a/processor/ethereum/router/build.rs b/processor/ethereum/router/build.rs index f80a0b77..f98ea730 100644 --- a/processor/ethereum/router/build.rs +++ b/processor/ethereum/router/build.rs @@ -19,8 +19,7 @@ fn sol(sol_files: &[&str], file: &str) { } fn main() { - let artifacts_path = - env::var("OUT_DIR").unwrap().to_string() + "/serai-processor-ethereum-router"; + let artifacts_path = env::var("OUT_DIR").unwrap().clone() + "/serai-processor-ethereum-router"; if !fs::exists(&artifacts_path).unwrap() { fs::create_dir(&artifacts_path).unwrap(); diff --git a/processor/ethereum/src/main.rs b/processor/ethereum/src/main.rs index 1a7ff773..792a216e 100644 --- a/processor/ethereum/src/main.rs +++ b/processor/ethereum/src/main.rs @@ -87,7 +87,7 @@ async fn main() { TransactionPublisher::new(db, provider, { let relayer_hostname = env::var("ETHEREUM_RELAYER_HOSTNAME") .expect("ethereum relayer hostname wasn't specified") - .to_string(); + .clone(); let relayer_port = env::var("ETHEREUM_RELAYER_PORT").expect("ethereum relayer port wasn't specified"); relayer_hostname + ":" + &relayer_port From 41c34d7f1176fcbb4f9d8f26a2ffc2c6ca745451 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Wed, 3 Sep 2025 06:41:42 -0400 Subject: [PATCH 12/15] Remove `crypto-bigint` from the public API of `prime-field` --- Cargo.lock | 2 ++ crypto/dalek-ff-group/Cargo.toml | 3 +- crypto/dalek-ff-group/src/lib.rs | 14 ++++++-- crypto/ed448/Cargo.toml | 3 +- crypto/ed448/src/point.rs | 42 ++++++++++++++++------ crypto/prime-field/src/lib.rs | 61 +++++++++++++++++++++++++++----- 6 files changed, 101 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f878b590..113df3c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2458,6 +2458,7 @@ version = "0.4.6" dependencies = [ "ciphersuite 0.4.2", "crypto-bigint 0.5.5", + "crypto-bigint 0.6.1", "curve25519-dalek", "digest 0.10.7", "ff-group-tests", @@ -6005,6 +6006,7 @@ name = "minimal-ed448" version = "0.4.2" dependencies = [ "ciphersuite 0.4.2", + "crypto-bigint 0.6.1", "ff-group-tests", "hex", "prime-field", diff --git a/crypto/dalek-ff-group/Cargo.toml b/crypto/dalek-ff-group/Cargo.toml index 46d32f51..215386a9 100644 --- a/crypto/dalek-ff-group/Cargo.toml +++ b/crypto/dalek-ff-group/Cargo.toml @@ -28,7 +28,8 @@ sha2 = { version = "0.11.0-rc.0", default-features = false } prime-field = { path = "../prime-field", default-features = false } ciphersuite = { version = "0.4.2", path = "../ciphersuite", default-features = false } -crypto-bigint = { version = "0.5", default-features = false, features = ["zeroize"] } +crypto-bigint-05 = { package = "crypto-bigint", version = "0.5", default-features = false, features = ["zeroize"] } +crypto-bigint = { version = "0.6", default-features = false, features = ["zeroize"] } curve25519-dalek = { version = ">= 4.0, < 4.2", default-features = false, features = ["zeroize", "digest", "group", "precomputed-tables"] } diff --git a/crypto/dalek-ff-group/src/lib.rs b/crypto/dalek-ff-group/src/lib.rs index 74b38887..dbe4d3e2 100644 --- a/crypto/dalek-ff-group/src/lib.rs +++ b/crypto/dalek-ff-group/src/lib.rs @@ -500,8 +500,18 @@ impl FieldElement { /// /// This will reduce the `U256` by the modulus, into a member of the field. #[deprecated] - pub const fn from_u256(u256: &crypto_bigint::U256) -> Self { - FieldElement::from(&prime_field::crypto_bigint::U256::from_words(*u256.as_words())) + pub const fn from_u256(u256: &crypto_bigint_05::U256) -> Self { + const MODULUS: crypto_bigint::U256 = crypto_bigint::U256::from_be_hex( + "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed", + ); + let mut u256 = crypto_bigint::U256::from_words(*u256.as_words()); + loop { + let result = FieldElement::from_bytes(&u256.to_le_bytes()); + if let Some(result) = result { + return result; + } + u256 = u256.wrapping_sub(&MODULUS); + } } /// Create a `FieldElement` from the reduction of a 512-bit number. diff --git a/crypto/ed448/Cargo.toml b/crypto/ed448/Cargo.toml index 2a698230..4c78ea86 100644 --- a/crypto/ed448/Cargo.toml +++ b/crypto/ed448/Cargo.toml @@ -21,6 +21,7 @@ zeroize = { version = "1", default-features = false, features = ["zeroize_derive sha3 = { version = "0.11.0-rc.0", default-features = false } +crypto-bigint = { version = "0.6", default-features = false, features = ["zeroize"] } prime-field = { path = "../prime-field", default-features = false } ciphersuite = { path = "../ciphersuite", default-features = false } @@ -32,6 +33,6 @@ rand_core = { version = "0.6", default-features = false, features = ["std"] } ff-group-tests = { path = "../ff-group-tests" } [features] -alloc = ["zeroize/alloc", "sha3/alloc", "prime-field/alloc", "ciphersuite/alloc"] +alloc = ["zeroize/alloc", "sha3/alloc", "crypto-bigint/alloc", "prime-field/alloc", "ciphersuite/alloc"] std = ["alloc", "zeroize/std", "prime-field/std", "ciphersuite/std"] default = ["std"] diff --git a/crypto/ed448/src/point.rs b/crypto/ed448/src/point.rs index 95552663..8fb1fa7a 100644 --- a/crypto/ed448/src/point.rs +++ b/crypto/ed448/src/point.rs @@ -7,8 +7,8 @@ use prime_field::{ subtle::{Choice, CtOption, ConstantTimeEq, ConditionallySelectable, ConditionallyNegatable}, zeroize::Zeroize, rand_core::RngCore, - crypto_bigint::U512, }; +use crypto_bigint::U512; use ciphersuite::group::{ ff::{Field, PrimeField, PrimeFieldBits}, @@ -18,17 +18,37 @@ use ciphersuite::group::{ use crate::{u8_from_bool, Scalar, FieldElement}; -const G_Y: FieldElement = FieldElement::from(&U512::from_be_hex(concat!( - "0000000000000000", - "693f46716eb6bc248876203756c9c7624bea73736ca3984087789c1e", - "05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14", -))); +const G_Y: FieldElement = { + let bytes = U512::from_be_hex(concat!( + "0000000000000000", + "693f46716eb6bc248876203756c9c7624bea73736ca3984087789c1e", + "05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14", + )) + .to_le_bytes(); + let mut dest = [0; 57]; + let mut i = 0; + while i < dest.len() { + dest[i] = bytes[i]; + i += 1; + } + FieldElement::from_bytes(&dest).unwrap() +}; -const G_X: FieldElement = FieldElement::from(&U512::from_be_hex(concat!( - "0000000000000000", - "4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324", - "a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05e", -))); +const G_X: FieldElement = { + let bytes = U512::from_be_hex(concat!( + "0000000000000000", + "4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324", + "a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05e", + )) + .to_le_bytes(); + let mut dest = [0; 57]; + let mut i = 0; + while i < dest.len() { + dest[i] = bytes[i]; + i += 1; + } + FieldElement::from_bytes(&dest).unwrap() +}; fn recover_x(y: FieldElement) -> CtOption { #[allow(non_snake_case)] diff --git a/crypto/prime-field/src/lib.rs b/crypto/prime-field/src/lib.rs index 46124194..6733fc85 100644 --- a/crypto/prime-field/src/lib.rs +++ b/crypto/prime-field/src/lib.rs @@ -5,11 +5,11 @@ pub use subtle; pub use zeroize; pub use rand_core; -pub use crypto_bigint; pub use ff; #[doc(hidden)] pub mod __prime_field_private { + pub use crypto_bigint; pub use paste; #[cfg(feature = "std")] pub use ff_group_tests; @@ -94,6 +94,8 @@ pub mod __prime_field_private { /// less than `modulus_as_be_hex`. /// /// `big_endian` controls if the encoded representation will be big-endian or not. +/// +/// `repr` must satisfy the requirements for `PrimeField::Repr`. #[doc(hidden)] #[macro_export] macro_rules! odd_prime_field_with_specific_repr { @@ -116,13 +118,15 @@ macro_rules! odd_prime_field_with_specific_repr { }, zeroize::Zeroize, rand_core::RngCore, - crypto_bigint::{ - Limb, Encoding, Integer, Uint, - modular::{ConstMontyParams, ConstMontyForm}, - impl_modulus, - }, ff::*, - __prime_field_private::*, + __prime_field_private::{ + crypto_bigint::{ + Limb, Encoding, Integer, Uint, + modular::{ConstMontyParams, ConstMontyForm}, + impl_modulus, + }, + *, + }, }; const MODULUS_WITHOUT_PREFIX: &str = hex_str_without_prefix($modulus_as_be_hex); @@ -180,7 +184,7 @@ macro_rules! odd_prime_field_with_specific_repr { const MODULUS_MINUS_TWO: UnderlyingUint = MODULUS.wrapping_sub(&UnderlyingUint::from_u8(2)); const T: UnderlyingUint = MODULUS_MINUS_ONE.shr_vartime($name::S); - /// A field automatically generated with `short-weierstrass`. + /// A field automatically generated with `prime-field`. #[derive(Clone, Copy, Eq, Debug)] pub struct $name(Underlying); @@ -192,9 +196,47 @@ macro_rules! odd_prime_field_with_specific_repr { impl $name { /// Create a `$name` from the `Uint` type underlying it. - pub const fn from(value: &UnderlyingUint) -> Self { + const fn from(value: &UnderlyingUint) -> Self { $name(Underlying::new(value)) } + + /// Create a `$name` from bytes within a `const` context. + /// + /// This function executes in variable time. `<$name as PrimeField>::from_repr` SHOULD + /// be used instead. + pub const fn from_bytes(value: &[u8; MODULUS_BYTES]) -> Option { + let mut expanded_repr = [0; UnderlyingUint::BYTES]; + let repr: &[u8] = value.as_slice(); + let (uint, repr) = if $big_endian { + let start = UnderlyingUint::BYTES - MODULUS_BYTES; + let mut i = 0; + while i < repr.len() { + expanded_repr[start + i] = repr[i]; + i += 1; + } + let uint = Underlying::new(&UnderlyingUint::from_be_slice(&expanded_repr)); + (uint, uint.retrieve().to_be_bytes()) + } else { + let mut i = 0; + while i < repr.len() { + expanded_repr[i] = repr[i]; + i += 1; + } + let uint = Underlying::new(&UnderlyingUint::from_le_slice(&expanded_repr)); + (uint, uint.retrieve().to_le_bytes()) + }; + + // Ensure the representations match + let mut i = 0; + while i < expanded_repr.len() { + if repr[i] != expanded_repr[i] { + return None; + } + i += 1; + } + + Some(Self(uint)) + } } impl From for $name { fn from(value: u8) -> Self { @@ -416,6 +458,7 @@ macro_rules! odd_prime_field_with_specific_repr { } /// The encoded representation of a `$name`. + // This is required to be bespoke to satisfy `Default`. #[derive(Clone, Copy)] pub struct Repr([u8; MODULUS_BYTES]); impl Default for Repr { From 215e41fdb6c63f451bd6bdaef17a42a5f1ca2763 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Wed, 3 Sep 2025 06:49:44 -0400 Subject: [PATCH 13/15] Remove deprecated APIs from `dalek-ff-group` For backwards compatibility, we now use as a patch (as prior done with `ciphersuite`). Removes `crypto-bigint 0.5` from the tree and shapes up what the next release will look like. --- Cargo.lock | 61 ++++++++++++++++++------------- Cargo.toml | 8 ++-- crypto/dalek-ff-group/Cargo.toml | 3 +- crypto/dalek-ff-group/src/lib.rs | 28 -------------- patches/ciphersuite/README.md | 4 +- patches/dalek-ff-group/Cargo.toml | 29 +++++++++++++++ patches/dalek-ff-group/LICENSE | 21 +++++++++++ patches/dalek-ff-group/README.md | 4 ++ patches/dalek-ff-group/src/lib.rs | 44 ++++++++++++++++++++++ 9 files changed, 141 insertions(+), 61 deletions(-) create mode 100644 patches/dalek-ff-group/Cargo.toml create mode 100644 patches/dalek-ff-group/LICENSE create mode 100644 patches/dalek-ff-group/README.md create mode 100644 patches/dalek-ff-group/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 113df3c6..dcb7b37d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1939,7 +1939,7 @@ name = "ciphersuite" version = "0.4.99" dependencies = [ "ciphersuite 0.4.2", - "dalek-ff-group", + "dalek-ff-group 0.4.6", ] [[package]] @@ -2457,7 +2457,6 @@ name = "dalek-ff-group" version = "0.4.6" dependencies = [ "ciphersuite 0.4.2", - "crypto-bigint 0.5.5", "crypto-bigint 0.6.1", "curve25519-dalek", "digest 0.10.7", @@ -2470,6 +2469,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "dalek-ff-group" +version = "0.4.99" +dependencies = [ + "crypto-bigint 0.5.5", + "crypto-bigint 0.6.1", + "dalek-ff-group 0.4.6", + "prime-field", +] + [[package]] name = "darling" version = "0.20.11" @@ -2795,7 +2804,7 @@ dependencies = [ "blake2 0.11.0-rc.0", "ciphersuite 0.4.2", "ciphersuite-kp256", - "dalek-ff-group", + "dalek-ff-group 0.4.6", "dkg", "dkg-recovery", "ec-divisors", @@ -2820,7 +2829,7 @@ name = "dkg-musig" version = "0.6.0" dependencies = [ "ciphersuite 0.4.2", - "dalek-ff-group", + "dalek-ff-group 0.4.6", "dkg", "dkg-recovery", "multiexp", @@ -2913,7 +2922,7 @@ name = "ec-divisors" version = "0.1.0" source = "git+https://github.com/monero-oxide/monero-oxide?rev=a6f8797007e768488568b821435cf5006517a962#a6f8797007e768488568b821435cf5006517a962" dependencies = [ - "dalek-ff-group", + "dalek-ff-group 0.4.99", "ff", "group", "rand_core 0.6.4", @@ -3025,7 +3034,7 @@ dependencies = [ "blake2 0.11.0-rc.0", "ciphersuite 0.4.2", "curve25519-dalek", - "dalek-ff-group", + "dalek-ff-group 0.4.6", "ff-group-tests", "generalized-bulletproofs-ec-gadgets", "hex", @@ -3535,7 +3544,7 @@ name = "frost-schnorrkel" version = "0.2.0" dependencies = [ "ciphersuite 0.4.2", - "dalek-ff-group", + "dalek-ff-group 0.4.6", "flexible-transcript", "group", "modular-frost", @@ -6074,7 +6083,7 @@ version = "0.10.1" dependencies = [ "ciphersuite 0.4.2", "ciphersuite-kp256", - "dalek-ff-group", + "dalek-ff-group 0.4.6", "dkg", "dkg-dealer", "dkg-recovery", @@ -6148,7 +6157,7 @@ version = "0.1.0" source = "git+https://github.com/monero-oxide/monero-oxide?rev=6966575e05fe09b77674c46984b21686ed9304ff#6966575e05fe09b77674c46984b21686ed9304ff" dependencies = [ "curve25519-dalek", - "dalek-ff-group", + "dalek-ff-group 0.4.99", "flexible-transcript", "group", "modular-frost", @@ -6170,7 +6179,7 @@ source = "git+https://github.com/monero-oxide/monero-oxide?rev=6966575e05fe09b77 dependencies = [ "crypto-bigint 0.5.5", "curve25519-dalek", - "dalek-ff-group", + "dalek-ff-group 0.4.99", "group", "monero-io", "sha3 0.10.8", @@ -6267,7 +6276,7 @@ version = "0.1.0" source = "git+https://github.com/monero-oxide/monero-oxide?rev=6966575e05fe09b77674c46984b21686ed9304ff#6966575e05fe09b77674c46984b21686ed9304ff" dependencies = [ "curve25519-dalek", - "dalek-ff-group", + "dalek-ff-group 0.4.99", "flexible-transcript", "hex", "modular-frost", @@ -6318,7 +6327,7 @@ dependencies = [ name = "multiexp" version = "0.4.2" dependencies = [ - "dalek-ff-group", + "dalek-ff-group 0.4.6", "ff", "group", "k256", @@ -9456,7 +9465,7 @@ name = "schnorr-signatures" version = "0.5.2" dependencies = [ "ciphersuite 0.4.2", - "dalek-ff-group", + "dalek-ff-group 0.4.6", "flexible-transcript", "hex", "multiexp", @@ -9741,7 +9750,7 @@ dependencies = [ "borsh", "ciphersuite 0.4.2", "ciphersuite-kp256", - "dalek-ff-group", + "dalek-ff-group 0.4.6", "dkg-musig", "dockertest", "frame-system", @@ -9802,7 +9811,7 @@ dependencies = [ "blake2 0.11.0-rc.0", "borsh", "ciphersuite 0.4.2", - "dalek-ff-group", + "dalek-ff-group 0.4.6", "dkg-musig", "env_logger", "flexible-transcript", @@ -9893,7 +9902,7 @@ dependencies = [ "blake2 0.11.0-rc.0", "borsh", "ciphersuite 0.4.2", - "dalek-ff-group", + "dalek-ff-group 0.4.6", "dkg", "log", "parity-scale-codec", @@ -10157,7 +10166,7 @@ version = "0.1.0" dependencies = [ "borsh", "ciphersuite 0.4.2", - "dalek-ff-group", + "dalek-ff-group 0.4.6", "env_logger", "flexible-transcript", "hex", @@ -10178,7 +10187,7 @@ name = "serai-message-queue-tests" version = "0.1.0" dependencies = [ "ciphersuite 0.4.2", - "dalek-ff-group", + "dalek-ff-group 0.4.6", "dockertest", "hex", "rand_core 0.6.4", @@ -10195,7 +10204,7 @@ version = "0.1.0" dependencies = [ "borsh", "ciphersuite 0.4.2", - "dalek-ff-group", + "dalek-ff-group 0.4.6", "dkg-evrf", "log", "modular-frost", @@ -10225,7 +10234,7 @@ version = "0.1.0" dependencies = [ "bitcoin-serai", "ciphersuite 0.4.2", - "dalek-ff-group", + "dalek-ff-group 0.4.6", "dkg", "dkg-evrf", "embedwards25519", @@ -10247,7 +10256,7 @@ dependencies = [ "ciphersuite-kp256", "clap", "curve25519-dalek", - "dalek-ff-group", + "dalek-ff-group 0.4.6", "embedwards25519", "frame-benchmarking", "futures-util", @@ -10298,7 +10307,7 @@ name = "serai-orchestrator" version = "0.0.1" dependencies = [ "ciphersuite 0.4.2", - "dalek-ff-group", + "dalek-ff-group 0.4.6", "embedwards25519", "flexible-transcript", "hex", @@ -10536,7 +10545,7 @@ dependencies = [ "blake2 0.11.0-rc.0", "borsh", "ciphersuite 0.4.2", - "dalek-ff-group", + "dalek-ff-group 0.4.6", "frost-schnorrkel", "log", "modular-frost", @@ -10714,7 +10723,7 @@ version = "0.1.0" dependencies = [ "bitvec", "ciphersuite 0.4.2", - "dalek-ff-group", + "dalek-ff-group 0.4.6", "dkg-musig", "frame-support", "frame-system", @@ -10749,7 +10758,7 @@ version = "0.1.0" dependencies = [ "borsh", "ciphersuite 0.4.2", - "dalek-ff-group", + "dalek-ff-group 0.4.6", "dkg-musig", "parity-scale-codec", "scale-info", @@ -12602,7 +12611,7 @@ version = "0.1.0" dependencies = [ "blake2 0.11.0-rc.0", "ciphersuite 0.4.2", - "dalek-ff-group", + "dalek-ff-group 0.4.6", "flexible-transcript", "futures-channel", "futures-util", diff --git a/Cargo.toml b/Cargo.toml index 067e9d06..fb7d1912 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,10 +14,12 @@ members = [ "patches/option-ext", "patches/directories-next", - # monero-oxide expects ciphersuite, yet the ciphersuite in-tree here has breaking changes - # This re-exports the in-tree ciphersuite _without_ changes breaking to monero-oxide + # monero-oxide expects `ciphersuite`, yet the `ciphersuite` in-tree here has breaking changes + # This re-exports the in-tree `ciphersuite` _without_ changes breaking to monero-oxide # Not included in workspace to prevent having two crates with the same name (an error) # "patches/ciphersuite", + # Same for `dalek-ff-group` + # "patches/dalek-ff-group", "common/std-shims", "common/zalloc", @@ -196,7 +198,7 @@ simple-request = { path = "common/request" } multiexp = { path = "crypto/multiexp" } flexible-transcript = { path = "crypto/transcript" } ciphersuite = { path = "patches/ciphersuite" } -dalek-ff-group = { path = "crypto/dalek-ff-group" } +dalek-ff-group = { path = "patches/dalek-ff-group" } minimal-ed448 = { path = "crypto/ed448" } modular-frost = { path = "crypto/frost" } diff --git a/crypto/dalek-ff-group/Cargo.toml b/crypto/dalek-ff-group/Cargo.toml index 215386a9..9937a700 100644 --- a/crypto/dalek-ff-group/Cargo.toml +++ b/crypto/dalek-ff-group/Cargo.toml @@ -28,7 +28,6 @@ sha2 = { version = "0.11.0-rc.0", default-features = false } prime-field = { path = "../prime-field", default-features = false } ciphersuite = { version = "0.4.2", path = "../ciphersuite", default-features = false } -crypto-bigint-05 = { package = "crypto-bigint", version = "0.5", default-features = false, features = ["zeroize"] } crypto-bigint = { version = "0.6", default-features = false, features = ["zeroize"] } curve25519-dalek = { version = ">= 4.0, < 4.2", default-features = false, features = ["zeroize", "digest", "group", "precomputed-tables"] } @@ -39,6 +38,6 @@ rand_core = { version = "0.6", default-features = false, features = ["std"] } ff-group-tests = { path = "../ff-group-tests" } [features] -alloc = ["zeroize/alloc", "digest/alloc", "prime-field/alloc", "ciphersuite/alloc", "curve25519-dalek/alloc"] +alloc = ["zeroize/alloc", "digest/alloc", "prime-field/alloc", "ciphersuite/alloc", "crypto-bigint/alloc", "curve25519-dalek/alloc"] std = ["alloc", "zeroize/std", "subtle/std", "rand_core/std", "digest/std", "prime-field/std", "ciphersuite/std"] default = ["std"] diff --git a/crypto/dalek-ff-group/src/lib.rs b/crypto/dalek-ff-group/src/lib.rs index dbe4d3e2..4f58b437 100644 --- a/crypto/dalek-ff-group/src/lib.rs +++ b/crypto/dalek-ff-group/src/lib.rs @@ -494,31 +494,3 @@ prime_field::odd_prime_field_with_specific_repr!( false, crate::ThirtyTwoArray ); - -impl FieldElement { - /// Create a FieldElement from a `crypto_bigint::U256`. - /// - /// This will reduce the `U256` by the modulus, into a member of the field. - #[deprecated] - pub const fn from_u256(u256: &crypto_bigint_05::U256) -> Self { - const MODULUS: crypto_bigint::U256 = crypto_bigint::U256::from_be_hex( - "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed", - ); - let mut u256 = crypto_bigint::U256::from_words(*u256.as_words()); - loop { - let result = FieldElement::from_bytes(&u256.to_le_bytes()); - if let Some(result) = result { - return result; - } - u256 = u256.wrapping_sub(&MODULUS); - } - } - - /// Create a `FieldElement` from the reduction of a 512-bit number. - /// - /// The bytes are interpreted in little-endian format. - #[deprecated] - pub fn wide_reduce(value: [u8; 64]) -> Self { - >::from_uniform_bytes(&value) - } -} diff --git a/patches/ciphersuite/README.md b/patches/ciphersuite/README.md index e5aa0ff3..53ec0b79 100644 --- a/patches/ciphersuite/README.md +++ b/patches/ciphersuite/README.md @@ -1,4 +1,4 @@ # Ciphersuite -Patch for the `crates.io` ciphersuite to use the in-tree ciphersuite, resolving -breaking changes made since. +Patch for the `crates.io` `ciphersuite` to use the in-tree `ciphersuite`, +resolving relevant breaking changes made since. diff --git a/patches/dalek-ff-group/Cargo.toml b/patches/dalek-ff-group/Cargo.toml new file mode 100644 index 00000000..3525cf12 --- /dev/null +++ b/patches/dalek-ff-group/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "dalek-ff-group" +version = "0.4.99" +description = "ff/group bindings around curve25519-dalek" +license = "MIT" +repository = "https://github.com/serai-dex/serai/tree/develop/crypto/dalek-ff-group" +authors = ["Luke Parker "] +keywords = ["curve25519", "ed25519", "ristretto", "dalek", "group"] +edition = "2021" +rust-version = "1.85" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[lints] +workspace = true + +[dependencies] +dalek-ff-group = { path = "../../crypto/dalek-ff-group", default-features = false } + +crypto-bigint-05 = { package = "crypto-bigint", version = "0.5", default-features = false, features = ["zeroize"] } +crypto-bigint = { version = "0.6", default-features = false, features = ["zeroize"] } +prime-field = { path = "../../crypto/prime-field", default-features = false } + +[features] +alloc = ["dalek-ff-group/alloc", "crypto-bigint-05/alloc", "crypto-bigint/alloc", "prime-field/alloc"] +std = ["alloc", "dalek-ff-group/std", "prime-field/std"] +default = ["std"] diff --git a/patches/dalek-ff-group/LICENSE b/patches/dalek-ff-group/LICENSE new file mode 100644 index 00000000..32ff304a --- /dev/null +++ b/patches/dalek-ff-group/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022-2025 Luke Parker + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/patches/dalek-ff-group/README.md b/patches/dalek-ff-group/README.md new file mode 100644 index 00000000..5a25d05b --- /dev/null +++ b/patches/dalek-ff-group/README.md @@ -0,0 +1,4 @@ +# Dalek FF/Group + +Patch for the `crates.io` `dalek-ff-group` to use the in-tree `dalek-ff-group`, +resolving relevant breaking changes made since. diff --git a/patches/dalek-ff-group/src/lib.rs b/patches/dalek-ff-group/src/lib.rs new file mode 100644 index 00000000..848f2a8f --- /dev/null +++ b/patches/dalek-ff-group/src/lib.rs @@ -0,0 +1,44 @@ +#![allow(deprecated)] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![no_std] // Prevents writing new code, in what should be a simple wrapper, which requires std +#![doc = include_str!("../README.md")] +#![allow(clippy::redundant_closure_call)] + +pub use dalek_ff_group::{Scalar, EdwardsPoint, RistrettoPoint, Ed25519, Ristretto}; + +type ThirtyTwoArray = [u8; 32]; +prime_field::odd_prime_field_with_specific_repr!( + FieldElement, + "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed", + "02", + false, + crate::ThirtyTwoArray +); + +impl FieldElement { + /// Create a FieldElement from a `crypto_bigint::U256`. + /// + /// This will reduce the `U256` by the modulus, into a member of the field. + #[deprecated] + pub const fn from_u256(u256: &crypto_bigint_05::U256) -> Self { + const MODULUS: crypto_bigint::U256 = crypto_bigint::U256::from_be_hex( + "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed", + ); + let mut u256 = crypto_bigint::U256::from_words(*u256.as_words()); + loop { + let result = FieldElement::from_bytes(&u256.to_le_bytes()); + if let Some(result) = result { + return result; + } + u256 = u256.wrapping_sub(&MODULUS); + } + } + + /// Create a `FieldElement` from the reduction of a 512-bit number. + /// + /// The bytes are interpreted in little-endian format. + #[deprecated] + pub fn wide_reduce(value: [u8; 64]) -> Self { + >::from_uniform_bytes(&value) + } +} From a141deaf36821691c8e726734d17de1ec9f7a4a9 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Wed, 3 Sep 2025 12:25:37 -0400 Subject: [PATCH 14/15] 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`. --- Cargo.lock | 186 ++++++------ Cargo.toml | 3 - coordinator/Cargo.toml | 2 - coordinator/src/dkg_confirmation.rs | 13 +- coordinator/src/main.rs | 6 +- coordinator/src/substrate.rs | 4 +- coordinator/src/tributary.rs | 14 +- coordinator/tributary-sdk/src/blockchain.rs | 10 +- coordinator/tributary-sdk/src/lib.rs | 8 +- coordinator/tributary-sdk/src/mempool.rs | 10 +- .../tributary-sdk/src/tendermint/mod.rs | 25 +- .../tributary-sdk/src/tendermint/tx.rs | 4 +- coordinator/tributary-sdk/src/tests/block.rs | 11 +- .../tributary-sdk/src/tests/blockchain.rs | 16 +- .../tributary-sdk/src/tests/mempool.rs | 8 +- .../src/tests/transaction/mod.rs | 24 +- .../src/tests/transaction/signed.rs | 4 +- .../src/tests/transaction/tendermint.rs | 9 +- coordinator/tributary-sdk/src/transaction.rs | 12 +- coordinator/tributary/src/transaction.rs | 20 +- crypto/ciphersuite/Cargo.toml | 15 +- crypto/ciphersuite/kp256/Cargo.toml | 2 +- crypto/ciphersuite/kp256/src/lib.rs | 15 +- crypto/ciphersuite/src/lib.rs | 156 ++++++---- crypto/dalek-ff-group/Cargo.toml | 14 +- crypto/dalek-ff-group/src/ciphersuite.rs | 69 +++-- crypto/dalek-ff-group/src/lib.rs | 277 +++--------------- crypto/dkg/dealer/src/lib.rs | 4 +- crypto/dkg/evrf/Cargo.toml | 13 +- crypto/dkg/evrf/src/curves.rs | 27 +- crypto/dkg/evrf/src/lib.rs | 68 +++-- crypto/dkg/evrf/src/proof/mod.rs | 119 ++++---- crypto/dkg/evrf/src/tests/mod.rs | 36 +-- crypto/dkg/evrf/src/tests/proof.rs | 10 +- crypto/dkg/evrf/src/utils.rs | 4 +- crypto/dkg/musig/src/tests.rs | 16 +- crypto/dkg/recovery/src/lib.rs | 4 +- crypto/dkg/src/lib.rs | 22 +- crypto/ed448/Cargo.toml | 2 +- crypto/ed448/src/ciphersuite.rs | 29 +- crypto/ed448/src/lib.rs | 1 - crypto/embedwards25519/Cargo.toml | 5 +- crypto/embedwards25519/src/lib.rs | 60 ++-- crypto/frost/Cargo.toml | 4 +- crypto/frost/src/curve/dalek.rs | 51 +++- crypto/frost/src/curve/ed448.rs | 14 +- crypto/frost/src/curve/kp256.rs | 12 +- crypto/frost/src/curve/mod.rs | 25 +- crypto/frost/src/sign.rs | 7 +- crypto/frost/src/tests/literal/ed448.rs | 2 +- crypto/frost/src/tests/mod.rs | 4 +- crypto/schnorr/Cargo.toml | 1 + crypto/schnorr/src/aggregate.rs | 73 ++--- crypto/schnorr/src/lib.rs | 14 +- crypto/schnorr/src/tests/mod.rs | 30 +- crypto/schnorr/src/tests/rfc8032.rs | 2 +- crypto/schnorrkel/Cargo.toml | 3 +- crypto/schnorrkel/src/lib.rs | 10 +- crypto/secq256k1/Cargo.toml | 6 +- crypto/secq256k1/src/lib.rs | 44 +-- crypto/short-weierstrass/Cargo.toml | 2 +- crypto/short-weierstrass/src/projective.rs | 4 +- crypto/transcript/Cargo.toml | 8 +- crypto/transcript/src/lib.rs | 31 +- message-queue/Cargo.toml | 2 +- message-queue/src/client.rs | 21 +- message-queue/src/main.rs | 8 +- message-queue/src/messages.rs | 28 +- networks/bitcoin/Cargo.toml | 2 +- networks/bitcoin/src/crypto.rs | 8 +- networks/bitcoin/src/wallet/mod.rs | 4 +- orchestration/src/coordinator.rs | 6 +- orchestration/src/main.rs | 22 +- orchestration/src/message_queue.rs | 10 +- orchestration/src/processor.rs | 6 +- orchestration/src/serai.rs | 4 +- patches/ciphersuite/Cargo.toml | 8 +- patches/ciphersuite/src/lib.rs | 30 +- patches/dalek-ff-group/Cargo.toml | 2 +- processor/bin/Cargo.toml | 2 +- processor/bin/src/lib.rs | 8 +- processor/bitcoin/src/key_gen.rs | 6 +- processor/bitcoin/src/primitives/block.rs | 4 +- processor/bitcoin/src/primitives/mod.rs | 4 +- processor/bitcoin/src/primitives/output.rs | 12 +- processor/bitcoin/src/scan.rs | 16 +- processor/bitcoin/src/scheduler.rs | 8 +- processor/ethereum/src/key_gen.rs | 8 +- processor/ethereum/src/primitives/block.rs | 4 +- processor/ethereum/src/primitives/machine.rs | 8 +- processor/ethereum/src/primitives/output.rs | 10 +- processor/key-gen/Cargo.toml | 4 +- processor/key-gen/src/db.rs | 17 +- processor/key-gen/src/lib.rs | 49 ++-- processor/monero/Cargo.toml | 4 +- processor/monero/src/primitives/block.rs | 4 +- processor/monero/src/primitives/mod.rs | 6 +- processor/monero/src/primitives/output.rs | 8 +- processor/monero/src/scheduler.rs | 8 +- processor/scheduler/primitives/src/lib.rs | 2 +- processor/signers/Cargo.toml | 3 +- processor/signers/src/batch/mod.rs | 3 +- processor/signers/src/cosign/mod.rs | 3 +- processor/signers/src/lib.rs | 5 +- processor/signers/src/slash_report.rs | 3 +- processor/signers/src/wrapped_schnorrkel.rs | 2 +- processor/view-keys/src/lib.rs | 2 +- substrate/client/Cargo.toml | 6 +- substrate/client/src/networks/monero.rs | 8 +- .../client/tests/common/genesis_liquidity.rs | 13 +- .../client/tests/common/validator_sets.rs | 15 +- substrate/node/Cargo.toml | 2 +- substrate/node/src/rpc.rs | 15 +- substrate/primitives/src/account.rs | 2 +- substrate/validator-sets/pallet/src/tests.rs | 9 +- .../validator-sets/primitives/src/lib.rs | 5 +- tests/coordinator/src/lib.rs | 12 +- tests/coordinator/src/tests/batch.rs | 6 +- tests/coordinator/src/tests/key_gen.rs | 10 +- tests/coordinator/src/tests/mod.rs | 4 +- tests/message-queue/src/lib.rs | 11 +- tests/no-std/Cargo.toml | 2 +- tests/processor/src/lib.rs | 6 +- tests/processor/src/networks.rs | 10 +- 124 files changed, 1003 insertions(+), 1211 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dcb7b37d..2bce2dd9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1526,11 +1526,11 @@ dependencies = [ [[package]] name = "blake2" -version = "0.11.0-rc.0" +version = "0.11.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce3d950855224a23299348898f8a2127860e1afea78df3e51deebb89d1cb2f8f" +checksum = "1edac47499deef695d9431bf241c75ea29f4cf3dcb78d39e19b31515e4ad3b08" dependencies = [ - "digest 0.11.0-rc.0", + "digest 0.11.0-rc.1", ] [[package]] @@ -1588,11 +1588,12 @@ dependencies = [ [[package]] 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" -checksum = "a229bfd78e4827c91b9b95784f69492c1b77c1ab75a45a8a037b139215086f94" +checksum = "e9ef36a6fcdb072aa548f3da057640ec10859eb4e91ddf526ee648d50c76a949" dependencies = [ "hybrid-array", + "zeroize", ] [[package]] @@ -1922,13 +1923,11 @@ dependencies = [ name = "ciphersuite" version = "0.4.2" dependencies = [ - "digest 0.11.0-rc.0", + "digest 0.11.0-rc.1", "ff", "ff-group-tests", - "flexible-transcript", "group", "hex", - "rand_core 0.6.4", "std-shims", "subtle", "zeroize", @@ -1939,7 +1938,9 @@ name = "ciphersuite" version = "0.4.99" dependencies = [ "ciphersuite 0.4.2", - "dalek-ff-group 0.4.6", + "dalek-ff-group 0.5.0", + "std-shims", + "zeroize", ] [[package]] @@ -1952,7 +1953,7 @@ dependencies = [ "k256", "p256", "rand_core 0.6.4", - "sha2 0.11.0-rc.0", + "sha2 0.11.0-rc.2", "zeroize", ] @@ -2345,9 +2346,9 @@ dependencies = [ [[package]] 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" -checksum = "8a23fa214dea9efd4dacee5a5614646b30216ae0f05d4bb51bafb50e9da1c5be" +checksum = "6a8235645834fbc6832939736ce2f2d08192652269e11010a6240f61b908a1c6" dependencies = [ "hybrid-array", ] @@ -2371,6 +2372,7 @@ dependencies = [ "cpufeatures", "curve25519-dalek-derive", "digest 0.10.7", + "ff", "fiat-crypto", "group", "rand_core 0.6.4", @@ -2454,28 +2456,27 @@ dependencies = [ [[package]] name = "dalek-ff-group" -version = "0.4.6" +version = "0.5.0" dependencies = [ + "blake2 0.11.0-rc.2", "ciphersuite 0.4.2", - "crypto-bigint 0.6.1", "curve25519-dalek", - "digest 0.10.7", "ff-group-tests", "hex", "prime-field", "rand_core 0.6.4", - "sha2 0.11.0-rc.0", + "sha2 0.11.0-rc.2", "subtle", "zeroize", ] [[package]] name = "dalek-ff-group" -version = "0.4.99" +version = "0.5.99" dependencies = [ "crypto-bigint 0.5.5", "crypto-bigint 0.6.1", - "dalek-ff-group 0.4.6", + "dalek-ff-group 0.5.0", "prime-field", ] @@ -2551,7 +2552,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976" dependencies = [ "data-encoding", - "syn 2.0.106", + "syn 1.0.109", ] [[package]] @@ -2714,13 +2715,14 @@ dependencies = [ [[package]] name = "digest" -version = "0.11.0-rc.0" +version = "0.11.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460dd7f37e4950526b54a5a6b1f41b6c8e763c58eb9a8fc8fc05ba5c2f44ca7b" +checksum = "3a4aae35a0fcbe22ff1be50fe96df72002d5a4a6fb4aae9193cf2da0daa36da2" dependencies = [ - "block-buffer 0.11.0-rc.4", - "crypto-common 0.2.0-rc.3", + "block-buffer 0.11.0-rc.5", + "crypto-common 0.2.0-rc.4", "subtle", + "zeroize", ] [[package]] @@ -2801,10 +2803,10 @@ dependencies = [ name = "dkg-evrf" version = "0.1.0" dependencies = [ - "blake2 0.11.0-rc.0", + "blake2 0.11.0-rc.2", "ciphersuite 0.4.2", "ciphersuite-kp256", - "dalek-ff-group 0.4.6", + "dalek-ff-group 0.5.0", "dkg", "dkg-recovery", "ec-divisors", @@ -2829,7 +2831,7 @@ name = "dkg-musig" version = "0.6.0" dependencies = [ "ciphersuite 0.4.2", - "dalek-ff-group 0.4.6", + "dalek-ff-group 0.5.0", "dkg", "dkg-recovery", "multiexp", @@ -2920,9 +2922,9 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] name = "ec-divisors" 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 = [ - "dalek-ff-group 0.4.99", + "dalek-ff-group 0.5.99", "ff", "group", "rand_core 0.6.4", @@ -3031,10 +3033,9 @@ dependencies = [ name = "embedwards25519" version = "0.1.0" dependencies = [ - "blake2 0.11.0-rc.0", + "blake2 0.11.0-rc.2", "ciphersuite 0.4.2", "curve25519-dalek", - "dalek-ff-group 0.4.6", "ff-group-tests", "generalized-bulletproofs-ec-gadgets", "hex", @@ -3321,10 +3322,10 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" name = "flexible-transcript" version = "0.3.4" dependencies = [ - "blake2 0.11.0-rc.0", - "digest 0.11.0-rc.0", + "blake2 0.11.0-rc.2", + "digest 0.11.0-rc.1", "merlin", - "sha2 0.11.0-rc.0", + "sha2 0.11.0-rc.2", "zeroize", ] @@ -3544,7 +3545,6 @@ name = "frost-schnorrkel" version = "0.2.0" dependencies = [ "ciphersuite 0.4.2", - "dalek-ff-group 0.4.6", "flexible-transcript", "group", "modular-frost", @@ -3771,7 +3771,7 @@ dependencies = [ [[package]] name = "generalized-bulletproofs" 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 = [ "blake2 0.10.6", "ciphersuite 0.4.99", @@ -3786,7 +3786,7 @@ dependencies = [ [[package]] name = "generalized-bulletproofs-circuit-abstraction" 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 = [ "ciphersuite 0.4.99", "generalized-bulletproofs", @@ -3797,7 +3797,7 @@ dependencies = [ [[package]] name = "generalized-bulletproofs-ec-gadgets" 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 = [ "ciphersuite 0.4.99", "generalized-bulletproofs-circuit-abstraction", @@ -4221,8 +4221,9 @@ checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" [[package]] name = "hybrid-array" -version = "0.3.1" -source = "git+https://github.com/kayabaNerve/hybrid-array?rev=8caa508976c93696a67f40734537c91be7cecd96#8caa508976c93696a67f40734537c91be7cecd96" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe39a812f039072707ce38020acbab2f769087952eddd9e2b890f37654b2349" dependencies = [ "typenum", ] @@ -6020,7 +6021,7 @@ dependencies = [ "hex", "prime-field", "rand_core 0.6.4", - "sha3 0.11.0-rc.0", + "sha3 0.11.0-rc.2", "zeroize", ] @@ -6079,11 +6080,11 @@ dependencies = [ [[package]] name = "modular-frost" -version = "0.10.1" +version = "0.11.0" dependencies = [ "ciphersuite 0.4.2", "ciphersuite-kp256", - "dalek-ff-group 0.4.6", + "dalek-ff-group 0.5.0", "dkg", "dkg-dealer", "dkg-recovery", @@ -6105,7 +6106,7 @@ dependencies = [ [[package]] name = "monero-address" 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 = [ "curve25519-dalek", "monero-base58", @@ -6117,7 +6118,7 @@ dependencies = [ [[package]] name = "monero-base58" 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 = [ "monero-primitives", "std-shims", @@ -6126,7 +6127,7 @@ dependencies = [ [[package]] name = "monero-borromean" 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 = [ "curve25519-dalek", "monero-generators", @@ -6139,7 +6140,7 @@ dependencies = [ [[package]] name = "monero-bulletproofs" 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 = [ "curve25519-dalek", "monero-generators", @@ -6154,10 +6155,10 @@ dependencies = [ [[package]] name = "monero-clsag" 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 = [ "curve25519-dalek", - "dalek-ff-group 0.4.99", + "dalek-ff-group 0.5.99", "flexible-transcript", "group", "modular-frost", @@ -6175,11 +6176,11 @@ dependencies = [ [[package]] name = "monero-generators" 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 = [ "crypto-bigint 0.5.5", "curve25519-dalek", - "dalek-ff-group 0.4.99", + "dalek-ff-group 0.5.99", "group", "monero-io", "sha3 0.10.8", @@ -6190,16 +6191,17 @@ dependencies = [ [[package]] name = "monero-io" 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 = [ "curve25519-dalek", "std-shims", + "zeroize", ] [[package]] name = "monero-mlsag" 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 = [ "curve25519-dalek", "monero-generators", @@ -6213,7 +6215,7 @@ dependencies = [ [[package]] name = "monero-oxide" 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 = [ "curve25519-dalek", "hex-literal", @@ -6231,7 +6233,7 @@ dependencies = [ [[package]] name = "monero-primitives" 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 = [ "curve25519-dalek", "monero-generators", @@ -6244,7 +6246,7 @@ dependencies = [ [[package]] name = "monero-rpc" 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 = [ "curve25519-dalek", "hex", @@ -6260,7 +6262,7 @@ dependencies = [ [[package]] name = "monero-simple-request-rpc" 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 = [ "digest_auth", "hex", @@ -6273,10 +6275,10 @@ dependencies = [ [[package]] name = "monero-wallet" 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 = [ "curve25519-dalek", - "dalek-ff-group 0.4.99", + "dalek-ff-group 0.5.99", "flexible-transcript", "hex", "modular-frost", @@ -6327,7 +6329,7 @@ dependencies = [ name = "multiexp" version = "0.4.2" dependencies = [ - "dalek-ff-group 0.4.6", + "dalek-ff-group 0.5.0", "ff", "group", "k256", @@ -6688,7 +6690,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ - "proc-macro-crate 3.2.0", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 2.0.106", @@ -9465,7 +9467,8 @@ name = "schnorr-signatures" version = "0.5.2" dependencies = [ "ciphersuite 0.4.2", - "dalek-ff-group 0.4.6", + "dalek-ff-group 0.5.0", + "digest 0.11.0-rc.1", "flexible-transcript", "hex", "multiexp", @@ -9602,7 +9605,7 @@ dependencies = [ "k256", "prime-field", "rand_core 0.6.4", - "sha2 0.11.0-rc.0", + "sha2 0.11.0-rc.2", "short-weierstrass", "std-shims", ] @@ -9746,11 +9749,11 @@ dependencies = [ "async-lock", "bitcoin", "bitvec", - "blake2 0.11.0-rc.0", + "blake2 0.11.0-rc.2", "borsh", "ciphersuite 0.4.2", "ciphersuite-kp256", - "dalek-ff-group 0.4.6", + "dalek-ff-group 0.5.0", "dkg-musig", "dockertest", "frame-system", @@ -9808,20 +9811,18 @@ name = "serai-coordinator" version = "0.1.0" dependencies = [ "bitvec", - "blake2 0.11.0-rc.0", + "blake2 0.11.0-rc.2", "borsh", "ciphersuite 0.4.2", - "dalek-ff-group 0.4.6", + "dalek-ff-group 0.5.0", "dkg-musig", "env_logger", - "flexible-transcript", "frost-schnorrkel", "hex", "log", "modular-frost", "parity-scale-codec", "rand_core 0.6.4", - "schnorr-signatures", "schnorrkel", "serai-client", "serai-coordinator-libp2p-p2p", @@ -9845,7 +9846,7 @@ name = "serai-coordinator-libp2p-p2p" version = "0.1.0" dependencies = [ "async-trait", - "blake2 0.11.0-rc.0", + "blake2 0.11.0-rc.2", "borsh", "futures-util", "hex", @@ -9899,10 +9900,10 @@ dependencies = [ name = "serai-coordinator-tributary" version = "0.1.0" dependencies = [ - "blake2 0.11.0-rc.0", + "blake2 0.11.0-rc.2", "borsh", "ciphersuite 0.4.2", - "dalek-ff-group 0.4.6", + "dalek-ff-group 0.5.0", "dkg", "log", "parity-scale-codec", @@ -9922,7 +9923,7 @@ dependencies = [ name = "serai-cosign" version = "0.1.0" dependencies = [ - "blake2 0.11.0-rc.0", + "blake2 0.11.0-rc.2", "borsh", "log", "parity-scale-codec", @@ -10166,7 +10167,7 @@ version = "0.1.0" dependencies = [ "borsh", "ciphersuite 0.4.2", - "dalek-ff-group 0.4.6", + "dalek-ff-group 0.5.0", "env_logger", "flexible-transcript", "hex", @@ -10187,7 +10188,7 @@ name = "serai-message-queue-tests" version = "0.1.0" dependencies = [ "ciphersuite 0.4.2", - "dalek-ff-group 0.4.6", + "dalek-ff-group 0.5.0", "dockertest", "hex", "rand_core 0.6.4", @@ -10204,7 +10205,7 @@ version = "0.1.0" dependencies = [ "borsh", "ciphersuite 0.4.2", - "dalek-ff-group 0.4.6", + "dalek-ff-group 0.5.0", "dkg-evrf", "log", "modular-frost", @@ -10234,7 +10235,7 @@ version = "0.1.0" dependencies = [ "bitcoin-serai", "ciphersuite 0.4.2", - "dalek-ff-group 0.4.6", + "dalek-ff-group 0.5.0", "dkg", "dkg-evrf", "embedwards25519", @@ -10256,7 +10257,7 @@ dependencies = [ "ciphersuite-kp256", "clap", "curve25519-dalek", - "dalek-ff-group 0.4.6", + "dalek-ff-group 0.5.0", "embedwards25519", "frame-benchmarking", "futures-util", @@ -10307,7 +10308,7 @@ name = "serai-orchestrator" version = "0.0.1" dependencies = [ "ciphersuite 0.4.2", - "dalek-ff-group 0.4.6", + "dalek-ff-group 0.5.0", "embedwards25519", "flexible-transcript", "hex", @@ -10462,12 +10463,14 @@ dependencies = [ name = "serai-processor-key-gen" version = "0.1.0" dependencies = [ - "blake2 0.11.0-rc.0", + "blake2 0.11.0-rc.2", "borsh", "ciphersuite 0.4.2", "dkg-evrf", + "embedwards25519", "flexible-transcript", "log", + "modular-frost", "parity-scale-codec", "rand_chacha 0.3.1", "rand_core 0.6.4", @@ -10510,7 +10513,7 @@ dependencies = [ name = "serai-processor-scanner" version = "0.1.0" dependencies = [ - "blake2 0.11.0-rc.0", + "blake2 0.11.0-rc.2", "borsh", "group", "hex", @@ -10542,10 +10545,9 @@ dependencies = [ name = "serai-processor-signers" version = "0.1.0" dependencies = [ - "blake2 0.11.0-rc.0", + "blake2 0.11.0-rc.2", "borsh", "ciphersuite 0.4.2", - "dalek-ff-group 0.4.6", "frost-schnorrkel", "log", "modular-frost", @@ -10723,7 +10725,7 @@ version = "0.1.0" dependencies = [ "bitvec", "ciphersuite 0.4.2", - "dalek-ff-group 0.4.6", + "dalek-ff-group 0.5.0", "dkg-musig", "frame-support", "frame-system", @@ -10758,7 +10760,7 @@ version = "0.1.0" dependencies = [ "borsh", "ciphersuite 0.4.2", - "dalek-ff-group 0.4.6", + "dalek-ff-group 0.5.0", "dkg-musig", "parity-scale-codec", "scale-info", @@ -10943,13 +10945,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.11.0-rc.0" +version = "0.11.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa1d2e6b3cc4e43a8258a9a3b17aa5dfd2cc5186c7024bba8a64aa65b2c71a59" +checksum = "d1e3878ab0f98e35b2df35fe53201d088299b41a6bb63e3e34dada2ac4abd924" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.11.0-rc.0", + "digest 0.11.0-rc.1", ] [[package]] @@ -10964,11 +10966,11 @@ dependencies = [ [[package]] name = "sha3" -version = "0.11.0-rc.0" +version = "0.11.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e6a92fd180fd205defdc0b78288ce847c7309d329fd6647a814567e67db50e" +checksum = "b3c185ed8cff82204014bfaa7649b4c945ca565e03c0534eb33a8d2a01572932" dependencies = [ - "digest 0.11.0-rc.0", + "digest 0.11.0-rc.1", "keccak 0.2.0-pre.0", ] @@ -12609,9 +12611,9 @@ dependencies = [ name = "tributary-sdk" version = "0.1.0" dependencies = [ - "blake2 0.11.0-rc.0", + "blake2 0.11.0-rc.2", "ciphersuite 0.4.2", - "dalek-ff-group 0.4.6", + "dalek-ff-group 0.5.0", "flexible-transcript", "futures-channel", "futures-util", diff --git a/Cargo.toml b/Cargo.toml index fb7d1912..a5443344 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -228,9 +228,6 @@ directories-next = { path = "patches/directories-next" } k256 = { git = "https://github.com/kayabaNerve/elliptic-curves", rev = "4994c9ab163781a88cd4a49beae812a89a44e8c3" } p256 = { git = "https://github.com/kayabaNerve/elliptic-curves", rev = "4994c9ab163781a88cd4a49beae812a89a44e8c3" } -# https://github.com/RustCrypto/hybrid-array/issues/131 -hybrid-array = { git = "https://github.com/kayabaNerve/hybrid-array", rev = "8caa508976c93696a67f40734537c91be7cecd96" } - [workspace.lints.clippy] unwrap_or_default = "allow" map_unwrap_or = "allow" diff --git a/coordinator/Cargo.toml b/coordinator/Cargo.toml index fdb019d3..8d24a666 100644 --- a/coordinator/Cargo.toml +++ b/coordinator/Cargo.toml @@ -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"] } 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"] } 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"] } frost = { package = "modular-frost", path = "../crypto/frost" } frost-schnorrkel = { path = "../crypto/schnorrkel" } diff --git a/coordinator/src/dkg_confirmation.rs b/coordinator/src/dkg_confirmation.rs index fac044e0..a26d9e6e 100644 --- a/coordinator/src/dkg_confirmation.rs +++ b/coordinator/src/dkg_confirmation.rs @@ -3,11 +3,10 @@ use std::{boxed::Box, collections::HashMap}; use zeroize::Zeroizing; use rand_core::OsRng; -use ciphersuite::{group::GroupEncoding, Ciphersuite}; -use dalek_ff_group::Ristretto; +use ciphersuite::{group::GroupEncoding, *}; use dkg::{Participant, musig}; use frost_schnorrkel::{ - frost::{FrostError, sign::*}, + frost::{curve::Ristretto, FrostError, sign::*}, Schnorrkel, }; @@ -31,7 +30,7 @@ fn schnorrkel() -> Schnorrkel { fn our_i( set: &NewSetInformation, - key: &Zeroizing<::F>, + key: &Zeroizing<::F>, data: &HashMap>, ) -> Participant { let public = SeraiAddress((Ristretto::generator() * key.deref()).to_bytes()); @@ -125,7 +124,7 @@ pub(crate) struct ConfirmDkgTask { set: NewSetInformation, tributary_db: TD, - key: Zeroizing<::F>, + key: Zeroizing<::F>, signer: Option, } @@ -134,7 +133,7 @@ impl ConfirmDkgTask { db: CD, set: NewSetInformation, tributary_db: TD, - key: Zeroizing<::F>, + key: Zeroizing<::F>, ) -> Self { Self { db, set, tributary_db, key, signer: None } } @@ -153,7 +152,7 @@ impl ConfirmDkgTask { db: &mut CD, set: ExternalValidatorSet, attempt: u32, - key: Zeroizing<::F>, + key: Zeroizing<::F>, signer: &mut Option, ) { // Perform the preprocess diff --git a/coordinator/src/main.rs b/coordinator/src/main.rs index 39a2b91e..c0e9f578 100644 --- a/coordinator/src/main.rs +++ b/coordinator/src/main.rs @@ -7,7 +7,7 @@ use rand_core::{RngCore, OsRng}; use dalek_ff_group::Ristretto; use ciphersuite::{ group::{ff::PrimeField, GroupEncoding}, - Ciphersuite, + *, }; use borsh::BorshDeserialize; @@ -352,7 +352,7 @@ async fn main() { let mut key_bytes = [0; 32]; key_bytes.copy_from_slice(&key_vec); key_vec.zeroize(); - let key = Zeroizing::new(::F::from_repr(key_bytes).unwrap()); + let key = Zeroizing::new(::F::from_repr(key_bytes).unwrap()); key_bytes.zeroize(); key }; @@ -439,7 +439,7 @@ async fn main() { EphemeralEventStream::new( db.clone(), serai.clone(), - SeraiAddress((::generator() * serai_key.deref()).to_bytes()), + SeraiAddress((::generator() * serai_key.deref()).to_bytes()), ) .continually_run(substrate_ephemeral_task_def, vec![substrate_task]), ); diff --git a/coordinator/src/substrate.rs b/coordinator/src/substrate.rs index ad8b890b..4e8a66a6 100644 --- a/coordinator/src/substrate.rs +++ b/coordinator/src/substrate.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use zeroize::Zeroizing; -use ciphersuite::Ciphersuite; +use ciphersuite::*; use dalek_ff_group::Ristretto; use tokio::sync::mpsc; @@ -23,7 +23,7 @@ use serai_coordinator_p2p::P2p; use crate::{Db, KeySet}; pub(crate) struct SubstrateTask { - pub(crate) serai_key: Zeroizing<::F>, + pub(crate) serai_key: Zeroizing<::F>, pub(crate) db: Db, pub(crate) message_queue: Arc, pub(crate) p2p: P, diff --git a/coordinator/src/tributary.rs b/coordinator/src/tributary.rs index c5ecdf5b..41e8a1c8 100644 --- a/coordinator/src/tributary.rs +++ b/coordinator/src/tributary.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use zeroize::Zeroizing; use rand_core::OsRng; use blake2::{digest::typenum::U32, Digest, Blake2s}; -use ciphersuite::Ciphersuite; +use ciphersuite::*; use dalek_ff_group::Ristretto; use tokio::sync::mpsc; @@ -160,7 +160,7 @@ impl ContinuallyRan #[must_use] async fn add_signed_unsigned_transaction( tributary: &Tributary, - key: &Zeroizing<::F>, + key: &Zeroizing<::F>, mut tx: Transaction, ) -> bool { // If this is a signed transaction, sign it @@ -213,7 +213,7 @@ async fn add_with_recognition_check( set: ExternalValidatorSet, tributary_db: &mut TD, tributary: &Tributary, - key: &Zeroizing<::F>, + key: &Zeroizing<::F>, tx: Transaction, ) -> bool { let kind = tx.kind(); @@ -252,7 +252,7 @@ pub(crate) struct AddTributaryTransactionsTask tributary_db: TD, tributary: Tributary, set: NewSetInformation, - key: Zeroizing<::F>, + key: Zeroizing<::F>, } impl ContinuallyRan for AddTributaryTransactionsTask { type Error = DoesNotError; @@ -382,7 +382,7 @@ pub(crate) struct SignSlashReportTask { tributary_db: TD, tributary: Tributary, set: NewSetInformation, - key: Zeroizing<::F>, + key: Zeroizing<::F>, } impl ContinuallyRan for SignSlashReportTask { type Error = DoesNotError; @@ -470,7 +470,7 @@ pub(crate) async fn spawn_tributary( p2p: P, p2p_add_tributary: &mpsc::UnboundedSender<(ExternalValidatorSet, Tributary)>, set: NewSetInformation, - serai_key: Zeroizing<::F>, + serai_key: Zeroizing<::F>, ) { // Don't spawn retired Tributaries if crate::db::RetiredTributary::get(&db, set.set.network).map(|session| session.0) >= @@ -490,7 +490,7 @@ pub(crate) async fn spawn_tributary( let mut tributary_validators = Vec::with_capacity(set.validators.len()); for (validator, weight) in set.validators.iter().copied() { - let validator_key = ::read_G(&mut validator.0.as_slice()) + let validator_key = ::read_G(&mut validator.0.as_slice()) .expect("Serai validator had an invalid public key"); let weight = u64::from(weight); tributary_validators.push((validator_key, weight)); diff --git a/coordinator/tributary-sdk/src/blockchain.rs b/coordinator/tributary-sdk/src/blockchain.rs index 682e8472..55259fc1 100644 --- a/coordinator/tributary-sdk/src/blockchain.rs +++ b/coordinator/tributary-sdk/src/blockchain.rs @@ -1,7 +1,7 @@ use std::collections::{VecDeque, HashSet}; use dalek_ff_group::Ristretto; -use ciphersuite::{group::GroupEncoding, Ciphersuite}; +use ciphersuite::{group::GroupEncoding, *}; use serai_db::{Get, DbTxn, Db}; @@ -21,7 +21,7 @@ pub(crate) struct Blockchain { block_number: u64, tip: [u8; 32], - participants: HashSet<::G>, + participants: HashSet<::G>, provided: ProvidedTransactions, mempool: Mempool, @@ -56,7 +56,7 @@ impl Blockchain { } fn next_nonce_key( genesis: &[u8; 32], - signer: &::G, + signer: &::G, order: &[u8], ) -> Vec { D::key( @@ -69,7 +69,7 @@ impl Blockchain { pub(crate) fn new( db: D, genesis: [u8; 32], - participants: &[::G], + participants: &[::G], ) -> Self { let mut res = Self { db: Some(db.clone()), @@ -196,7 +196,7 @@ impl Blockchain { pub(crate) fn next_nonce( &self, - signer: &::G, + signer: &::G, order: &[u8], ) -> Option { if let Some(next_nonce) = self.mempool.next_nonce_in_mempool(signer, order.to_vec()) { diff --git a/coordinator/tributary-sdk/src/lib.rs b/coordinator/tributary-sdk/src/lib.rs index 0f45482e..442853d6 100644 --- a/coordinator/tributary-sdk/src/lib.rs +++ b/coordinator/tributary-sdk/src/lib.rs @@ -3,7 +3,7 @@ use std::{sync::Arc, io}; use zeroize::Zeroizing; -use ciphersuite::Ciphersuite; +use ciphersuite::*; use dalek_ff_group::Ristretto; use scale::Decode; @@ -162,8 +162,8 @@ impl Tributary { db: D, genesis: [u8; 32], start_time: u64, - key: Zeroizing<::F>, - validators: Vec<(::G, u64)>, + key: Zeroizing<::F>, + validators: Vec<(::G, u64)>, p2p: P, ) -> Option { log::info!("new Tributary with genesis {}", hex::encode(genesis)); @@ -235,7 +235,7 @@ impl Tributary { pub async fn next_nonce( &self, - signer: &::G, + signer: &::G, order: &[u8], ) -> Option { self.network.blockchain.read().await.next_nonce(signer, order) diff --git a/coordinator/tributary-sdk/src/mempool.rs b/coordinator/tributary-sdk/src/mempool.rs index 19c73dba..f0d99a42 100644 --- a/coordinator/tributary-sdk/src/mempool.rs +++ b/coordinator/tributary-sdk/src/mempool.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use dalek_ff_group::Ristretto; -use ciphersuite::Ciphersuite; +use ciphersuite::*; use serai_db::{DbTxn, Db}; @@ -21,9 +21,9 @@ pub(crate) struct Mempool { db: D, genesis: [u8; 32], - last_nonce_in_mempool: HashMap<(::G, Vec), u32>, + last_nonce_in_mempool: HashMap<(::G, Vec), u32>, txs: HashMap<[u8; 32], Transaction>, - txs_per_signer: HashMap<::G, u32>, + txs_per_signer: HashMap<::G, u32>, } impl Mempool { @@ -107,7 +107,7 @@ impl Mempool { // Returns Ok(true) if new, Ok(false) if an already present unsigned, or the error. pub(crate) fn add< N: Network, - F: FnOnce(::G, Vec) -> Option, + F: FnOnce(::G, Vec) -> Option, >( &mut self, blockchain_next_nonce: F, @@ -179,7 +179,7 @@ impl Mempool { // Returns None if the mempool doesn't have a nonce tracked. pub(crate) fn next_nonce_in_mempool( &self, - signer: &::G, + signer: &::G, order: Vec, ) -> Option { self.last_nonce_in_mempool.get(&(*signer, order)).copied().map(|nonce| nonce + 1) diff --git a/coordinator/tributary-sdk/src/tendermint/mod.rs b/coordinator/tributary-sdk/src/tendermint/mod.rs index 373aacff..b1939341 100644 --- a/coordinator/tributary-sdk/src/tendermint/mod.rs +++ b/coordinator/tributary-sdk/src/tendermint/mod.rs @@ -10,11 +10,8 @@ use rand_chacha::ChaCha12Rng; use transcript::{Transcript, RecommendedTranscript}; use ciphersuite::{ - group::{ - GroupEncoding, - ff::{Field, PrimeField}, - }, - Ciphersuite, + group::{ff::PrimeField, GroupEncoding}, + *, }; use dalek_ff_group::Ristretto; use schnorr::{ @@ -51,24 +48,26 @@ fn challenge( key: [u8; 32], nonce: &[u8], msg: &[u8], -) -> ::F { +) -> ::F { let mut transcript = RecommendedTranscript::new(b"Tributary Chain Tendermint Message"); transcript.append_message(b"genesis", genesis); transcript.append_message(b"key", key); transcript.append_message(b"nonce", nonce); transcript.append_message(b"message", msg); - ::F::from_bytes_mod_order_wide(&transcript.challenge(b"schnorr").into()) + ::F::from_bytes_mod_order_wide( + &transcript.challenge(b"schnorr").into(), + ) } #[derive(Clone, PartialEq, Eq, Debug)] pub struct Signer { genesis: [u8; 32], - key: Zeroizing<::F>, + key: Zeroizing<::F>, } impl Signer { - pub(crate) fn new(genesis: [u8; 32], key: Zeroizing<::F>) -> Signer { + pub(crate) fn new(genesis: [u8; 32], key: Zeroizing<::F>) -> Signer { Signer { genesis, key } } } @@ -101,10 +100,10 @@ impl SignerTrait for Signer { assert_eq!(nonce_ref, [0; 64].as_ref()); let nonce = - Zeroizing::new(::F::from_bytes_mod_order_wide(&nonce_arr)); + Zeroizing::new(::F::from_bytes_mod_order_wide(&nonce_arr)); nonce_arr.zeroize(); - assert!(!bool::from(nonce.ct_eq(&::F::ZERO))); + assert!(!bool::from(nonce.ct_eq(&::F::ZERO))); let challenge = challenge( self.genesis, @@ -133,7 +132,7 @@ pub struct Validators { impl Validators { pub(crate) fn new( genesis: [u8; 32], - validators: Vec<(::G, u64)>, + validators: Vec<(::G, u64)>, ) -> Option { let mut total_weight = 0; let mut weights = HashMap::new(); @@ -220,7 +219,7 @@ impl SignatureScheme for Validators { signers .iter() .zip(challenges) - .map(|(s, c)| (::read_G(&mut s.as_slice()).unwrap(), c)) + .map(|(s, c)| (::read_G(&mut s.as_slice()).unwrap(), c)) .collect::>() .as_slice(), ) diff --git a/coordinator/tributary-sdk/src/tendermint/tx.rs b/coordinator/tributary-sdk/src/tendermint/tx.rs index 61d2e21a..3b60381b 100644 --- a/coordinator/tributary-sdk/src/tendermint/tx.rs +++ b/coordinator/tributary-sdk/src/tendermint/tx.rs @@ -5,7 +5,7 @@ use scale::{Encode, Decode, IoReader}; use blake2::{Digest, Blake2s256}; use dalek_ff_group::Ristretto; -use ciphersuite::Ciphersuite; +use ciphersuite::*; use crate::{ transaction::{Transaction, TransactionKind, TransactionError}, @@ -50,7 +50,7 @@ impl Transaction for TendermintTx { Blake2s256::digest(self.serialize()).into() } - fn sig_hash(&self, _genesis: [u8; 32]) -> ::F { + fn sig_hash(&self, _genesis: [u8; 32]) -> ::F { match self { TendermintTx::SlashEvidence(_) => panic!("sig_hash called on slash evidence transaction"), } diff --git a/coordinator/tributary-sdk/src/tests/block.rs b/coordinator/tributary-sdk/src/tests/block.rs index ab8ed215..7e84aee0 100644 --- a/coordinator/tributary-sdk/src/tests/block.rs +++ b/coordinator/tributary-sdk/src/tests/block.rs @@ -3,10 +3,7 @@ use std::{sync::Arc, io, collections::HashMap, fmt::Debug}; use blake2::{Digest, Blake2s256}; use dalek_ff_group::Ristretto; -use ciphersuite::{ - group::{ff::Field, Group}, - Ciphersuite, -}; +use ciphersuite::{group::Group, *}; use schnorr::SchnorrSignature; use serai_db::MemDb; @@ -32,11 +29,11 @@ impl NonceTransaction { nonce, distinguisher, Signed { - signer: ::G::identity(), + signer: ::G::identity(), nonce, signature: SchnorrSignature:: { - R: ::G::identity(), - s: ::F::ZERO, + R: ::G::identity(), + s: ::F::ZERO, }, }, ) diff --git a/coordinator/tributary-sdk/src/tests/blockchain.rs b/coordinator/tributary-sdk/src/tests/blockchain.rs index b08d92f8..14478d9e 100644 --- a/coordinator/tributary-sdk/src/tests/blockchain.rs +++ b/coordinator/tributary-sdk/src/tests/blockchain.rs @@ -11,7 +11,7 @@ use rand::rngs::OsRng; use blake2::{Digest, Blake2s256}; use dalek_ff_group::Ristretto; -use ciphersuite::{group::ff::Field, Ciphersuite}; +use ciphersuite::*; use serai_db::{DbTxn, Db, MemDb}; @@ -31,7 +31,7 @@ type N = TendermintNetwork; fn new_blockchain( genesis: [u8; 32], - participants: &[::G], + participants: &[::G], ) -> (MemDb, Blockchain) { let db = MemDb::new(); let blockchain = Blockchain::new(db.clone(), genesis, participants); @@ -82,7 +82,7 @@ fn invalid_block() { assert!(blockchain.verify_block::(&block, &validators, false).is_err()); } - let key = Zeroizing::new(::F::random(&mut OsRng)); + let key = Zeroizing::new(::F::random(&mut OsRng)); let tx = crate::tests::signed_transaction(&mut OsRng, genesis, &key, 0); // Not a participant @@ -134,7 +134,7 @@ fn invalid_block() { blockchain.verify_block::(&block, &validators, false).unwrap(); match &mut block.transactions[0] { Transaction::Application(tx) => { - tx.1.signature.s += ::F::ONE; + tx.1.signature.s += ::F::ONE; } _ => panic!("non-signed tx found"), } @@ -150,7 +150,7 @@ fn invalid_block() { fn signed_transaction() { let genesis = new_genesis(); let validators = Arc::new(Validators::new(genesis, vec![]).unwrap()); - let key = Zeroizing::new(::F::random(&mut OsRng)); + let key = Zeroizing::new(::F::random(&mut OsRng)); let tx = crate::tests::signed_transaction(&mut OsRng, genesis, &key, 0); let signer = tx.1.signer; @@ -339,7 +339,7 @@ fn provided_transaction() { #[tokio::test] async fn tendermint_evidence_tx() { let genesis = new_genesis(); - let key = Zeroizing::new(::F::random(&mut OsRng)); + let key = Zeroizing::new(::F::random(&mut OsRng)); let signer = Signer::new(genesis, key.clone()); let signer_id = Ristretto::generator() * key.deref(); 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> = vec![]; let mut signers = vec![]; for _ in 0 .. 5 { - let key = Zeroizing::new(::F::random(&mut OsRng)); + let key = Zeroizing::new(::F::random(&mut OsRng)); let signer = Signer::new(genesis, key.clone()); let signer_id = Ristretto::generator() * key.deref(); signers.push((signer_id, 1)); @@ -446,7 +446,7 @@ async fn block_tx_ordering() { } let genesis = new_genesis(); - let key = Zeroizing::new(::F::random(&mut OsRng)); + let key = Zeroizing::new(::F::random(&mut OsRng)); // signer let signer = crate::tests::signed_transaction(&mut OsRng, genesis, &key, 0).1.signer; diff --git a/coordinator/tributary-sdk/src/tests/mempool.rs b/coordinator/tributary-sdk/src/tests/mempool.rs index 77a68dac..5921d971 100644 --- a/coordinator/tributary-sdk/src/tests/mempool.rs +++ b/coordinator/tributary-sdk/src/tests/mempool.rs @@ -4,7 +4,7 @@ use zeroize::Zeroizing; use rand::{RngCore, rngs::OsRng}; use dalek_ff_group::Ristretto; -use ciphersuite::{group::ff::Field, Ciphersuite}; +use ciphersuite::*; use tendermint::ext::Commit; @@ -33,7 +33,7 @@ async fn mempool_addition() { Some(Commit::> { end_time: 0, validators: vec![], signature: vec![] }) }; let unsigned_in_chain = |_: [u8; 32]| false; - let key = Zeroizing::new(::F::random(&mut OsRng)); + let key = Zeroizing::new(::F::random(&mut OsRng)); let first_tx = signed_transaction(&mut OsRng, genesis, &key, 0); 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 // blockchain's - let second_key = Zeroizing::new(::F::random(&mut OsRng)); + let second_key = Zeroizing::new(::F::random(&mut OsRng)); let tx = signed_transaction(&mut OsRng, genesis, &second_key, 2); let second_signer = tx.1.signer; assert_eq!(mempool.next_nonce_in_mempool(&second_signer, vec![]), None); @@ -165,7 +165,7 @@ fn too_many_mempool() { Some(Commit::> { end_time: 0, validators: vec![], signature: vec![] }) }; let unsigned_in_chain = |_: [u8; 32]| false; - let key = Zeroizing::new(::F::random(&mut OsRng)); + let key = Zeroizing::new(::F::random(&mut OsRng)); // We should be able to add transactions up to the limit for i in 0 .. ACCOUNT_MEMPOOL_LIMIT { diff --git a/coordinator/tributary-sdk/src/tests/transaction/mod.rs b/coordinator/tributary-sdk/src/tests/transaction/mod.rs index 26fb0dac..deaf2e56 100644 --- a/coordinator/tributary-sdk/src/tests/transaction/mod.rs +++ b/coordinator/tributary-sdk/src/tests/transaction/mod.rs @@ -7,10 +7,7 @@ use rand::{RngCore, CryptoRng, rngs::OsRng}; use blake2::{Digest, Blake2s256}; use dalek_ff_group::Ristretto; -use ciphersuite::{ - group::{ff::Field, Group}, - Ciphersuite, -}; +use ciphersuite::{group::Group, *}; use schnorr::SchnorrSignature; use scale::Encode; @@ -34,11 +31,11 @@ mod tendermint; pub fn random_signed(rng: &mut R) -> Signed { Signed { - signer: ::G::random(&mut *rng), + signer: ::G::random(&mut *rng), nonce: u32::try_from(rng.next_u64() >> 32 >> 1).unwrap(), signature: SchnorrSignature:: { - R: ::G::random(&mut *rng), - s: ::F::random(rng), + R: ::G::random(&mut *rng), + s: ::F::random(rng), }, } } @@ -137,18 +134,18 @@ impl Transaction for SignedTransaction { pub fn signed_transaction( rng: &mut R, genesis: [u8; 32], - key: &Zeroizing<::F>, + key: &Zeroizing<::F>, nonce: u32, ) -> SignedTransaction { let mut data = vec![0; 512]; rng.fill_bytes(&mut data); - let signer = ::generator() * **key; + let signer = ::generator() * **key; let mut tx = SignedTransaction(data, Signed { signer, nonce, signature: random_signed(rng).signature }); - let sig_nonce = Zeroizing::new(::F::random(rng)); + let sig_nonce = Zeroizing::new(::F::random(rng)); tx.1.signature.R = Ristretto::generator() * sig_nonce.deref(); tx.1.signature = SchnorrSignature::sign(key, sig_nonce, tx.sig_hash(genesis)); @@ -163,7 +160,7 @@ pub fn random_signed_transaction( let mut genesis = [0; 32]; rng.fill_bytes(&mut genesis); - let key = Zeroizing::new(::F::random(&mut *rng)); + let key = Zeroizing::new(::F::random(&mut *rng)); // Shift over an additional bit to ensure it won't overflow when incremented 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) // signer let genesis = new_genesis(); let signer = - Signer::new(genesis, Zeroizing::new(::F::random(&mut OsRng))); + Signer::new(genesis, Zeroizing::new(::F::random(&mut OsRng))); let validator_id = signer.validator_id().await.unwrap(); // schema - let signer_pub = - ::read_G::<&[u8]>(&mut validator_id.as_slice()).unwrap(); + let signer_pub = ::read_G::<&[u8]>(&mut validator_id.as_slice()).unwrap(); let validators = Arc::new(Validators::new(genesis, vec![(signer_pub, 1)]).unwrap()); (genesis, signer, validator_id, validators) diff --git a/coordinator/tributary-sdk/src/tests/transaction/signed.rs b/coordinator/tributary-sdk/src/tests/transaction/signed.rs index aa1e250e..ea1ce912 100644 --- a/coordinator/tributary-sdk/src/tests/transaction/signed.rs +++ b/coordinator/tributary-sdk/src/tests/transaction/signed.rs @@ -3,7 +3,7 @@ use rand::rngs::OsRng; use blake2::{Digest, Blake2s256}; use dalek_ff_group::Ristretto; -use ciphersuite::{group::ff::Field, Ciphersuite}; +use ciphersuite::*; use crate::{ ReadWrite, @@ -69,7 +69,7 @@ fn signed_transaction() { } { let mut tx = tx.clone(); - tx.1.signature.s += ::F::ONE; + tx.1.signature.s += ::F::ONE; assert!(verify_transaction(&tx, genesis, &mut |_, _| Some(tx.1.nonce)).is_err()); } diff --git a/coordinator/tributary-sdk/src/tests/transaction/tendermint.rs b/coordinator/tributary-sdk/src/tests/transaction/tendermint.rs index ca7decc0..30685099 100644 --- a/coordinator/tributary-sdk/src/tests/transaction/tendermint.rs +++ b/coordinator/tributary-sdk/src/tests/transaction/tendermint.rs @@ -4,7 +4,7 @@ use zeroize::Zeroizing; use rand::{RngCore, rngs::OsRng}; use dalek_ff_group::Ristretto; -use ciphersuite::{Ciphersuite, group::ff::Field}; +use ciphersuite::*; 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 signer_2 = - Signer::new(genesis, Zeroizing::new(::F::random(&mut OsRng))); + Signer::new(genesis, Zeroizing::new(::F::random(&mut OsRng))); let signed_id_2 = signer_2.validator_id().await.unwrap(); let signed_2 = signed_from_data::( 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 - let signer_pub = - ::read_G::<&[u8]>(&mut signer_id.as_slice()).unwrap(); + let signer_pub = ::read_G::<&[u8]>(&mut signer_id.as_slice()).unwrap(); let signer_pub_2 = - ::read_G::<&[u8]>(&mut signed_id_2.as_slice()).unwrap(); + ::read_G::<&[u8]>(&mut signed_id_2.as_slice()).unwrap(); let validators = Arc::new(Validators::new(genesis, vec![(signer_pub, 1), (signer_pub_2, 1)]).unwrap()); diff --git a/coordinator/tributary-sdk/src/transaction.rs b/coordinator/tributary-sdk/src/transaction.rs index 36adef11..9132834c 100644 --- a/coordinator/tributary-sdk/src/transaction.rs +++ b/coordinator/tributary-sdk/src/transaction.rs @@ -8,7 +8,7 @@ use blake2::{Digest, Blake2b512}; use ciphersuite::{ group::{Group, GroupEncoding}, - Ciphersuite, + *, }; use dalek_ff_group::Ristretto; use schnorr::SchnorrSignature; @@ -43,7 +43,7 @@ pub enum TransactionError { /// Data for a signed transaction. #[derive(Clone, PartialEq, Eq, Debug)] pub struct Signed { - pub signer: ::G, + pub signer: ::G, pub nonce: u32, pub signature: SchnorrSignature, } @@ -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. /// /// Panics if called on non-signed transactions. - fn sig_hash(&self, genesis: [u8; 32]) -> ::F { + fn sig_hash(&self, genesis: [u8; 32]) -> ::F { match self.kind() { TransactionKind::Signed(order, Signed { signature, .. }) => { - ::F::from_bytes_mod_order_wide( + ::F::from_bytes_mod_order_wide( &Blake2b512::digest( [ b"Tributary Signed Transaction", @@ -182,8 +182,8 @@ pub trait Transaction: 'static + Send + Sync + Clone + Eq + Debug + ReadWrite { } } -pub trait GAIN: FnMut(&::G, &[u8]) -> Option {} -impl::G, &[u8]) -> Option> GAIN for F {} +pub trait GAIN: FnMut(&::G, &[u8]) -> Option {} +impl::G, &[u8]) -> Option> GAIN for F {} pub(crate) fn verify_transaction( tx: &T, diff --git a/coordinator/tributary/src/transaction.rs b/coordinator/tributary/src/transaction.rs index 11f77d7c..8fbb43c3 100644 --- a/coordinator/tributary/src/transaction.rs +++ b/coordinator/tributary/src/transaction.rs @@ -6,8 +6,8 @@ use rand_core::{RngCore, CryptoRng}; use blake2::{digest::typenum::U32, Digest, Blake2b}; use ciphersuite::{ - group::{ff::Field, Group, GroupEncoding}, - Ciphersuite, + group::{Group, GroupEncoding}, + *, }; use dalek_ff_group::Ristretto; use schnorr::SchnorrSignature; @@ -52,7 +52,7 @@ impl SigningProtocolRound { #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct Signed { /// The signer. - signer: ::G, + signer: ::G, /// The signature. signature: SchnorrSignature, } @@ -73,7 +73,7 @@ impl BorshDeserialize for Signed { impl Signed { /// Fetch the signer. - pub(crate) fn signer(&self) -> ::G { + pub(crate) fn signer(&self) -> ::G { self.signer } @@ -86,10 +86,10 @@ impl Signed { impl Default for Signed { fn default() -> Self { Self { - signer: ::G::identity(), + signer: ::G::identity(), signature: SchnorrSignature { - R: ::G::identity(), - s: ::F::ZERO, + R: ::G::identity(), + s: ::F::ZERO, }, } } @@ -356,7 +356,7 @@ impl Transaction { &mut self, rng: &mut R, genesis: [u8; 32], - key: &Zeroizing<::F>, + key: &Zeroizing<::F>, ) { fn signed(tx: &mut Transaction) -> &mut Signed { #[allow(clippy::match_same_arms)] // This doesn't make semantic sense here @@ -380,13 +380,13 @@ impl Transaction { } // Decide the nonce to sign with - let sig_nonce = Zeroizing::new(::F::random(rng)); + let sig_nonce = Zeroizing::new(::F::random(rng)); { // Set the signer and the nonce let signed = signed(self); signed.signer = Ristretto::generator() * key.deref(); - signed.signature.R = ::generator() * sig_nonce.deref(); + signed.signature.R = ::generator() * sig_nonce.deref(); } // Get the signature hash (which now includes `R || A` making it valid as the challenge) diff --git a/crypto/ciphersuite/Cargo.toml b/crypto/ciphersuite/Cargo.toml index f17e417f..d1911369 100644 --- a/crypto/ciphersuite/Cargo.toml +++ b/crypto/ciphersuite/Cargo.toml @@ -17,15 +17,12 @@ rustdoc-args = ["--cfg", "docsrs"] workspace = true [dependencies] -std-shims = { path = "../../common/std-shims", version = "^0.1.1", default-features = false, optional = true } - -rand_core = { version = "0.6", default-features = false } +std-shims = { path = "../../common/std-shims", version = "0.1.4", default-features = false, optional = true } zeroize = { version = "^1.5", default-features = false, features = ["derive"] } subtle = { version = "^2.4", default-features = false } -digest = { version = "0.11.0-rc.0", default-features = false, features = ["block-api"] } -transcript = { package = "flexible-transcript", path = "../transcript", version = "^0.3.2", default-features = false } +digest = { version = "0.11.0-rc.1", default-features = false } ff = { version = "0.13", default-features = false, features = ["bits"] } group = { version = "0.13", default-features = false } @@ -33,24 +30,18 @@ group = { version = "0.13", default-features = false } [dev-dependencies] 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" } [features] -alloc = ["std-shims", "digest/alloc", "ff/alloc"] +alloc = ["std-shims", "zeroize/alloc", "digest/alloc", "ff/alloc"] std = [ "alloc", "std-shims/std", - "rand_core/std", - "zeroize/std", "subtle/std", - "transcript/std", - "ff/std", ] diff --git a/crypto/ciphersuite/kp256/Cargo.toml b/crypto/ciphersuite/kp256/Cargo.toml index ff4df971..e4f0cd0e 100644 --- a/crypto/ciphersuite/kp256/Cargo.toml +++ b/crypto/ciphersuite/kp256/Cargo.toml @@ -21,7 +21,7 @@ rand_core = { version = "0.6", default-features = false } 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"] } k256 = { version = "^0.13.1", default-features = false, features = ["arithmetic", "bits", "hash2curve"] } diff --git a/crypto/ciphersuite/kp256/src/lib.rs b/crypto/ciphersuite/kp256/src/lib.rs index 4ff57a0b..c9f5c681 100644 --- a/crypto/ciphersuite/kp256/src/lib.rs +++ b/crypto/ciphersuite/kp256/src/lib.rs @@ -5,7 +5,7 @@ use zeroize::Zeroize; use sha2::Sha512; -use ciphersuite::Ciphersuite; +use ciphersuite::{WrappedGroup, Id, WithPreferredHash, GroupCanonicalEncoding}; pub use k256; pub use p256; @@ -18,17 +18,20 @@ macro_rules! kp_curve { $Ciphersuite: ident, $ID: literal ) => { - impl Ciphersuite for $Ciphersuite { + impl WrappedGroup for $Ciphersuite { type F = $lib::Scalar; type G = $lib::ProjectivePoint; - type H = Sha512; - - const ID: &'static [u8] = $ID; - fn generator() -> Self::G { $lib::ProjectivePoint::GENERATOR } } + impl Id for $Ciphersuite { + const ID: &'static [u8] = $ID; + } + impl WithPreferredHash for $Ciphersuite { + type H = Sha512; + } + impl GroupCanonicalEncoding for $Ciphersuite {} }; } diff --git a/crypto/ciphersuite/src/lib.rs b/crypto/ciphersuite/src/lib.rs index 7e37c561..4816565b 100644 --- a/crypto/ciphersuite/src/lib.rs +++ b/crypto/ciphersuite/src/lib.rs @@ -9,22 +9,18 @@ use std_shims::prelude::*; #[cfg(feature = "alloc")] use std_shims::io::{self, Read}; -use rand_core::{RngCore, CryptoRng}; - +use subtle::{CtOption, ConstantTimeEq, ConditionallySelectable}; use zeroize::Zeroize; -use subtle::ConstantTimeEq; pub use digest; -use digest::{array::ArraySize, block_api::BlockSizeUser, OutputSizeUser, Digest, HashMarker}; -use transcript::SecureDigest; +use digest::{array::ArraySize, OutputSizeUser, Digest, HashMarker}; pub use group; use group::{ - ff::{Field, PrimeField, PrimeFieldBits}, + ff::{PrimeField, PrimeFieldBits}, Group, GroupOps, prime::PrimeGroup, }; -#[cfg(feature = "alloc")] use group::GroupEncoding; pub trait FromUniformBytes { @@ -36,74 +32,118 @@ impl> FromUniformBytes<[u8; N] } } -/// Unified trait defining a ciphersuite around an elliptic curve. -pub trait Ciphersuite: +/// A marker trait for fields which fleshes them out a bit more. +pub trait F: PrimeField + PrimeFieldBits + Zeroize {} +impl 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 { /// Scalar field element type. - // This is available via G::Scalar yet `C::G::Scalar` is ambiguous, forcing horrific accesses - type F: PrimeField - + PrimeFieldBits - + Zeroize - + FromUniformBytes<<::OutputSize as ArraySize>::ArrayType>; + // This is available via `G::Scalar` yet `WG::G::Scalar` is ambiguous, forcing horrific accesses + type F: F; /// Group element type. - type G: Group + GroupOps + PrimeGroup + Zeroize + ConstantTimeEq; - /// 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]; - + type G: Group + G; /// 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; +} +impl> WrappedGroup for Gr { + type F = ::Scalar; + type G = Gr; + fn generator() -> Self::G { + ::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<<::OutputSize as ArraySize>::ArrayType>, +> +{ + type H: Send + Clone + Digest + HashMarker; #[allow(non_snake_case)] fn hash_to_F(data: &[u8]) -> Self::F { Self::F::from_uniform_bytes(&Self::H::digest(data).into()) } +} - /// Generate a random non-zero scalar. - #[allow(non_snake_case)] - fn random_nonzero_F(rng: &mut R) -> Self::F { - let mut res; - 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(reader: &mut R) -> io::Result { - let mut encoding = ::Repr::default(); - reader.read_exact(encoding.as_mut())?; - - // ff mandates this is canonical - let res = Option::::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. +/// A group which always encodes points canonically and supports decoding points while checking +/// they have a canonical encoding. +pub trait GroupCanonicalEncoding: WrappedGroup { + /// Decode a point from its canonical encoding. /// - /// The provided implementation is safe so long as `GroupEncoding::to_bytes` always returns a - /// canonical serialization. + /// Returns `None` if the point was invalid or not the encoding wasn't canonical. + /// + /// If `::from_bytes` already only accepts canonical encodings, this + /// SHOULD be overriden with `::from_bytes(bytes)`. + fn from_canonical_bytes(bytes: &::Repr) -> CtOption { + 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(reader: &mut R) -> io::Result { + let mut bytes = ::Repr::default(); + reader.read_exact(bytes.as_mut())?; + + // `ff` mandates this is canonical + let res = Option::::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")] #[allow(non_snake_case)] fn read_G(reader: &mut R) -> io::Result { - let mut encoding = ::Repr::default(); - reader.read_exact(encoding.as_mut())?; + let mut bytes = ::Repr::default(); + reader.read_exact(bytes.as_mut())?; - let point = Option::::from(Self::G::from_bytes(&encoding)) + let res = Option::::from(Self::from_canonical_bytes(&bytes)) .ok_or_else(|| io::Error::other("invalid point"))?; - if point.to_bytes().as_ref() != encoding.as_ref() { - Err(io::Error::other("non-canonical point"))?; - } - Ok(point) + bytes.as_mut().zeroize(); + + Ok(res) } } +impl GroupIo for Gr {} + +/// Unified trait defining a ciphersuite around an elliptic curve. +pub trait Ciphersuite: Id + WithPreferredHash + GroupCanonicalEncoding {} +impl Ciphersuite for C {} diff --git a/crypto/dalek-ff-group/Cargo.toml b/crypto/dalek-ff-group/Cargo.toml index 9937a700..ea2f323b 100644 --- a/crypto/dalek-ff-group/Cargo.toml +++ b/crypto/dalek-ff-group/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dalek-ff-group" -version = "0.4.6" +version = "0.5.0" description = "ff/group bindings around curve25519-dalek" license = "MIT" 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 } -digest = { version = "0.10", default-features = false } -sha2 = { version = "0.11.0-rc.0", default-features = false } +sha2 = { version = "0.11.0-rc.2", default-features = false, features = ["zeroize"] } +blake2 = { version = "0.11.0-rc.2", default-features = false, features = ["zeroize"] } prime-field = { path = "../prime-field", 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", "precomputed-tables"] } +curve25519-dalek = { version = ">= 4.0, < 4.2", default-features = false, features = ["zeroize", "digest", "group-bits", "precomputed-tables"] } [dev-dependencies] hex = "0.4" @@ -38,6 +36,6 @@ rand_core = { version = "0.6", default-features = false, features = ["std"] } ff-group-tests = { path = "../ff-group-tests" } [features] -alloc = ["zeroize/alloc", "digest/alloc", "prime-field/alloc", "ciphersuite/alloc", "crypto-bigint/alloc", "curve25519-dalek/alloc"] -std = ["alloc", "zeroize/std", "subtle/std", "rand_core/std", "digest/std", "prime-field/std", "ciphersuite/std"] +alloc = ["zeroize/alloc", "prime-field/alloc", "ciphersuite/alloc", "curve25519-dalek/alloc"] +std = ["alloc", "zeroize/std", "subtle/std", "rand_core/std", "prime-field/std", "ciphersuite/std"] default = ["std"] diff --git a/crypto/dalek-ff-group/src/ciphersuite.rs b/crypto/dalek-ff-group/src/ciphersuite.rs index 137d032f..783be14e 100644 --- a/crypto/dalek-ff-group/src/ciphersuite.rs +++ b/crypto/dalek-ff-group/src/ciphersuite.rs @@ -1,49 +1,48 @@ use zeroize::Zeroize; use sha2::Sha512; +use blake2::Blake2b512; -use ciphersuite::{group::Group, Ciphersuite}; +use ::ciphersuite::{group::Group, *}; -use crate::Scalar; - -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() - } - } - }; -} +use crate::*; /// Ciphersuite for Ristretto. #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] pub struct Ristretto; -dalek_curve!("ristretto", Ristretto, RistrettoPoint, b"ristretto"); -#[test] -fn test_ristretto() { - ff_group_tests::group::test_prime_group_bits::<_, RistrettoPoint>(&mut rand_core::OsRng); +impl WrappedGroup for Ristretto { + type F = Scalar; + type G = RistrettoPoint; + fn generator() -> Self::G { + ::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: &::Repr) -> CtOption { + Self::G::from_bytes(bytes) + } } -/// Ciphersuite for Ed25519, inspired by RFC-8032. +/// Ciphersuite for Ed25519. #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] pub struct Ed25519; -dalek_curve!("ed25519", Ed25519, EdwardsPoint, b"edwards25519"); -#[test] -fn test_ed25519() { - ff_group_tests::group::test_prime_group_bits::<_, EdwardsPoint>(&mut rand_core::OsRng); +impl WrappedGroup for Ed25519 { + type F = Scalar; + type G = EdwardsPoint; + fn generator() -> Self::G { + ::generator() + } } +impl Id for Ed25519 { + const ID: &[u8] = b"ed25519"; +} +impl WithPreferredHash for Ed25519 { + type H = Sha512; +} +impl GroupCanonicalEncoding for Ed25519 {} diff --git a/crypto/dalek-ff-group/src/lib.rs b/crypto/dalek-ff-group/src/lib.rs index 4f58b437..563ae40a 100644 --- a/crypto/dalek-ff-group/src/lib.rs +++ b/crypto/dalek-ff-group/src/lib.rs @@ -7,7 +7,7 @@ use core::{ borrow::Borrow, ops::{Deref, Add, AddAssign, Sub, SubAssign, Neg, Mul, MulAssign}, - iter::{Iterator, Sum, Product}, + iter::{Iterator, Sum}, hash::{Hash, Hasher}, }; @@ -15,25 +15,16 @@ use zeroize::Zeroize; use subtle::{ConstantTimeEq, ConditionallySelectable}; use rand_core::RngCore; -use digest::{consts::U64, Digest, HashMarker}; use subtle::{Choice, CtOption}; -pub use curve25519_dalek as dalek; - -use dalek::{ - constants::{self, BASEPOINT_ORDER}, - scalar::Scalar as DScalar, - edwards::{EdwardsPoint as DEdwardsPoint, EdwardsBasepointTable, CompressedEdwardsY}, - ristretto::{RistrettoPoint as DRistrettoPoint, RistrettoBasepointTable, CompressedRistretto}, +use curve25519_dalek::{ + edwards::{EdwardsPoint as DEdwardsPoint, CompressedEdwardsY}, + ristretto::{RistrettoPoint as DRistrettoPoint, CompressedRistretto}, }; -pub use constants::{ED25519_BASEPOINT_TABLE, RISTRETTO_BASEPOINT_TABLE}; +pub use curve25519_dalek::Scalar; -use ::ciphersuite::group::{ - ff::{Field, PrimeField, FieldBits, PrimeFieldBits, FromUniformBytes}, - Group, GroupEncoding, - prime::PrimeGroup, -}; +use ::ciphersuite::group::{Group, GroupEncoding, prime::PrimeGroup}; mod ciphersuite; 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 { ( @@ -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 { ($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 { 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 + 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(::random(rng)) - } - - fn square(&self) -> Self { - Self(self.0.square()) - } - fn double(&self) -> Self { - Self(self.0.double()) - } - fn invert(&self) -> CtOption { - ::invert(&self.0).map(Self) - } - - fn sqrt(&self) -> CtOption { - 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 = ::MODULUS; - - const NUM_BITS: u32 = ::NUM_BITS; - const CAPACITY: u32 = ::CAPACITY; - - const TWO_INV: Scalar = Scalar(::TWO_INV); - - const MULTIPLICATIVE_GENERATOR: Scalar = - Scalar(::MULTIPLICATIVE_GENERATOR); - const S: u32 = ::S; - - const ROOT_OF_UNITY: Scalar = Scalar(::ROOT_OF_UNITY); - const ROOT_OF_UNITY_INV: Scalar = Scalar(::ROOT_OF_UNITY_INV); - - const DELTA: Scalar = Scalar(::DELTA); - - fn from_repr(bytes: [u8; 32]) -> CtOption { - ::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.to_repr().into() - } - - fn char_le_bits() -> FieldBits { - 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 for Scalar { - fn sum>(iter: I) -> Scalar { - Self(DScalar::sum(iter)) - } -} - -impl<'a> Sum<&'a Scalar> for Scalar { - fn sum>(iter: I) -> Scalar { - Self(DScalar::sum(iter)) - } -} - -impl Product for Scalar { - fn product>(iter: I) -> Scalar { - Self(DScalar::product(iter)) - } -} - -impl<'a> Product<&'a Scalar> for Scalar { - fn product>(iter: I) -> Scalar { - Self(DScalar::product(iter)) - } -} - macro_rules! dalek_group { ( $Point: ident, @@ -347,9 +183,6 @@ macro_rules! dalek_group { $Table: ident, $DCompressed: ident, - - $BASEPOINT_POINT: ident, - $BASEPOINT_TABLE: ident ) => { /// Wrapper around the dalek Point type. /// @@ -363,9 +196,6 @@ macro_rules! dalek_group { constant_time!($Point, $DPoint); 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 { fn sum>(iter: I) -> $Point { Self($DPoint::sum(iter)) @@ -396,7 +226,7 @@ macro_rules! dalek_group { Self($DPoint::identity()) } fn generator() -> Self { - $BASEPOINT_POINT + Self(<$DPoint as Group>::generator()) } fn is_identity(&self) -> Choice { self.0.ct_eq(&$DPoint::identity()) @@ -430,13 +260,6 @@ macro_rules! dalek_group { impl PrimeGroup for $Point {} - impl Mul for &$Table { - type Output = $Point; - fn mul(self, b: Scalar) -> $Point { - $Point(&b.0 * self) - } - } - // 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 // use cases for public key -> value lookups @@ -456,24 +279,14 @@ dalek_group!( |point: DEdwardsPoint| point.is_torsion_free(), EdwardsBasepointTable, CompressedEdwardsY, - ED25519_BASEPOINT_POINT, - ED25519_BASEPOINT_TABLE ); -impl EdwardsPoint { - pub fn mul_by_cofactor(&self) -> EdwardsPoint { - EdwardsPoint(self.0.mul_by_cofactor()) - } -} - dalek_group!( RistrettoPoint, DRistrettoPoint, |_| true, RistrettoBasepointTable, CompressedRistretto, - RISTRETTO_BASEPOINT_POINT, - RISTRETTO_BASEPOINT_TABLE ); #[test] diff --git a/crypto/dkg/dealer/src/lib.rs b/crypto/dkg/dealer/src/lib.rs index f00d5d85..ce375a4b 100644 --- a/crypto/dkg/dealer/src/lib.rs +++ b/crypto/dkg/dealer/src/lib.rs @@ -10,12 +10,12 @@ use rand_core::{RngCore, CryptoRng}; use ciphersuite::{ group::ff::{Field, PrimeField}, - Ciphersuite, + GroupIo, Id, }; pub use dkg::*; /// Create a key via a dealer key generation protocol. -pub fn key_gen( +pub fn key_gen( rng: &mut R, threshold: u16, participants: u16, diff --git a/crypto/dkg/evrf/Cargo.toml b/crypto/dkg/evrf/Cargo.toml index 7db35571..21c2e8de 100644 --- a/crypto/dkg/evrf/Cargo.toml +++ b/crypto/dkg/evrf/Cargo.toml @@ -31,13 +31,13 @@ ciphersuite = { path = "../../ciphersuite", version = "^0.4.1", default-features multiexp = { path = "../../multiexp", version = "0.4", default-features = false } 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 } -generalized-bulletproofs = { git = "https://github.com/monero-oxide/monero-oxide", rev = "a6f8797007e768488568b821435cf5006517a962", default-features = false } -ec-divisors = { 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 = "a6f8797007e768488568b821435cf5006517a962", default-features = false } -generalized-bulletproofs-ec-gadgets = { 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 = "7216a2e84c7671c167c3d81eafe0d2b1f418f102", 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 = "7216a2e84c7671c167c3d81eafe0d2b1f418f102", 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"] } embedwards25519 = { path = "../../embedwards25519", 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" } [features] @@ -86,6 +86,5 @@ std = [ ] secp256k1 = ["ciphersuite-kp256", "secq256k1"] ed25519 = ["dalek-ff-group", "embedwards25519"] -ristretto = ["dalek-ff-group", "embedwards25519"] tests = ["rand_core/getrandom"] default = ["std"] diff --git a/crypto/dkg/evrf/src/curves.rs b/crypto/dkg/evrf/src/curves.rs index 04720662..afaa57d9 100644 --- a/crypto/dkg/evrf/src/curves.rs +++ b/crypto/dkg/evrf/src/curves.rs @@ -17,7 +17,7 @@ type Blake2s256Keyed = Blake2sMac; use ciphersuite::{ group::{ff::FromUniformBytes, GroupEncoding}, - Ciphersuite, + WrappedGroup, Id, GroupIo, }; use ec_divisors::DivisorCurve; @@ -27,10 +27,10 @@ use generalized_bulletproofs_ec_gadgets::*; /// A pair of curves to perform the eVRF with. pub trait Curves { /// The towering curve, for which the resulting key is on. - type ToweringCurve: Ciphersuite>; + type ToweringCurve: Id + GroupIo>; /// The embedded curve which participants represent their public keys over. - type EmbeddedCurve: Ciphersuite< - G: DivisorCurve::F>, + type EmbeddedCurve: GroupIo< + G: DivisorCurve::F>, >; /// The parameters to use the embedded curve with the discrete-log gadget. type EmbeddedCurveParameters: DiscreteLogParameters; @@ -49,14 +49,14 @@ impl Generators { pub fn new(max_threshold: u16, max_participants: u16) -> Generators { let entropy = ::new(&{ let mut key = Array::::KeySize>::default(); - let key_len = key.len().min(::ID.len()); + let key_len = key.len().min(::ID.len()); { let key: &mut [u8] = key.as_mut(); - key[.. key_len].copy_from_slice(&::ID[.. key_len]) + key[.. key_len].copy_from_slice(&::ID[.. key_len]) } key }) - .chain_update(::generator().to_bytes()) + .chain_update(::generator().to_bytes()) .finalize() .into_bytes(); let mut rng = ChaCha20Rng::from_seed(entropy.into()); @@ -71,7 +71,8 @@ impl Generators { h_bold.push(crate::sample_point::(&mut rng)); } Self( - BpGenerators::new(::generator(), h, g_bold, h_bold).unwrap(), + BpGenerators::new(::generator(), h, g_bold, h_bold) + .unwrap(), ) } } @@ -95,13 +96,3 @@ impl Curves for Ed25519 { type EmbeddedCurve = 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; -} diff --git a/crypto/dkg/evrf/src/lib.rs b/crypto/dkg/evrf/src/lib.rs index 93d7b1d5..f5519869 100644 --- a/crypto/dkg/evrf/src/lib.rs +++ b/crypto/dkg/evrf/src/lib.rs @@ -21,7 +21,7 @@ use ciphersuite::{ ff::{Field, PrimeField}, Group, GroupEncoding, }, - Ciphersuite, + WrappedGroup, GroupIo, }; use multiexp::multiexp_vartime; @@ -49,7 +49,7 @@ mod tests; #[derive(Clone, PartialEq, Eq, Debug)] pub struct Participation { proof: Vec, - encrypted_secret_shares: HashMap::F>, + encrypted_secret_shares: HashMap::F>, } impl Participation { @@ -79,7 +79,7 @@ impl Participation { let mut encrypted_secret_shares = HashMap::with_capacity(usize::from(n)); for i in Participant::iter().take(usize::from(n)) { - encrypted_secret_shares.insert(i, ::read_F(reader)?); + encrypted_secret_shares.insert(i, ::read_F(reader)?); } Ok(Self { proof, encrypted_secret_shares }) @@ -151,14 +151,14 @@ pub enum VerifyResult { pub struct Dkg { t: u16, n: u16, - evrf_public_keys: Vec<::G>, - verification_shares: HashMap::G>, + evrf_public_keys: Vec<::G>, + verification_shares: HashMap::G>, #[allow(clippy::type_complexity)] encrypted_secret_shares: HashMap< Participant, HashMap< Participant, - ([::G; 2], ::F), + ([::G; 2], ::F), >, >, } @@ -167,7 +167,7 @@ impl Dkg { // Form the initial transcript for the proofs. fn initial_transcript( invocation: [u8; 32], - evrf_public_keys: &[::G], + evrf_public_keys: &[::G], t: u16, ) -> [u8; 32] { let mut transcript = Blake2s256::new(); @@ -188,8 +188,8 @@ impl Dkg { generators: &Generators, context: [u8; 32], t: u16, - evrf_public_keys: &[::G], - evrf_private_key: &Zeroizing<::F>, + evrf_public_keys: &[::G], + evrf_private_key: &Zeroizing<::F>, ) -> Result, Error> { let Ok(n) = u16::try_from(evrf_public_keys.len()) else { Err(Error::TooManyParticipants { provided: evrf_public_keys.len() })? @@ -202,7 +202,8 @@ impl Dkg { }; // This also ensures the private key is not 0, due to the prior check the identity point wasn't // present - let evrf_public_key = ::generator() * evrf_private_key.deref(); + let evrf_public_key = + ::generator() * evrf_private_key.deref(); if !evrf_public_keys.contains(&evrf_public_key) { Err(Error::NotAParticipant)?; }; @@ -231,7 +232,7 @@ impl Dkg { 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) { - let share = polynomial::<::F>(&coefficients, l); + let share = polynomial::<::F>(&coefficients, l); encrypted_secret_shares.insert(l, *share + *encryption_key); } @@ -243,26 +244,26 @@ impl Dkg { #[allow(clippy::type_complexity)] fn verifiable_encryption_statements( rng: &mut (impl RngCore + CryptoRng), - coefficients: &[::G], - encryption_key_commitments: &[::G], - encrypted_secret_shares: &HashMap::F>, + coefficients: &[::G], + encryption_key_commitments: &[::G], + encrypted_secret_shares: &HashMap::F>, ) -> ( - ::F, - Vec<(::F, ::G)>, + ::F, + Vec<(::F, ::G)>, ) { - let mut g_scalar = ::F::ZERO; + let mut g_scalar = ::F::ZERO; let mut pairs = Vec::with_capacity(coefficients.len() + encryption_key_commitments.len()); // Push on the commitments to the polynomial being secret-shared for coefficient in coefficients { // This uses `0` as we'll add to it later, given its fixed position - pairs.push((::F::ZERO, *coefficient)); + pairs.push((::F::ZERO, *coefficient)); } for (i, encrypted_secret_share) in encrypted_secret_shares { let encryption_key_commitment = encryption_key_commitments[usize::from(u16::from(*i)) - 1]; - let weight = ::F::random(&mut *rng); + let weight = ::F::random(&mut *rng); /* The encrypted secret share scaling `G`, minus the encryption key commitment, minus the @@ -274,7 +275,7 @@ fn verifiable_encryption_statements( pairs.push((weight, encryption_key_commitment)); // Calculate the commitment to the secret share via the commitments to the polynomial { - let i = ::F::from(u64::from(u16::from(*i))); + let i = ::F::from(u64::from(u16::from(*i))); (0 .. coefficients.len()).fold(weight, |exp, j| { pairs[j].0 += exp; exp * i @@ -300,7 +301,7 @@ impl Dkg { generators: &Generators, context: [u8; 32], t: u16, - evrf_public_keys: &[::G], + evrf_public_keys: &[::G], participations: &HashMap>, ) -> Result, Error> { let Ok(n) = u16::try_from(evrf_public_keys.len()) else { @@ -386,7 +387,7 @@ impl Dkg { { let mut share_verification_statements_actual = HashMap::with_capacity(valid.len()); if !{ - let mut g_scalar = ::F::ZERO; + let mut g_scalar = ::F::ZERO; let mut pairs = Vec::with_capacity(valid.len() * (usize::from(t) + evrf_public_keys.len())); for (i, (encrypted_secret_shares, data)) in &valid { let (this_g_scalar, mut these_pairs) = verifiable_encryption_statements::( @@ -417,9 +418,11 @@ impl Dkg { let sum_encrypted_secret_share = sum_encrypted_secret_shares .get(j) .copied() - .unwrap_or(::F::ZERO); - let sum_mask = - sum_masks.get(j).copied().unwrap_or(::G::identity()); + .unwrap_or(::F::ZERO); + let sum_mask = sum_masks + .get(j) + .copied() + .unwrap_or(::G::identity()); sum_encrypted_secret_shares.insert(*j, sum_encrypted_secret_share + enc_share); let j_index = usize::from(u16::from(*j)) - 1; @@ -487,7 +490,7 @@ impl Dkg { for i in Participant::iter().take(usize::from(n)) { verification_shares.insert( i, - (::generator() * sum_encrypted_secret_shares[&i]) - + (::generator() * sum_encrypted_secret_shares[&i]) - sum_masks[&i], ); } @@ -506,9 +509,10 @@ impl Dkg { /// This will return _all_ keys belong to the participant. pub fn keys( &self, - evrf_private_key: &Zeroizing<::F>, + evrf_private_key: &Zeroizing<::F>, ) -> Vec> { - let evrf_public_key = ::generator() * evrf_private_key.deref(); + let evrf_public_key = + ::generator() * evrf_private_key.deref(); let mut is = Vec::with_capacity(1); for (i, evrf_key) in Participant::iter().zip(self.evrf_public_keys.iter()) { if *evrf_key == evrf_public_key { @@ -518,14 +522,14 @@ impl Dkg { let mut res = Vec::with_capacity(is.len()); for i in is { - let mut secret_share = Zeroizing::new(::F::ZERO); + let mut secret_share = Zeroizing::new(::F::ZERO); for shares in self.encrypted_secret_shares.values() { let (ecdh_commitments, encrypted_secret_share) = shares[&i]; - let mut ecdh = Zeroizing::new(::F::ZERO); + let mut ecdh = Zeroizing::new(::F::ZERO); for point in ecdh_commitments { let (mut x, mut y) = - ::G::to_xy(point * evrf_private_key.deref()).unwrap(); + ::G::to_xy(point * evrf_private_key.deref()).unwrap(); *ecdh += x; x.zeroize(); y.zeroize(); @@ -534,7 +538,7 @@ impl Dkg { } debug_assert_eq!( self.verification_shares[&i], - ::G::generator() * secret_share.deref() + ::generator() * secret_share.deref() ); res.push( diff --git a/crypto/dkg/evrf/src/proof/mod.rs b/crypto/dkg/evrf/src/proof/mod.rs index 64318b92..5f852fbc 100644 --- a/crypto/dkg/evrf/src/proof/mod.rs +++ b/crypto/dkg/evrf/src/proof/mod.rs @@ -8,7 +8,7 @@ use zeroize::Zeroizing; use rand_core::{RngCore, CryptoRng, SeedableRng}; use rand_chacha::ChaCha20Rng; -use ciphersuite::{group::ff::Field, Ciphersuite}; +use ciphersuite::{group::ff::Field, WrappedGroup}; use generalized_bulletproofs::{ Generators, BatchVerifier, PedersenCommitment, PedersenVectorCommitment, @@ -28,8 +28,8 @@ mod tape; use tape::*; type EmbeddedPoint = ( - <<::EmbeddedCurve as Ciphersuite>::G as DivisorCurve>::FieldElement, - <<::EmbeddedCurve as Ciphersuite>::G as DivisorCurve>::FieldElement, + <<::EmbeddedCurve as WrappedGroup>::G as DivisorCurve>::FieldElement, + <<::EmbeddedCurve as WrappedGroup>::G as DivisorCurve>::FieldElement, ); #[allow(non_snake_case)] @@ -37,14 +37,15 @@ struct Circuit< 'a, C: Curves, CG: Iterator< - Item = ChallengedGenerator<::F, C::EmbeddedCurveParameters>, + Item = ChallengedGenerator<::F, C::EmbeddedCurveParameters>, >, > { - curve_spec: &'a CurveSpec<<::G as DivisorCurve>::FieldElement>, + curve_spec: &'a CurveSpec<<::G as DivisorCurve>::FieldElement>, circuit: &'a mut BpCircuit, - challenge: DiscreteLogChallenge<::F, C::EmbeddedCurveParameters>, + challenge: + DiscreteLogChallenge<::F, C::EmbeddedCurveParameters>, challenged_G: - ChallengedGenerator<::F, C::EmbeddedCurveParameters>, + ChallengedGenerator<::F, C::EmbeddedCurveParameters>, challenged_generators: &'a mut CG, tape: Tape, pedersen_commitment_tape: PedersenCommitmentTape, @@ -54,7 +55,7 @@ impl< 'a, C: Curves, CG: Iterator< - Item = ChallengedGenerator<::F, C::EmbeddedCurveParameters>, + Item = ChallengedGenerator<::F, C::EmbeddedCurveParameters>, >, > Circuit<'a, C, CG> { @@ -92,7 +93,7 @@ impl< &self.challenge, &challenged_generator, ); - lincomb = lincomb.term(::F::ONE, point.x()); + lincomb = lincomb.term(::F::ONE, point.x()); } /* 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, &challenged_public_key, ); - lincomb = lincomb.term(::F::ONE, point.x()); + lincomb = lincomb.term(::F::ONE, point.x()); debug_assert!(point_with_dlogs.next().is_none()); } @@ -152,20 +153,20 @@ impl< /// The result of proving. pub(super) struct ProveResult { /// The coefficients for use in the DKG. - pub(super) coefficients: Vec::F>>, + pub(super) coefficients: Vec::F>>, /// The masks to encrypt secret shares with. - pub(super) encryption_keys: Vec::F>>, + pub(super) encryption_keys: Vec::F>>, /// The proof itself. pub(super) proof: Vec, } pub(super) struct Verified { /// The commitments to the coefficients used within the DKG. - pub(super) coefficients: Vec<::G>, + pub(super) coefficients: Vec<::G>, /// The ephemeral public keys to perform ECDHs with - pub(super) ecdh_commitments: Vec<[::G; 2]>, + pub(super) ecdh_commitments: Vec<[::G; 2]>, /// The commitments to the masks used to encrypt secret shares with. - pub(super) encryption_key_commitments: Vec<::G>, + pub(super) encryption_key_commitments: Vec<::G>, } impl fmt::Debug for Verified { @@ -175,7 +176,7 @@ impl fmt::Debug for Verified { } type GeneratorTable = generalized_bulletproofs_ec_gadgets::GeneratorTable< - <<::EmbeddedCurve as Ciphersuite>::G as DivisorCurve>::FieldElement, + <<::EmbeddedCurve as WrappedGroup>::G as DivisorCurve>::FieldElement, ::EmbeddedCurveParameters, >; @@ -219,7 +220,7 @@ impl Proof { } fn circuit( - curve_spec: &CurveSpec<<::G as DivisorCurve>::FieldElement>, + curve_spec: &CurveSpec<<::G as DivisorCurve>::FieldElement>, evrf_public_key: EmbeddedPoint, coefficients: usize, ecdh_commitments: &[[EmbeddedPoint; 2]], @@ -281,7 +282,7 @@ impl Proof { fn sample_coefficients_evrf_points( seed: [u8; 32], coefficients: usize, - ) -> Vec<::G> { + ) -> Vec<::G> { let mut rng = ChaCha20Rng::from_seed(seed); let quantity = 2 * coefficients; let mut res = Vec::with_capacity(quantity); @@ -293,28 +294,29 @@ impl Proof { /// Create the required tables for the generators. fn generator_tables( - coefficients_evrf_points: &[::G], - participants: &[<::EmbeddedCurve as Ciphersuite>::G], + coefficients_evrf_points: &[::G], + participants: &[<::EmbeddedCurve as WrappedGroup>::G], ) -> Vec> { let curve_spec = CurveSpec { - a: <::EmbeddedCurve as Ciphersuite>::G::a(), - b: <::EmbeddedCurve as Ciphersuite>::G::b(), + a: <::EmbeddedCurve as WrappedGroup>::G::a(), + b: <::EmbeddedCurve as WrappedGroup>::G::b(), }; let mut generator_tables = Vec::with_capacity(1 + coefficients_evrf_points.len() + participants.len()); { - let (x, y) = - ::G::to_xy(::generator()) - .unwrap(); + let (x, y) = ::G::to_xy( + ::generator(), + ) + .unwrap(); generator_tables.push(GeneratorTable::::new(&curve_spec, x, y)); } for generator in coefficients_evrf_points { - let (x, y) = ::G::to_xy(*generator).unwrap(); + let (x, y) = ::G::to_xy(*generator).unwrap(); generator_tables.push(GeneratorTable::::new(&curve_spec, x, y)); } for generator in participants { - let (x, y) = ::G::to_xy(*generator).unwrap(); + let (x, y) = ::G::to_xy(*generator).unwrap(); generator_tables.push(GeneratorTable::::new(&curve_spec, x, y)); } generator_tables @@ -325,12 +327,12 @@ impl Proof { generators: &Generators, transcript: [u8; 32], coefficients: usize, - participant_public_keys: &[<::EmbeddedCurve as Ciphersuite>::G], - evrf_private_key: &Zeroizing<<::EmbeddedCurve as Ciphersuite>::F>, + participant_public_keys: &[<::EmbeddedCurve as WrappedGroup>::G], + evrf_private_key: &Zeroizing<<::EmbeddedCurve as WrappedGroup>::F>, ) -> Result, AcProveError> { let curve_spec = CurveSpec { - a: <::EmbeddedCurve as Ciphersuite>::G::a(), - b: <::EmbeddedCurve as Ciphersuite>::G::b(), + a: <::EmbeddedCurve as WrappedGroup>::G::a(), + b: <::EmbeddedCurve as WrappedGroup>::G::b(), }; let coefficients_evrf_points = Self::sample_coefficients_evrf_points(transcript, coefficients); @@ -340,7 +342,7 @@ impl Proof { // Push a discrete logarithm onto the tape let discrete_log = |vector_commitment_tape: &mut Vec<_>, - dlog: &ScalarDecomposition<<::EmbeddedCurve as Ciphersuite>::F>| { + dlog: &ScalarDecomposition<<::EmbeddedCurve as WrappedGroup>::F>| { for coefficient in dlog.decomposition() { vector_commitment_tape.push(<_>::from(*coefficient)); } @@ -351,8 +353,8 @@ impl Proof { // Returns the point for which the claim was made. let discrete_log_claim = |vector_commitment_tape: &mut Vec<_>, - dlog: &ScalarDecomposition<<::EmbeddedCurve as Ciphersuite>::F>, - generator: <::EmbeddedCurve as Ciphersuite>::G| { + dlog: &ScalarDecomposition<<::EmbeddedCurve as WrappedGroup>::F>, + generator: <::EmbeddedCurve as WrappedGroup>::G| { { let divisor = Zeroizing::new(dlog.scalar_mul_divisor(generator).normalize_x_coefficient()); @@ -368,12 +370,12 @@ impl Proof { .y_coefficients .first() .copied() - .unwrap_or(::F::ZERO), + .unwrap_or(::F::ZERO), ); } let dh = generator * dlog.scalar(); - let (x, y) = ::G::to_xy(dh).unwrap(); + let (x, y) = ::G::to_xy(dh).unwrap(); vector_commitment_tape.push(x); vector_commitment_tape.push(y); (dh, (x, y)) @@ -387,7 +389,7 @@ impl Proof { let mut coefficients = Vec::with_capacity(coefficients); let evrf_public_key = { let evrf_private_key = - ScalarDecomposition::<::F>::new(**evrf_private_key) + ScalarDecomposition::<::F>::new(**evrf_private_key) .expect("eVRF private key was zero"); discrete_log(&mut vector_commitment_tape, &evrf_private_key); @@ -396,12 +398,12 @@ impl Proof { let (_, evrf_public_key) = discrete_log_claim( &mut vector_commitment_tape, &evrf_private_key, - <::EmbeddedCurve as Ciphersuite>::generator(), + <::EmbeddedCurve as WrappedGroup>::generator(), ); // Push the divisor for each point we use in the eVRF for pair in coefficients_evrf_points.chunks(2) { - let mut coefficient = Zeroizing::new(::F::ZERO); + let mut coefficient = Zeroizing::new(::F::ZERO); for point in pair { let (_, (dh_x, _)) = discrete_log_claim(&mut vector_commitment_tape, &evrf_private_key, *point); @@ -418,15 +420,16 @@ impl Proof { let mut ecdh_commitments = Vec::with_capacity(2 * participant_public_keys.len()); let mut ecdh_commitments_xy = Vec::with_capacity(participant_public_keys.len()); for participant_public_key in participant_public_keys { - let mut ecdh_commitments_xy_i = - [(::F::ZERO, ::F::ZERO); - 2]; - let mut encryption_key = Zeroizing::new(::F::ZERO); + let mut ecdh_commitments_xy_i = [( + ::F::ZERO, + ::F::ZERO, + ); 2]; + let mut encryption_key = Zeroizing::new(::F::ZERO); for ecdh_commitments_xy_i_j_dest in &mut ecdh_commitments_xy_i { let mut ecdh_ephemeral_secret; loop { ecdh_ephemeral_secret = - Zeroizing::new(::F::random(&mut *rng)); + Zeroizing::new(::F::random(&mut *rng)); // 0 would produce the identity, which isn't representable within the discrete-log proof. if bool::from(!ecdh_ephemeral_secret.is_zero()) { break; @@ -434,7 +437,7 @@ impl Proof { } let ecdh_ephemeral_secret = - ScalarDecomposition::<::F>::new(*ecdh_ephemeral_secret) + ScalarDecomposition::<::F>::new(*ecdh_ephemeral_secret) .expect("ECDH ephemeral secret zero"); discrete_log(&mut vector_commitment_tape, &ecdh_ephemeral_secret); @@ -442,7 +445,7 @@ impl Proof { let (ecdh_commitment, ecdh_commitment_xy_i_j) = discrete_log_claim( &mut vector_commitment_tape, &ecdh_ephemeral_secret, - <::EmbeddedCurve as Ciphersuite>::generator(), + <::EmbeddedCurve as WrappedGroup>::generator(), ); ecdh_commitments.push(ecdh_commitment); *ecdh_commitments_xy_i_j_dest = ecdh_commitment_xy_i_j; @@ -470,7 +473,7 @@ impl Proof { for chunk in vector_commitment_tape.chunks(generators_to_use) { vector_commitments.push(PedersenVectorCommitment { g_values: chunk.into(), - mask: ::F::random(&mut *rng), + mask: ::F::random(&mut *rng), }); } @@ -479,13 +482,13 @@ impl Proof { for coefficient in &coefficients { commitments.push(PedersenCommitment { value: **coefficient, - mask: ::F::random(&mut *rng), + mask: ::F::random(&mut *rng), }); } for enc_mask in &encryption_keys { commitments.push(PedersenCommitment { value: **enc_mask, - mask: ::F::random(&mut *rng), + mask: ::F::random(&mut *rng), }); } @@ -536,13 +539,13 @@ impl Proof { } // Prove the openings of the commitments were correct - let mut x = Zeroizing::new(::F::ZERO); + let mut x = Zeroizing::new(::F::ZERO); for commitment in commitments { *x += commitment.mask * transcript.challenge::(); } // Produce a Schnorr PoK for the weighted-sum of the Pedersen commitments' blinding factors - let r = Zeroizing::new(::F::random(&mut *rng)); + let r = Zeroizing::new(::F::random(&mut *rng)); transcript.push_point(&(generators.h() * r.deref())); let c = transcript.challenge::(); transcript.push_scalar((c * x.deref()) + r.deref()); @@ -557,14 +560,14 @@ impl Proof { verifier: &mut BatchVerifier, transcript: [u8; 32], coefficients: usize, - participant_public_keys: &[<::EmbeddedCurve as Ciphersuite>::G], - evrf_public_key: <::EmbeddedCurve as Ciphersuite>::G, + participant_public_keys: &[<::EmbeddedCurve as WrappedGroup>::G], + evrf_public_key: <::EmbeddedCurve as WrappedGroup>::G, proof: &[u8], ) -> Result, ()> { let (mut transcript, ecdh_commitments, pedersen_commitments) = { let curve_spec = CurveSpec { - a: <::EmbeddedCurve as Ciphersuite>::G::a(), - b: <::EmbeddedCurve as Ciphersuite>::G::b(), + a: <::EmbeddedCurve as WrappedGroup>::G::a(), + b: <::EmbeddedCurve as WrappedGroup>::G::b(), }; let coefficients_evrf_points = @@ -600,9 +603,9 @@ impl Proof { ecdh_commitments.push(ecdh_commitments_i); // This inherently bans using the identity point, as it won't have an affine representation ecdh_commitments_xy.push([ - <::G as DivisorCurve>::to_xy(ecdh_commitments_i[0]) + <::G as DivisorCurve>::to_xy(ecdh_commitments_i[0]) .ok_or(())?, - <::G as DivisorCurve>::to_xy(ecdh_commitments_i[1]) + <::G as DivisorCurve>::to_xy(ecdh_commitments_i[1]) .ok_or(())?, ]); } @@ -610,7 +613,7 @@ impl Proof { let mut circuit = BpCircuit::verify(); Self::circuit( &curve_spec, - ::G::to_xy(evrf_public_key).ok_or(())?, + ::G::to_xy(evrf_public_key).ok_or(())?, coefficients, &ecdh_commitments_xy, &generator_tables.iter().collect::>(), diff --git a/crypto/dkg/evrf/src/tests/mod.rs b/crypto/dkg/evrf/src/tests/mod.rs index ec10fb07..db1829d4 100644 --- a/crypto/dkg/evrf/src/tests/mod.rs +++ b/crypto/dkg/evrf/src/tests/mod.rs @@ -4,11 +4,11 @@ use zeroize::Zeroizing; use rand_core::OsRng; use rand::seq::SliceRandom; -use ciphersuite::{group::ff::Field, Ciphersuite}; +use ciphersuite::{group::ff::Field, WrappedGroup}; use embedwards25519::Embedwards25519; use dkg_recovery::recover_key; -use crate::{Participant, Curves, Generators, VerifyResult, Dkg, Ristretto}; +use crate::{Participant, Curves, Generators, VerifyResult, Dkg, Ed25519}; mod proof; @@ -17,14 +17,14 @@ const PARTICIPANTS: u16 = 5; #[test] fn dkg() { - let generators = Generators::::new(THRESHOLD, PARTICIPANTS); + let generators = Generators::::new(THRESHOLD, PARTICIPANTS); let context = [0; 32]; let mut priv_keys = vec![]; let mut pub_keys = vec![]; for i in 0 .. PARTICIPANTS { - let priv_key = ::F::random(&mut OsRng); - pub_keys.push(::generator() * priv_key); + let priv_key = ::F::random(&mut OsRng); + pub_keys.push(::generator() * 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)) { participations.insert( *i, - Dkg::::participate( - &mut OsRng, - &generators, - context, - THRESHOLD, - &pub_keys, - priv_key, - ) - .unwrap(), + Dkg::::participate(&mut OsRng, &generators, context, THRESHOLD, &pub_keys, priv_key) + .unwrap(), ); } - let VerifyResult::Valid(dkg) = Dkg::::verify( - &mut OsRng, - &generators, - context, - THRESHOLD, - &pub_keys, - &participations, - ) - .unwrap() else { + let VerifyResult::Valid(dkg) = + Dkg::::verify(&mut OsRng, &generators, context, THRESHOLD, &pub_keys, &participations) + .unwrap() + else { panic!("verify didn't return VerifyResult::Valid") }; @@ -80,7 +68,7 @@ fn dkg() { // TODO: Test for all possible combinations of keys assert_eq!( - <::ToweringCurve as Ciphersuite>::generator() * + <::ToweringCurve as WrappedGroup>::generator() * *recover_key(&all_keys.values().cloned().collect::>()).unwrap(), group_key.unwrap() ); diff --git a/crypto/dkg/evrf/src/tests/proof.rs b/crypto/dkg/evrf/src/tests/proof.rs index 59b69ccf..243c66c2 100644 --- a/crypto/dkg/evrf/src/tests/proof.rs +++ b/crypto/dkg/evrf/src/tests/proof.rs @@ -6,13 +6,13 @@ use zeroize::Zeroizing; use ciphersuite::{ group::{ff::Field, Group}, - Ciphersuite, + WrappedGroup, }; use generalized_bulletproofs::{Generators, tests::insecure_test_generators}; use crate::{ - Curves, Ristretto, + Curves, Ed25519, proof::*, tests::{THRESHOLD, PARTICIPANTS}, }; @@ -20,9 +20,9 @@ use crate::{ fn proof() { let generators = insecure_test_generators(&mut OsRng, 2048).unwrap(); let embedded_private_key = - Zeroizing::new(::F::random(&mut OsRng)); + Zeroizing::new(::F::random(&mut OsRng)); let ecdh_public_keys: [_; PARTICIPANTS as usize] = - core::array::from_fn(|_| ::G::random(&mut OsRng)); + core::array::from_fn(|_| ::G::random(&mut OsRng)); let time = Instant::now(); let res = Proof::::prove( &mut OsRng, @@ -54,5 +54,5 @@ fn proof() { #[test] fn ristretto_proof() { - proof::(); + proof::(); } diff --git a/crypto/dkg/evrf/src/utils.rs b/crypto/dkg/evrf/src/utils.rs index bb121a5f..5eee47b7 100644 --- a/crypto/dkg/evrf/src/utils.rs +++ b/crypto/dkg/evrf/src/utils.rs @@ -5,7 +5,7 @@ use rand_core::{RngCore, CryptoRng}; use ciphersuite::{ group::{ff::PrimeField, Group, GroupEncoding}, - Ciphersuite, + GroupIo, }; use dkg::Participant; @@ -13,7 +13,7 @@ use dkg::Participant; /// Sample a random, unbiased point on the elliptic curve with an unknown discrete logarithm. /// /// This keeps it simple by using rejection sampling. -pub(crate) fn sample_point(rng: &mut (impl RngCore + CryptoRng)) -> C::G { +pub(crate) fn sample_point(rng: &mut (impl RngCore + CryptoRng)) -> C::G { let mut repr = ::Repr::default(); loop { rng.fill_bytes(repr.as_mut()); diff --git a/crypto/dkg/musig/src/tests.rs b/crypto/dkg/musig/src/tests.rs index 784960f5..60e8edf7 100644 --- a/crypto/dkg/musig/src/tests.rs +++ b/crypto/dkg/musig/src/tests.rs @@ -4,7 +4,7 @@ use zeroize::Zeroizing; use rand_core::OsRng; use dalek_ff_group::Ristretto; -use ciphersuite::{group::ff::Field, Ciphersuite}; +use ciphersuite::WrappedGroup; use dkg_recovery::recover_key; use crate::*; @@ -17,21 +17,21 @@ pub fn test_musig() { let mut keys = vec![]; let mut pub_keys = vec![]; for _ in 0 .. PARTICIPANTS { - let key = Zeroizing::new(::F::random(&mut OsRng)); - pub_keys.push(::generator() * *key); + let key = Zeroizing::new(::F::random(&mut OsRng)); + pub_keys.push(::generator() * *key); keys.push(key); } const CONTEXT: [u8; 32] = *b"MuSig Test "; // Empty signing set - musig::(CONTEXT, Zeroizing::new(::F::ZERO), &[]) + musig::(CONTEXT, Zeroizing::new(::F::ZERO), &[]) .unwrap_err(); // Signing set we're not part of musig::( CONTEXT, - Zeroizing::new(::F::ZERO), - &[::generator()], + Zeroizing::new(::F::ZERO), + &[::generator()], ) .unwrap_err(); @@ -48,7 +48,7 @@ pub fn test_musig() { verification_shares.insert( these_keys.params().i(), - ::generator() * **these_keys.original_secret_share(), + ::generator() * **these_keys.original_secret_share(), ); assert_eq!(these_keys.group_key(), group_key); @@ -63,7 +63,7 @@ pub fn test_musig() { } assert_eq!( - ::generator() * + ::generator() * *recover_key(&created_keys.values().cloned().collect::>()).unwrap(), group_key ); diff --git a/crypto/dkg/recovery/src/lib.rs b/crypto/dkg/recovery/src/lib.rs index bef0956b..c7d0763c 100644 --- a/crypto/dkg/recovery/src/lib.rs +++ b/crypto/dkg/recovery/src/lib.rs @@ -8,7 +8,7 @@ use alloc::vec::Vec; use zeroize::Zeroizing; -use ciphersuite::Ciphersuite; +use ciphersuite::{GroupIo, Id}; pub use dkg::*; @@ -34,7 +34,7 @@ pub enum RecoveryError { } /// Recover a shared secret from a collection of `dkg::ThresholdKeys`. -pub fn recover_key( +pub fn recover_key( keys: &[ThresholdKeys], ) -> Result, RecoveryError> { let included = keys.iter().map(|keys| keys.params().i()).collect::>(); diff --git a/crypto/dkg/src/lib.rs b/crypto/dkg/src/lib.rs index f7d8cdcf..83700e26 100644 --- a/crypto/dkg/src/lib.rs +++ b/crypto/dkg/src/lib.rs @@ -17,7 +17,7 @@ use ciphersuite::{ ff::{Field, PrimeField}, GroupEncoding, }, - Ciphersuite, + GroupIo, Id, }; /// The ID of a participant, defined as a non-zero u16. @@ -268,7 +268,7 @@ impl Interpolation { /// heap-allocated pointer to minimize copies on the stack (`ThresholdKeys`, the publicly exposed /// type). #[derive(Clone, PartialEq, Eq)] -struct ThresholdCore { +struct ThresholdCore { params: ThresholdParams, group_key: C::G, verification_shares: HashMap, @@ -276,7 +276,7 @@ struct ThresholdCore { secret_share: Zeroizing, } -impl fmt::Debug for ThresholdCore { +impl fmt::Debug for ThresholdCore { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt .debug_struct("ThresholdCore") @@ -288,7 +288,7 @@ impl fmt::Debug for ThresholdCore { } } -impl Zeroize for ThresholdCore { +impl Zeroize for ThresholdCore { fn zeroize(&mut self) { self.params.zeroize(); self.group_key.zeroize(); @@ -302,7 +302,7 @@ impl Zeroize for ThresholdCore { /// Threshold keys usable for signing. #[derive(Clone, Debug, Zeroize)] -pub struct ThresholdKeys { +pub struct ThresholdKeys { // Core keys. #[zeroize(skip)] core: Arc>>, @@ -315,7 +315,7 @@ pub struct ThresholdKeys { /// View of keys, interpolated and with the expected linear combination taken for usage. #[derive(Clone)] -pub struct ThresholdView { +pub struct ThresholdView { interpolation: Interpolation, scalar: C::F, offset: C::F, @@ -326,7 +326,7 @@ pub struct ThresholdView { verification_shares: HashMap, } -impl fmt::Debug for ThresholdView { +impl fmt::Debug for ThresholdView { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt .debug_struct("ThresholdView") @@ -341,7 +341,7 @@ impl fmt::Debug for ThresholdView { } } -impl Zeroize for ThresholdView { +impl Zeroize for ThresholdView { fn zeroize(&mut self) { self.scalar.zeroize(); self.offset.zeroize(); @@ -357,7 +357,7 @@ impl Zeroize for ThresholdView { } } -impl ThresholdKeys { +impl ThresholdKeys { /// Create a new set of ThresholdKeys. pub fn new( params: ThresholdParams, @@ -632,7 +632,7 @@ impl ThresholdKeys { let mut verification_shares = HashMap::new(); for l in (1 ..= n).map(Participant) { - verification_shares.insert(l, ::read_G(reader)?); + verification_shares.insert(l, C::read_G(reader)?); } ThresholdKeys::new( @@ -645,7 +645,7 @@ impl ThresholdKeys { } } -impl ThresholdView { +impl ThresholdView { /// Return the scalar applied to this view. pub fn scalar(&self) -> C::F { self.scalar diff --git a/crypto/ed448/Cargo.toml b/crypto/ed448/Cargo.toml index 4c78ea86..f7441f57 100644 --- a/crypto/ed448/Cargo.toml +++ b/crypto/ed448/Cargo.toml @@ -19,7 +19,7 @@ workspace = true [dependencies] zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } -sha3 = { version = "0.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"] } prime-field = { path = "../prime-field", default-features = false } diff --git a/crypto/ed448/src/ciphersuite.rs b/crypto/ed448/src/ciphersuite.rs index 707f9fb3..d568bac6 100644 --- a/crypto/ed448/src/ciphersuite.rs +++ b/crypto/ed448/src/ciphersuite.rs @@ -1,4 +1,4 @@ -use zeroize::Zeroize; +use prime_field::subtle::CtOption; use sha3::{ digest::{ @@ -8,9 +8,9 @@ use sha3::{ 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. #[derive(Clone, Default)] @@ -49,21 +49,14 @@ impl FixedOutput for Shake256_114 { } impl HashMarker for Shake256_114 {} -#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] -pub struct Ed448; -impl Ciphersuite for Ed448 { - type F = Scalar; - type G = Point; +impl Id for Point { + const ID: &[u8] = b"ed448"; +} +impl WithPreferredHash for Point { type H = Shake256_114; - - const ID: &'static [u8] = b"ed448"; - - fn generator() -> Self::G { - Point::generator() +} +impl GroupCanonicalEncoding for Point { + fn from_canonical_bytes(bytes: &::Repr) -> CtOption { + Self::G::from_bytes(bytes) } } - -#[test] -fn test_ed448() { - ff_group_tests::group::test_prime_group_bits::<_, Point>(&mut rand_core::OsRng); -} diff --git a/crypto/ed448/src/lib.rs b/crypto/ed448/src/lib.rs index 05f3fc12..ddbb5cac 100644 --- a/crypto/ed448/src/lib.rs +++ b/crypto/ed448/src/lib.rs @@ -29,7 +29,6 @@ mod point; pub use point::Point; mod ciphersuite; -pub use crate::ciphersuite::Ed448; pub(crate) fn u8_from_bool(bit_ref: &mut bool) -> u8 { use core::hint::black_box; diff --git a/crypto/embedwards25519/Cargo.toml b/crypto/embedwards25519/Cargo.toml index 02c1235c..84bcbe0e 100644 --- a/crypto/embedwards25519/Cargo.toml +++ b/crypto/embedwards25519/Cargo.toml @@ -25,12 +25,11 @@ typenum = { version = "1", default-features = false } prime-field = { path = "../prime-field", default-features = false } short-weierstrass = { path = "../short-weierstrass", default-features = false } curve25519-dalek = { version = "4", default-features = false, features = ["legacy_compatibility"] } -dalek-ff-group = { path = "../dalek-ff-group", version = "0.4", default-features = false } -blake2 = { version = "0.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 } -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] hex = "0.4" diff --git a/crypto/embedwards25519/src/lib.rs b/crypto/embedwards25519/src/lib.rs index f83be7cd..71e13dc9 100644 --- a/crypto/embedwards25519/src/lib.rs +++ b/crypto/embedwards25519/src/lib.rs @@ -5,17 +5,14 @@ #[cfg(feature = "alloc")] #[allow(unused_imports)] use std_shims::prelude::*; -#[cfg(feature = "alloc")] -use std_shims::io::{self, Read}; -use prime_field::{subtle::Choice, zeroize::Zeroize}; -use ciphersuite::group::{ - ff::{Field, PrimeField}, - Group, +use prime_field::{ + subtle::{Choice, CtOption}, + zeroize::Zeroize, }; +use ciphersuite::group::{ff::PrimeField, Group, GroupEncoding}; -use curve25519_dalek::Scalar as DalekScalar; -pub use dalek_ff_group::Scalar as FieldElement; +pub use curve25519_dalek::Scalar as FieldElement; 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 :/ impl ShortWeierstrass for Embedwards25519 { type FieldElement = FieldElement; - const A: FieldElement = FieldElement(DalekScalar::from_bits(hex_literal::hex!( + const A: FieldElement = FieldElement::from_bits(hex_literal::hex!( "ead3f55c1a631258d69cf7a2def9de1400000000000000000000000000000010" - ))); - const B: FieldElement = FieldElement(DalekScalar::from_bits(hex_literal::hex!( + )); + const B: FieldElement = FieldElement::from_bits(hex_literal::hex!( "5f07603a853f20370b682036210d463e64903a23ea669d07ca26cfc13f594209" - ))); + )); const PRIME_ORDER: bool = true; const GENERATOR: Affine = Affine::from_xy_unchecked( FieldElement::ONE, - FieldElement(DalekScalar::from_bits(hex_literal::hex!( + FieldElement::from_bits(hex_literal::hex!( "2e4118080a484a3dfbafe2199a0e36b7193581d676c0dadfa376b0265616020c" - ))), + )), ); type Scalar = Scalar; @@ -80,30 +77,23 @@ impl ShortWeierstrass for Embedwards25519 { pub type Point = Projective; -impl ciphersuite::Ciphersuite for Embedwards25519 { +impl ciphersuite::WrappedGroup for Embedwards25519 { type F = Scalar; type G = Point; - type H = blake2::Blake2b512; - - const ID: &'static [u8] = b"embedwards25519"; fn generator() -> Self::G { - Point::generator() + ::generator() } - - // We override the provided impl, which compares against the reserialization, because - // we already require canonicity - #[cfg(feature = "alloc")] - #[allow(non_snake_case)] - fn read_G(reader: &mut R) -> io::Result { - use ciphersuite::group::GroupEncoding; - - let mut encoding = ::Repr::default(); - reader.read_exact(encoding.as_mut())?; - - let point = Option::::from(Self::G::from_bytes(&encoding)) - .ok_or_else(|| io::Error::other("invalid point"))?; - Ok(point) +} +impl ciphersuite::Id for Embedwards25519 { + const ID: &[u8] = b"embedwards25519"; +} +impl ciphersuite::WithPreferredHash for Embedwards25519 { + type H = blake2::Blake2b512; +} +impl ciphersuite::GroupCanonicalEncoding for Embedwards25519 { + fn from_canonical_bytes(bytes: &::Repr) -> CtOption { + Self::G::from_bytes(bytes) } } @@ -119,9 +109,8 @@ fn test_curve() { #[test] fn generator() { - use ciphersuite::group::{Group, GroupEncoding}; assert_eq!( - Point::generator(), + ::generator(), Point::from_bytes(&hex_literal::hex!( "0100000000000000000000000000000000000000000000000000000000000000" )) @@ -139,6 +128,5 @@ fn zero_x_is_off_curve() { // Checks random won't infinitely loop #[test] fn random() { - use ciphersuite::group::Group; Point::random(&mut rand_core::OsRng); } diff --git a/crypto/frost/Cargo.toml b/crypto/frost/Cargo.toml index 572298a7..790e4e3c 100644 --- a/crypto/frost/Cargo.toml +++ b/crypto/frost/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "modular-frost" -version = "0.10.1" +version = "0.11.0" description = "Modular implementation of FROST over ff/group" license = "MIT" 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"] } -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 } ciphersuite = { path = "../ciphersuite", version = "^0.4.1", default-features = false, features = ["std"] } diff --git a/crypto/frost/src/curve/dalek.rs b/crypto/frost/src/curve/dalek.rs index 6c9f067e..49160c74 100644 --- a/crypto/frost/src/curve/dalek.rs +++ b/crypto/frost/src/curve/dalek.rs @@ -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 crate::{curve::Curve, algorithm::Hram}; macro_rules! dalek_curve { ( - $feature: literal, - $Curve: ident, $Hram: ident, $CONTEXT: literal, $chal: literal ) => { - pub use dalek_ff_group::$Curve; - impl Curve for $Curve { const CONTEXT: &'static [u8] = $CONTEXT; fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F { - let mut digest = ::H::new(); + let mut digest = ::H::new(); digest.update(Self::CONTEXT); digest.update(dst); digest.update(msg); @@ -31,8 +31,12 @@ macro_rules! dalek_curve { pub struct $Hram; impl Hram<$Curve> for $Hram { #[allow(non_snake_case)] - fn hram(R: &<$Curve as Ciphersuite>::G, A: &<$Curve as Ciphersuite>::G, m: &[u8]) -> Scalar { - let mut hash = <$Curve as Ciphersuite>::H::new(); + fn hram( + 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 { hash.update($CONTEXT); 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 = ::H; +} +impl ciphersuite::GroupCanonicalEncoding for Ristretto { + fn from_canonical_bytes(bytes: &::Repr) -> CtOption { + dalek_ff_group::Ristretto::from_canonical_bytes(bytes) + } +} +dalek_curve!(Ristretto, IetfRistrettoHram, b"FROST-RISTRETTO255-SHA512-v1", b"chal"); -#[cfg(feature = "ed25519")] -dalek_curve!("ed25519", Ed25519, IetfEd25519Hram, b"FROST-ED25519-SHA512-v1", b""); +pub use dalek_ff_group::Ed25519; +dalek_curve!(Ed25519, IetfEd25519Hram, b"FROST-ED25519-SHA512-v1", b""); diff --git a/crypto/frost/src/curve/ed448.rs b/crypto/frost/src/curve/ed448.rs index 67821d33..3c725c27 100644 --- a/crypto/frost/src/curve/ed448.rs +++ b/crypto/frost/src/curve/ed448.rs @@ -1,6 +1,6 @@ -pub use ciphersuite::{digest::Digest, group::GroupEncoding, FromUniformBytes, Ciphersuite}; -use minimal_ed448::{Scalar, Point}; -pub use minimal_ed448::Ed448; +pub use ciphersuite::{digest::Digest, group::GroupEncoding, FromUniformBytes, WithPreferredHash}; +use minimal_ed448::Scalar; +pub use minimal_ed448::Point as Ed448; use crate::{curve::Curve, algorithm::Hram}; @@ -9,7 +9,7 @@ const CONTEXT: &[u8] = b"FROST-ED448-SHAKE256-v1"; impl Curve for Ed448 { const CONTEXT: &'static [u8] = CONTEXT; fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F { - let mut digest = ::H::new(); + let mut digest = ::H::new(); digest.update(Self::CONTEXT); digest.update(dst); digest.update(msg); @@ -22,8 +22,8 @@ impl Curve for Ed448 { pub(crate) struct Ietf8032Ed448Hram; impl Ietf8032Ed448Hram { #[allow(non_snake_case)] - pub(crate) fn hram(context: &[u8], R: &Point, A: &Point, m: &[u8]) -> Scalar { - let mut digest = ::H::new(); + pub(crate) fn hram(context: &[u8], R: &Ed448, A: &Ed448, m: &[u8]) -> Scalar { + let mut digest = ::H::new(); digest.update(b"SigEd448"); digest.update([0, u8::try_from(context.len()).unwrap()]); digest.update(context); @@ -39,7 +39,7 @@ impl Ietf8032Ed448Hram { pub struct IetfEd448Hram; impl Hram for IetfEd448Hram { #[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) } } diff --git a/crypto/frost/src/curve/kp256.rs b/crypto/frost/src/curve/kp256.rs index 2ffeb148..c65d9370 100644 --- a/crypto/frost/src/curve/kp256.rs +++ b/crypto/frost/src/curve/kp256.rs @@ -7,7 +7,7 @@ use ciphersuite::{ ff::{Field, PrimeField}, GroupEncoding, }, - Ciphersuite, + WrappedGroup, }; use elliptic_curve::{ @@ -20,7 +20,7 @@ use elliptic_curve::{ use crate::{curve::Curve, algorithm::Hram}; #[allow(non_snake_case)] -fn hash_to_F>>>( +fn hash_to_F>>>( dst: &[u8], msg: &[u8], ) -> C::F { @@ -112,10 +112,10 @@ macro_rules! kp_curve { impl Hram<$Curve> for $Hram { #[allow(non_snake_case)] fn hram( - R: &<$Curve as Ciphersuite>::G, - A: &<$Curve as Ciphersuite>::G, + R: &<$Curve as WrappedGroup>::G, + A: &<$Curve as WrappedGroup>::G, m: &[u8], - ) -> <$Curve as Ciphersuite>::F { + ) -> <$Curve as WrappedGroup>::F { <$Curve as Curve>::hash_to_F( b"chal", &[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"); #[cfg(test)] -fn test_oversize_dst>>>() { +fn test_oversize_dst>>>() { use sha2::Digest; // The draft specifies DSTs >255 bytes should be hashed into a 32-byte DST diff --git a/crypto/frost/src/curve/mod.rs b/crypto/frost/src/curve/mod.rs index ae0796b1..0796c5ef 100644 --- a/crypto/frost/src/curve/mod.rs +++ b/crypto/frost/src/curve/mod.rs @@ -6,21 +6,16 @@ use rand_core::{RngCore, CryptoRng}; use zeroize::{Zeroize, Zeroizing}; use subtle::ConstantTimeEq; -pub use ciphersuite::{ - digest::Digest, - group::{ - ff::{Field, PrimeField}, - Group, - }, - Ciphersuite, +use ciphersuite::group::{ + ff::{Field, PrimeField}, + Group, }; +pub use ciphersuite::{digest::Digest, WrappedGroup, GroupIo, Ciphersuite}; #[cfg(any(feature = "ristretto", feature = "ed25519"))] mod dalek; -#[cfg(feature = "ristretto")] -pub use dalek::{Ristretto, IetfRistrettoHram}; -#[cfg(feature = "ed25519")] -pub use dalek::{Ed25519, IetfEd25519Hram}; +#[cfg(any(feature = "ristretto", feature = "ed25519"))] +pub use dalek::*; #[cfg(any(feature = "secp256k1", feature = "p256"))] mod kp256; @@ -38,11 +33,11 @@ pub(crate) use ed448::Ietf8032Ed448Hram; /// 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. -pub trait Curve: Ciphersuite { +pub trait Curve: GroupIo + Ciphersuite { /// 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. 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. #[allow(non_snake_case)] fn read_G(reader: &mut R) -> io::Result { - let res = ::read_G(reader)?; + let res = ::read_G(reader)?; if res.is_identity().into() { Err(io::Error::other("identity point"))?; } diff --git a/crypto/frost/src/sign.rs b/crypto/frost/src/sign.rs index b3be81fd..833c251c 100644 --- a/crypto/frost/src/sign.rs +++ b/crypto/frost/src/sign.rs @@ -11,10 +11,9 @@ use zeroize::{Zeroize, Zeroizing}; use transcript::Transcript; -use ciphersuite::group::{ - ff::{Field, PrimeField}, - GroupEncoding, -}; +use ciphersuite::group::{ff::PrimeField, GroupEncoding}; +#[cfg(any(test, feature = "tests"))] +use ciphersuite::group::ff::Field; use multiexp::BatchVerifier; use crate::{ diff --git a/crypto/frost/src/tests/literal/ed448.rs b/crypto/frost/src/tests/literal/ed448.rs index 95a31505..4e662451 100644 --- a/crypto/frost/src/tests/literal/ed448.rs +++ b/crypto/frost/src/tests/literal/ed448.rs @@ -1,6 +1,6 @@ use rand_core::OsRng; -use ciphersuite::Ciphersuite; +use ciphersuite::GroupIo; use schnorr::SchnorrSignature; diff --git a/crypto/frost/src/tests/mod.rs b/crypto/frost/src/tests/mod.rs index 79ac9ded..f4f6330b 100644 --- a/crypto/frost/src/tests/mod.rs +++ b/crypto/frost/src/tests/mod.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use rand_core::{RngCore, CryptoRng}; -use ciphersuite::Ciphersuite; +use ciphersuite::{GroupIo, Id}; pub use dkg_recovery::recover_key; use crate::{ @@ -28,7 +28,7 @@ pub const PARTICIPANTS: u16 = 5; pub const THRESHOLD: u16 = ((PARTICIPANTS * 2) / 3) + 1; /// Create a key, for testing purposes. -pub fn key_gen( +pub fn key_gen( rng: &mut R, ) -> HashMap> { let res = dkg_dealer::key_gen::(rng, THRESHOLD, PARTICIPANTS).unwrap(); diff --git a/crypto/schnorr/Cargo.toml b/crypto/schnorr/Cargo.toml index 009deb99..ef2e6103 100644 --- a/crypto/schnorr/Cargo.toml +++ b/crypto/schnorr/Cargo.toml @@ -22,6 +22,7 @@ std-shims = { path = "../../common/std-shims", version = "^0.1.1", default-featu rand_core = { version = "0.6", default-features = false } 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 } diff --git a/crypto/schnorr/src/aggregate.rs b/crypto/schnorr/src/aggregate.rs index cc0ac620..314644bd 100644 --- a/crypto/schnorr/src/aggregate.rs +++ b/crypto/schnorr/src/aggregate.rs @@ -5,74 +5,34 @@ use std_shims::{ use zeroize::Zeroize; -use transcript::{Transcript, SecureDigest, DigestTranscript}; +use transcript::{Transcript, DigestTranscript}; use ciphersuite::{ group::{ ff::{Field, PrimeField}, Group, GroupEncoding, }, - Ciphersuite, + FromUniformBytes, GroupIo, WithPreferredHash, }; use multiexp::multiexp_vartime; use crate::SchnorrSignature; // Returns a unbiased scalar weight to use on a signature in order to prevent malleability -fn weight(digest: &mut DigestTranscript) -> F { - let mut bytes = digest.challenge(b"aggregation_weight"); - debug_assert_eq!(bytes.len() % 8, 0); - // 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 +fn weight(digest: &mut DigestTranscript) -> C::F { + let bytes = digest.challenge(b"aggregation_weight"); + C::F::from_uniform_bytes(&bytes.into()) } /// Aggregate Schnorr signature as defined in . #[allow(non_snake_case)] #[derive(Clone, PartialEq, Eq, Debug, Zeroize)] -pub struct SchnorrAggregate { +pub struct SchnorrAggregate { Rs: Vec, s: C::F, } -impl SchnorrAggregate { +impl SchnorrAggregate { /// Read a SchnorrAggregate from something implementing Read. pub fn read(reader: &mut R) -> io::Result { let mut len = [0; 4]; @@ -137,7 +97,7 @@ impl SchnorrAggregate { let mut pairs = Vec::with_capacity((2 * keys_and_challenges.len()) + 1); for (i, (key, challenge)) in keys_and_challenges.iter().enumerate() { - let z = weight(&mut digest); + let z = weight::(&mut digest); pairs.push((z, self.Rs[i])); pairs.push((z * challenge, *key)); } @@ -148,13 +108,22 @@ impl SchnorrAggregate { /// A signature aggregator capable of consuming signatures in order to produce an aggregate. #[allow(non_snake_case)] -#[derive(Clone, Debug, Zeroize)] -pub struct SchnorrAggregator { +#[derive(Clone, Debug)] +pub struct SchnorrAggregator { digest: DigestTranscript, sigs: Vec>, } +impl Zeroize for SchnorrAggregator +where + C::H: digest::block_api::BlockSizeUser, +{ + fn zeroize(&mut self) { + self.digest.zeroize(); + self.sigs.zeroize(); + } +} -impl SchnorrAggregator { +impl SchnorrAggregator { /// Create a new aggregator. /// /// The DST used here must prevent a collision with whatever hash function produced the @@ -180,7 +149,7 @@ impl SchnorrAggregator { let mut aggregate = SchnorrAggregate { Rs: Vec::with_capacity(self.sigs.len()), s: C::F::ZERO }; for i in 0 .. self.sigs.len() { 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::(&mut self.digest); } Some(aggregate) } diff --git a/crypto/schnorr/src/lib.rs b/crypto/schnorr/src/lib.rs index e5b9f3c2..42aca4d1 100644 --- a/crypto/schnorr/src/lib.rs +++ b/crypto/schnorr/src/lib.rs @@ -20,7 +20,7 @@ use ciphersuite::{ ff::{Field, PrimeField}, Group, GroupEncoding, }, - Ciphersuite, + GroupIo, }; use multiexp::{multiexp_vartime, BatchVerifier}; @@ -33,20 +33,20 @@ mod tests; /// 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. /// -/// RFC 8032 has an alternative verification formula, 8R = 8s - 8cX, which is intended to handle -/// torsioned nonces/public keys. Due to this library's strict requirements, such signatures will -/// not be verifiable with this library. +/// RFC 8032 has an alternative verification formula for Ed25519, `8R = 8s - 8cX`, which is +/// intended to handle torsioned nonces/public keys. Due to this library's strict requirements, +/// such signatures will not be verifiable with this library. #[allow(non_snake_case)] #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] -pub struct SchnorrSignature { +pub struct SchnorrSignature { pub R: C::G, pub s: C::F, } -impl SchnorrSignature { +impl SchnorrSignature { /// Read a SchnorrSignature from something implementing Read. pub fn read(reader: &mut R) -> io::Result { Ok(SchnorrSignature { R: C::read_G(reader)?, s: C::read_F(reader)? }) diff --git a/crypto/schnorr/src/tests/mod.rs b/crypto/schnorr/src/tests/mod.rs index 79380f81..bec3eb42 100644 --- a/crypto/schnorr/src/tests/mod.rs +++ b/crypto/schnorr/src/tests/mod.rs @@ -6,7 +6,7 @@ use rand_core::OsRng; use dalek_ff_group::Ed25519; use ciphersuite::{ group::{ff::Field, Group}, - Ciphersuite, + GroupIo, WithPreferredHash, }; use multiexp::BatchVerifier; @@ -16,10 +16,10 @@ use crate::aggregate::{SchnorrAggregator, SchnorrAggregate}; mod rfc8032; -pub(crate) fn sign() { - let private_key = Zeroizing::new(C::random_nonzero_F(&mut OsRng)); - let nonce = Zeroizing::new(C::random_nonzero_F(&mut OsRng)); - let challenge = C::random_nonzero_F(&mut OsRng); // Doesn't bother to craft an HRAm +pub(crate) fn sign() { + let private_key = Zeroizing::new(C::F::random(&mut OsRng)); + let nonce = Zeroizing::new(C::F::random(&mut OsRng)); + let challenge = C::F::random(&mut OsRng); // Doesn't bother to craft an HRAm assert!(SchnorrSignature::::sign(&private_key, nonce, challenge) .verify(C::generator() * private_key.deref(), challenge)); } @@ -27,22 +27,22 @@ pub(crate) fn sign() { // The above sign function verifies signing works // This verifies invalid signatures don't pass, using zero signatures, which should effectively be // random -pub(crate) fn verify() { +pub(crate) fn verify() { assert!(!SchnorrSignature:: { 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() { +pub(crate) fn batch_verify() { // Create 5 signatures let mut keys = vec![]; let mut challenges = vec![]; let mut sigs = vec![]; for i in 0 .. 5 { - keys.push(Zeroizing::new(C::random_nonzero_F(&mut OsRng))); - challenges.push(C::random_nonzero_F(&mut OsRng)); + keys.push(Zeroizing::new(C::F::random(&mut OsRng))); + challenges.push(C::F::random(&mut OsRng)); sigs.push(SchnorrSignature::::sign( &keys[i], - Zeroizing::new(C::random_nonzero_F(&mut OsRng)), + Zeroizing::new(C::F::random(&mut OsRng)), challenges[i], )); } @@ -78,7 +78,7 @@ pub(crate) fn batch_verify() { } #[cfg(feature = "aggregate")] -pub(crate) fn aggregate() { +pub(crate) fn aggregate() { const DST: &[u8] = b"Schnorr Aggregator Test"; // Create 5 signatures @@ -86,14 +86,14 @@ pub(crate) fn aggregate() { let mut challenges = vec![]; let mut aggregator = SchnorrAggregator::::new(DST); 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 - challenges.push(C::random_nonzero_F(&mut OsRng)); + challenges.push(C::F::random(&mut OsRng)); aggregator.aggregate( challenges[i], SchnorrSignature::::sign( &keys[i], - Zeroizing::new(C::random_nonzero_F(&mut OsRng)), + Zeroizing::new(C::F::random(&mut OsRng)), challenges[i], ), ); diff --git a/crypto/schnorr/src/tests/rfc8032.rs b/crypto/schnorr/src/tests/rfc8032.rs index 63b4e7a1..a347a869 100644 --- a/crypto/schnorr/src/tests/rfc8032.rs +++ b/crypto/schnorr/src/tests/rfc8032.rs @@ -6,7 +6,7 @@ use sha2::{Digest, Sha512}; use dalek_ff_group::{Scalar, Ed25519}; -use ciphersuite::{group::GroupEncoding, Ciphersuite}; +use ciphersuite::{group::GroupEncoding, GroupIo}; use crate::SchnorrSignature; diff --git a/crypto/schnorrkel/Cargo.toml b/crypto/schnorrkel/Cargo.toml index dfb10d9c..030c4c28 100644 --- a/crypto/schnorrkel/Cargo.toml +++ b/crypto/schnorrkel/Cargo.toml @@ -24,10 +24,9 @@ transcript = { package = "flexible-transcript", path = "../transcript", version group = "0.13" -dalek-ff-group = { path = "../dalek-ff-group" } ciphersuite = { path = "../ciphersuite", version = "^0.4.1", features = ["std"] } 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" } diff --git a/crypto/schnorrkel/src/lib.rs b/crypto/schnorrkel/src/lib.rs index 5d657196..4eb3c853 100644 --- a/crypto/schnorrkel/src/lib.rs +++ b/crypto/schnorrkel/src/lib.rs @@ -9,16 +9,16 @@ use zeroize::Zeroizing; use transcript::{Transcript, MerlinTranscript}; -use dalek_ff_group::Ristretto; use ciphersuite::{ group::{ff::PrimeField, GroupEncoding}, - Ciphersuite, + WrappedGroup, }; use schnorr::SchnorrSignature; use ::frost::{ Participant, ThresholdKeys, ThresholdView, FrostError, algorithm::{Hram, Algorithm, Schnorr}, + curve::Ristretto, }; /// The [modular-frost](https://docs.rs/modular-frost) library. @@ -28,8 +28,8 @@ pub mod frost { use schnorrkel::{PublicKey, Signature, context::SigningTranscript, signing_context}; -type RistrettoPoint = ::G; -type Scalar = ::F; +type RistrettoPoint = ::G; +type Scalar = ::F; #[cfg(test)] mod tests; @@ -83,7 +83,7 @@ impl Algorithm for Schnorrkel { self.schnorr.transcript() } - fn nonces(&self) -> Vec::G>> { + fn nonces(&self) -> Vec::G>> { self.schnorr.nonces() } diff --git a/crypto/secq256k1/Cargo.toml b/crypto/secq256k1/Cargo.toml index db4bd1b0..777a6ec1 100644 --- a/crypto/secq256k1/Cargo.toml +++ b/crypto/secq256k1/Cargo.toml @@ -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 } -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 } 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 } -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] hex = "0.4" diff --git a/crypto/secq256k1/src/lib.rs b/crypto/secq256k1/src/lib.rs index 89a46f77..ed92dce1 100644 --- a/crypto/secq256k1/src/lib.rs +++ b/crypto/secq256k1/src/lib.rs @@ -5,17 +5,12 @@ #[cfg(feature = "alloc")] #[allow(unused_imports)] use std_shims::prelude::*; -#[cfg(feature = "alloc")] -use std_shims::io::{self, Read}; -use sha2::{ - digest::array::{typenum::U33, Array}, - Sha512, -}; +use sha2::digest::array::{typenum::U33, Array}; use k256::elliptic_curve::{ - subtle::{Choice, ConstantTimeEq, ConditionallySelectable}, + subtle::{Choice, CtOption, ConstantTimeEq, ConditionallySelectable}, zeroize::Zeroize, - group::{ff::PrimeField, Group}, + group::{ff::PrimeField, Group, GroupEncoding}, sec1::Tag, }; @@ -109,32 +104,25 @@ impl ShortWeierstrass for Secq256k1 { pub type Point = Projective; -impl ciphersuite::Ciphersuite for Secq256k1 { +impl ciphersuite::WrappedGroup for Secq256k1 { type F = Scalar; type G = Point; - type H = Sha512; - - const ID: &'static [u8] = b"secq256k1"; fn generator() -> Self::G { - Point::generator() + ::generator() } - - // We override the provided impl, which compares against the reserialization, because - // we already require canonicity - #[cfg(feature = "alloc")] - #[allow(non_snake_case)] - fn read_G(reader: &mut R) -> io::Result { - use ciphersuite::group::GroupEncoding; - - let mut encoding = ::Repr::default(); - reader.read_exact(encoding.as_mut())?; - - let point = Option::::from(Self::G::from_bytes(&encoding)) - .ok_or_else(|| io::Error::other("invalid point"))?; - Ok(point) +} +impl ciphersuite::Id for Secq256k1 { + const ID: &[u8] = b"secq256k1"; +} +impl ciphersuite::GroupCanonicalEncoding for Secq256k1 { + fn from_canonical_bytes(bytes: &::Repr) -> CtOption { + Self::G::from_bytes(bytes) } } +impl ciphersuite::WithPreferredHash for Secq256k1 { + type H = sha2::Sha512; +} #[cfg(feature = "alloc")] impl generalized_bulletproofs_ec_gadgets::DiscreteLogParameter for Secq256k1 { @@ -150,7 +138,7 @@ fn test_curve() { fn generator() { use ciphersuite::group::GroupEncoding; assert_eq!( - Point::generator(), + ::generator(), Point::from_bytes(&Array(hex_literal::hex!( "020000000000000000000000000000000000000000000000000000000000000001" ))) diff --git a/crypto/short-weierstrass/Cargo.toml b/crypto/short-weierstrass/Cargo.toml index a6e63331..3ad36bf6 100644 --- a/crypto/short-weierstrass/Cargo.toml +++ b/crypto/short-weierstrass/Cargo.toml @@ -21,7 +21,7 @@ rand_core = { version = "0.6", default-features = false } ff = { version = "0.13", default-features = false, features = ["bits"] } 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] alloc = ["zeroize/alloc", "rand_core/alloc", "ff/alloc", "group/alloc", "ec-divisors"] diff --git a/crypto/short-weierstrass/src/projective.rs b/crypto/short-weierstrass/src/projective.rs index 37ebe133..0a76e33c 100644 --- a/crypto/short-weierstrass/src/projective.rs +++ b/crypto/short-weierstrass/src/projective.rs @@ -413,7 +413,6 @@ impl> PrimeGroup for Projective { #[cfg(feature = "alloc")] mod alloc { - use core::borrow::Borrow; use ff::{PrimeField, PrimeFieldBits}; use crate::{ShortWeierstrass, Affine, Projective}; @@ -421,7 +420,8 @@ mod alloc { type FieldElement = C::FieldElement; type XyPoint = ec_divisors::Projective; - fn interpolator_for_scalar_mul() -> impl Borrow> { + type BorrowedInterpolator = ec_divisors::Interpolator; + fn interpolator_for_scalar_mul() -> Self::BorrowedInterpolator { ec_divisors::Interpolator::new((::NUM_BITS as usize).div_ceil(2) + 2) } diff --git a/crypto/transcript/Cargo.toml b/crypto/transcript/Cargo.toml index de4f282c..2b50502d 100644 --- a/crypto/transcript/Cargo.toml +++ b/crypto/transcript/Cargo.toml @@ -19,14 +19,14 @@ workspace = true [dependencies] 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 } [dev-dependencies] -sha2 = { version = "0.11.0-rc.0", default-features = false } -blake2 = { 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.2", default-features = false } [features] std = ["zeroize/std", "merlin?/std"] diff --git a/crypto/transcript/src/lib.rs b/crypto/transcript/src/lib.rs index 8363d781..1a15bf35 100644 --- a/crypto/transcript/src/lib.rs +++ b/crypto/transcript/src/lib.rs @@ -4,13 +4,7 @@ use zeroize::Zeroize; -use digest::{ - typenum::{ - consts::U32, marker_traits::NonZero, type_operators::IsGreaterOrEqual, operator_aliases::GrEq, - }, - block_api::BlockSizeUser, - Digest, Output, HashMarker, -}; +use digest::{block_api::BlockSizeUser, Digest, Output, HashMarker}; #[cfg(feature = "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 SecureDigest for D -where - // This just lets us perform the comparison - D::OutputSize: IsGreaterOrEqual, - // 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: NonZero, -{ -} - /// A simple transcript format constructed around the specified hash algorithm. #[derive(Clone, Debug)] -pub struct DigestTranscript(D); +pub struct DigestTranscript(D); -impl DigestTranscript { +impl DigestTranscript { fn append(&mut self, kind: DigestTranscriptMember, value: &[u8]) { self.0.update([kind.as_u8()]); // Assumes messages don't exceed 16 exabytes @@ -101,7 +82,7 @@ impl DigestTranscript { } } -impl Transcript for DigestTranscript { +impl Transcript for DigestTranscript { type Challenge = Output; fn new(name: &'static [u8]) -> Self { @@ -140,7 +121,7 @@ impl Transcript for DigestTranscript { // Digest doesn't implement Zeroize // 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 -impl Zeroize for DigestTranscript +impl Zeroize for DigestTranscript where D: BlockSizeUser, { @@ -159,7 +140,7 @@ where // These writes may be optimized out if they're never read // Attempt to get them marked as read - fn mark_read(transcript: &DigestTranscript) { + fn mark_read(transcript: &DigestTranscript) { // Just get a challenge from the state let mut challenge = core::hint::black_box(transcript.0.clone().finalize()); challenge.as_mut().zeroize(); diff --git a/message-queue/Cargo.toml b/message-queue/Cargo.toml index fc65e59b..7257fb46 100644 --- a/message-queue/Cargo.toml +++ b/message-queue/Cargo.toml @@ -29,7 +29,7 @@ zeroize = { version = "1", default-features = false, features = ["std"] } rand_core = { version = "0.6", default-features = false, features = ["std"] } # 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"] } ciphersuite = { path = "../crypto/ciphersuite", default-features = false, features = ["std"] } schnorr-signatures = { path = "../crypto/schnorr", default-features = false, features = ["std"] } diff --git a/message-queue/src/client.rs b/message-queue/src/client.rs index 60036f67..6fe7eb48 100644 --- a/message-queue/src/client.rs +++ b/message-queue/src/client.rs @@ -4,10 +4,7 @@ use zeroize::{Zeroize, Zeroizing}; use rand_core::OsRng; use dalek_ff_group::Ristretto; -use ciphersuite::{ - group::ff::{Field, PrimeField}, - Ciphersuite, -}; +use ciphersuite::{group::ff::PrimeField, WrappedGroup}; use schnorr_signatures::SchnorrSignature; use tokio::{ @@ -22,8 +19,8 @@ use crate::{Service, Metadata, QueuedMessage, MessageQueueRequest, message_chall pub struct MessageQueue { pub service: Service, - priv_key: Zeroizing<::F>, - pub_key: ::G, + priv_key: Zeroizing<::F>, + pub_key: ::G, url: String, } @@ -31,7 +28,7 @@ impl MessageQueue { pub fn new( service: Service, mut url: String, - priv_key: Zeroizing<::F>, + priv_key: Zeroizing<::F>, ) -> MessageQueue { // 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 @@ -46,16 +43,16 @@ impl MessageQueue { pub fn from_env(service: Service) -> MessageQueue { let url = env::var("MESSAGE_QUEUE_RPC").expect("message-queue RPC wasn't specified"); - let priv_key: Zeroizing<::F> = { + let priv_key: Zeroizing<::F> = { let key_str = Zeroizing::new(env::var("MESSAGE_QUEUE_KEY").expect("message-queue key wasn't specified")); let key_bytes = Zeroizing::new( hex::decode(&key_str).expect("invalid message-queue key specified (wasn't hex)"), ); - let mut bytes = <::F as PrimeField>::Repr::default(); + let mut bytes = <::F as PrimeField>::Repr::default(); bytes.copy_from_slice(&key_bytes); let key = Zeroizing::new( - Option::from(<::F as PrimeField>::from_repr(bytes)) + Option::from(<::F as PrimeField>::from_repr(bytes)) .expect("invalid message-queue key specified"), ); bytes.zeroize(); @@ -79,7 +76,7 @@ impl MessageQueue { } pub async fn queue(&self, metadata: Metadata, msg: Vec) -> Result<(), String> { - let nonce = Zeroizing::new(::F::random(&mut OsRng)); + let nonce = Zeroizing::new(::F::random(&mut OsRng)); let nonce_pub = Ristretto::generator() * nonce.deref(); let sig = SchnorrSignature::::sign( &self.priv_key, @@ -215,7 +212,7 @@ impl MessageQueue { pub async fn ack(&self, from: Service, id: u64) { // TODO: Should this use OsRng? Deterministic or deterministic + random may be better. - let nonce = Zeroizing::new(::F::random(&mut OsRng)); + let nonce = Zeroizing::new(::F::random(&mut OsRng)); let nonce_pub = Ristretto::generator() * nonce.deref(); let sig = SchnorrSignature::::sign( &self.priv_key, diff --git a/message-queue/src/main.rs b/message-queue/src/main.rs index 2b9d6b8f..055ce78b 100644 --- a/message-queue/src/main.rs +++ b/message-queue/src/main.rs @@ -4,7 +4,7 @@ pub(crate) use std::{ }; 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 serai_primitives::ExternalNetworkId; @@ -29,7 +29,7 @@ pub(crate) type Db = serai_db::RocksDB; mod clippy { use super::*; use once_cell::sync::Lazy; - pub(crate) static KEYS: Lazy::G>>>> = + pub(crate) static KEYS: Lazy::G>>>> = Lazy::new(|| Arc::new(RwLock::new(HashMap::new()))); pub(crate) static QUEUES: Lazy>>>>> = Lazy::new(|| Arc::new(RwLock::new(HashMap::new()))); @@ -189,9 +189,9 @@ async fn main() { let read_key = |str| { let key = serai_env::var(str)?; - let mut repr = <::G as GroupEncoding>::Repr::default(); + let mut repr = <::G as GroupEncoding>::Repr::default(); repr.as_mut().copy_from_slice(&hex::decode(key).unwrap()); - Some(::G::from_bytes(&repr).unwrap()) + Some(::from_canonical_bytes(&repr).unwrap()) }; let register_service = |service, key| { diff --git a/message-queue/src/messages.rs b/message-queue/src/messages.rs index bcc4ef8c..2fc45a44 100644 --- a/message-queue/src/messages.rs +++ b/message-queue/src/messages.rs @@ -1,6 +1,6 @@ -use transcript::{Transcript, RecommendedTranscript}; +use transcript::{Transcript, DigestTranscript}; use dalek_ff_group::Ristretto; -use ciphersuite::{group::GroupEncoding, Ciphersuite}; +use ciphersuite::{group::GroupEncoding, FromUniformBytes, WrappedGroup, WithPreferredHash}; use borsh::{BorshSerialize, BorshDeserialize}; @@ -36,13 +36,15 @@ pub enum MessageQueueRequest { pub fn message_challenge( from: Service, - from_key: ::G, + from_key: ::G, to: Service, intent: &[u8], msg: &[u8], - nonce: ::G, -) -> ::F { - let mut transcript = RecommendedTranscript::new(b"Serai Message Queue v0.1 Message"); + nonce: ::G, +) -> ::F { + let mut transcript = DigestTranscript::<::H>::new( + b"Serai Message Queue v0.1 Message", + ); transcript.domain_separate(b"metadata"); transcript.append_message(b"from", borsh::to_vec(&from).unwrap()); 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.domain_separate(b"signature"); transcript.append_message(b"nonce", nonce.to_bytes()); - ::hash_to_F(&transcript.challenge(b"challenge")) + ::F::from_uniform_bytes(&transcript.challenge(b"challenge").into()) } pub fn ack_challenge( to: Service, - to_key: ::G, + to_key: ::G, from: Service, id: u64, - nonce: ::G, -) -> ::F { - let mut transcript = RecommendedTranscript::new(b"Serai Message Queue v0.1 Acknowledgement"); + nonce: ::G, +) -> ::F { + let mut transcript = DigestTranscript::<::H>::new( + b"Serai Message Queue v0.1 Acknowledgement", + ); transcript.domain_separate(b"metadata"); transcript.append_message(b"to", borsh::to_vec(&to).unwrap()); 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.domain_separate(b"signature"); transcript.append_message(b"nonce", nonce.to_bytes()); - ::hash_to_F(&transcript.challenge(b"challenge")) + ::F::from_uniform_bytes(&transcript.challenge(b"challenge").into()) } diff --git a/networks/bitcoin/Cargo.toml b/networks/bitcoin/Cargo.toml index 91d0d9af..9147feee 100644 --- a/networks/bitcoin/Cargo.toml +++ b/networks/bitcoin/Cargo.toml @@ -27,7 +27,7 @@ rand_core = { version = "0.6", default-features = false } bitcoin = { version = "0.32", default-features = false } 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 } serde = { version = "1", default-features = false, features = ["derive"], optional = true } diff --git a/networks/bitcoin/src/crypto.rs b/networks/bitcoin/src/crypto.rs index 061fd466..51e0f852 100644 --- a/networks/bitcoin/src/crypto.rs +++ b/networks/bitcoin/src/crypto.rs @@ -40,7 +40,7 @@ mod frost_crypto { use k256::{elliptic_curve::ops::Reduce, U256, Scalar}; use frost::{ - curve::{Ciphersuite, Secp256k1}, + curve::{WrappedGroup, Secp256k1}, Participant, ThresholdKeys, ThresholdView, FrostError, algorithm::{Hram as HramTrait, Algorithm, IetfSchnorr as FrostSchnorr}, }; @@ -128,10 +128,10 @@ mod frost_crypto { fn sign_share( &mut self, params: &ThresholdView, - nonce_sums: &[Vec<::G>], - nonces: Vec::F>>, + nonce_sums: &[Vec<::G>], + nonces: Vec::F>>, msg: &[u8], - ) -> ::F { + ) -> ::F { self.0.sign_share(params, nonce_sums, nonces, msg) } diff --git a/networks/bitcoin/src/wallet/mod.rs b/networks/bitcoin/src/wallet/mod.rs index 1dc385df..97319f5f 100644 --- a/networks/bitcoin/src/wallet/mod.rs +++ b/networks/bitcoin/src/wallet/mod.rs @@ -13,7 +13,7 @@ use k256::{ #[cfg(feature = "std")] use frost::{ - curve::{Ciphersuite, Secp256k1}, + curve::{WrappedGroup, GroupIo, Secp256k1}, ThresholdKeys, }; @@ -59,7 +59,7 @@ pub fn tweak_keys(keys: ThresholdKeys) -> ThresholdKeys { 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. */ - keys.offset(::F::reduce(U256::from_be_bytes( + keys.offset(::F::reduce(U256::from_be_bytes( *tweak_hash.to_raw_hash().as_ref(), ))) }; diff --git a/orchestration/src/coordinator.rs b/orchestration/src/coordinator.rs index 32489393..83b762b0 100644 --- a/orchestration/src/coordinator.rs +++ b/orchestration/src/coordinator.rs @@ -3,7 +3,7 @@ use std::path::Path; use zeroize::Zeroizing; 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}; @@ -11,8 +11,8 @@ use crate::{Network, Os, mimalloc, os, build_serai_service, write_dockerfile}; pub fn coordinator( orchestration_path: &Path, network: Network, - coordinator_key: Zeroizing<::F>, - serai_key: &Zeroizing<::F>, + coordinator_key: Zeroizing<::F>, + serai_key: &Zeroizing<::F>, ) { let db = network.db(); let longer_reattempts = if network == Network::Dev { "longer-reattempts" } else { "" }; diff --git a/orchestration/src/main.rs b/orchestration/src/main.rs index 06e591ac..b1e7b1cb 100644 --- a/orchestration/src/main.rs +++ b/orchestration/src/main.rs @@ -24,7 +24,7 @@ use ciphersuite::{ ff::{Field, PrimeField}, GroupEncoding, }, - Ciphersuite, + WrappedGroup, }; use embedwards25519::Embedwards25519; use secq256k1::Secq256k1; @@ -221,8 +221,10 @@ fn orchestration_path(network: Network) -> PathBuf { orchestration_path } -type InfrastructureKeys = - HashMap<&'static str, (Zeroizing<::F>, ::G)>; +type InfrastructureKeys = HashMap< + &'static str, + (Zeroizing<::F>, ::G), +>; fn infrastructure_keys(network: Network) -> InfrastructureKeys { // 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 key_pair = || { - let key = Zeroizing::new(::F::random(&mut rng)); + let key = Zeroizing::new(::F::random(&mut rng)); let public = Ristretto::generator() * key.deref(); (key, public) }; @@ -307,12 +309,12 @@ fn embedded_curve_keys(network: Network) -> EmbeddedCurveKeys { EmbeddedCurveKeys { embedwards25519: { - let key = Zeroizing::new(::F::random(&mut rng)); + let key = Zeroizing::new(::F::random(&mut rng)); let pub_key = Embedwards25519::generator() * key.deref(); (Zeroizing::new(key.to_repr().as_ref().to_vec()), pub_key.to_bytes().to_vec()) }, secq256k1: { - let key = Zeroizing::new(::F::random(&mut rng)); + let key = Zeroizing::new(::F::random(&mut rng)); let pub_key = Secq256k1::generator() * key.deref(); (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"), ); let mut serai_key_repr = - Zeroizing::new(<::F as PrimeField>::Repr::default()); + Zeroizing::new(<::F as PrimeField>::Repr::default()); serai_key_repr.as_mut().copy_from_slice(serai_key.as_ref()); - Zeroizing::new(::F::from_repr(*serai_key_repr).unwrap()) + Zeroizing::new(::F::from_repr(*serai_key_repr).unwrap()) }; coordinator(&orchestration_path, network, coordinator_key.0, &serai_key); @@ -399,7 +401,7 @@ fn key_gen(network: Network) { return; } - let key = ::F::random(&mut OsRng); + let key = ::F::random(&mut OsRng); let _ = fs::create_dir_all(&serai_dir); 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 println!( "Public Key: {}", - hex::encode((::generator() * key).to_bytes()) + hex::encode((::generator() * key).to_bytes()) ); } diff --git a/orchestration/src/message_queue.rs b/orchestration/src/message_queue.rs index e5fdb7a0..2a45f06d 100644 --- a/orchestration/src/message_queue.rs +++ b/orchestration/src/message_queue.rs @@ -1,17 +1,17 @@ use std::path::Path; 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}; pub fn message_queue( orchestration_path: &Path, network: Network, - coordinator_key: ::G, - bitcoin_key: ::G, - ethereum_key: ::G, - monero_key: ::G, + coordinator_key: ::G, + bitcoin_key: ::G, + ethereum_key: ::G, + monero_key: ::G, ) { let setup = mimalloc(Os::Debian).to_string() + &build_serai_service("", network.release(), network.db(), "serai-message-queue"); diff --git a/orchestration/src/processor.rs b/orchestration/src/processor.rs index 2605e7a0..7932e50e 100644 --- a/orchestration/src/processor.rs +++ b/orchestration/src/processor.rs @@ -3,7 +3,7 @@ use std::path::Path; use zeroize::Zeroizing; 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}; @@ -12,8 +12,8 @@ pub fn processor( orchestration_path: &Path, network: Network, coin: &'static str, - _coordinator_key: ::G, - processor_key: Zeroizing<::F>, + _coordinator_key: ::G, + processor_key: Zeroizing<::F>, substrate_evrf_key: Zeroizing>, network_evrf_key: Zeroizing>, ) { diff --git a/orchestration/src/serai.rs b/orchestration/src/serai.rs index e812242a..b963adc2 100644 --- a/orchestration/src/serai.rs +++ b/orchestration/src/serai.rs @@ -2,14 +2,14 @@ use std::path::Path; use zeroize::Zeroizing; 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}; pub fn serai( orchestration_path: &Path, network: Network, - serai_key: &Zeroizing<::F>, + serai_key: &Zeroizing<::F>, ) { // Always builds in release for performance reasons let setup = mimalloc(Os::Debian).to_string() + &build_serai_service("", true, "", "serai-node"); diff --git a/patches/ciphersuite/Cargo.toml b/patches/ciphersuite/Cargo.toml index ade5a85e..6d95f18b 100644 --- a/patches/ciphersuite/Cargo.toml +++ b/patches/ciphersuite/Cargo.toml @@ -16,13 +16,19 @@ rustdoc-args = ["--cfg", "docsrs"] workspace = true [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 } + dalek-ff-group = { path = "../../crypto/dalek-ff-group", default-features = false, optional = true } [features] -alloc = ["ciphersuite/alloc"] +alloc = ["std-shims", "zeroize/alloc", "ciphersuite/alloc", "dalek-ff-group/alloc"] std = [ "alloc", + "std-shims/std", + "zeroize/std", "ciphersuite/std", "dalek-ff-group?/std", ] diff --git a/patches/ciphersuite/src/lib.rs b/patches/ciphersuite/src/lib.rs index 679ea363..b1b75683 100644 --- a/patches/ciphersuite/src/lib.rs +++ b/patches/ciphersuite/src/lib.rs @@ -1,5 +1,33 @@ #![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 + GroupOps + PrimeGroup + Zeroize; + #[cfg(feature = "alloc")] + #[allow(non_snake_case)] + fn read_F(reader: &mut R) -> io::Result; + #[cfg(feature = "alloc")] + #[allow(non_snake_case)] + fn read_G(reader: &mut R) -> io::Result; +} +impl Ciphersuite for C { + type F = ::F; + type G = ::G; + #[cfg(feature = "alloc")] + fn read_F(reader: &mut R) -> io::Result { + ::read_F(reader) + } + #[cfg(feature = "alloc")] + fn read_G(reader: &mut R) -> io::Result { + ::read_G(reader) +} +} + #[cfg(feature = "ed25519")] pub use dalek_ff_group::Ed25519; diff --git a/patches/dalek-ff-group/Cargo.toml b/patches/dalek-ff-group/Cargo.toml index 3525cf12..0cac3c94 100644 --- a/patches/dalek-ff-group/Cargo.toml +++ b/patches/dalek-ff-group/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dalek-ff-group" -version = "0.4.99" +version = "0.5.99" description = "ff/group bindings around curve25519-dalek" license = "MIT" repository = "https://github.com/serai-dex/serai/tree/develop/crypto/dalek-ff-group" diff --git a/processor/bin/Cargo.toml b/processor/bin/Cargo.toml index 7df18918..28c1f4d8 100644 --- a/processor/bin/Cargo.toml +++ b/processor/bin/Cargo.toml @@ -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"] } 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-cosign = { path = "../../coordinator/cosign" } diff --git a/processor/bin/src/lib.rs b/processor/bin/src/lib.rs index 73a0e374..3b2d327d 100644 --- a/processor/bin/src/lib.rs +++ b/processor/bin/src/lib.rs @@ -4,9 +4,9 @@ use zeroize::{Zeroize, Zeroizing}; use ciphersuite::{ group::{ff::PrimeField, GroupEncoding}, - Ciphersuite, + *, }; -use dkg::{Curves, Ristretto}; +use dkg::Curves; 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 primitives::EncodableG; -use ::key_gen::{KeyGenParams, KeyGen}; +use ::key_gen::{Ristretto, KeyGenParams, KeyGen}; use scheduler::{SignableTransaction, TransactionFor}; use scanner::{ScannerFeed, Scanner, KeyFor, Scheduler}; use signers::{TransactionPublisher, Signers}; @@ -80,7 +80,7 @@ pub fn url() -> String { } fn key_gen() -> KeyGen { - fn read_key_from_env(label: &'static str) -> Zeroizing { + fn read_key_from_env(label: &'static str) -> Zeroizing { let key_hex = Zeroizing::new(env::var(label).unwrap_or_else(|| panic!("{label} wasn't provided"))); let bytes = Zeroizing::new( diff --git a/processor/bitcoin/src/key_gen.rs b/processor/bitcoin/src/key_gen.rs index afbfc7ac..99145b2a 100644 --- a/processor/bitcoin/src/key_gen.rs +++ b/processor/bitcoin/src/key_gen.rs @@ -1,4 +1,4 @@ -use ciphersuite::{group::GroupEncoding, Ciphersuite}; +use ciphersuite::{group::GroupEncoding, *}; use dkg::{ThresholdKeys, Curves, Secp256k1}; use crate::{primitives::x_coord_to_even_point, scan::scanner}; @@ -18,7 +18,7 @@ impl key_gen::KeyGenParams for KeyGenParams { } fn encode_key( - key: <::ToweringCurve as Ciphersuite>::G, + key: <::ToweringCurve as WrappedGroup>::G, ) -> Vec { let key = key.to_bytes(); let key: &[u8] = key.as_ref(); @@ -28,7 +28,7 @@ impl key_gen::KeyGenParams for KeyGenParams { fn decode_key( key: &[u8], - ) -> Option<<::ToweringCurve as Ciphersuite>::G> { + ) -> Option<<::ToweringCurve as WrappedGroup>::G> { x_coord_to_even_point(key) } } diff --git a/processor/bitcoin/src/primitives/block.rs b/processor/bitcoin/src/primitives/block.rs index 057c5799..ac93ccb0 100644 --- a/processor/bitcoin/src/primitives/block.rs +++ b/processor/bitcoin/src/primitives/block.rs @@ -1,7 +1,7 @@ use core::fmt; use std::collections::HashMap; -use ciphersuite::Ciphersuite; +use ciphersuite::*; use ciphersuite_kp256::Secp256k1; use bitcoin_serai::bitcoin::block::{Header, Block as BBlock}; @@ -35,7 +35,7 @@ impl fmt::Debug for Block { impl primitives::Block for Block { type Header = BlockHeader; - type Key = ::G; + type Key = ::G; type Address = Address; type Output = Output; type Eventuality = Eventuality; diff --git a/processor/bitcoin/src/primitives/mod.rs b/processor/bitcoin/src/primitives/mod.rs index e11d9203..10136531 100644 --- a/processor/bitcoin/src/primitives/mod.rs +++ b/processor/bitcoin/src/primitives/mod.rs @@ -1,4 +1,4 @@ -use ciphersuite::Ciphersuite; +use ciphersuite::*; use ciphersuite_kp256::Secp256k1; use bitcoin_serai::bitcoin::key::{Parity, XOnlyPublicKey}; @@ -7,7 +7,7 @@ pub(crate) mod output; pub(crate) mod transaction; pub(crate) mod block; -pub(crate) fn x_coord_to_even_point(key: &[u8]) -> Option<::G> { +pub(crate) fn x_coord_to_even_point(key: &[u8]) -> Option<::G> { if key.len() != 32 { None? }; diff --git a/processor/bitcoin/src/primitives/output.rs b/processor/bitcoin/src/primitives/output.rs index bd9ec8a7..da2ce3e6 100644 --- a/processor/bitcoin/src/primitives/output.rs +++ b/processor/bitcoin/src/primitives/output.rs @@ -1,6 +1,6 @@ use std::io; -use ciphersuite::Ciphersuite; +use ciphersuite::*; use ciphersuite_kp256::Secp256k1; use bitcoin_serai::{ @@ -55,7 +55,7 @@ pub(crate) struct Output { impl Output { pub(crate) fn new( getter: &impl Get, - key: ::G, + key: ::G, tx: &Transaction, output: WalletOutput, ) -> Self { @@ -71,7 +71,7 @@ impl Output { } pub(crate) fn new_with_presumed_origin( - key: ::G, + key: ::G, tx: &Transaction, presumed_origin: Option
, output: WalletOutput, @@ -88,7 +88,7 @@ impl Output { } } -impl ReceivedOutput<::G, Address> for Output { +impl ReceivedOutput<::G, Address> for Output { type Id = OutputId; type TransactionId = [u8; 32]; @@ -108,7 +108,7 @@ impl ReceivedOutput<::G, Address> for Output { res } - fn key(&self) -> ::G { + fn key(&self) -> ::G { // We read the key from the script pubkey so we don't have to independently store it let script = &self.output.output().script_pubkey; @@ -121,7 +121,7 @@ impl ReceivedOutput<::G, Address> for Output { .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 - key - (::G::GENERATOR * self.output.offset()) + key - (::G::GENERATOR * self.output.offset()) } fn presumed_origin(&self) -> Option
{ diff --git a/processor/bitcoin/src/scan.rs b/processor/bitcoin/src/scan.rs index c8a5fa74..975b75bc 100644 --- a/processor/bitcoin/src/scan.rs +++ b/processor/bitcoin/src/scan.rs @@ -1,6 +1,6 @@ use std::{sync::LazyLock, collections::HashMap}; -use ciphersuite::Ciphersuite; +use ciphersuite::*; use ciphersuite_kp256::Secp256k1; use bitcoin_serai::{ @@ -20,20 +20,20 @@ use primitives::OutputType; use crate::hash_bytes; // TODO: Bitcoin HD derivation, instead of these bespoke labels? -static BRANCH_BASE_OFFSET: LazyLock<::F> = +static BRANCH_BASE_OFFSET: LazyLock<::F> = LazyLock::new(|| Secp256k1::hash_to_F(b"branch")); -static CHANGE_BASE_OFFSET: LazyLock<::F> = +static CHANGE_BASE_OFFSET: LazyLock<::F> = LazyLock::new(|| Secp256k1::hash_to_F(b"change")); -static FORWARD_BASE_OFFSET: LazyLock<::F> = +static FORWARD_BASE_OFFSET: LazyLock<::F> = LazyLock::new(|| Secp256k1::hash_to_F(b"forward")); // Unfortunately, we have per-key offsets as it's the root key plus the base offset may not be // even. While we could tweak the key until all derivations are even, that'd require significantly // more tweaking. This algorithmic complexity is preferred. pub(crate) fn offsets_for_key( - key: ::G, -) -> HashMap::F> { - let mut offsets = HashMap::from([(OutputType::External, ::F::ZERO)]); + key: ::G, +) -> HashMap::F> { + let mut offsets = HashMap::from([(OutputType::External, ::F::ZERO)]); // We create an actual Bitcoin scanner as upon adding an offset, it yields the tweaked offset // actually used @@ -50,7 +50,7 @@ pub(crate) fn offsets_for_key( offsets } -pub(crate) fn scanner(key: ::G) -> Scanner { +pub(crate) fn scanner(key: ::G) -> Scanner { let mut scanner = Scanner::new(key).unwrap(); for (_, offset) in offsets_for_key(key) { let tweaked_offset = scanner.register_offset(offset).unwrap(); diff --git a/processor/bitcoin/src/scheduler.rs b/processor/bitcoin/src/scheduler.rs index 2799f883..5a411673 100644 --- a/processor/bitcoin/src/scheduler.rs +++ b/processor/bitcoin/src/scheduler.rs @@ -1,6 +1,6 @@ use core::future::Future; -use ciphersuite::Ciphersuite; +use ciphersuite::*; use ciphersuite_kp256::Secp256k1; use bitcoin_serai::{ @@ -26,8 +26,8 @@ use crate::{ rpc::Rpc, }; -fn address_from_serai_key(key: ::G, kind: OutputType) -> Address { - let offset = ::G::GENERATOR * offsets_for_key(key)[&kind]; +fn address_from_serai_key(key: ::G, kind: OutputType) -> Address { + let offset = ::G::GENERATOR * offsets_for_key(key)[&kind]; Address::new( p2tr_script_buf(key + offset) .expect("creating address from Serai key which wasn't properly tweaked"), @@ -72,7 +72,7 @@ fn signable_transaction( */ payments.push(( // The generator is even so this is valid - p2tr_script_buf(::G::GENERATOR).unwrap(), + p2tr_script_buf(::G::GENERATOR).unwrap(), // 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` bitcoin_serai::wallet::DUST, diff --git a/processor/ethereum/src/key_gen.rs b/processor/ethereum/src/key_gen.rs index 34cedc15..3d902f92 100644 --- a/processor/ethereum/src/key_gen.rs +++ b/processor/ethereum/src/key_gen.rs @@ -1,4 +1,4 @@ -use ciphersuite::Ciphersuite; +use ciphersuite::*; use dkg::{ThresholdKeys, Curves, Secp256k1}; use ethereum_schnorr::PublicKey; @@ -13,19 +13,19 @@ impl key_gen::KeyGenParams for KeyGenParams { keys: &mut ThresholdKeys<::ToweringCurve>, ) { while PublicKey::new(keys.group_key()).is_none() { - *keys = keys.clone().offset(<::ToweringCurve as Ciphersuite>::F::ONE); + *keys = keys.clone().offset(<::ToweringCurve as WrappedGroup>::F::ONE); } } fn encode_key( - key: <::ToweringCurve as Ciphersuite>::G, + key: <::ToweringCurve as WrappedGroup>::G, ) -> Vec { PublicKey::new(key).unwrap().eth_repr().to_vec() } fn decode_key( key: &[u8], - ) -> Option<<::ToweringCurve as Ciphersuite>::G> { + ) -> Option<<::ToweringCurve as WrappedGroup>::G> { PublicKey::from_eth_repr(key.try_into().ok()?).map(|key| key.point()) } } diff --git a/processor/ethereum/src/primitives/block.rs b/processor/ethereum/src/primitives/block.rs index cf25a6bb..7ace3d02 100644 --- a/processor/ethereum/src/primitives/block.rs +++ b/processor/ethereum/src/primitives/block.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use ciphersuite::Ciphersuite; +use ciphersuite::*; use ciphersuite_kp256::Secp256k1; use serai_client::networks::ethereum::Address; @@ -41,7 +41,7 @@ pub(crate) struct FullEpoch { impl primitives::Block for FullEpoch { type Header = Epoch; - type Key = ::G; + type Key = ::G; type Address = Address; type Output = Output; type Eventuality = Eventuality; diff --git a/processor/ethereum/src/primitives/machine.rs b/processor/ethereum/src/primitives/machine.rs index 55e65fb8..54e43279 100644 --- a/processor/ethereum/src/primitives/machine.rs +++ b/processor/ethereum/src/primitives/machine.rs @@ -2,7 +2,7 @@ use std::{io, collections::HashMap}; use rand_core::{RngCore, CryptoRng}; -use ciphersuite::Ciphersuite; +use ciphersuite::*; use ciphersuite_kp256::Secp256k1; use frost::{ dkg::{Participant, ThresholdKeys}, @@ -24,10 +24,10 @@ pub struct EthereumHram; impl Hram for EthereumHram { #[allow(non_snake_case)] fn hram( - R: &::G, - A: &::G, + R: &::G, + A: &::G, m: &[u8], - ) -> ::F { + ) -> ::F { Signature::challenge(*R, &PublicKey::new(*A).unwrap(), m) } } diff --git a/processor/ethereum/src/primitives/output.rs b/processor/ethereum/src/primitives/output.rs index 9fe2ba60..c6780ab9 100644 --- a/processor/ethereum/src/primitives/output.rs +++ b/processor/ethereum/src/primitives/output.rs @@ -1,6 +1,6 @@ use std::io; -use ciphersuite::{group::GroupEncoding, Ciphersuite}; +use ciphersuite::{group::GroupEncoding, *}; use ciphersuite_kp256::Secp256k1; use alloy_core::primitives::U256; @@ -61,10 +61,10 @@ impl AsMut<[u8]> for OutputId { #[derive(Clone, PartialEq, Eq, Debug)] pub(crate) enum Output { - Output { key: ::G, instruction: EthereumInInstruction }, - Eventuality { key: ::G, nonce: u64 }, + Output { key: ::G, instruction: EthereumInInstruction }, + Eventuality { key: ::G, nonce: u64 }, } -impl ReceivedOutput<::G, Address> for Output { +impl ReceivedOutput<::G, Address> for Output { type Id = OutputId; type TransactionId = [u8; 32]; @@ -107,7 +107,7 @@ impl ReceivedOutput<::G, Address> for Output { } } - fn key(&self) -> ::G { + fn key(&self) -> ::G { match self { Output::Output { key, .. } | Output::Eventuality { key, .. } => *key, } diff --git a/processor/key-gen/Cargo.toml b/processor/key-gen/Cargo.toml index c1de1a81..0d7ad39f 100644 --- a/processor/key-gen/Cargo.toml +++ b/processor/key-gen/Cargo.toml @@ -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"] } transcript = { package = "flexible-transcript", path = "../../crypto/transcript", 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 serai-validator-sets-primitives = { path = "../../substrate/validator-sets/primitives", default-features = false, features = ["std"] } diff --git a/processor/key-gen/src/db.rs b/processor/key-gen/src/db.rs index 4496a9c6..bd656b90 100644 --- a/processor/key-gen/src/db.rs +++ b/processor/key-gen/src/db.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use zeroize::Zeroizing; -use ciphersuite::{group::GroupEncoding, Ciphersuite}; +use ciphersuite::{group::GroupEncoding, *}; use dkg::*; use serai_validator_sets_primitives::Session; @@ -11,15 +11,15 @@ use serai_validator_sets_primitives::Session; use borsh::{BorshSerialize, BorshDeserialize}; use serai_db::{Get, DbTxn}; -use crate::KeyGenParams; +use crate::{Ristretto, KeyGenParams}; pub(crate) struct Params { pub(crate) t: u16, pub(crate) n: u16, pub(crate) substrate_evrf_public_keys: - Vec<<::EmbeddedCurve as Ciphersuite>::G>, + Vec<<::EmbeddedCurve as WrappedGroup>::G>, pub(crate) network_evrf_public_keys: - Vec<<::EmbeddedCurve as Ciphersuite>::G>, + Vec<<::EmbeddedCurve as WrappedGroup>::G>, } #[derive(BorshSerialize, BorshDeserialize)] @@ -85,17 +85,16 @@ impl KeyGenDb

{ .substrate_evrf_public_keys .into_iter() .map(|key| { - <::EmbeddedCurve as Ciphersuite>::read_G(&mut key.as_slice()) - .unwrap() + <::EmbeddedCurve as GroupIo>::read_G(&mut key.as_slice()).unwrap() }) .collect(), network_evrf_public_keys: params .network_evrf_public_keys .into_iter() .map(|key| { - <::EmbeddedCurve as Ciphersuite>::read_G::< - &[u8], - >(&mut key.as_ref()) + <::EmbeddedCurve as GroupIo>::read_G::<&[u8]>( + &mut key.as_ref(), + ) .unwrap() }) .collect(), diff --git a/processor/key-gen/src/lib.rs b/processor/key-gen/src/lib.rs index c605b791..28201143 100644 --- a/processor/key-gen/src/lib.rs +++ b/processor/key-gen/src/lib.rs @@ -13,7 +13,7 @@ use blake2::{Digest, Blake2s256}; use transcript::{Transcript, RecommendedTranscript}; use ciphersuite::{ group::{Group, GroupEncoding}, - Ciphersuite, + *, }; use dkg::*; @@ -28,6 +28,14 @@ use generators::generators; mod db; 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. pub trait KeyGenParams { /// The ID for this instantiation. @@ -49,7 +57,7 @@ pub trait KeyGenParams { /// /// A default implementation is provided which calls the traditional `to_bytes`. fn encode_key( - key: <::ToweringCurve as Ciphersuite>::G, + key: <::ToweringCurve as WrappedGroup>::G, ) -> 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`. fn decode_key( mut key: &[u8], - ) -> Option<<::ToweringCurve as Ciphersuite>::G> { - let res = <::ToweringCurve as Ciphersuite>::read_G( - &mut key, - ) - .ok()?; + ) -> Option<<::ToweringCurve as WrappedGroup>::G> { + let res = + <::ToweringCurve as GroupIo>::read_G(&mut key) + .ok()?; if !key.is_empty() { None?; } @@ -101,14 +108,14 @@ pub trait KeyGenParams { */ fn coerce_keys( key_bytes: &[impl AsRef<[u8]>], -) -> (Vec<::G>, Vec) { - fn evrf_key(key: &[u8]) -> Option<::G> { - let mut repr = <::G as GroupEncoding>::Repr::default(); +) -> (Vec<::G>, Vec) { + fn evrf_key(key: &[u8]) -> Option<::G> { + let mut repr = <::G as GroupEncoding>::Repr::default(); if repr.as_ref().len() != key.len() { None?; } repr.as_mut().copy_from_slice(key); - let point = Option::<::G>::from(<_>::from_bytes(&repr))?; + let point = Option::<::G>::from(<_>::from_bytes(&repr))?; if bool::from(point.is_identity()) { None?; } @@ -131,10 +138,10 @@ fn coerce_keys( // Generate a random key let mut rng = ChaCha20Rng::from_seed(Blake2s256::digest(key).into()); loop { - let mut repr = <::G as GroupEncoding>::Repr::default(); + let mut repr = <::G as GroupEncoding>::Repr::default(); rng.fill_bytes(repr.as_mut()); if let Some(key) = - Option::<::G>::from(<_>::from_bytes(&repr)) + Option::<::G>::from(<_>::from_bytes(&repr)) { break key; } @@ -149,18 +156,20 @@ fn coerce_keys( /// An instance of the Serai key generation protocol. #[derive(Debug)] pub struct KeyGen { - substrate_evrf_private_key: Zeroizing<<::EmbeddedCurve as Ciphersuite>::F>, + substrate_evrf_private_key: Zeroizing<<::EmbeddedCurve as WrappedGroup>::F>, network_evrf_private_key: - Zeroizing<<::EmbeddedCurve as Ciphersuite>::F>, + Zeroizing<<::EmbeddedCurve as WrappedGroup>::F>, } impl KeyGen

{ /// Create a new key generation instance. #[allow(clippy::new_ret_no_self)] pub fn new( - substrate_evrf_private_key: Zeroizing<<::EmbeddedCurve as Ciphersuite>::F>, + substrate_evrf_private_key: Zeroizing< + <::EmbeddedCurve as WrappedGroup>::F, + >, network_evrf_private_key: Zeroizing< - <::EmbeddedCurve as Ciphersuite>::F, + <::EmbeddedCurve as WrappedGroup>::F, >, ) -> KeyGen

{ KeyGen { substrate_evrf_private_key, network_evrf_private_key } @@ -214,8 +223,8 @@ impl KeyGen

{ fn participate( context: [u8; 32], threshold: u16, - evrf_public_keys: &[::G], - evrf_private_key: &Zeroizing<::F>, + evrf_public_keys: &[::G], + evrf_private_key: &Zeroizing<::F>, output: &mut impl io::Write, ) { let participation = Dkg::::participate( @@ -411,7 +420,7 @@ impl KeyGen

{ session: Session, true_if_substrate_false_if_network: bool, threshold: u16, - evrf_public_keys: &[::G], + evrf_public_keys: &[::G], substrate_participations: &mut HashMap>, network_participations: &mut HashMap>, ) -> Result, Vec> { diff --git a/processor/monero/Cargo.toml b/processor/monero/Cargo.toml index 49b79814..8ceef0f9 100644 --- a/processor/monero/Cargo.toml +++ b/processor/monero/Cargo.toml @@ -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"] } 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-simple-request-rpc = { git = "https://github.com/monero-oxide/monero-oxide", rev = "6966575e05fe09b77674c46984b21686ed9304ff", default-features = false } +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 = "7f37cc8f770858aa1739e0f56dbe447db86f4ba6", default-features = false } serai-client = { path = "../../substrate/client", default-features = false, features = ["monero"] } diff --git a/processor/monero/src/primitives/block.rs b/processor/monero/src/primitives/block.rs index e00b6ff2..5132ffbb 100644 --- a/processor/monero/src/primitives/block.rs +++ b/processor/monero/src/primitives/block.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use ciphersuite::Ciphersuite; +use ciphersuite::*; use dalek_ff_group::Ed25519; use monero_wallet::{ @@ -32,7 +32,7 @@ pub(crate) struct Block(pub(crate) MScannableBlock); impl primitives::Block for Block { type Header = BlockHeader; - type Key = ::G; + type Key = ::G; type Address = Address; type Output = Output; type Eventuality = Eventuality; diff --git a/processor/monero/src/primitives/mod.rs b/processor/monero/src/primitives/mod.rs index 8428da4c..aa01d81c 100644 --- a/processor/monero/src/primitives/mod.rs +++ b/processor/monero/src/primitives/mod.rs @@ -1,6 +1,6 @@ use zeroize::Zeroizing; -use ciphersuite::Ciphersuite; +use ciphersuite::*; use dalek_ff_group::Ed25519; 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"), }; -pub(crate) fn view_pair(key: ::G) -> GuaranteedViewPair { - match GuaranteedViewPair::new(key.0, Zeroizing::new(*view_key::(0))) { +pub(crate) fn view_pair(key: ::G) -> GuaranteedViewPair { + match GuaranteedViewPair::new(key.0, Zeroizing::new(view_key::(0))) { Ok(view_pair) => view_pair, Err(ViewPairError::TorsionedSpendKey) => { unreachable!("dalek_ff_group::EdwardsPoint had torsion") diff --git a/processor/monero/src/primitives/output.rs b/processor/monero/src/primitives/output.rs index f26ed01c..5a4ce43d 100644 --- a/processor/monero/src/primitives/output.rs +++ b/processor/monero/src/primitives/output.rs @@ -1,6 +1,6 @@ use std::io; -use ciphersuite::{group::Group, Ciphersuite}; +use ciphersuite::WrappedGroup; use dalek_ff_group::Ed25519; use monero_wallet::WalletOutput; @@ -35,7 +35,7 @@ impl AsMut<[u8]> for OutputId { #[derive(Clone, PartialEq, Eq, Debug)] pub(crate) struct Output(pub(crate) WalletOutput); -impl ReceivedOutput<::G, Address> for Output { +impl ReceivedOutput<::G, Address> for Output { type Id = OutputId; type TransactionId = [u8; 32]; @@ -64,12 +64,12 @@ impl ReceivedOutput<::G, Address> for Output { self.0.transaction() } - fn key(&self) -> ::G { + fn key(&self) -> ::G { // 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 spend key is dalek_ff_group::EdwardsPoint( - self.0.key() - (*::G::generator() * self.0.key_offset()), + self.0.key() - (*::generator() * self.0.key_offset()), ) } diff --git a/processor/monero/src/scheduler.rs b/processor/monero/src/scheduler.rs index 45b837a0..77a2af1c 100644 --- a/processor/monero/src/scheduler.rs +++ b/processor/monero/src/scheduler.rs @@ -4,7 +4,7 @@ use zeroize::Zeroizing; use rand_core::SeedableRng; use rand_chacha::ChaCha20Rng; -use ciphersuite::Ciphersuite; +use ciphersuite::*; use dalek_ff_group::Ed25519; use monero_wallet::rpc::{FeeRate, RpcError}; @@ -33,7 +33,7 @@ use crate::{ rpc::Rpc, }; -fn address_from_serai_key(key: ::G, kind: OutputType) -> Address { +fn address_from_serai_key(key: ::G, kind: OutputType) -> Address { view_pair(key) .address( Network::Mainnet, @@ -118,8 +118,8 @@ async fn signable_transaction( MoneroAddress::new( Network::Mainnet, AddressType::Legacy, - ::generator().0, - ::generator().0, + ::generator().0, + ::generator().0, ), 0, )); diff --git a/processor/scheduler/primitives/src/lib.rs b/processor/scheduler/primitives/src/lib.rs index 3c214d15..293c588d 100644 --- a/processor/scheduler/primitives/src/lib.rs +++ b/processor/scheduler/primitives/src/lib.rs @@ -5,7 +5,7 @@ use core::marker::PhantomData; use std::io; -use ciphersuite::{group::GroupEncoding, Ciphersuite}; +use ciphersuite::{group::GroupEncoding, *}; use frost::{dkg::ThresholdKeys, sign::PreprocessMachine}; use serai_db::DbTxn; diff --git a/processor/signers/Cargo.toml b/processor/signers/Cargo.toml index 2a81e7bb..3d235fde 100644 --- a/processor/signers/Cargo.toml +++ b/processor/signers/Cargo.toml @@ -26,8 +26,7 @@ zeroize = { version = "1", default-features = false, features = ["std"] } blake2 = { version = "0.11.0-rc.0", default-features = false, features = ["alloc"] } ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, features = ["std"] } -dalek-ff-group = { path = "../../crypto/dalek-ff-group", default-features = false, features = ["std"] } -frost = { package = "modular-frost", path = "../../crypto/frost", default-features = false } +frost = { package = "modular-frost", path = "../../crypto/frost", default-features = false, features = ["ristretto"] } frost-schnorrkel = { path = "../../crypto/schnorrkel", default-features = false } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std"] } diff --git a/processor/signers/src/batch/mod.rs b/processor/signers/src/batch/mod.rs index 695ce4e0..2516c1f6 100644 --- a/processor/signers/src/batch/mod.rs +++ b/processor/signers/src/batch/mod.rs @@ -3,8 +3,7 @@ use std::collections::HashSet; use blake2::{digest::typenum::U32, Digest, Blake2b}; use ciphersuite::group::GroupEncoding; -use dalek_ff_group::Ristretto; -use frost::dkg::ThresholdKeys; +use frost::{dkg::ThresholdKeys, curve::Ristretto}; use scale::Encode; diff --git a/processor/signers/src/cosign/mod.rs b/processor/signers/src/cosign/mod.rs index 2dc16c31..c8670fca 100644 --- a/processor/signers/src/cosign/mod.rs +++ b/processor/signers/src/cosign/mod.rs @@ -1,7 +1,6 @@ use core::future::Future; -use dalek_ff_group::Ristretto; -use frost::dkg::ThresholdKeys; +use frost::{dkg::ThresholdKeys, curve::Ristretto}; use scale::Encode; use serai_primitives::Signature; diff --git a/processor/signers/src/lib.rs b/processor/signers/src/lib.rs index 79b152ab..959064bf 100644 --- a/processor/signers/src/lib.rs +++ b/processor/signers/src/lib.rs @@ -7,9 +7,8 @@ use std::collections::HashMap; use zeroize::Zeroizing; -use ciphersuite::{group::GroupEncoding, Ciphersuite}; -use dalek_ff_group::Ristretto; -use frost::dkg::ThresholdKeys; +use ciphersuite::{group::GroupEncoding, *}; +use frost::{dkg::ThresholdKeys, curve::Ristretto}; use serai_primitives::Signature; use serai_validator_sets_primitives::{Session, SlashReport}; diff --git a/processor/signers/src/slash_report.rs b/processor/signers/src/slash_report.rs index 25448401..63c48a0b 100644 --- a/processor/signers/src/slash_report.rs +++ b/processor/signers/src/slash_report.rs @@ -1,7 +1,6 @@ use core::{marker::PhantomData, future::Future}; -use dalek_ff_group::Ristretto; -use frost::dkg::ThresholdKeys; +use frost::{dkg::ThresholdKeys, curve::Ristretto}; use serai_primitives::Signature; use serai_validator_sets_primitives::Session; diff --git a/processor/signers/src/wrapped_schnorrkel.rs b/processor/signers/src/wrapped_schnorrkel.rs index 52a09d24..fb556ba6 100644 --- a/processor/signers/src/wrapped_schnorrkel.rs +++ b/processor/signers/src/wrapped_schnorrkel.rs @@ -5,9 +5,9 @@ use std::{ use rand_core::{RngCore, CryptoRng}; -use dalek_ff_group::Ristretto; use frost::{ dkg::{Participant, ThresholdKeys}, + curve::Ristretto, FrostError, algorithm::Algorithm, sign::*, diff --git a/processor/view-keys/src/lib.rs b/processor/view-keys/src/lib.rs index 0708836a..c3b0eb8f 100644 --- a/processor/view-keys/src/lib.rs +++ b/processor/view-keys/src/lib.rs @@ -2,7 +2,7 @@ #![doc = include_str!("../README.md")] #![deny(missing_docs)] -use ciphersuite::Ciphersuite; +use ciphersuite::*; /// Generate a view key for usage within Serai. /// diff --git a/substrate/client/Cargo.toml b/substrate/client/Cargo.toml index 2d9e56ef..0df6540b 100644 --- a/substrate/client/Cargo.toml +++ b/substrate/client/Cargo.toml @@ -41,9 +41,9 @@ simple-request = { path = "../../common/request", version = "0.1", optional = tr bitcoin = { version = "0.32", optional = true } +ciphersuite = { path = "../../crypto/ciphersuite", optional = true } dalek-ff-group = { path = "../../crypto/dalek-ff-group", optional = true } -ciphersuite = { path = "../../crypto/ciphersuite", version = "0.4", optional = true } -monero-address = { git = "https://github.com/monero-oxide/monero-oxide", rev = "6966575e05fe09b77674c46984b21686ed9304ff", version = "0.1.0", default-features = false, features = ["std"], optional = true } +monero-address = { git = "https://github.com/monero-oxide/monero-oxide", rev = "7f37cc8f770858aa1739e0f56dbe447db86f4ba6", version = "0.1.0", default-features = false, features = ["std"], optional = true } [dev-dependencies] rand_core = "0.6" @@ -70,7 +70,7 @@ borsh = ["serai-abi/borsh"] networks = [] bitcoin = ["networks", "dep:bitcoin"] ethereum = ["networks"] -monero = ["networks", "dalek-ff-group", "ciphersuite", "monero-address"] +monero = ["networks", "ciphersuite", "dalek-ff-group", "monero-address"] # Assumes the default usage is to use Serai as a DEX, which doesn't actually # require connecting to a Serai node diff --git a/substrate/client/src/networks/monero.rs b/substrate/client/src/networks/monero.rs index 5e8f6ddc..bd5bdd2f 100644 --- a/substrate/client/src/networks/monero.rs +++ b/substrate/client/src/networks/monero.rs @@ -1,7 +1,7 @@ use core::{str::FromStr, fmt}; -use dalek_ff_group::Ed25519; -use ciphersuite::Ciphersuite; +use dalek_ff_group::{EdwardsPoint, Ed25519}; +use ciphersuite::GroupIo; use monero_address::{Network, AddressType as MoneroAddressType, MoneroAddress}; @@ -18,8 +18,8 @@ enum AddressType { #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct Address { kind: AddressType, - spend: ::G, - view: ::G, + spend: EdwardsPoint, + view: EdwardsPoint, } fn byte_for_kind(kind: AddressType) -> u8 { diff --git a/substrate/client/tests/common/genesis_liquidity.rs b/substrate/client/tests/common/genesis_liquidity.rs index 2e799602..82bff745 100644 --- a/substrate/client/tests/common/genesis_liquidity.rs +++ b/substrate/client/tests/common/genesis_liquidity.rs @@ -3,8 +3,8 @@ use std::collections::HashMap; use rand_core::{RngCore, OsRng}; use zeroize::Zeroizing; -use dalek_ff_group::Ristretto; -use ciphersuite::Ciphersuite; +use frost::curve::Ristretto; +use ciphersuite::{WrappedGroup, GroupIo}; use dkg_musig::musig; use schnorrkel::Schnorrkel; @@ -96,11 +96,10 @@ async fn set_values(serai: &Serai, values: &Values) { // we publish the tx in set 1 let set = ValidatorSet { session: Session(1), network: NetworkId::Serai }; - let public_key = ::read_G::<&[u8]>(&mut public.0.as_ref()).unwrap(); - let secret_key = ::read_F::<&[u8]>( - &mut pair.as_ref().secret.to_bytes()[.. 32].as_ref(), - ) - .unwrap(); + let public_key = ::read_G::<&[u8]>(&mut public.0.as_ref()).unwrap(); + let secret_key = + ::read_F::<&[u8]>(&mut pair.as_ref().secret.to_bytes()[.. 32].as_ref()) + .unwrap(); assert_eq!(Ristretto::generator() * secret_key, public_key); let threshold_keys = diff --git a/substrate/client/tests/common/validator_sets.rs b/substrate/client/tests/common/validator_sets.rs index 666ea379..d9be4321 100644 --- a/substrate/client/tests/common/validator_sets.rs +++ b/substrate/client/tests/common/validator_sets.rs @@ -1,9 +1,13 @@ use std::collections::HashMap; -use serai_abi::primitives::NetworkId; use zeroize::Zeroizing; use rand_core::OsRng; +use frost::curve::Ristretto; +use ciphersuite::{WrappedGroup, GroupIo}; +use dkg_musig::musig; +use schnorrkel::Schnorrkel; + use sp_core::{ ConstU32, bounded_vec::BoundedVec, @@ -11,10 +15,7 @@ use sp_core::{ Pair as PairTrait, }; -use dalek_ff_group::Ristretto; -use ciphersuite::Ciphersuite; -use dkg_musig::musig; -use schnorrkel::Schnorrkel; +use serai_abi::primitives::NetworkId; use serai_client::{ primitives::{EmbeddedEllipticCurve, Amount}, @@ -37,13 +38,13 @@ pub async fn set_keys( let mut pub_keys = vec![]; for pair in pairs { let public_key = - ::read_G::<&[u8]>(&mut pair.public().0.as_ref()).unwrap(); + ::read_G::<&[u8]>(&mut pair.public().0.as_ref()).unwrap(); pub_keys.push(public_key); } let mut threshold_keys = vec![]; for i in 0 .. pairs.len() { - let secret_key = ::read_F::<&[u8]>( + let secret_key = ::read_F::<&[u8]>( &mut pairs[i].as_ref().secret.to_bytes()[.. 32].as_ref(), ) .unwrap(); diff --git a/substrate/node/Cargo.toml b/substrate/node/Cargo.toml index 59d6d14e..25cb6d57 100644 --- a/substrate/node/Cargo.toml +++ b/substrate/node/Cargo.toml @@ -82,7 +82,7 @@ serai-env = { path = "../../common/env" } curve25519-dalek = { version = "4", default-features = false, features = ["alloc", "zeroize"] } bitcoin-serai = { path = "../../networks/bitcoin", default-features = false, features = ["std", "hazmat"] } -monero-address = { git = "https://github.com/monero-oxide/monero-oxide", rev = "6966575e05fe09b77674c46984b21686ed9304ff", default-features = false, features = ["std"] } +monero-address = { git = "https://github.com/monero-oxide/monero-oxide", rev = "7f37cc8f770858aa1739e0f56dbe447db86f4ba6", default-features = false, features = ["std"] } [build-dependencies] substrate-build-script-utils = { git = "https://github.com/serai-dex/substrate" } diff --git a/substrate/node/src/rpc.rs b/substrate/node/src/rpc.rs index 481b7ebb..6dd4b28c 100644 --- a/substrate/node/src/rpc.rs +++ b/substrate/node/src/rpc.rs @@ -50,7 +50,7 @@ where { use substrate_frame_rpc_system::{System, SystemApiServer}; use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; - use ciphersuite::Ciphersuite; + use ciphersuite::{GroupIo, WithPreferredHash}; use ciphersuite_kp256::{k256::elliptic_curve::point::AffineCoordinates, Secp256k1}; use dalek_ff_group::Ed25519; use bitcoin_serai::bitcoin; @@ -126,7 +126,7 @@ where match network { ExternalNetworkId::Bitcoin => { - let key = ::read_G::<&[u8]>(&mut external_key.as_slice()) + let key = ::read_G::<&[u8]>(&mut external_key.as_slice()) .map_err(|_| Error::Custom("invalid key stored in db".to_string()))?; let addr = bitcoin::Address::p2tr_tweaked( @@ -144,14 +144,11 @@ where ExternalNetworkId::Ethereum => Ok(String::new()), ExternalNetworkId::Monero => { // TODO: Serai view-key crate - let view_private = zeroize::Zeroizing::new( - ::hash_to_F( - &["Monero".as_bytes(), &0u64.to_le_bytes()].concat(), - ) - .0, - ); + let view_private = zeroize::Zeroizing::new(::hash_to_F( + &["Monero".as_bytes(), &0u64.to_le_bytes()].concat(), + )); - let spend = ::read_G::<&[u8]>(&mut external_key.as_slice()) + let spend = ::read_G::<&[u8]>(&mut external_key.as_slice()) .map_err(|_| Error::Custom("invalid key stored in db".to_string()))?; let addr = monero_address::MoneroAddress::new( diff --git a/substrate/primitives/src/account.rs b/substrate/primitives/src/account.rs index 9680adc5..d5ad442c 100644 --- a/substrate/primitives/src/account.rs +++ b/substrate/primitives/src/account.rs @@ -102,7 +102,7 @@ pub fn insecure_pair_from_name(name: &str) -> Pair { /// /// This key should never be considered a secure private key. It has effectively no entropy. #[cfg(feature = "std")] -pub fn insecure_arbitrary_key_from_name(name: &str) -> C::F { +pub fn insecure_arbitrary_key_from_name(name: &str) -> C::F { C::hash_to_F(name.as_bytes()) } diff --git a/substrate/validator-sets/pallet/src/tests.rs b/substrate/validator-sets/pallet/src/tests.rs index 4fa35a51..d97a4bb6 100644 --- a/substrate/validator-sets/pallet/src/tests.rs +++ b/substrate/validator-sets/pallet/src/tests.rs @@ -2,10 +2,9 @@ use crate::{mock::*, primitives::*}; use std::collections::HashMap; -use ciphersuite::Ciphersuite; -use dalek_ff_group::Ristretto; +use ciphersuite::{WrappedGroup, GroupIo}; use dkg_musig::musig; -use schnorrkel::Schnorrkel; +use schnorrkel::{frost::curve::Ristretto, Schnorrkel}; use zeroize::Zeroizing; use rand_core::OsRng; @@ -75,13 +74,13 @@ fn set_keys_signature(set: &ExternalValidatorSet, key_pair: &KeyPair, pairs: &[P let mut pub_keys = vec![]; for pair in pairs { let public_key = - ::read_G::<&[u8]>(&mut pair.public().0.as_ref()).unwrap(); + ::read_G::<&[u8]>(&mut pair.public().0.as_ref()).unwrap(); pub_keys.push(public_key); } let mut threshold_keys = vec![]; for i in 0 .. pairs.len() { - let secret_key = ::read_F::<&[u8]>( + let secret_key = ::read_F::<&[u8]>( &mut pairs[i].as_ref().secret.to_bytes()[.. 32].as_ref(), ) .unwrap(); diff --git a/substrate/validator-sets/primitives/src/lib.rs b/substrate/validator-sets/primitives/src/lib.rs index 9b252607..4b390067 100644 --- a/substrate/validator-sets/primitives/src/lib.rs +++ b/substrate/validator-sets/primitives/src/lib.rs @@ -6,7 +6,7 @@ use core::time::Duration; use zeroize::Zeroize; use dalek_ff_group::Ristretto; -use ciphersuite::{group::GroupEncoding, Ciphersuite}; +use ciphersuite::{group::GroupEncoding, GroupIo}; use scale::{Encode, Decode, MaxEncodedLen}; use scale_info::TypeInfo; @@ -138,8 +138,7 @@ pub fn musig_key(set: ValidatorSet, set_keys: &[Public]) -> Public { let mut keys = Vec::new(); for key in set_keys { keys.push( - ::read_G::<&[u8]>(&mut key.0.as_ref()) - .expect("invalid participant"), + ::read_G::<&[u8]>(&mut key.0.as_ref()).expect("invalid participant"), ); } Public(dkg_musig::musig_key_vartime::(musig_context(set), &keys).unwrap().to_bytes()) diff --git a/tests/coordinator/src/lib.rs b/tests/coordinator/src/lib.rs index 8f432b51..fa3bd5cd 100644 --- a/tests/coordinator/src/lib.rs +++ b/tests/coordinator/src/lib.rs @@ -16,7 +16,7 @@ use zeroize::Zeroizing; use ciphersuite::{ group::{ff::PrimeField, GroupEncoding}, - Ciphersuite, + WrappedGroup, }; use dalek_ff_group::Ristretto; use embedwards25519::Embedwards25519; @@ -39,7 +39,7 @@ mod tests; pub fn coordinator_instance( name: &str, - message_queue_key: ::F, + message_queue_key: ::F, ) -> TestBodySpecification { serai_docker_tests::build("coordinator".to_string()); @@ -123,7 +123,7 @@ pub struct Processor { evrf_public_keys: ([u8; 32], Vec), - substrate_key: Arc::F>>>>, + substrate_key: Arc::F>>>>, } impl Drop for Processor { @@ -140,7 +140,7 @@ impl Processor { network: ExternalNetworkId, ops: &DockerOperations, handles: Handles, - processor_key: ::F, + processor_key: ::F, ) -> Processor { let message_queue_rpc = ops.handle(&handles.message_queue).host_port(2287).unwrap(); let message_queue_rpc = format!("{}:{}", message_queue_rpc.0, message_queue_rpc.1); @@ -321,7 +321,7 @@ impl Processor { schnorrkel_key_pair[.. 32].copy_from_slice(&substrate_key.to_repr()); OsRng.fill_bytes(&mut schnorrkel_key_pair[32 .. 64]); schnorrkel_key_pair[64 ..].copy_from_slice( - &(::generator() * *substrate_key).to_bytes(), + &(::generator() * *substrate_key).to_bytes(), ); let signature = Signature( schnorrkel::keys::Keypair::from_bytes(&schnorrkel_key_pair) @@ -390,7 +390,7 @@ impl Processor { pub async fn set_substrate_key( &mut self, - substrate_key: Zeroizing<::F>, + substrate_key: Zeroizing<::F>, ) { *self.substrate_key.lock().await = Some(substrate_key); } diff --git a/tests/coordinator/src/tests/batch.rs b/tests/coordinator/src/tests/batch.rs index d1d1c9bc..bece6df2 100644 --- a/tests/coordinator/src/tests/batch.rs +++ b/tests/coordinator/src/tests/batch.rs @@ -10,7 +10,7 @@ use blake2::{ digest::{consts::U32, Digest}, Blake2b, }; -use ciphersuite::{group::GroupEncoding, Ciphersuite} +use ciphersuite::{group::GroupEncoding, WrappedGroup} use ciphersuite_kp256::Secp256k1; use dalek_ff_group::Ristretto; use dkg::Participant; @@ -36,7 +36,7 @@ pub async fn batch( processors: &mut [Processor], processor_is: &[u8], session: Session, - substrate_key: &Zeroizing<::F>, + substrate_key: &Zeroizing<::F>, batch: Batch, ) -> u64 { let id = SubstrateSignId { session, id: SubstrateSignableId::Batch(batch.id), attempt: 0 }; @@ -164,7 +164,7 @@ pub async fn batch( schnorrkel_key_pair[.. 32].copy_from_slice(&substrate_key.to_repr()); OsRng.fill_bytes(&mut schnorrkel_key_pair[32 .. 64]); schnorrkel_key_pair[64 ..] - .copy_from_slice(&(::generator() * **substrate_key).to_bytes()); + .copy_from_slice(&(::generator() * **substrate_key).to_bytes()); let signature = Signature( schnorrkel::keys::Keypair::from_bytes(&schnorrkel_key_pair) .unwrap() diff --git a/tests/coordinator/src/tests/key_gen.rs b/tests/coordinator/src/tests/key_gen.rs index 2b033d30..7dcad04e 100644 --- a/tests/coordinator/src/tests/key_gen.rs +++ b/tests/coordinator/src/tests/key_gen.rs @@ -5,7 +5,7 @@ use rand_core::OsRng; use ciphersuite::{ group::{ff::Field, GroupEncoding}, - Ciphersuite, + WrappedGroup, }; use ciphersuite_kp256::Secq256k1; use dalek_ff_group::Ristretto; @@ -19,10 +19,10 @@ use messages::CoordinatorMessage; use crate::tests::*; -pub async fn key_gen( +pub async fn key_gen( processors: &mut [Processor], session: Session, -) -> (Vec, Zeroizing<::F>, Zeroizing) { +) -> (Vec, Zeroizing<::F>, Zeroizing) { let coordinators = processors.len(); let mut participant_is = vec![]; @@ -93,8 +93,8 @@ pub async fn key_gen( } // Now that we've received all participations, publish the key pair - let substrate_priv_key = Zeroizing::new(::F::random(&mut OsRng)); - let substrate_key = (::generator() * *substrate_priv_key).to_bytes(); + let substrate_priv_key = Zeroizing::new(::F::random(&mut OsRng)); + let substrate_key = (::generator() * *substrate_priv_key).to_bytes(); let network_priv_key = Zeroizing::new(C::F::random(&mut OsRng)); let network_key = (C::generator() * *network_priv_key).to_bytes().as_ref().to_vec(); diff --git a/tests/coordinator/src/tests/mod.rs b/tests/coordinator/src/tests/mod.rs index 6d27d218..f3f35866 100644 --- a/tests/coordinator/src/tests/mod.rs +++ b/tests/coordinator/src/tests/mod.rs @@ -1,6 +1,8 @@ use core::future::Future; use std::{sync::OnceLock, collections::HashMap}; +use ciphersuite::WrappedGroup; + use tokio::sync::Mutex; use dockertest::{ @@ -125,7 +127,7 @@ pub(crate) async fn new_test(test_body: impl TestBody, fast_epoch: bool) { struct Context { pending_coordinator_compositions: Mutex>, - handles_and_keys: Vec<(Handles, ::F)>, + handles_and_keys: Vec<(Handles, ::F)>, test_body: Box, } static CONTEXT: OnceLock>> = OnceLock::new(); diff --git a/tests/message-queue/src/lib.rs b/tests/message-queue/src/lib.rs index 6f7a4139..52c76663 100644 --- a/tests/message-queue/src/lib.rs +++ b/tests/message-queue/src/lib.rs @@ -2,10 +2,7 @@ use std::collections::HashMap; use rand_core::OsRng; -use ciphersuite::{ - group::{ff::Field, GroupEncoding}, - Ciphersuite, -}; +use ciphersuite::{group::GroupEncoding, WrappedGroup}; use dalek_ff_group::Ristretto; use serai_primitives::{ExternalNetworkId, EXTERNAL_NETWORKS}; @@ -14,7 +11,7 @@ use dockertest::{ PullPolicy, Image, LogAction, LogPolicy, LogSource, LogOptions, TestBodySpecification, }; -pub type MessageQueuePrivateKey = ::F; +pub type MessageQueuePrivateKey = ::F; pub fn instance() -> ( MessageQueuePrivateKey, HashMap, @@ -22,10 +19,10 @@ pub fn instance() -> ( ) { serai_docker_tests::build("message-queue".to_string()); - let coord_key = ::F::random(&mut OsRng); + let coord_key = ::F::random(&mut OsRng); let priv_keys = EXTERNAL_NETWORKS .into_iter() - .map(|n| (n, ::F::random(&mut OsRng))) + .map(|n| (n, ::F::random(&mut OsRng))) .collect::>(); let composition = TestBodySpecification::with_image( diff --git a/tests/no-std/Cargo.toml b/tests/no-std/Cargo.toml index 1988cdcc..3777d8ec 100644 --- a/tests/no-std/Cargo.toml +++ b/tests/no-std/Cargo.toml @@ -34,7 +34,7 @@ secq256k1 = { path = "../../crypto/secq256k1", default-features = false } embedwards25519 = { path = "../../crypto/embedwards25519", default-features = false } dkg = { path = "../../crypto/dkg", default-features = false, optional = true } -dkg-evrf = { path = "../../crypto/dkg/evrf", default-features = false, features = ["secp256k1", "ed25519", "ristretto"], optional = true } +dkg-evrf = { path = "../../crypto/dkg/evrf", default-features = false, features = ["secp256k1", "ed25519"], optional = true } # modular-frost = { path = "../../crypto/frost", default-features = false } # frost-schnorrkel = { path = "../../crypto/schnorrkel", default-features = false } diff --git a/tests/processor/src/lib.rs b/tests/processor/src/lib.rs index aa8faaf8..9309e227 100644 --- a/tests/processor/src/lib.rs +++ b/tests/processor/src/lib.rs @@ -6,7 +6,7 @@ use zeroize::Zeroizing; use ciphersuite::{ group::{ff::PrimeField, GroupEncoding}, - Ciphersuite, + WrappedGroup, }; use ciphersuite_kp256::Secp256k1; use dalek_ff_group::{Ed25519, Ristretto}; @@ -40,7 +40,7 @@ pub fn processor_instance( name: &str, network: ExternalNetworkId, port: u32, - message_queue_key: ::F, + message_queue_key: ::F, ) -> (Vec, EvrfPublicKeys) { let substrate_evrf_key = insecure_arbitrary_key_from_name::<::EmbeddedCurve>(name); @@ -113,7 +113,7 @@ pub fn processor_instance( } pub struct ProcessorKeys { - coordinator: ::F, + coordinator: ::F, evrf: EvrfPublicKeys, } diff --git a/tests/processor/src/networks.rs b/tests/processor/src/networks.rs index c4947f82..edc04715 100644 --- a/tests/processor/src/networks.rs +++ b/tests/processor/src/networks.rs @@ -1,6 +1,8 @@ use zeroize::Zeroizing; use rand_core::{RngCore, OsRng}; +use ciphersuite::{WrappedGroup, GroupIo}; + use scale::Encode; use serai_client::{ @@ -90,7 +92,7 @@ pub enum Wallet { }, Ethereum { rpc_url: String, - key: ::F, + key: ::F, nonce: u64, }, Monero { @@ -158,9 +160,9 @@ impl Wallet { network::Ethereum, }; - let key = ::F::random(&mut OsRng); + let key = ::F::random(&mut OsRng); let address = - ethereum_serai::crypto::address(&(::generator() * key)); + ethereum_serai::crypto::address(&(::generator() * key)); let provider = RootProvider::<_, Ethereum>::new( ClientBuilder::default().transport(SimpleRequest::new(rpc_url.clone()), true), @@ -321,7 +323,7 @@ impl Wallet { )); let to_as_key = PublicKey::new( - ::read_G(&mut to.as_slice()).unwrap(), + ::read_G(&mut to.as_slice()).unwrap(), ) .unwrap(); let router_addr = { From 5265cc69de0ce750591f5c7818fb093963352332 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Wed, 3 Sep 2025 13:56:48 -0400 Subject: [PATCH 15/15] hex-literal 1 --- Cargo.lock | 8 ++++---- crypto/embedwards25519/Cargo.toml | 2 +- crypto/secq256k1/Cargo.toml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2bce2dd9..5bb18250 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2552,7 +2552,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976" dependencies = [ "data-encoding", - "syn 1.0.109", + "syn 2.0.106", ] [[package]] @@ -4050,9 +4050,9 @@ dependencies = [ [[package]] name = "hex-literal" -version = "0.4.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +checksum = "bcaaec4551594c969335c98c903c1397853d4198408ea609190f420500f6be71" [[package]] name = "hex_fmt" @@ -6690,7 +6690,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "syn 2.0.106", diff --git a/crypto/embedwards25519/Cargo.toml b/crypto/embedwards25519/Cargo.toml index 84bcbe0e..6d2efed8 100644 --- a/crypto/embedwards25519/Cargo.toml +++ b/crypto/embedwards25519/Cargo.toml @@ -14,7 +14,7 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [dependencies] -hex-literal = { version = "0.4", default-features = false } +hex-literal = { version = "1", default-features = false } std-shims = { version = "0.1", path = "../../common/std-shims", default-features = false, optional = true } diff --git a/crypto/secq256k1/Cargo.toml b/crypto/secq256k1/Cargo.toml index 777a6ec1..e0c4f3f4 100644 --- a/crypto/secq256k1/Cargo.toml +++ b/crypto/secq256k1/Cargo.toml @@ -14,7 +14,7 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [dependencies] -hex-literal = { version = "0.4", default-features = false } +hex-literal = { version = "1", default-features = false } std-shims = { version = "0.1", path = "../../common/std-shims", default-features = false, optional = true }