use crypto_bigint::U256;
use subtle::{Choice, ConditionallySelectable};
use crate::error::Error;
use crate::sm9::fields::fp::{
fp_add, fp_from_bytes, fp_inv, fp_mul, fp_square, fp_sub, fp_to_bytes, Fp, FIELD_MODULUS, G1X,
G1Y,
};
const CURVE_B: Fp = Fp::new(&U256::from_be_hex(
"0000000000000000000000000000000000000000000000000000000000000005",
));
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct G1Affine {
pub x: Fp,
pub y: Fp,
}
#[derive(Clone, Copy, Debug)]
pub struct G1Jacobian {
pub(crate) x: Fp,
pub(crate) y: Fp,
pub(crate) z: Fp,
}
impl ConditionallySelectable for G1Jacobian {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
G1Jacobian {
x: Fp::conditional_select(&a.x, &b.x, choice),
y: Fp::conditional_select(&a.y, &b.y, choice),
z: Fp::conditional_select(&a.z, &b.z, choice),
}
}
}
impl G1Jacobian {
pub const INFINITY: Self = G1Jacobian {
x: Fp::ONE,
y: Fp::ONE,
z: Fp::ZERO,
};
pub fn from_affine(p: &G1Affine) -> Self {
G1Jacobian {
x: p.x,
y: p.y,
z: Fp::ONE,
}
}
pub fn to_affine(&self) -> Result<G1Affine, Error> {
if self.is_infinity() {
return Err(Error::PointAtInfinity);
}
let z_inv = fp_inv(&self.z).ok_or(Error::PointAtInfinity)?;
let z_inv2 = fp_square(&z_inv);
let z_inv3 = fp_mul(&z_inv2, &z_inv);
Ok(G1Affine {
x: fp_mul(&self.x, &z_inv2),
y: fp_mul(&self.y, &z_inv3),
})
}
pub fn is_infinity(&self) -> bool {
fp_to_bytes(&self.z).iter().all(|&b| b == 0)
}
pub fn double(&self) -> Self {
if self.is_infinity() {
return *self;
}
let (x1, y1, z1) = (&self.x, &self.y, &self.z);
let a = fp_square(x1); let b = fp_square(y1); let c = fp_square(&b);
let x1_b = fp_add(x1, &b);
let tmp = fp_square(&x1_b); let tmp = fp_sub(&tmp, &a); let tmp = fp_sub(&tmp, &c); let d = fp_add(&tmp, &tmp);
let e = fp_add(&fp_add(&a, &a), &a);
let x3 = fp_sub(&fp_square(&e), &fp_add(&d, &d));
let z3 = fp_add(&fp_mul(y1, z1), &fp_mul(y1, z1));
let eight_c = fp_add(
&fp_add(&fp_add(&c, &c), &fp_add(&c, &c)),
&fp_add(&fp_add(&c, &c), &fp_add(&c, &c)),
);
let y3 = fp_sub(&fp_mul(&e, &fp_sub(&d, &x3)), &eight_c);
G1Jacobian {
x: x3,
y: y3,
z: z3,
}
}
pub fn add(p: &G1Jacobian, q: &G1Jacobian) -> G1Jacobian {
if p.is_infinity() {
return *q;
}
if q.is_infinity() {
return *p;
}
let z1sq = fp_square(&p.z);
let z2sq = fp_square(&q.z);
let u1 = fp_mul(&p.x, &z2sq);
let u2 = fp_mul(&q.x, &z1sq);
let s1 = fp_mul(&p.y, &fp_mul(&q.z, &z2sq));
let s2 = fp_mul(&q.y, &fp_mul(&p.z, &z1sq));
let h = fp_sub(&u2, &u1);
let r = fp_sub(&s2, &s1);
if fp_to_bytes(&h).iter().all(|&b| b == 0) {
return if fp_to_bytes(&r).iter().all(|&b| b == 0) {
p.double()
} else {
G1Jacobian::INFINITY
};
}
let h2 = fp_square(&h);
let h3 = fp_mul(&h, &h2);
let u1h2 = fp_mul(&u1, &h2);
let x3 = fp_sub(&fp_sub(&fp_square(&r), &h3), &fp_add(&u1h2, &u1h2));
let y3 = fp_sub(&fp_mul(&r, &fp_sub(&u1h2, &x3)), &fp_mul(&s1, &h3));
let z3 = fp_mul(&fp_mul(&h, &p.z), &q.z);
G1Jacobian {
x: x3,
y: y3,
z: z3,
}
}
pub fn scalar_mul(k: &U256, p: &G1Jacobian) -> G1Jacobian {
let mut result = G1Jacobian::INFINITY;
for byte in &k.to_be_bytes() {
for b in (0..8).rev() {
result = result.double();
let sum = G1Jacobian::add(&result, p);
let bit = Choice::from((byte >> b) & 1);
result = G1Jacobian::conditional_select(&result, &sum, bit);
}
}
result
}
pub fn scalar_mul_g1(k: &U256) -> G1Jacobian {
let g = G1Jacobian::from_affine(&G1Affine { x: G1X, y: G1Y });
Self::scalar_mul(k, &g)
}
}
impl G1Affine {
pub fn generator() -> Self {
G1Affine { x: G1X, y: G1Y }
}
pub fn is_on_curve(&self) -> bool {
let x3 = fp_mul(&fp_square(&self.x), &self.x);
let rhs = fp_add(&x3, &CURVE_B);
fp_square(&self.y) == rhs
}
pub fn from_bytes(bytes: &[u8; 65]) -> Result<Self, Error> {
if bytes[0] != 0x04 {
return Err(Error::InvalidPublicKey);
}
let x_bytes: [u8; 32] = bytes[1..33].try_into().unwrap();
let y_bytes: [u8; 32] = bytes[33..65].try_into().unwrap();
use crypto_bigint::subtle::ConstantTimeGreater;
let x_val = U256::from_be_slice(&x_bytes);
let y_val = U256::from_be_slice(&y_bytes);
if bool::from(x_val.ct_gt(&FIELD_MODULUS))
|| x_val == FIELD_MODULUS
|| bool::from(y_val.ct_gt(&FIELD_MODULUS))
|| y_val == FIELD_MODULUS
{
return Err(Error::InvalidPublicKey);
}
let p = G1Affine {
x: fp_from_bytes(&x_bytes),
y: fp_from_bytes(&y_bytes),
};
if !p.is_on_curve() {
return Err(Error::InvalidPublicKey);
}
Ok(p)
}
pub fn to_bytes(&self) -> [u8; 65] {
let mut out = [0u8; 65];
out[0] = 0x04;
out[1..33].copy_from_slice(&fp_to_bytes(&self.x));
out[33..65].copy_from_slice(&fp_to_bytes(&self.y));
out
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_g1_generator_on_curve() {
assert!(G1Affine::generator().is_on_curve());
}
#[test]
fn test_g1_double_on_curve() {
let g = G1Jacobian::from_affine(&G1Affine::generator());
let g2 = g.double().to_affine().unwrap();
assert!(g2.is_on_curve());
}
#[test]
fn test_g1_scalar_mul_one() {
let g1 = G1Jacobian::scalar_mul_g1(&U256::ONE).to_affine().unwrap();
assert_eq!(fp_to_bytes(&g1.x), fp_to_bytes(&G1X));
assert_eq!(fp_to_bytes(&g1.y), fp_to_bytes(&G1Y));
}
#[test]
fn test_g1_add_commutativity() {
let g = G1Jacobian::from_affine(&G1Affine::generator());
let g2 = g.double();
let p1 = G1Jacobian::add(&g, &g2).to_affine().unwrap();
let p2 = G1Jacobian::add(&g2, &g).to_affine().unwrap();
assert_eq!(fp_to_bytes(&p1.x), fp_to_bytes(&p2.x));
}
}