2022-06-05 16:08:51 -04:00
|
|
|
use rand_core::{RngCore, CryptoRng};
|
|
|
|
|
|
2022-06-06 02:18:25 -04:00
|
|
|
use sha2::{digest::Update, Digest, Sha256};
|
|
|
|
|
|
2022-06-28 01:25:26 -04:00
|
|
|
use group::{ff::Field, GroupEncoding};
|
2022-06-05 16:08:51 -04:00
|
|
|
|
2022-06-06 02:18:25 -04:00
|
|
|
use elliptic_curve::{bigint::{Encoding, U384}, hash2curve::{Expander, ExpandMsg, ExpandMsgXmd}};
|
2022-06-05 16:08:51 -04:00
|
|
|
|
2022-06-28 01:25:26 -04:00
|
|
|
use crate::{curve::{Curve, F_from_slice}, algorithm::Hram};
|
2022-06-24 08:44:12 -04:00
|
|
|
|
|
|
|
|
macro_rules! kp_curve {
|
|
|
|
|
(
|
|
|
|
|
$lib: ident,
|
|
|
|
|
$Curve: ident,
|
|
|
|
|
$Hram: ident,
|
|
|
|
|
|
|
|
|
|
$ID: literal,
|
|
|
|
|
$CONTEXT: literal
|
|
|
|
|
) => {
|
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
|
|
|
pub struct $Curve;
|
|
|
|
|
impl Curve for $Curve {
|
|
|
|
|
type F = $lib::Scalar;
|
|
|
|
|
type G = $lib::ProjectivePoint;
|
|
|
|
|
|
|
|
|
|
const ID: &'static [u8] = $ID;
|
|
|
|
|
const GENERATOR: Self::G = $lib::ProjectivePoint::GENERATOR;
|
|
|
|
|
|
|
|
|
|
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(&[$CONTEXT as &[u8], b"nonce"].concat(), &seed)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn hash_msg(msg: &[u8]) -> Vec<u8> {
|
|
|
|
|
(&Sha256::new()
|
|
|
|
|
.chain($CONTEXT)
|
|
|
|
|
.chain(b"digest")
|
|
|
|
|
.chain(msg)
|
|
|
|
|
.finalize()
|
|
|
|
|
).to_vec()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn hash_binding_factor(binding: &[u8]) -> Self::F {
|
|
|
|
|
Self::hash_to_F(&[$CONTEXT as &[u8], b"rho"].concat(), binding)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn hash_to_F(dst: &[u8], msg: &[u8]) -> Self::F {
|
|
|
|
|
let mut dst = dst;
|
|
|
|
|
let oversize = Sha256::digest([b"H2C-OVERSIZE-DST-", dst].concat());
|
|
|
|
|
if dst.len() > 255 {
|
|
|
|
|
dst = &oversize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// While one of these two libraries does support directly hashing to the Scalar field, the
|
|
|
|
|
// other doesn't. While that's probably an oversight, this is a universally working method
|
|
|
|
|
let mut modulus = vec![0; 16];
|
|
|
|
|
modulus.extend((Self::F::zero() - Self::F::one()).to_bytes());
|
|
|
|
|
let modulus = U384::from_be_slice(&modulus).wrapping_add(&U384::ONE);
|
2022-06-28 01:25:26 -04:00
|
|
|
F_from_slice::<Self::F>(
|
2022-06-24 08:44:12 -04:00
|
|
|
&U384::from_be_slice(&{
|
|
|
|
|
let mut bytes = [0; 48];
|
|
|
|
|
ExpandMsgXmd::<Sha256>::expand_message(
|
|
|
|
|
&[msg],
|
|
|
|
|
dst,
|
|
|
|
|
48
|
|
|
|
|
).unwrap().fill_bytes(&mut bytes);
|
|
|
|
|
bytes
|
|
|
|
|
}).reduce(&modulus).unwrap().to_be_bytes()[16 ..]
|
|
|
|
|
).unwrap()
|
|
|
|
|
}
|
2022-06-06 02:18:25 -04:00
|
|
|
}
|
|
|
|
|
|
2022-06-24 08:44:12 -04:00
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub struct $Hram;
|
|
|
|
|
impl Hram<$Curve> for $Hram {
|
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
|
fn hram(R: &$lib::ProjectivePoint, A: &$lib::ProjectivePoint, m: &[u8]) -> $lib::Scalar {
|
|
|
|
|
$Curve::hash_to_F(
|
|
|
|
|
&[$CONTEXT as &[u8], b"chal"].concat(),
|
2022-06-28 01:25:26 -04:00
|
|
|
&[R.to_bytes().as_ref(), A.to_bytes().as_ref(), m].concat()
|
2022-06-24 08:44:12 -04:00
|
|
|
)
|
|
|
|
|
}
|
2022-06-05 16:08:51 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-06 02:18:25 -04:00
|
|
|
|
2022-06-06 04:22:49 -04:00
|
|
|
#[cfg(feature = "p256")]
|
2022-06-24 08:44:12 -04:00
|
|
|
kp_curve!(
|
|
|
|
|
p256,
|
|
|
|
|
P256,
|
|
|
|
|
IetfP256Hram,
|
|
|
|
|
b"P-256",
|
|
|
|
|
b"FROST-P256-SHA256-v5"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "secp256k1")]
|
|
|
|
|
kp_curve!(
|
|
|
|
|
k256,
|
|
|
|
|
Secp256k1,
|
|
|
|
|
NonIetfSecp256k1Hram,
|
|
|
|
|
b"secp256k1",
|
2022-07-12 03:20:50 -04:00
|
|
|
b"FROST-secp256k1-SHA256-v7"
|
2022-06-24 08:44:12 -04:00
|
|
|
);
|