use alloc::vec::Vec;
use k256::{
AffinePoint, ProjectivePoint, Scalar, Secp256k1, U256,
elliptic_curve::{
PrimeField,
bigint::U512,
group::{Group, GroupEncoding},
ops::Reduce,
point::AffineCoordinates,
},
hash2curve::GroupDigest,
};
use crate::error::{Error, Result};
pub const H2C_DST: &[u8] = b"tecdsa-1ole/v1/h2c/secp256k1_XMD:SHA-256_SSWU_RO_";
pub fn x_coord(point: &ProjectivePoint) -> Scalar {
let x = point.to_affine().x();
<Scalar as Reduce<U256>>::reduce(&U256::from_be_slice(x.as_slice()))
}
pub fn derive_h_f(sid: &[u8]) -> Result<(ProjectivePoint, ProjectivePoint)> {
let derive = |label: &[u8]| {
Secp256k1::hash_from_bytes(&[label, sid], &[H2C_DST]).map_err(|_| Error::InvalidEncoding)
};
Ok((derive(b"h")?, derive(b"f")?))
}
pub fn encode_point(p: &ProjectivePoint) -> [u8; 33] {
let mut out = [0u8; 33];
out.copy_from_slice(p.to_affine().to_bytes().as_ref());
out
}
pub fn decode_point(bytes: &[u8]) -> Result<ProjectivePoint> {
let arr: [u8; 33] = bytes.try_into().map_err(|_| Error::InvalidEncoding)?;
if arr[0] != 0x02 && arr[0] != 0x03 {
return Err(Error::InvalidEncoding);
}
let p = Option::<AffinePoint>::from(AffinePoint::from_bytes(&arr.into()))
.ok_or(Error::InvalidEncoding)?;
let p = ProjectivePoint::from(p);
if is_identity(&p) {
return Err(Error::InvalidEncoding);
}
Ok(p)
}
pub fn encode_scalar(s: &Scalar) -> [u8; 32] {
let mut out = [0u8; 32];
out.copy_from_slice(s.to_repr().as_ref());
out
}
pub fn decode_scalar(bytes: &[u8]) -> Result<Scalar> {
let arr: [u8; 32] = bytes.try_into().map_err(|_| Error::InvalidEncoding)?;
Option::<Scalar>::from(Scalar::from_repr(arr.into())).ok_or(Error::InvalidEncoding)
}
pub fn random_nonzero_scalar<R: k256::elliptic_curve::rand_core::TryRng + ?Sized>(
rng: &mut R,
) -> Scalar {
loop {
let mut wide = Vec::from([0u8; 64]);
if rng.try_fill_bytes(&mut wide).is_err() {
continue;
}
let s = <Scalar as Reduce<U512>>::reduce(&U512::from_be_slice(&wide));
if !bool::from(k256::elliptic_curve::Field::is_zero(&s)) {
return s;
}
}
}
pub fn is_identity(p: &ProjectivePoint) -> bool {
bool::from(p.is_identity())
}
pub fn order() -> crypto_bigint::BoxedUint {
use k256::elliptic_curve::Curve;
let be = <Secp256k1 as Curve>::ORDER.to_be_bytes();
crypto_bigint::BoxedUint::from_be_slice_vartime(be.as_ref())
}
pub fn sbig_to_scalar(x: &crate::arith::sbig::SBig) -> Result<Scalar> {
let q = Option::<crypto_bigint::NonZero<crypto_bigint::BoxedUint>>::from(order().to_nz())
.ok_or(Error::InvalidModulus)?;
let r = x.rem_euclid(&q);
decode_scalar(&crate::transcript::uint_to_be(&r, 32)?)
}