arnaucube
arnaucube/plonky2-ecdsaPublic Self-hosted repository
plonky2-ecdsa/src/curve/glv.rs
src/curve/glv.rsRaw
  1use num::rational::Ratio;
  2use num::BigUint;
  3use plonky2::field::secp256k1_base::Secp256K1Base;
  4use plonky2::field::secp256k1_scalar::Secp256K1Scalar;
  5use plonky2::field::types::{Field, PrimeField};
  6
  7use crate::curve::curve_msm::msm_parallel;
  8use crate::curve::curve_types::{AffinePoint, ProjectivePoint};
  9use crate::curve::secp256k1::Secp256K1;
 10
 11pub const GLV_BETA: Secp256K1Base = Secp256K1Base([
 12    13923278643952681454,
 13    11308619431505398165,
 14    7954561588662645993,
 15    8856726876819556112,
 16]);
 17
 18pub const GLV_S: Secp256K1Scalar = Secp256K1Scalar([
 19    16069571880186789234,
 20    1310022930574435960,
 21    11900229862571533402,
 22    6008836872998760672,
 23]);
 24
 25const A1: Secp256K1Scalar = Secp256K1Scalar([16747920425669159701, 3496713202691238861, 0, 0]);
 26
 27const MINUS_B1: Secp256K1Scalar =
 28    Secp256K1Scalar([8022177200260244675, 16448129721693014056, 0, 0]);
 29
 30const A2: Secp256K1Scalar = Secp256K1Scalar([6323353552219852760, 1498098850674701302, 1, 0]);
 31
 32const B2: Secp256K1Scalar = Secp256K1Scalar([16747920425669159701, 3496713202691238861, 0, 0]);
 33
 34/// Algorithm 15.41 in Handbook of Elliptic and Hyperelliptic Curve Cryptography.
 35/// Decompose a scalar `k` into two small scalars `k1, k2` with `|k1|, |k2| < √p` that satisfy
 36/// `k1 + s * k2 = k`.
 37/// Returns `(|k1|, |k2|, k1 < 0, k2 < 0)`.
 38pub fn decompose_secp256k1_scalar(
 39    k: Secp256K1Scalar,
 40) -> (Secp256K1Scalar, Secp256K1Scalar, bool, bool) {
 41    let p = Secp256K1Scalar::order();
 42    let c1_biguint = Ratio::new(
 43        B2.to_canonical_biguint() * k.to_canonical_biguint(),
 44        p.clone(),
 45    )
 46    .round()
 47    .to_integer();
 48    let c1 = Secp256K1Scalar::from_noncanonical_biguint(c1_biguint);
 49    let c2_biguint = Ratio::new(
 50        MINUS_B1.to_canonical_biguint() * k.to_canonical_biguint(),
 51        p.clone(),
 52    )
 53    .round()
 54    .to_integer();
 55    let c2 = Secp256K1Scalar::from_noncanonical_biguint(c2_biguint);
 56
 57    let k1_raw = k - c1 * A1 - c2 * A2;
 58    let k2_raw = c1 * MINUS_B1 - c2 * B2;
 59    debug_assert!(k1_raw + GLV_S * k2_raw == k);
 60
 61    let two = BigUint::from_slice(&[2]);
 62    let k1_neg = k1_raw.to_canonical_biguint() > p.clone() / two.clone();
 63    let k1 = if k1_neg {
 64        Secp256K1Scalar::from_noncanonical_biguint(p.clone() - k1_raw.to_canonical_biguint())
 65    } else {
 66        k1_raw
 67    };
 68    let k2_neg = k2_raw.to_canonical_biguint() > p.clone() / two;
 69    let k2 = if k2_neg {
 70        Secp256K1Scalar::from_noncanonical_biguint(p - k2_raw.to_canonical_biguint())
 71    } else {
 72        k2_raw
 73    };
 74
 75    (k1, k2, k1_neg, k2_neg)
 76}
 77
 78/// See Section 15.2.1 in Handbook of Elliptic and Hyperelliptic Curve Cryptography.
 79/// GLV scalar multiplication `k * P = k1 * P + k2 * psi(P)`, where `k = k1 + s * k2` is the
 80/// decomposition computed in `decompose_secp256k1_scalar(k)` and `psi` is the Secp256k1
 81/// endomorphism `psi: (x, y) |-> (beta * x, y)` equivalent to scalar multiplication by `s`.
 82pub fn glv_mul(p: ProjectivePoint<Secp256K1>, k: Secp256K1Scalar) -> ProjectivePoint<Secp256K1> {
 83    let (k1, k2, k1_neg, k2_neg) = decompose_secp256k1_scalar(k);
 84
 85    let p_affine = p.to_affine();
 86    let sp = AffinePoint::<Secp256K1> {
 87        x: p_affine.x * GLV_BETA,
 88        y: p_affine.y,
 89        zero: p_affine.zero,
 90    };
 91
 92    let first = if k1_neg { p.neg() } else { p };
 93    let second = if k2_neg {
 94        sp.to_projective().neg()
 95    } else {
 96        sp.to_projective()
 97    };
 98
 99    msm_parallel(&[k1, k2], &[first, second], 5)
100}
101
102#[cfg(test)]
103mod tests {
104    use anyhow::Result;
105    use plonky2::field::secp256k1_scalar::Secp256K1Scalar;
106    use plonky2::field::types::{Field, Sample};
107
108    use crate::curve::curve_types::{Curve, CurveScalar};
109    use crate::curve::glv::{decompose_secp256k1_scalar, glv_mul, GLV_S};
110    use crate::curve::secp256k1::Secp256K1;
111
112    #[test]
113    fn test_glv_decompose() -> Result<()> {
114        let k = Secp256K1Scalar::rand();
115        let (k1, k2, k1_neg, k2_neg) = decompose_secp256k1_scalar(k);
116        let one = Secp256K1Scalar::ONE;
117        let m1 = if k1_neg { -one } else { one };
118        let m2 = if k2_neg { -one } else { one };
119
120        assert!(k1 * m1 + GLV_S * k2 * m2 == k);
121
122        Ok(())
123    }
124
125    #[test]
126    fn test_glv_mul() -> Result<()> {
127        for _ in 0..20 {
128            let k = Secp256K1Scalar::rand();
129
130            let p = CurveScalar(Secp256K1Scalar::rand()) * Secp256K1::GENERATOR_PROJECTIVE;
131
132            let kp = CurveScalar(k) * p;
133            let glv = glv_mul(p, k);
134
135            assert!(kp == glv);
136        }
137
138        Ok(())
139    }
140}