From 869a5860f424268b3b7368d98944acb1b638d003 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 28 Oct 2021 19:54:39 -0700 Subject: [PATCH] Secp256K1 scalar field --- src/curve/mod.rs | 1 + src/curve/secp256k1_curve.rs | 81 ++++++ src/field/mod.rs | 3 +- src/field/{secp256k1.rs => secp256k1_base.rs} | 2 +- src/field/secp256k1_scalar.rs | 253 ++++++++++++++++++ 5 files changed, 338 insertions(+), 2 deletions(-) create mode 100644 src/curve/secp256k1_curve.rs rename src/field/{secp256k1.rs => secp256k1_base.rs} (99%) create mode 100644 src/field/secp256k1_scalar.rs diff --git a/src/curve/mod.rs b/src/curve/mod.rs index 8b9df88e..01841018 100644 --- a/src/curve/mod.rs +++ b/src/curve/mod.rs @@ -2,3 +2,4 @@ pub mod curve_adds; pub mod curve_multiplication; pub mod curve_summation; pub mod curve_types; +//pub mod secp256k1_curve; \ No newline at end of file diff --git a/src/curve/secp256k1_curve.rs b/src/curve/secp256k1_curve.rs new file mode 100644 index 00000000..78ce993e --- /dev/null +++ b/src/curve/secp256k1_curve.rs @@ -0,0 +1,81 @@ +use crate::curve::curve_types::{AffinePoint, Curve}; +use crate::field::field_types::Field; +use crate::field::secp256k1_base::Secp256K1Base; +use crate::field::secp256k1_scalar::Secp256K1Scalar; + +// Parameters taken from the implementation of Bls12-377 in Zexe found here: +// https://github.com/scipr-lab/zexe/blob/master/algebra/src/curves/bls12_377/g1.rs + +#[derive(Debug, Copy, Clone)] +pub struct Secp256K1; + +impl Curve for Bls12377 { + type BaseField = Bls12377Base; + type ScalarField = Bls12377Scalar; + + const A: Bls12377Base = Bls12377Base::ZERO; + const B: Bls12377Base = Bls12377Base::ONE; + const GENERATOR_AFFINE: AffinePoint = AffinePoint { + x: BLS12_377_GENERATOR_X, + y: BLS12_377_GENERATOR_Y, + zero: false, + }; +} + +/// 81937999373150964239938255573465948239988671502647976594219695644855304257327692006745978603320413799295628339695 +const BLS12_377_GENERATOR_X: Bls12377Base = Bls12377Base { + limbs: [2742467569752756724, 14217256487979144792, 6635299530028159197, 8509097278468658840, + 14518893593143693938, 46181716169194829] +}; + +/// 241266749859715473739788878240585681733927191168601896383759122102112907357779751001206799952863815012735208165030 +const BLS12_377_GENERATOR_Y: Bls12377Base = Bls12377Base { + limbs: [9336971515457667571, 28021381849722296, 18085035374859187530, 14013031479170682136, + 3369780711397861396, 35370409237953649] +}; + +#[cfg(test)] +mod tests { + use crate::{blake_hash_usize_to_curve, Bls12377, Bls12377Scalar, Curve, Field, ProjectivePoint}; + + #[test] + fn test_double_affine() { + for i in 0..100 { + let p = blake_hash_usize_to_curve::(i); + assert_eq!( + p.double(), + p.to_projective().double().to_affine()); + } + } + + #[test] + fn test_naive_multiplication() { + let g = Bls12377::GENERATOR_PROJECTIVE; + let ten = Bls12377Scalar::from_canonical_u64(10); + let product = mul_naive(ten, g); + let sum = g + g + g + g + g + g + g + g + g + g; + assert_eq!(product, sum); + } + + #[test] + fn test_g1_multiplication() { + let lhs = Bls12377Scalar::from_canonical([11111111, 22222222, 33333333, 44444444]); + assert_eq!(Bls12377::convert(lhs) * Bls12377::GENERATOR_PROJECTIVE, mul_naive(lhs, Bls12377::GENERATOR_PROJECTIVE)); + } + + /// A simple, somewhat inefficient implementation of multiplication which is used as a reference + /// for correctness. + fn mul_naive(lhs: Bls12377Scalar, rhs: ProjectivePoint) -> ProjectivePoint { + let mut g = rhs; + let mut sum = ProjectivePoint::ZERO; + for limb in lhs.to_canonical().iter() { + for j in 0..64 { + if (limb >> j & 1u64) != 0u64 { + sum = sum + g; + } + g = g.double(); + } + } + sum + } +} diff --git a/src/field/mod.rs b/src/field/mod.rs index 5ed64a54..74e0fbf4 100644 --- a/src/field/mod.rs +++ b/src/field/mod.rs @@ -7,7 +7,8 @@ pub(crate) mod interpolation; mod inversion; pub(crate) mod packable; pub(crate) mod packed_field; -pub mod secp256k1; +pub mod secp256k1_base; +pub mod secp256k1_scalar; #[cfg(target_feature = "avx2")] pub(crate) mod packed_avx2; diff --git a/src/field/secp256k1.rs b/src/field/secp256k1_base.rs similarity index 99% rename from src/field/secp256k1.rs rename to src/field/secp256k1_base.rs index acb1df4e..a09edc30 100644 --- a/src/field/secp256k1.rs +++ b/src/field/secp256k1_base.rs @@ -88,7 +88,7 @@ impl Field for Secp256K1Base { // Sage: `g = GF(p).multiplicative_generator()` const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([5, 0, 0, 0]); - // Sage: `g_2 = g^((p - 1) / 2)` + // Sage: `g_2 = power_mod(g, (p - 1) // 2), p)` const POWER_OF_TWO_GENERATOR: Self = Self::NEG_ONE; const BITS: usize = 256; diff --git a/src/field/secp256k1_scalar.rs b/src/field/secp256k1_scalar.rs new file mode 100644 index 00000000..4423f726 --- /dev/null +++ b/src/field/secp256k1_scalar.rs @@ -0,0 +1,253 @@ +use std::convert::TryInto; +use std::fmt; +use std::fmt::{Debug, Display, Formatter}; +use std::hash::{Hash, Hasher}; +use std::iter::{Product, Sum}; +use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +use itertools::Itertools; +use num::bigint::{BigUint, RandBigInt}; +use num::{Integer, One}; +use rand::Rng; +use serde::{Deserialize, Serialize}; + +use crate::field::field_types::Field; +use crate::field::goldilocks_field::GoldilocksField; + +/// The base field of the secp256k1 elliptic curve. +/// +/// Its order is +/// ```ignore +/// P = 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141 +/// = 115792089237316195423570985008687907852837564279074904382605163141518161494337 +/// = 2**256 - 432420386565659656852420866394968145599 +/// ``` +#[derive(Copy, Clone, Serialize, Deserialize)] +pub struct Secp256K1Scalar(pub [u64; 4]); + +fn biguint_from_array(arr: [u64; 4]) -> BigUint { + BigUint::from_slice(&[ + arr[0] as u32, + (arr[0] >> 32) as u32, + arr[1] as u32, + (arr[1] >> 32) as u32, + arr[2] as u32, + (arr[2] >> 32) as u32, + arr[3] as u32, + (arr[3] >> 32) as u32, + ]) +} + +impl Default for Secp256K1Scalar { + fn default() -> Self { + Self::ZERO + } +} + +impl PartialEq for Secp256K1Scalar { + fn eq(&self, other: &Self) -> bool { + self.to_biguint() == other.to_biguint() + } +} + +impl Eq for Secp256K1Scalar {} + +impl Hash for Secp256K1Scalar { + fn hash(&self, state: &mut H) { + self.to_biguint().hash(state) + } +} + +impl Display for Secp256K1Scalar { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(&self.to_biguint(), f) + } +} + +impl Debug for Secp256K1Scalar { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Debug::fmt(&self.to_biguint(), f) + } +} + +impl Field for Secp256K1Scalar { + // TODO: fix + type PrimeField = GoldilocksField; + + const ZERO: Self = Self([0; 4]); + const ONE: Self = Self([1, 0, 0, 0]); + const TWO: Self = Self([2, 0, 0, 0]); + const NEG_ONE: Self = Self([ + 0xBFD25E8CD0364140, + 0xBAAEDCE6AF48A03B, + 0xFFFFFFFFFFFFFC2F, + 0xFFFFFFFFFFFFFFFF + ]); + + // TODO: fix + const CHARACTERISTIC: u64 = 0; + + const TWO_ADICITY: usize = 6; + + // Sage: `g = GF(p).multiplicative_generator()` + const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([7, 0, 0, 0]); + + // Sage: `g_2 = power_mod(g, (p - 1) // 2^6), p)` + // 5480320495727936603795231718619559942670027629901634955707709633242980176626 + const POWER_OF_TWO_GENERATOR: Self = Self([ + 0x992f4b5402b052f2, + 0x98BDEAB680756045, + 0xDF9879A3FBC483A8, + 0xC1DC060E7A91986, + ]); + + const BITS: usize = 256; + + fn order() -> BigUint { + BigUint::from_slice(&[ + 0xD0364141, 0xBFD25E8C, 0xAF48A03B, 0xBAAEDCE6, 0xFFFFFC2F, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF + ]) + } + + fn try_inverse(&self) -> Option { + if self.is_zero() { + return None; + } + + // Fermat's Little Theorem + Some(self.exp_biguint(&(Self::order() - BigUint::one() - BigUint::one()))) + } + + fn to_biguint(&self) -> BigUint { + let mut result = biguint_from_array(self.0); + if result >= Self::order() { + result -= Self::order(); + } + result + } + + fn from_biguint(val: BigUint) -> Self { + Self( + val.to_u64_digits() + .into_iter() + .pad_using(4, |_| 0) + .collect::>()[..] + .try_into() + .expect("error converting to u64 array"), + ) + } + + #[inline] + fn from_canonical_u64(n: u64) -> Self { + Self([n, 0, 0, 0]) + } + + #[inline] + fn from_noncanonical_u128(n: u128) -> Self { + Self([n as u64, (n >> 64) as u64, 0, 0]) + } + + #[inline] + fn from_noncanonical_u96(n: (u64, u32)) -> Self { + Self([n.0, n.1 as u64, 0, 0]) + } + + fn rand_from_rng(rng: &mut R) -> Self { + Self::from_biguint(rng.gen_biguint_below(&Self::order())) + } +} + +impl Neg for Secp256K1Scalar { + type Output = Self; + + #[inline] + fn neg(self) -> Self { + if self.is_zero() { + Self::ZERO + } else { + Self::from_biguint(Self::order() - self.to_biguint()) + } + } +} + +impl Add for Secp256K1Scalar { + type Output = Self; + + #[inline] + fn add(self, rhs: Self) -> Self { + let mut result = self.to_biguint() + rhs.to_biguint(); + if result >= Self::order() { + result -= Self::order(); + } + Self::from_biguint(result) + } +} + +impl AddAssign for Secp256K1Scalar { + #[inline] + fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs; + } +} + +impl Sum for Secp256K1Scalar { + fn sum>(iter: I) -> Self { + iter.fold(Self::ZERO, |acc, x| acc + x) + } +} + +impl Sub for Secp256K1Scalar { + type Output = Self; + + #[inline] + #[allow(clippy::suspicious_arithmetic_impl)] + fn sub(self, rhs: Self) -> Self { + self + -rhs + } +} + +impl SubAssign for Secp256K1Scalar { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; + } +} + +impl Mul for Secp256K1Scalar { + type Output = Self; + + #[inline] + fn mul(self, rhs: Self) -> Self { + Self::from_biguint((self.to_biguint() * rhs.to_biguint()).mod_floor(&Self::order())) + } +} + +impl MulAssign for Secp256K1Scalar { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = *self * rhs; + } +} + +impl Product for Secp256K1Scalar { + #[inline] + fn product>(iter: I) -> Self { + iter.reduce(|acc, x| acc * x).unwrap_or(Self::ONE) + } +} + +impl Div for Secp256K1Scalar { + type Output = Self; + + #[allow(clippy::suspicious_arithmetic_impl)] + fn div(self, rhs: Self) -> Self::Output { + self * rhs.inverse() + } +} + +impl DivAssign for Secp256K1Scalar { + fn div_assign(&mut self, rhs: Self) { + *self = *self / rhs; + } +}