mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-11 05:29:25 +00:00
Add support for Ristretto
Replaces P-256 as the curve used for testing FROST.
This commit is contained in:
163
crypto/frost/src/curves/dalek.rs
Normal file
163
crypto/frost/src/curves/dalek.rs
Normal file
@@ -0,0 +1,163 @@
|
||||
use core::convert::TryInto;
|
||||
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
use sha2::{Digest, Sha512};
|
||||
|
||||
use ff::PrimeField;
|
||||
use group::Group;
|
||||
|
||||
use dalek_ff_group::Scalar;
|
||||
|
||||
use crate::{CurveError, Curve, algorithm::Hram};
|
||||
|
||||
macro_rules! dalek_curve {
|
||||
(
|
||||
$Curve: ident,
|
||||
$Hram: ident,
|
||||
$Point: ident,
|
||||
$Compressed: ident,
|
||||
$Table: ident,
|
||||
|
||||
$POINT: ident,
|
||||
$TABLE: ident,
|
||||
|
||||
$torsioned: expr,
|
||||
|
||||
$ID: literal,
|
||||
$CONTEXT: literal,
|
||||
$chal: literal,
|
||||
$digest: literal,
|
||||
) => {
|
||||
use dalek_ff_group::{$Point, $Compressed, $Table, $POINT, $TABLE};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct $Curve;
|
||||
impl Curve for $Curve {
|
||||
type F = Scalar;
|
||||
type G = $Point;
|
||||
type T = &'static $Table;
|
||||
|
||||
const ID: &'static [u8] = $ID;
|
||||
|
||||
const GENERATOR: Self::G = $POINT;
|
||||
const GENERATOR_TABLE: Self::T = &$TABLE;
|
||||
|
||||
const LITTLE_ENDIAN: bool = true;
|
||||
|
||||
fn random_nonce<R: RngCore + CryptoRng>(secret: Self::F, rng: &mut R) -> Self::F {
|
||||
let mut seed = vec![0; 32];
|
||||
rng.fill_bytes(&mut seed);
|
||||
seed.extend(&secret.to_bytes());
|
||||
Self::hash_to_F(b"nonce", &seed)
|
||||
}
|
||||
|
||||
fn hash_msg(msg: &[u8]) -> Vec<u8> {
|
||||
Sha512::new()
|
||||
.chain_update($CONTEXT)
|
||||
.chain_update($digest)
|
||||
.chain_update(msg)
|
||||
.finalize()
|
||||
.to_vec()
|
||||
}
|
||||
|
||||
fn hash_binding_factor(binding: &[u8]) -> Self::F {
|
||||
Self::hash_to_F(b"rho", binding)
|
||||
}
|
||||
|
||||
fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F {
|
||||
Scalar::from_hash(Sha512::new().chain_update($CONTEXT).chain_update(dst).chain_update(msg))
|
||||
}
|
||||
|
||||
fn F_len() -> usize {
|
||||
32
|
||||
}
|
||||
|
||||
fn G_len() -> usize {
|
||||
32
|
||||
}
|
||||
|
||||
fn F_from_slice(slice: &[u8]) -> Result<Self::F, CurveError> {
|
||||
let scalar = Self::F::from_repr(
|
||||
slice.try_into().map_err(|_| CurveError::InvalidLength(32, slice.len()))?
|
||||
);
|
||||
if scalar.is_some().unwrap_u8() == 0 {
|
||||
Err(CurveError::InvalidScalar)?;
|
||||
}
|
||||
Ok(scalar.unwrap())
|
||||
}
|
||||
|
||||
fn G_from_slice(slice: &[u8]) -> Result<Self::G, CurveError> {
|
||||
let bytes = slice.try_into().map_err(|_| CurveError::InvalidLength(32, slice.len()))?;
|
||||
let point = $Compressed::new(bytes).decompress();
|
||||
|
||||
if let Some(point) = point {
|
||||
// Ban identity
|
||||
if point.is_identity().into() {
|
||||
Err(CurveError::InvalidPoint)?;
|
||||
}
|
||||
// Ban torsioned points to meet the prime order group requirement
|
||||
if $torsioned(point) {
|
||||
Err(CurveError::InvalidPoint)?;
|
||||
}
|
||||
// Ban points which weren't canonically encoded
|
||||
if point.compress().to_bytes() != bytes {
|
||||
Err(CurveError::InvalidPoint)?;
|
||||
}
|
||||
Ok(point)
|
||||
} else {
|
||||
Err(CurveError::InvalidPoint)
|
||||
}
|
||||
}
|
||||
|
||||
fn F_to_bytes(f: &Self::F) -> Vec<u8> {
|
||||
f.to_repr().to_vec()
|
||||
}
|
||||
|
||||
fn G_to_bytes(g: &Self::G) -> Vec<u8> {
|
||||
g.compress().to_bytes().to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct $Hram;
|
||||
impl Hram<$Curve> for $Hram {
|
||||
#[allow(non_snake_case)]
|
||||
fn hram(R: &$Point, A: &$Point, m: &[u8]) -> Scalar {
|
||||
$Curve::hash_to_F($chal, &[&R.compress().to_bytes(), &A.compress().to_bytes(), m].concat())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ed25519")]
|
||||
dalek_curve!(
|
||||
Ed25519,
|
||||
IetfEd25519Hram,
|
||||
EdwardsPoint,
|
||||
CompressedEdwardsY,
|
||||
EdwardsBasepointTable,
|
||||
ED25519_BASEPOINT_POINT,
|
||||
ED25519_BASEPOINT_TABLE,
|
||||
|point: EdwardsPoint| !bool::from(point.is_torsion_free()),
|
||||
b"edwards25519",
|
||||
b"",
|
||||
b"",
|
||||
b"",
|
||||
);
|
||||
|
||||
#[cfg(any(test, feature = "ristretto"))]
|
||||
dalek_curve!(
|
||||
Ristretto,
|
||||
IetfRistrettoHram,
|
||||
RistrettoPoint,
|
||||
CompressedRistretto,
|
||||
RistrettoBasepointTable,
|
||||
RISTRETTO_BASEPOINT_POINT,
|
||||
RISTRETTO_BASEPOINT_TABLE,
|
||||
|_| false,
|
||||
b"ristretto",
|
||||
b"FROST-RISTRETTO255-SHA512-v5",
|
||||
b"chal",
|
||||
b"digest",
|
||||
);
|
||||
@@ -1,104 +0,0 @@
|
||||
use core::convert::TryInto;
|
||||
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
use sha2::{Digest, Sha512};
|
||||
|
||||
use ff::PrimeField;
|
||||
use group::Group;
|
||||
|
||||
use dalek_ff_group::{
|
||||
EdwardsBasepointTable,
|
||||
ED25519_BASEPOINT_POINT, ED25519_BASEPOINT_TABLE,
|
||||
Scalar, EdwardsPoint, CompressedEdwardsY
|
||||
};
|
||||
|
||||
use crate::{CurveError, Curve, algorithm::Hram};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct Ed25519;
|
||||
impl Curve for Ed25519 {
|
||||
type F = Scalar;
|
||||
type G = EdwardsPoint;
|
||||
type T = &'static EdwardsBasepointTable;
|
||||
|
||||
const ID: &'static [u8] = b"edwards25519";
|
||||
|
||||
const GENERATOR: Self::G = ED25519_BASEPOINT_POINT;
|
||||
const GENERATOR_TABLE: Self::T = &ED25519_BASEPOINT_TABLE;
|
||||
|
||||
const LITTLE_ENDIAN: bool = true;
|
||||
|
||||
fn random_nonce<R: RngCore + CryptoRng>(secret: Self::F, rng: &mut R) -> Self::F {
|
||||
let mut seed = vec![0; 32];
|
||||
rng.fill_bytes(&mut seed);
|
||||
seed.extend(&secret.to_bytes());
|
||||
Self::hash_to_F(b"nonce", &seed)
|
||||
}
|
||||
|
||||
fn hash_msg(msg: &[u8]) -> Vec<u8> {
|
||||
Sha512::digest(msg).to_vec()
|
||||
}
|
||||
|
||||
fn hash_binding_factor(binding: &[u8]) -> Self::F {
|
||||
Self::hash_to_F(b"rho", binding)
|
||||
}
|
||||
|
||||
fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F {
|
||||
Scalar::from_hash(Sha512::new().chain_update(dst).chain_update(msg))
|
||||
}
|
||||
|
||||
fn F_len() -> usize {
|
||||
32
|
||||
}
|
||||
|
||||
fn G_len() -> usize {
|
||||
32
|
||||
}
|
||||
|
||||
fn F_from_slice(slice: &[u8]) -> Result<Self::F, CurveError> {
|
||||
let scalar = Self::F::from_repr(
|
||||
slice.try_into().map_err(|_| CurveError::InvalidLength(32, slice.len()))?
|
||||
);
|
||||
if scalar.is_some().unwrap_u8() == 0 {
|
||||
Err(CurveError::InvalidScalar)?;
|
||||
}
|
||||
Ok(scalar.unwrap())
|
||||
}
|
||||
|
||||
fn G_from_slice(slice: &[u8]) -> Result<Self::G, CurveError> {
|
||||
let bytes = slice.try_into().map_err(|_| CurveError::InvalidLength(32, slice.len()))?;
|
||||
let point = CompressedEdwardsY::new(bytes).decompress();
|
||||
|
||||
if let Some(point) = point {
|
||||
// Ban identity and torsioned points
|
||||
if point.is_identity().into() || (!bool::from(point.is_torsion_free())) {
|
||||
Err(CurveError::InvalidPoint)?;
|
||||
}
|
||||
// Ban points which weren't canonically encoded
|
||||
if point.compress().to_bytes() != bytes {
|
||||
Err(CurveError::InvalidPoint)?;
|
||||
}
|
||||
Ok(point)
|
||||
} else {
|
||||
Err(CurveError::InvalidPoint)
|
||||
}
|
||||
}
|
||||
|
||||
fn F_to_bytes(f: &Self::F) -> Vec<u8> {
|
||||
f.to_repr().to_vec()
|
||||
}
|
||||
|
||||
fn G_to_bytes(g: &Self::G) -> Vec<u8> {
|
||||
g.compress().to_bytes().to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct IetfEd25519Hram;
|
||||
impl Hram<Ed25519> for IetfEd25519Hram {
|
||||
#[allow(non_snake_case)]
|
||||
fn hram(R: &EdwardsPoint, A: &EdwardsPoint, m: &[u8]) -> Scalar {
|
||||
Ed25519::hash_to_F(b"", &[&R.compress().to_bytes(), &A.compress().to_bytes(), m].concat())
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ use group::{Group, GroupEncoding};
|
||||
use elliptic_curve::{bigint::{Encoding, U384}, hash2curve::{Expander, ExpandMsg, ExpandMsgXmd}};
|
||||
|
||||
use crate::{CurveError, Curve};
|
||||
#[cfg(any(test, feature = "p256"))]
|
||||
#[cfg(feature = "p256")]
|
||||
use crate::algorithm::Hram;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
@@ -25,9 +25,9 @@ pub(crate) trait KP256Instance<G> {
|
||||
const GENERATOR: G;
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "p256"))]
|
||||
#[cfg(feature = "p256")]
|
||||
pub type P256 = KP256<p256::ProjectivePoint>;
|
||||
#[cfg(any(test, feature = "p256"))]
|
||||
#[cfg(feature = "p256")]
|
||||
impl KP256Instance<p256::ProjectivePoint> for P256 {
|
||||
const CONTEXT: &'static [u8] = b"FROST-P256-SHA256-v5";
|
||||
const ID: &'static [u8] = b"P-256";
|
||||
@@ -139,10 +139,10 @@ impl<G: Group + GroupEncoding> Curve for KP256<G> where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "p256"))]
|
||||
#[cfg(feature = "p256")]
|
||||
#[derive(Clone)]
|
||||
pub struct IetfP256Hram;
|
||||
#[cfg(any(test, feature = "p256"))]
|
||||
#[cfg(feature = "p256")]
|
||||
impl Hram<P256> for IetfP256Hram {
|
||||
#[allow(non_snake_case)]
|
||||
fn hram(R: &p256::ProjectivePoint, A: &p256::ProjectivePoint, m: &[u8]) -> p256::Scalar {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#[cfg(any(test, feature = "kp256"))]
|
||||
pub mod kp256;
|
||||
#[cfg(any(test, feature = "dalek"))]
|
||||
pub mod dalek;
|
||||
|
||||
#[cfg(feature = "ed25519")]
|
||||
pub mod ed25519;
|
||||
#[cfg(feature = "kp256")]
|
||||
pub mod kp256;
|
||||
|
||||
Reference in New Issue
Block a user