Smash the singular Ciphersuite trait into multiple

This helps identify where the various functionalities are used, or rather, not
used. The `Ciphersuite` trait present in `patches/ciphersuite`, facilitating
the entire FCMP++ tree, only requires the markers _and_ canonical point
decoding. I've opened a PR to upstream such a trait into `group`
(https://github.com/zkcrypto/group/pull/68).

`WrappedGroup` is still justified for as long as `Group::generator` exists.
Moving `::generator()` to its own trait, on an independent structure (upstream)
would be massively appreciated. @tarcieri also wanted to update from
`fn generator()` to `const GENERATOR`, which would encourage further discussion
on https://github.com/zkcrypto/group/issues/32 and
https://github.com/zkcrypto/group/issues/45, which have been stagnant.

The `Id` trait is occasionally used yet really should be first off the chopping
block.

Finally, `WithPreferredHash` is only actually used around a third of the time,
which more than justifies it being a separate trait.

---

Updates `dalek_ff_group::Scalar` to directly re-export
`curve25519_dalek::Scalar`, as without issue. `dalek_ff_group::RistrettoPoint`
also could be replaced with an export of `curve25519_dalek::RistrettoPoint`,
yet the coordinator relies on how we implemented `Hash` on it for the hell of
it so it isn't worth it at this time. `dalek_ff_group::EdwardsPoint` can't be
replaced for an re-export of `curve25519_dalek::SubgroupPoint` as it doesn't
implement `zeroize`, `subtle` traits within a released, non-yanked version.
Relevance to https://github.com/serai-dex/serai/issues/201 and
https://github.com/dalek-cryptography/curve25519-dalek/issues/811#issuecomment-3247732746.

Also updates the `Ristretto` ciphersuite to prefer `Blake2b-512` over
`SHA2-512`. In order to maintain compliance with FROST's IETF standard,
`modular-frost` defines its own ciphersuite for Ristretto which still uses
`SHA2-512`.
This commit is contained in:
Luke Parker
2025-09-03 12:25:37 -04:00
parent 215e41fdb6
commit a141deaf36
124 changed files with 1003 additions and 1211 deletions

View File

@@ -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" }

View File

@@ -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<K: KeyGenParams>() -> KeyGen<K> {
fn read_key_from_env<C: Ciphersuite>(label: &'static str) -> Zeroizing<C::F> {
fn read_key_from_env<C: WrappedGroup>(label: &'static str) -> Zeroizing<C::F> {
let key_hex =
Zeroizing::new(env::var(label).unwrap_or_else(|| panic!("{label} wasn't provided")));
let bytes = Zeroizing::new(

View File

@@ -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: <<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as Ciphersuite>::G,
key: <<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as WrappedGroup>::G,
) -> Vec<u8> {
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<<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as Ciphersuite>::G> {
) -> Option<<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as WrappedGroup>::G> {
x_coord_to_even_point(key)
}
}

View File

@@ -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<D: Db> fmt::Debug for Block<D> {
impl<D: Db> primitives::Block for Block<D> {
type Header = BlockHeader;
type Key = <Secp256k1 as Ciphersuite>::G;
type Key = <Secp256k1 as WrappedGroup>::G;
type Address = Address;
type Output = Output;
type Eventuality = Eventuality;

View File

@@ -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<<Secp256k1 as Ciphersuite>::G> {
pub(crate) fn x_coord_to_even_point(key: &[u8]) -> Option<<Secp256k1 as WrappedGroup>::G> {
if key.len() != 32 {
None?
};

View File

@@ -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: <Secp256k1 as Ciphersuite>::G,
key: <Secp256k1 as WrappedGroup>::G,
tx: &Transaction,
output: WalletOutput,
) -> Self {
@@ -71,7 +71,7 @@ impl Output {
}
pub(crate) fn new_with_presumed_origin(
key: <Secp256k1 as Ciphersuite>::G,
key: <Secp256k1 as WrappedGroup>::G,
tx: &Transaction,
presumed_origin: Option<Address>,
output: WalletOutput,
@@ -88,7 +88,7 @@ impl Output {
}
}
impl ReceivedOutput<<Secp256k1 as Ciphersuite>::G, Address> for Output {
impl ReceivedOutput<<Secp256k1 as WrappedGroup>::G, Address> for Output {
type Id = OutputId;
type TransactionId = [u8; 32];
@@ -108,7 +108,7 @@ impl ReceivedOutput<<Secp256k1 as Ciphersuite>::G, Address> for Output {
res
}
fn key(&self) -> <Secp256k1 as Ciphersuite>::G {
fn key(&self) -> <Secp256k1 as WrappedGroup>::G {
// We read the key from the script pubkey so we don't have to independently store it
let script = &self.output.output().script_pubkey;
@@ -121,7 +121,7 @@ impl ReceivedOutput<<Secp256k1 as Ciphersuite>::G, Address> for Output {
.expect("last item in scanned v1 Taproot script wasn't a valid x-only public key");
// The output's key minus the output's offset is the root key
key - (<Secp256k1 as Ciphersuite>::G::GENERATOR * self.output.offset())
key - (<Secp256k1 as WrappedGroup>::G::GENERATOR * self.output.offset())
}
fn presumed_origin(&self) -> Option<Address> {

View File

@@ -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<<Secp256k1 as Ciphersuite>::F> =
static BRANCH_BASE_OFFSET: LazyLock<<Secp256k1 as WrappedGroup>::F> =
LazyLock::new(|| Secp256k1::hash_to_F(b"branch"));
static CHANGE_BASE_OFFSET: LazyLock<<Secp256k1 as Ciphersuite>::F> =
static CHANGE_BASE_OFFSET: LazyLock<<Secp256k1 as WrappedGroup>::F> =
LazyLock::new(|| Secp256k1::hash_to_F(b"change"));
static FORWARD_BASE_OFFSET: LazyLock<<Secp256k1 as Ciphersuite>::F> =
static FORWARD_BASE_OFFSET: LazyLock<<Secp256k1 as WrappedGroup>::F> =
LazyLock::new(|| Secp256k1::hash_to_F(b"forward"));
// 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: <Secp256k1 as Ciphersuite>::G,
) -> HashMap<OutputType, <Secp256k1 as Ciphersuite>::F> {
let mut offsets = HashMap::from([(OutputType::External, <Secp256k1 as Ciphersuite>::F::ZERO)]);
key: <Secp256k1 as WrappedGroup>::G,
) -> HashMap<OutputType, <Secp256k1 as WrappedGroup>::F> {
let mut offsets = HashMap::from([(OutputType::External, <Secp256k1 as WrappedGroup>::F::ZERO)]);
// We create an actual Bitcoin scanner as upon adding an offset, it yields the tweaked offset
// actually used
@@ -50,7 +50,7 @@ pub(crate) fn offsets_for_key(
offsets
}
pub(crate) fn scanner(key: <Secp256k1 as Ciphersuite>::G) -> Scanner {
pub(crate) fn scanner(key: <Secp256k1 as WrappedGroup>::G) -> Scanner {
let mut scanner = Scanner::new(key).unwrap();
for (_, offset) in offsets_for_key(key) {
let tweaked_offset = scanner.register_offset(offset).unwrap();

View File

@@ -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: <Secp256k1 as Ciphersuite>::G, kind: OutputType) -> Address {
let offset = <Secp256k1 as Ciphersuite>::G::GENERATOR * offsets_for_key(key)[&kind];
fn address_from_serai_key(key: <Secp256k1 as WrappedGroup>::G, kind: OutputType) -> Address {
let offset = <Secp256k1 as WrappedGroup>::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<D: Db>(
*/
payments.push((
// The generator is even so this is valid
p2tr_script_buf(<Secp256k1 as Ciphersuite>::G::GENERATOR).unwrap(),
p2tr_script_buf(<Secp256k1 as WrappedGroup>::G::GENERATOR).unwrap(),
// This uses the minimum output value allowed, as defined as a constant in bitcoin-serai
// TODO: Add a test for this comparing to bitcoin's `minimal_non_dust`
bitcoin_serai::wallet::DUST,

View File

@@ -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<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve>,
) {
while PublicKey::new(keys.group_key()).is_none() {
*keys = keys.clone().offset(<<Secp256k1 as Curves>::ToweringCurve as Ciphersuite>::F::ONE);
*keys = keys.clone().offset(<<Secp256k1 as Curves>::ToweringCurve as WrappedGroup>::F::ONE);
}
}
fn encode_key(
key: <<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as Ciphersuite>::G,
key: <<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as WrappedGroup>::G,
) -> Vec<u8> {
PublicKey::new(key).unwrap().eth_repr().to_vec()
}
fn decode_key(
key: &[u8],
) -> Option<<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as Ciphersuite>::G> {
) -> Option<<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as WrappedGroup>::G> {
PublicKey::from_eth_repr(key.try_into().ok()?).map(|key| key.point())
}
}

View File

@@ -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 = <Secp256k1 as Ciphersuite>::G;
type Key = <Secp256k1 as WrappedGroup>::G;
type Address = Address;
type Output = Output;
type Eventuality = Eventuality;

View File

@@ -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<Secp256k1> for EthereumHram {
#[allow(non_snake_case)]
fn hram(
R: &<Secp256k1 as Ciphersuite>::G,
A: &<Secp256k1 as Ciphersuite>::G,
R: &<Secp256k1 as WrappedGroup>::G,
A: &<Secp256k1 as WrappedGroup>::G,
m: &[u8],
) -> <Secp256k1 as Ciphersuite>::F {
) -> <Secp256k1 as WrappedGroup>::F {
Signature::challenge(*R, &PublicKey::new(*A).unwrap(), m)
}
}

View File

@@ -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: <Secp256k1 as Ciphersuite>::G, instruction: EthereumInInstruction },
Eventuality { key: <Secp256k1 as Ciphersuite>::G, nonce: u64 },
Output { key: <Secp256k1 as WrappedGroup>::G, instruction: EthereumInInstruction },
Eventuality { key: <Secp256k1 as WrappedGroup>::G, nonce: u64 },
}
impl ReceivedOutput<<Secp256k1 as Ciphersuite>::G, Address> for Output {
impl ReceivedOutput<<Secp256k1 as WrappedGroup>::G, Address> for Output {
type Id = OutputId;
type TransactionId = [u8; 32];
@@ -107,7 +107,7 @@ impl ReceivedOutput<<Secp256k1 as Ciphersuite>::G, Address> for Output {
}
}
fn key(&self) -> <Secp256k1 as Ciphersuite>::G {
fn key(&self) -> <Secp256k1 as WrappedGroup>::G {
match self {
Output::Output { key, .. } | Output::Eventuality { key, .. } => *key,
}

View File

@@ -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"] }

View File

@@ -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<P: KeyGenParams> {
pub(crate) t: u16,
pub(crate) n: u16,
pub(crate) substrate_evrf_public_keys:
Vec<<<Ristretto as Curves>::EmbeddedCurve as Ciphersuite>::G>,
Vec<<<Ristretto as Curves>::EmbeddedCurve as WrappedGroup>::G>,
pub(crate) network_evrf_public_keys:
Vec<<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as Ciphersuite>::G>,
Vec<<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as WrappedGroup>::G>,
}
#[derive(BorshSerialize, BorshDeserialize)]
@@ -85,17 +85,16 @@ impl<P: KeyGenParams> KeyGenDb<P> {
.substrate_evrf_public_keys
.into_iter()
.map(|key| {
<<Ristretto as Curves>::EmbeddedCurve as Ciphersuite>::read_G(&mut key.as_slice())
.unwrap()
<<Ristretto as Curves>::EmbeddedCurve as GroupIo>::read_G(&mut key.as_slice()).unwrap()
})
.collect(),
network_evrf_public_keys: params
.network_evrf_public_keys
.into_iter()
.map(|key| {
<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as Ciphersuite>::read_G::<
&[u8],
>(&mut key.as_ref())
<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as GroupIo>::read_G::<&[u8]>(
&mut key.as_ref(),
)
.unwrap()
})
.collect(),

View File

@@ -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: <<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as Ciphersuite>::G,
key: <<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as WrappedGroup>::G,
) -> Vec<u8> {
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<<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as Ciphersuite>::G> {
let res = <<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as Ciphersuite>::read_G(
&mut key,
)
.ok()?;
) -> Option<<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as WrappedGroup>::G> {
let res =
<<Self::ExternalNetworkCiphersuite as Curves>::ToweringCurve as GroupIo>::read_G(&mut key)
.ok()?;
if !key.is_empty() {
None?;
}
@@ -101,14 +108,14 @@ pub trait KeyGenParams {
*/
fn coerce_keys<C: 'static + Curves>(
key_bytes: &[impl AsRef<[u8]>],
) -> (Vec<<C::EmbeddedCurve as Ciphersuite>::G>, Vec<Participant>) {
fn evrf_key<C: 'static + Curves>(key: &[u8]) -> Option<<C::EmbeddedCurve as Ciphersuite>::G> {
let mut repr = <<C::EmbeddedCurve as Ciphersuite>::G as GroupEncoding>::Repr::default();
) -> (Vec<<C::EmbeddedCurve as WrappedGroup>::G>, Vec<Participant>) {
fn evrf_key<C: 'static + Curves>(key: &[u8]) -> Option<<C::EmbeddedCurve as WrappedGroup>::G> {
let mut repr = <<C::EmbeddedCurve as WrappedGroup>::G as GroupEncoding>::Repr::default();
if repr.as_ref().len() != key.len() {
None?;
}
repr.as_mut().copy_from_slice(key);
let point = Option::<<C::EmbeddedCurve as Ciphersuite>::G>::from(<_>::from_bytes(&repr))?;
let point = Option::<<C::EmbeddedCurve as WrappedGroup>::G>::from(<_>::from_bytes(&repr))?;
if bool::from(point.is_identity()) {
None?;
}
@@ -131,10 +138,10 @@ fn coerce_keys<C: 'static + Curves>(
// Generate a random key
let mut rng = ChaCha20Rng::from_seed(Blake2s256::digest(key).into());
loop {
let mut repr = <<C::EmbeddedCurve as Ciphersuite>::G as GroupEncoding>::Repr::default();
let mut repr = <<C::EmbeddedCurve as WrappedGroup>::G as GroupEncoding>::Repr::default();
rng.fill_bytes(repr.as_mut());
if let Some(key) =
Option::<<C::EmbeddedCurve as Ciphersuite>::G>::from(<_>::from_bytes(&repr))
Option::<<C::EmbeddedCurve as WrappedGroup>::G>::from(<_>::from_bytes(&repr))
{
break key;
}
@@ -149,18 +156,20 @@ fn coerce_keys<C: 'static + Curves>(
/// An instance of the Serai key generation protocol.
#[derive(Debug)]
pub struct KeyGen<P: KeyGenParams> {
substrate_evrf_private_key: Zeroizing<<<Ristretto as Curves>::EmbeddedCurve as Ciphersuite>::F>,
substrate_evrf_private_key: Zeroizing<<<Ristretto as Curves>::EmbeddedCurve as WrappedGroup>::F>,
network_evrf_private_key:
Zeroizing<<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as Ciphersuite>::F>,
Zeroizing<<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as WrappedGroup>::F>,
}
impl<P: KeyGenParams> KeyGen<P> {
/// Create a new key generation instance.
#[allow(clippy::new_ret_no_self)]
pub fn new(
substrate_evrf_private_key: Zeroizing<<<Ristretto as Curves>::EmbeddedCurve as Ciphersuite>::F>,
substrate_evrf_private_key: Zeroizing<
<<Ristretto as Curves>::EmbeddedCurve as WrappedGroup>::F,
>,
network_evrf_private_key: Zeroizing<
<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as Ciphersuite>::F,
<<P::ExternalNetworkCiphersuite as Curves>::EmbeddedCurve as WrappedGroup>::F,
>,
) -> KeyGen<P> {
KeyGen { substrate_evrf_private_key, network_evrf_private_key }
@@ -214,8 +223,8 @@ impl<P: KeyGenParams> KeyGen<P> {
fn participate<C: 'static + Curves>(
context: [u8; 32],
threshold: u16,
evrf_public_keys: &[<C::EmbeddedCurve as Ciphersuite>::G],
evrf_private_key: &Zeroizing<<C::EmbeddedCurve as Ciphersuite>::F>,
evrf_public_keys: &[<C::EmbeddedCurve as WrappedGroup>::G],
evrf_private_key: &Zeroizing<<C::EmbeddedCurve as WrappedGroup>::F>,
output: &mut impl io::Write,
) {
let participation = Dkg::<C>::participate(
@@ -411,7 +420,7 @@ impl<P: KeyGenParams> KeyGen<P> {
session: Session,
true_if_substrate_false_if_network: bool,
threshold: u16,
evrf_public_keys: &[<C::EmbeddedCurve as Ciphersuite>::G],
evrf_public_keys: &[<C::EmbeddedCurve as WrappedGroup>::G],
substrate_participations: &mut HashMap<Participant, Vec<u8>>,
network_participations: &mut HashMap<Participant, Vec<u8>>,
) -> Result<Dkg<C>, Vec<ProcessorMessage>> {

View File

@@ -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"] }

View File

@@ -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 = <Ed25519 as Ciphersuite>::G;
type Key = <Ed25519 as WrappedGroup>::G;
type Address = Address;
type Output = Output;
type Eventuality = Eventuality;

View File

@@ -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: <Ed25519 as Ciphersuite>::G) -> GuaranteedViewPair {
match GuaranteedViewPair::new(key.0, Zeroizing::new(*view_key::<Ed25519>(0))) {
pub(crate) fn view_pair(key: <Ed25519 as WrappedGroup>::G) -> GuaranteedViewPair {
match GuaranteedViewPair::new(key.0, Zeroizing::new(view_key::<Ed25519>(0))) {
Ok(view_pair) => view_pair,
Err(ViewPairError::TorsionedSpendKey) => {
unreachable!("dalek_ff_group::EdwardsPoint had torsion")

View File

@@ -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<<Ed25519 as Ciphersuite>::G, Address> for Output {
impl ReceivedOutput<<Ed25519 as WrappedGroup>::G, Address> for Output {
type Id = OutputId;
type TransactionId = [u8; 32];
@@ -64,12 +64,12 @@ impl ReceivedOutput<<Ed25519 as Ciphersuite>::G, Address> for Output {
self.0.transaction()
}
fn key(&self) -> <Ed25519 as Ciphersuite>::G {
fn key(&self) -> <Ed25519 as WrappedGroup>::G {
// The spend key will be a key we generated, so it'll be in the prime-order subgroup
// The 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() - (*<Ed25519 as Ciphersuite>::G::generator() * self.0.key_offset()),
self.0.key() - (*<Ed25519 as WrappedGroup>::generator() * self.0.key_offset()),
)
}

View File

@@ -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: <Ed25519 as Ciphersuite>::G, kind: OutputType) -> Address {
fn address_from_serai_key(key: <Ed25519 as WrappedGroup>::G, kind: OutputType) -> Address {
view_pair(key)
.address(
Network::Mainnet,
@@ -118,8 +118,8 @@ async fn signable_transaction(
MoneroAddress::new(
Network::Mainnet,
AddressType::Legacy,
<Ed25519 as Ciphersuite>::generator().0,
<Ed25519 as Ciphersuite>::generator().0,
<Ed25519 as WrappedGroup>::generator().0,
<Ed25519 as WrappedGroup>::generator().0,
),
0,
));

View File

@@ -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;

View File

@@ -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"] }

View File

@@ -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;

View File

@@ -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;

View File

@@ -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};

View File

@@ -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;

View File

@@ -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::*,

View File

@@ -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.
///