mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 20:29:23 +00:00
* Add dkg crate * Remove F_len and G_len They're generally no longer used. * Replace hash_to_vec with a provided method around associated type H: Digest Part of trying to minimize this trait so it can be moved elsewhere. Vec, which isn't std, may have been a blocker. * Encrypt secret shares within the FROST library Reduces requirements on callers in order to be correct. * Update usage of Zeroize within FROST * Inline functions in key_gen There was no reason to have them separated as they were. sign probably has the same statement available, yet that isn't the focus right now. * Add a ciphersuite package which provides hash_to_F * Set the Ciphersuite version to something valid * Have ed448 export Scalar/FieldElement/Point at the top level * Move FROST over to Ciphersuite * Correct usage of ff in ciphersuite * Correct documentation handling * Move Schnorr signatures to their own crate * Remove unused feature from schnorr * Fix Schnorr tests * Split DKG into a separate crate * Add serialize to Commitments and SecretShare Helper for buf = vec![]; .write(buf).unwrap(); buf * Move FROST over to the new dkg crate * Update Monero lib to latest FROST * Correct ethereum's usage of features * Add serialize to GeneratorProof * Add serialize helper function to FROST * Rename AddendumSerialize to WriteAddendum * Update processor * Slight fix to processor
107 lines
3.1 KiB
Rust
107 lines
3.1 KiB
Rust
#![cfg_attr(docsrs, feature(doc_cfg))]
|
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
|
#![cfg_attr(not(feature = "std"), no_std)]
|
|
|
|
use core::fmt::Debug;
|
|
#[cfg(feature = "std")]
|
|
use std::io::{self, Read};
|
|
|
|
use rand_core::{RngCore, CryptoRng};
|
|
|
|
use zeroize::Zeroize;
|
|
use subtle::ConstantTimeEq;
|
|
|
|
use digest::{core_api::BlockSizeUser, Digest};
|
|
|
|
use group::{
|
|
ff::{Field, PrimeField, PrimeFieldBits},
|
|
Group, GroupOps,
|
|
prime::PrimeGroup,
|
|
};
|
|
#[cfg(feature = "std")]
|
|
use group::GroupEncoding;
|
|
|
|
#[cfg(feature = "dalek")]
|
|
mod dalek;
|
|
#[cfg(feature = "ristretto")]
|
|
pub use dalek::Ristretto;
|
|
#[cfg(feature = "ed25519")]
|
|
pub use dalek::Ed25519;
|
|
|
|
#[cfg(feature = "kp256")]
|
|
mod kp256;
|
|
#[cfg(feature = "secp256k1")]
|
|
pub use kp256::Secp256k1;
|
|
#[cfg(feature = "p256")]
|
|
pub use kp256::P256;
|
|
|
|
#[cfg(feature = "ed448")]
|
|
mod ed448;
|
|
#[cfg(feature = "ed448")]
|
|
pub use ed448::*;
|
|
|
|
/// Unified trait defining a ciphersuite around an elliptic curve.
|
|
pub trait Ciphersuite: 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;
|
|
/// Group element type.
|
|
type G: Group<Scalar = Self::F> + GroupOps + PrimeGroup + Zeroize + ConstantTimeEq;
|
|
/// Hash algorithm used with this curve.
|
|
// Requires BlockSizeUser so it can be used within Hkdf which requies that.
|
|
type H: Clone + BlockSizeUser + Digest;
|
|
|
|
/// ID for this curve.
|
|
const ID: &'static [u8];
|
|
|
|
/// 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;
|
|
|
|
/// Hash the provided dst and message to a scalar.
|
|
#[allow(non_snake_case)]
|
|
fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F;
|
|
|
|
/// Generate a random non-zero scalar.
|
|
#[allow(non_snake_case)]
|
|
fn random_nonzero_F<R: RngCore + CryptoRng>(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 = "std")]
|
|
#[allow(non_snake_case)]
|
|
fn read_F<R: Read>(reader: &mut R) -> io::Result<Self::F> {
|
|
let mut encoding = <Self::F as PrimeField>::Repr::default();
|
|
reader.read_exact(encoding.as_mut())?;
|
|
|
|
// ff mandates this is canonical
|
|
let res = Option::<Self::F>::from(Self::F::from_repr(encoding))
|
|
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "non-canonical scalar"));
|
|
for b in encoding.as_mut() {
|
|
b.zeroize();
|
|
}
|
|
res
|
|
}
|
|
|
|
/// Read a canonical point from something implementing std::io::Read.
|
|
#[cfg(feature = "std")]
|
|
#[allow(non_snake_case)]
|
|
fn read_G<R: Read>(reader: &mut R) -> io::Result<Self::G> {
|
|
let mut encoding = <Self::G as GroupEncoding>::Repr::default();
|
|
reader.read_exact(encoding.as_mut())?;
|
|
|
|
let point = Option::<Self::G>::from(Self::G::from_bytes(&encoding))
|
|
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid point"))?;
|
|
if point.to_bytes().as_ref() != encoding.as_ref() {
|
|
Err(io::Error::new(io::ErrorKind::Other, "non-canonical point"))?;
|
|
}
|
|
Ok(point)
|
|
}
|
|
}
|