use core::convert::TryInto; use digest::Digest; use ff::PrimeField; use group::GroupEncoding; use sha2::{Sha256, Sha512}; use k256::{ elliptic_curve::{generic_array::GenericArray, bigint::{ArrayEncoding, U512}, ops::Reduce}, Scalar, ProjectivePoint }; use frost::{CurveError, Curve, multiexp_vartime, algorithm::Hram}; #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct Secp256k1; impl Curve for Secp256k1 { type F = Scalar; type G = ProjectivePoint; type T = ProjectivePoint; fn id() -> String { "secp256k1".to_string() } fn id_len() -> u8 { Self::id().len() as u8 } fn generator() -> Self::G { Self::G::GENERATOR } fn generator_table() -> Self::T { Self::G::GENERATOR } fn multiexp_vartime(scalars: &[Self::F], points: &[Self::G]) -> Self::G { multiexp_vartime::(scalars, points) } // The IETF draft doesn't specify a secp256k1 ciphersuite // This test just uses the simplest ciphersuite which would still be viable to deploy fn hash_msg(msg: &[u8]) -> Vec { (&Sha256::digest(msg)).to_vec() } // Use wide reduction for security fn hash_to_F(data: &[u8]) -> Self::F { Scalar::from_uint_reduced( U512::from_be_byte_array(Sha512::new().chain_update("rho").chain_update(data).finalize()) ) } fn F_len() -> usize { 32 } fn G_len() -> usize { 33 } fn F_from_le_slice(slice: &[u8]) -> Result { let mut bytes: [u8; 32] = slice.try_into().map_err( |_| CurveError::InvalidLength(32, slice.len()) )?; bytes.reverse(); let scalar = Scalar::from_repr(bytes.into()); if scalar.is_none().unwrap_u8() == 1 { Err(CurveError::InvalidScalar)?; } Ok(scalar.unwrap()) } fn G_from_slice(slice: &[u8]) -> Result { let point = ProjectivePoint::from_bytes(GenericArray::from_slice(slice)); if point.is_none().unwrap_u8() == 1 { Err(CurveError::InvalidScalar)?; } Ok(point.unwrap()) } fn F_to_le_bytes(f: &Self::F) -> Vec { let mut res: [u8; 32] = f.to_bytes().into(); res.reverse(); res.to_vec() } fn G_to_bytes(g: &Self::G) -> Vec { (&g.to_bytes()).to_vec() } } #[allow(non_snake_case)] #[derive(Clone)] pub struct TestHram {} impl Hram for TestHram { #[allow(non_snake_case)] fn hram(R: &ProjectivePoint, A: &ProjectivePoint, m: &[u8]) -> Scalar { Scalar::from_uint_reduced( U512::from_be_byte_array( Sha512::new() .chain_update(Secp256k1::G_to_bytes(R)) .chain_update(Secp256k1::G_to_bytes(A)) .chain_update(m) .finalize() ) ) } }