1use alloc::vec::Vec;
3use k256::{
4 AffinePoint, ProjectivePoint, Scalar, Secp256k1, U256,
5 elliptic_curve::{
6 PrimeField,
7 bigint::U512,
8 group::{Group, GroupEncoding},
9 ops::Reduce,
10 point::AffineCoordinates,
11 },
12 hash2curve::GroupDigest,
13};
14
15use crate::error::{Error, Result};
16
17pub const H2C_DST: &[u8] = b"tecdsa-1ole/v1/h2c/secp256k1_XMD:SHA-256_SSWU_RO_";
19
20pub fn x_coord(point: &ProjectivePoint) -> Scalar {
22 let x = point.to_affine().x();
23 <Scalar as Reduce<U256>>::reduce(&U256::from_be_slice(x.as_slice()))
24}
25
26pub fn derive_h_f(sid: &[u8]) -> Result<(ProjectivePoint, ProjectivePoint)> {
28 let derive = |label: &[u8]| {
29 Secp256k1::hash_from_bytes(&[label, sid], &[H2C_DST]).map_err(|_| Error::InvalidEncoding)
30 };
31 Ok((derive(b"h")?, derive(b"f")?))
32}
33
34pub fn encode_point(p: &ProjectivePoint) -> [u8; 33] {
36 let mut out = [0u8; 33];
37 out.copy_from_slice(p.to_affine().to_bytes().as_ref());
38 out
39}
40
41pub fn decode_point(bytes: &[u8]) -> Result<ProjectivePoint> {
43 let arr: [u8; 33] = bytes.try_into().map_err(|_| Error::InvalidEncoding)?;
44 if arr[0] != 0x02 && arr[0] != 0x03 {
46 return Err(Error::InvalidEncoding);
47 }
48 let p = Option::<AffinePoint>::from(AffinePoint::from_bytes(&arr.into()))
49 .ok_or(Error::InvalidEncoding)?;
50 let p = ProjectivePoint::from(p);
51 if is_identity(&p) {
52 return Err(Error::InvalidEncoding);
53 }
54 Ok(p)
55}
56
57pub fn encode_scalar(s: &Scalar) -> [u8; 32] {
59 let mut out = [0u8; 32];
60 out.copy_from_slice(s.to_repr().as_ref());
61 out
62}
63
64pub fn decode_scalar(bytes: &[u8]) -> Result<Scalar> {
66 let arr: [u8; 32] = bytes.try_into().map_err(|_| Error::InvalidEncoding)?;
67 Option::<Scalar>::from(Scalar::from_repr(arr.into())).ok_or(Error::InvalidEncoding)
68}
69
70pub fn random_nonzero_scalar<R: k256::elliptic_curve::rand_core::TryRng + ?Sized>(
72 rng: &mut R,
73) -> Scalar {
74 loop {
75 let mut wide = Vec::from([0u8; 64]);
76 if rng.try_fill_bytes(&mut wide).is_err() {
77 continue;
78 }
79 let s = <Scalar as Reduce<U512>>::reduce(&U512::from_be_slice(&wide));
80 if !bool::from(k256::elliptic_curve::Field::is_zero(&s)) {
81 return s;
82 }
83 }
84}
85
86pub fn is_identity(p: &ProjectivePoint) -> bool {
88 bool::from(p.is_identity())
89}
90
91pub fn order() -> crypto_bigint::BoxedUint {
93 use k256::elliptic_curve::Curve;
94 let be = <Secp256k1 as Curve>::ORDER.to_be_bytes();
95 crypto_bigint::BoxedUint::from_be_slice_vartime(be.as_ref())
96}
97
98pub fn sbig_to_scalar(x: &crate::arith::sbig::SBig) -> Result<Scalar> {
100 let q = Option::<crypto_bigint::NonZero<crypto_bigint::BoxedUint>>::from(order().to_nz())
101 .ok_or(Error::InvalidModulus)?;
102 let r = x.rem_euclid(&q);
103 decode_scalar(&crate::transcript::uint_to_be(&r, 32)?)
104}