From 352c6de21837465cd9e9a48d75ab50e6f93833a9 Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Wed, 31 May 2023 11:07:19 -0600 Subject: [PATCH] add hex, endian, multi-exp and hash methods --- Cargo.toml | 31 +- rust-toolchain.toml | 2 +- src/fp.rs | 354 ++++++++- src/fp12.rs | 29 +- src/fp2.rs | 131 +++- src/fp6.rs | 41 +- src/g1.rs | 420 +++++++--- src/g2.rs | 617 +++++++++++---- src/hash_to_curve/chain.rs | 920 ---------------------- src/hash_to_curve/expand_msg.rs | 1282 ------------------------------- src/hash_to_curve/map_g1.rs | 961 ----------------------- src/hash_to_curve/map_g2.rs | 900 ---------------------- src/hash_to_curve/map_scalar.rs | 39 - src/hash_to_curve/mod.rs | 113 --- src/isogeny.rs | 743 ++++++++++++++++++ src/lib.rs | 15 +- src/pairings.rs | 295 +++++-- src/scalar.rs | 255 ++++-- src/tests/mod.rs | 4 +- src/util.rs | 177 +++++ 20 files changed, 2650 insertions(+), 4679 deletions(-) delete mode 100644 src/hash_to_curve/chain.rs delete mode 100644 src/hash_to_curve/expand_msg.rs delete mode 100644 src/hash_to_curve/map_g1.rs delete mode 100644 src/hash_to_curve/map_g2.rs delete mode 100644 src/hash_to_curve/map_scalar.rs delete mode 100644 src/hash_to_curve/mod.rs create mode 100644 src/isogeny.rs diff --git a/Cargo.toml b/Cargo.toml index 7d46f832..6bc6fc58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,26 +16,21 @@ edition = "2021" rustdoc-args = [ "--html-in-header", "katex-header.html" ] [dev-dependencies] -csv = ">= 1.0, < 1.2" # csv 1.2 has MSRV 1.60 -criterion = "0.3" +csv = "1.2.1" +criterion = "0.5" hex = "0.4" rand_xorshift = "0.3" -sha2 = "0.9" -sha3 = "0.9" +sha2 = "0.10" +sha3 = "0.10" [[bench]] name = "groups" harness = false required-features = ["groups"] -[[bench]] -name = "hash_to_curve" -harness = false -required-features = ["experimental"] - -[dependencies.digest] -version = "0.9" -optional = true +[dependencies.elliptic-curve] +version = "0.13" +default-features = false [dependencies.ff] version = "0.13" @@ -55,19 +50,23 @@ version = "0.6" default-features = false [dependencies.subtle] -version = "2.2.1" +version = "2.4" default-features = false [dependencies.zeroize] -version = "1.4" +version = "1.6" default-features = false optional = true +[dependencies.arrayref] +version = "0.3" + [features] -default = ["groups", "pairings", "alloc", "bits"] +default = ["groups", "pairings", "alloc", "bits", "hashing"] bits = ["ff/bits"] groups = ["group"] +hashing = ["elliptic-curve/hash2curve"] pairings = ["groups", "pairing"] alloc = ["group/alloc"] -experimental = ["digest"] +experimental = [] nightly = ["subtle/nightly"] diff --git a/rust-toolchain.toml b/rust-toolchain.toml index de43b230..fb11b593 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.56.0" +channel = "1.66.0" components = [ "clippy", "rustfmt" ] diff --git a/src/fp.rs b/src/fp.rs index 281c66e6..5d99fd38 100644 --- a/src/fp.rs +++ b/src/fp.rs @@ -1,16 +1,31 @@ //! This module provides an implementation of the BLS12-381 base field `GF(p)` //! where `p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab` +use crate::G1Projective; +use core::convert::TryFrom; use core::fmt; -use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use core::iter::{Iterator, Product, Sum}; +use core::ops::{Add, AddAssign, BitOr, Mul, MulAssign, Neg, Sub, SubAssign}; +#[cfg(feature = "hashing")] +use elliptic_curve::{ + generic_array::{ + typenum::{U16, U64}, + GenericArray, + }, + hash2curve::{ + ExpandMsg, Expander, FromOkm, Isogeny, IsogenyCoefficients, MapToCurve, OsswuMap, + OsswuMapParams, Sgn0, + }, +}; +use ff::Field; use rand_core::RngCore; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +use subtle::{Choice, ConditionallyNegatable, ConditionallySelectable, ConstantTimeEq, CtOption}; use crate::util::{adc, mac, sbb}; -// The internal representation of this type is six 64-bit unsigned -// integers in little-endian order. `Fp` values are always in -// Montgomery form; i.e., Scalar(a) = aR mod p, with R = 2^384. +/// The internal representation of this type is six 64-bit unsigned +/// integers in little-endian order. `Fp` values are always in +/// Montgomery form; i.e., Scalar(a) = aR mod p, with R = 2^384. #[derive(Copy, Clone)] pub struct Fp(pub(crate) [u64; 6]); @@ -27,7 +42,7 @@ impl fmt::Debug for Fp { impl Default for Fp { fn default() -> Self { - Fp::zero() + Fp::ZERO } } @@ -67,7 +82,7 @@ impl ConditionallySelectable for Fp { } /// p = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 -const MODULUS: [u64; 6] = [ +pub(crate) const MODULUS: [u64; 6] = [ 0xb9fe_ffff_ffff_aaab, 0x1eab_fffe_b153_ffff, 0x6730_d2a0_f6b0_f624, @@ -157,21 +172,234 @@ impl<'a, 'b> Mul<&'b Fp> for &'a Fp { impl_binops_additive!(Fp, Fp); impl_binops_multiplicative!(Fp, Fp); +#[cfg(feature = "hashing")] +impl FromOkm for Fp { + type Length = U64; + + fn from_okm(data: &GenericArray) -> Self { + let input = arrayref::array_ref![data, 0, 64]; + Self::from_random_bytes(*input) + } +} + +#[cfg(feature = "hashing")] +impl Sgn0 for Fp { + fn sgn0(&self) -> Choice { + let bytes = self.to_bytes(); + (bytes[47] & 1).into() + } +} + +#[cfg(feature = "hashing")] +impl OsswuMap for Fp { + const PARAMS: OsswuMapParams = OsswuMapParams { + c1: &[ + 0xee7f_bfff_ffff_eaaau64, + 0x07aa_ffff_ac54_ffffu64, + 0xd9cc_34a8_3dac_3d89u64, + 0xd91d_d2e1_3ce1_44afu64, + 0x92c6_e9ed_90d2_eb35u64, + 0x0680_447a_8e5f_f9a6u64, + ], + c2: Fp([ + 0x43b5_71ca_d321_5f1fu64, + 0xccb4_60ef_1c70_2dc2u64, + 0x742d_884f_4f97_100bu64, + 0xdb2c_3e32_38a3_382bu64, + 0xe40f_3fa1_3fce_8f88u64, + 0x0073_a2af_9892_a2ffu64, + ]), + map_a: Fp([ + 0x2f65_aa0e_9af5_aa51u64, + 0x8646_4c2d_1e84_16c3u64, + 0xb85c_e591_b7bd_31e2u64, + 0x27e1_1c91_b5f2_4e7cu64, + 0x2837_6eda_6bfc_1835u64, + 0x1554_55c3_e507_1d85u64, + ]), + map_b: Fp([ + 0xfb99_6971_fe22_a1e0u64, + 0x9aa9_3eb3_5b74_2d6fu64, + 0x8c47_6013_de99_c5c4u64, + 0x873e_27c3_a221_e571u64, + 0xca72_b5e4_5a52_d888u64, + 0x0682_4061_418a_386bu64, + ]), + z: Fp([ + 0x886c00000023ffdcu64, + 0xf70008d3090001du64, + 0x77672417ed5828c3u64, + 0x9dac23e943dc1740u64, + 0x50553f1b9c131521u64, + 0x78c712fbe0ab6e8u64, + ]), + }; + + fn osswu(&self) -> (Self, Self) { + let xd1 = Self::PARAMS.z.mul(&Self::PARAMS.map_a); + + // tv1 = u^2 + let tv1 = self.square(); + // tv3 = Z * tv1 + let tv3 = Self::PARAMS.z * tv1; + // tv2 = tv3^2 + let mut tv2 = tv3.square(); + // xd = tv2 + tv3 + let mut xd = tv2 + tv3; + // x1n = xd + 1 + // x1n = x1n * B + let x1n = (xd + Fp::ONE) * Self::PARAMS.map_b; + // xd = -A * xd + xd *= Self::PARAMS.map_a.neg(); + // xd = CMOV(xd, Z * A, xd == 0) + xd.conditional_assign(&xd1, xd.is_zero()); + // tv2 = xd^2 + tv2 = xd.square(); + let gxd = tv2 * xd; + tv2 *= Self::PARAMS.map_a; + let mut gx1 = (x1n.square() + tv2) * x1n; + tv2 = Self::PARAMS.map_b * gxd; + gx1 += tv2; + let mut tv4 = gxd.square(); + tv2 = gx1 * gxd; + tv4 *= tv2; + let y1 = tv4.pow_vartime(arrayref::array_ref![Self::PARAMS.c1, 0, 6]) * tv2; + let mut x2n = tv3 * x1n; + let mut y2 = y1 * Self::PARAMS.c2 * tv1 * self; + tv2 = y1.square() * gxd; + let e2 = ((tv2 == gx1) as u8).into(); + + x2n.conditional_assign(&x1n, e2); + y2.conditional_assign(&y1, e2); + + let e3 = self.sgn0() ^ y2.sgn0(); + y2.conditional_negate(e3); + + (x2n * xd.invert().unwrap(), y2) + } +} + +#[cfg(feature = "hashing")] +impl MapToCurve for Fp { + type Output = G1Projective; + + fn map_to_curve(&self) -> Self::Output { + let (rx, ry) = self.osswu(); + let (qx, qy) = Fp::isogeny(rx, ry); + G1Projective { + x: qx, + y: qy, + z: Fp::ONE, + } + } +} + +#[cfg(feature = "hashing")] +impl Isogeny for Fp { + type Degree = U16; + const COEFFICIENTS: IsogenyCoefficients = IsogenyCoefficients { + xnum: &crate::isogeny::g1::XNUM, + xden: &crate::isogeny::g1::XDEN, + ynum: &crate::isogeny::g1::YNUM, + yden: &crate::isogeny::g1::YDEN, + }; +} + +impl Field for Fp { + const ZERO: Self = Fp::ZERO; + const ONE: Self = Fp::ONE; + + fn random(rng: impl RngCore) -> Self { + Fp::random(rng) + } + + fn square(&self) -> Self { + self.square() + } + + fn double(&self) -> Self { + self.double() + } + + fn invert(&self) -> CtOption { + self.invert() + } + + fn sqrt_ratio(_num: &Self, _div: &Self) -> (Choice, Self) { + // ff::helpers::sqrt_ratio_generic(num, div) + unimplemented!() + } +} + +impl From for Fp { + fn from(value: u64) -> Self { + Self([value, 0, 0, 0, 0, 0]) * R2 + } +} + +impl Sum for Fp { + fn sum>(iter: I) -> Self { + let mut result = Fp::ZERO; + for f in iter { + result += f; + } + result + } +} + +impl<'a> Sum<&'a Fp> for Fp { + fn sum>(iter: I) -> Self { + let mut result = Fp::ZERO; + for f in iter { + result += f; + } + result + } +} + +impl Product for Fp { + fn product>(iter: I) -> Self { + let mut result = Fp::ONE; + for f in iter { + result *= f; + } + result + } +} + +impl<'a> Product<&'a Fp> for Fp { + fn product>(iter: I) -> Self { + let mut result = Fp::ONE; + for f in iter { + result *= f; + } + result + } +} + impl Fp { + /// The additive identity. + pub const ZERO: Fp = Fp([0, 0, 0, 0, 0, 0]); + /// The multiplicative identity. + pub const ONE: Fp = R; + /// Returns zero, the additive identity. #[inline] + #[deprecated(since = "0.8.0", note = "Use ZERO instead.")] pub const fn zero() -> Fp { Fp([0, 0, 0, 0, 0, 0]) } /// Returns one, the multiplicative identity. #[inline] + #[deprecated(since = "0.8.0", note = "Use ONE instead.")] pub const fn one() -> Fp { R } + /// Returns true if field is the additive identity pub fn is_zero(&self) -> Choice { - self.ct_eq(&Fp::zero()) + self.ct_eq(&Fp::ZERO) } /// Attempts to convert a big-endian byte representation of @@ -226,12 +454,13 @@ impl Fp { res } + /// Create a random field element pub(crate) fn random(mut rng: impl RngCore) -> Fp { let mut bytes = [0u8; 96]; rng.fill_bytes(&mut bytes); // Parse the random bytes as a big-endian number, to match Fp encoding order. - Fp::from_u768([ + Fp::from_u768_be([ u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[0..8]).unwrap()), u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[8..16]).unwrap()), u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[16..24]).unwrap()), @@ -248,7 +477,7 @@ impl Fp { } /// Reduces a big-endian 64-bit limb representation of a 768-bit number. - fn from_u768(limbs: [u64; 12]) -> Fp { + fn from_u768_be(limbs: [u64; 12]) -> Fp { // We reduce an arbitrary 768-bit number by decomposing it into two 384-bit digits // with the higher bits multiplied by 2^384. Thus, we perform two reductions // @@ -268,6 +497,27 @@ impl Fp { d0 * R2 + d1 * R3 } + /// Reduces a big-endian 64-bit limb representation of a 768-bit number. + fn from_u768_le(limbs: [u64; 12]) -> Fp { + // We reduce an arbitrary 768-bit number by decomposing it into two 384-bit digits + // with the higher bits multiplied by 2^384. Thus, we perform two reductions + // + // 1. the lower bits are multiplied by R^2, as normal + // 2. the upper bits are multiplied by R^2 * 2^384 = R^3 + // + // and computing their sum in the field. It remains to see that arbitrary 384-bit + // numbers can be placed into Montgomery form safely using the reduction. The + // reduction works so long as the product is less than R=2^384 multiplied by + // the modulus. This holds because for any `c` smaller than the modulus, we have + // that (2^384 - 1)*c is an acceptable product for the reduction. Therefore, the + // reduction always works so long as `c` is in the field; in this case it is either the + // constant `R2` or `R3`. + let d1 = Fp([limbs[6], limbs[7], limbs[8], limbs[9], limbs[10], limbs[11]]); + let d0 = Fp([limbs[0], limbs[1], limbs[2], limbs[3], limbs[4], limbs[5]]); + // Convert to Montgomery form + d0 * R2 + d1 * R3 + } + /// Returns whether or not this element is strictly lexicographically /// larger than its negation. pub fn lexicographically_largest(&self) -> Choice { @@ -307,7 +557,7 @@ impl Fp { /// variable time with respect to the exponent. It /// is also not exposed in the public API. pub fn pow_vartime(&self, by: &[u64; 6]) -> Self { - let mut res = Self::one(); + let mut res = Self::ONE; for e in by.iter().rev() { for i in (0..64).rev() { res = res.square(); @@ -320,6 +570,7 @@ impl Fp { res } + /// Compute the modular square root of this field element #[inline] pub fn sqrt(&self) -> CtOption { // We use Shank's method, as p = 3 (mod 4). This means @@ -378,6 +629,7 @@ impl Fp { Fp([r0, r1, r2, r3, r4, r5]) } + /// Add `self` to `rhs` and return the result #[inline] pub const fn add(&self, rhs: &Fp) -> Fp { let (d0, carry) = adc(self.0[0], rhs.0[0], 0); @@ -392,6 +644,7 @@ impl Fp { (&Fp([d0, d1, d2, d3, d4, d5])).subtract_p() } + /// Negate this element #[inline] pub const fn neg(&self) -> Fp { let (d0, borrow) = sbb(MODULUS[0], self.0[0], 0); @@ -417,6 +670,7 @@ impl Fp { ]) } + /// Subtract `rhs` from `self` and return the result #[inline] pub const fn sub(&self, rhs: &Fp) -> Fp { (&rhs.neg()).add(self) @@ -561,6 +815,13 @@ impl Fp { (&Fp([r6, r7, r8, r9, r10, r11])).subtract_p() } + /// Return 2*self + #[inline(always)] + pub const fn double(&self) -> Fp { + Fp::add(self, self) + } + + /// Compute `self` * `rhs` #[inline] pub const fn mul(&self, rhs: &Fp) -> Fp { let (t0, carry) = mac(0, self.0[0], rhs.0[0], 0); @@ -658,6 +919,69 @@ impl Fp { Self::montgomery_reduce(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11) } + + /// Returns true whenever value is a square in the field + /// using Euler's criterion + #[inline] + pub fn is_square(&self) -> Choice { + const PM1DIV2: [u64; 6] = [ + 0xdcff_7fff_ffff_d555u64, + 0x0f55_ffff_58a9_ffffu64, + 0xb398_6950_7b58_7b12u64, + 0xb23b_a5c2_79c2_895fu64, + 0x258d_d3db_21a5_d66bu64, + 0x0d00_88f5_1cbf_f34du64, + ]; + + let res = self.pow_vartime(&PM1DIV2); + res.is_zero().bitor(res.ct_eq(&Self::ONE)) + } + + #[cfg(feature = "hashing")] + /// Take 64 bytes and compute the result reduced by the field modulus + pub(crate) fn from_random_bytes(okm: [u8; 64]) -> Self { + Self::from_u768_le([ + u64::from_be_bytes(<[u8; 8]>::try_from(&okm[56..64]).unwrap()), + u64::from_be_bytes(<[u8; 8]>::try_from(&okm[48..56]).unwrap()), + u64::from_be_bytes(<[u8; 8]>::try_from(&okm[40..48]).unwrap()), + u64::from_be_bytes(<[u8; 8]>::try_from(&okm[32..40]).unwrap()), + u64::from_be_bytes(<[u8; 8]>::try_from(&okm[24..32]).unwrap()), + u64::from_be_bytes(<[u8; 8]>::try_from(&okm[16..24]).unwrap()), + u64::from_be_bytes(<[u8; 8]>::try_from(&okm[8..16]).unwrap()), + u64::from_be_bytes(<[u8; 8]>::try_from(&okm[0..8]).unwrap()), + 0u64, + 0u64, + 0u64, + 0u64, + ]) + } + + #[cfg(feature = "hashing")] + pub(crate) fn hash(msg: &[u8], dst: &[u8]) -> [Fp; 2] + where + X: for<'a> ExpandMsg<'a>, + { + let dst = [dst]; + let mut random_bytes = [0u8; 128]; + let mut expander = X::expand_message(&[msg], &dst, random_bytes.len()).unwrap(); + expander.fill_bytes(&mut random_bytes); + [ + Fp::from_random_bytes(<[u8; 64]>::try_from(&random_bytes[..64]).unwrap()), + Fp::from_random_bytes(<[u8; 64]>::try_from(&random_bytes[64..]).unwrap()), + ] + } + + #[cfg(feature = "hashing")] + pub(crate) fn encode(msg: &[u8], dst: &[u8]) -> Fp + where + X: for<'a> ExpandMsg<'a>, + { + let dst = [dst]; + let mut random_bytes = [0u8; 64]; + let mut expander = X::expand_message(&[msg], &dst, random_bytes.len()).unwrap(); + expander.fill_bytes(&mut random_bytes); + Fp::from_random_bytes(random_bytes) + } } #[test] @@ -868,7 +1192,7 @@ fn test_from_bytes() { } assert_eq!( - -Fp::one(), + -Fp::ONE, Fp::from_bytes(&[ 26, 1, 17, 234, 57, 127, 230, 154, 75, 27, 167, 182, 67, 75, 172, 215, 100, 119, 75, 132, 243, 133, 18, 191, 103, 48, 210, 160, 246, 176, 246, 36, 30, 171, 255, 254, 177, @@ -936,13 +1260,13 @@ fn test_inversion() { ]); assert_eq!(a.invert().unwrap(), b); - assert!(bool::from(Fp::zero().invert().is_none())); + assert!(bool::from(Fp::ZERO.invert().is_none())); } #[test] fn test_lexicographic_largest() { - assert!(!bool::from(Fp::zero().lexicographically_largest())); - assert!(!bool::from(Fp::one().lexicographically_largest())); + assert!(!bool::from(Fp::ZERO.lexicographically_largest())); + assert!(!bool::from(Fp::ONE.lexicographically_largest())); assert!(!bool::from( Fp::from_raw_unchecked([ 0xa1fa_ffff_fffe_5557, diff --git a/src/fp12.rs b/src/fp12.rs index 26b48043..148db411 100644 --- a/src/fp12.rs +++ b/src/fp12.rs @@ -19,7 +19,7 @@ impl From for Fp12 { fn from(f: Fp) -> Fp12 { Fp12 { c0: Fp6::from(f), - c1: Fp6::zero(), + c1: Fp6::ZERO, } } } @@ -28,7 +28,7 @@ impl From for Fp12 { fn from(f: Fp2) -> Fp12 { Fp12 { c0: Fp6::from(f), - c1: Fp6::zero(), + c1: Fp6::ZERO, } } } @@ -37,7 +37,7 @@ impl From for Fp12 { fn from(f: Fp6) -> Fp12 { Fp12 { c0: f, - c1: Fp6::zero(), + c1: Fp6::ZERO, } } } @@ -58,7 +58,7 @@ impl Clone for Fp12 { impl Default for Fp12 { fn default() -> Self { - Fp12::zero() + Fp12::ZERO } } @@ -89,19 +89,28 @@ impl ConstantTimeEq for Fp12 { } impl Fp12 { + pub const ZERO: Fp12 = Fp12 { + c0: Fp6::ZERO, + c1: Fp6::ZERO, + }; + pub const ONE: Fp12 = Fp12 { + c0: Fp6::ONE, + c1: Fp6::ZERO, + }; + #[inline] pub fn zero() -> Self { Fp12 { - c0: Fp6::zero(), - c1: Fp6::zero(), + c0: Fp6::ZERO, + c1: Fp6::ZERO, } } #[inline] pub fn one() -> Self { Fp12 { - c0: Fp6::one(), - c1: Fp6::zero(), + c0: Fp6::ONE, + c1: Fp6::ZERO, } } @@ -628,7 +637,7 @@ fn test_arithmetic() { a.invert().unwrap() * b.invert().unwrap(), (a * b).invert().unwrap() ); - assert_eq!(a.invert().unwrap() * a, Fp12::one()); + assert_eq!(a.invert().unwrap() * a, Fp12::ONE); assert!(a != a.frobenius_map()); assert_eq!( @@ -653,7 +662,7 @@ fn test_arithmetic() { fn test_zeroize() { use zeroize::Zeroize; - let mut a = Fp12::one(); + let mut a = Fp12::ONE; a.zeroize(); assert!(bool::from(a.is_zero())); } diff --git a/src/fp2.rs b/src/fp2.rs index 1c3ec502..ad5a0c92 100644 --- a/src/fp2.rs +++ b/src/fp2.rs @@ -6,7 +6,12 @@ use rand_core::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; use crate::fp::Fp; +#[cfg(feature = "hashing")] +use core::convert::TryFrom; +#[cfg(feature = "hashing")] +use elliptic_curve::hash2curve::{ExpandMsg, Expander, Sgn0}; +/// A point in the multiplicative group of order p^2 #[derive(Copy, Clone)] pub struct Fp2 { pub c0: Fp, @@ -21,7 +26,7 @@ impl fmt::Debug for Fp2 { impl Default for Fp2 { fn default() -> Self { - Fp2::zero() + Fp2::ZERO } } @@ -32,7 +37,7 @@ impl From for Fp2 { fn from(f: Fp) -> Fp2 { Fp2 { c0: f, - c1: Fp::zero(), + c1: Fp::ZERO, } } } @@ -108,28 +113,36 @@ impl<'a, 'b> Mul<&'b Fp2> for &'a Fp2 { impl_binops_additive!(Fp2, Fp2); impl_binops_multiplicative!(Fp2, Fp2); -impl Fp2 { - #[inline] - pub const fn zero() -> Fp2 { - Fp2 { - c0: Fp::zero(), - c1: Fp::zero(), +#[cfg(feature = "hashing")] +impl Sgn0 for Fp2 { + fn sgn0(&self) -> Choice { + if self.c0.is_zero().into() { + self.c1.sgn0() + } else { + self.c0.sgn0() } } +} - #[inline] - pub const fn one() -> Fp2 { - Fp2 { - c0: Fp::one(), - c1: Fp::zero(), - } - } +impl Fp2 { + /// The additive identity element + pub const ZERO: Self = Self { + c0: Fp::ZERO, + c1: Fp::ZERO, + }; + /// The multiplicative identity element + pub const ONE: Self = Self { + c0: Fp::ONE, + c1: Fp::ZERO, + }; + /// True if this element is the additive identity pub fn is_zero(&self) -> Choice { self.c0.is_zero() & self.c1.is_zero() } - pub(crate) fn random(mut rng: impl RngCore) -> Fp2 { + /// Return a random element + pub fn random(mut rng: impl RngCore) -> Self { Fp2 { c0: Fp::random(&mut rng), c1: Fp::random(&mut rng), @@ -144,6 +157,7 @@ impl Fp2 { self.conjugate() } + /// Conjugation of this element #[inline(always)] pub fn conjugate(&self) -> Self { Fp2 { @@ -179,7 +193,8 @@ impl Fp2 { | (self.c1.is_zero() & self.c0.lexicographically_largest()) } - pub const fn square(&self) -> Fp2 { + /// Compute the square of this element + pub const fn square(&self) -> Self { // Complex squaring: // // v0 = c0 * c1 @@ -202,7 +217,7 @@ impl Fp2 { } } - pub fn mul(&self, rhs: &Fp2) -> Fp2 { + pub fn mul(&self, rhs: &Fp2) -> Self { // F_{p^2} x F_{p^2} multiplication implemented with operand scanning (schoolbook) // computes the result as: // @@ -221,32 +236,44 @@ impl Fp2 { } } - pub const fn add(&self, rhs: &Fp2) -> Fp2 { + /// Add self + rhs + pub const fn add(&self, rhs: &Fp2) -> Self { Fp2 { c0: (&self.c0).add(&rhs.c0), c1: (&self.c1).add(&rhs.c1), } } - pub const fn sub(&self, rhs: &Fp2) -> Fp2 { - Fp2 { + /// Subtract self - rhs + pub const fn sub(&self, rhs: &Fp2) -> Self { + Self { c0: (&self.c0).sub(&rhs.c0), c1: (&self.c1).sub(&rhs.c1), } } - pub const fn neg(&self) -> Fp2 { + /// Negate this element + pub const fn neg(&self) -> Self { Fp2 { c0: (&self.c0).neg(), c1: (&self.c1).neg(), } } + /// Double this element + pub const fn double(&self) -> Self { + Fp2 { + c0: self.c0.double(), + c1: self.c1.double(), + } + } + + /// Square root of this element pub fn sqrt(&self) -> CtOption { // Algorithm 9, https://eprint.iacr.org/2012/685.pdf // with constant time modifications. - CtOption::new(Fp2::zero(), self.is_zero()).or_else(|| { + CtOption::new(Fp2::ZERO, self.is_zero()).or_else(|| { // a1 = self^((p - 3) / 4) let a1 = self.pow_vartime(&[ 0xee7f_bfff_ffff_eaaa, @@ -272,12 +299,12 @@ impl Fp2 { c0: -x0.c1, c1: x0.c0, }, - alpha.ct_eq(&(&Fp2::one()).neg()), + alpha.ct_eq(&Fp2::ONE.neg()), ) // Otherwise, the correct solution is (1 + alpha)^((q - 1) // 2) * x0 .or_else(|| { CtOption::new( - (alpha + Fp2::one()).pow_vartime(&[ + (alpha + Fp2::ONE).pow_vartime(&[ 0xdcff_7fff_ffff_d555, 0x0f55_ffff_58a9_ffff, 0xb398_6950_7b58_7b12, @@ -322,7 +349,7 @@ impl Fp2 { /// variable time with respect to the exponent. It /// is also not exposed in the public API. pub fn pow_vartime(&self, by: &[u64; 6]) -> Self { - let mut res = Self::one(); + let mut res = Self::ONE; for e in by.iter().rev() { for i in (0..64).rev() { res = res.square(); @@ -351,6 +378,42 @@ impl Fp2 { } res } + + #[cfg(feature = "hashing")] + /// Take 64 bytes and compute the result reduced by the field modulus + pub fn from_random_bytes(okm: [u8; 128]) -> Self { + Self { + c0: Fp::from_random_bytes(<[u8; 64]>::try_from(&okm[..64]).unwrap()), + c1: Fp::from_random_bytes(<[u8; 64]>::try_from(&okm[64..]).unwrap()), + } + } + + #[cfg(feature = "hashing")] + pub(crate) fn hash(msg: &[u8], dst: &[u8]) -> [Self; 2] + where + X: for<'a> ExpandMsg<'a>, + { + let dst = [dst]; + let mut random_bytes = [0u8; 256]; + let mut expander = X::expand_message(&[msg], &dst, random_bytes.len()).unwrap(); + expander.fill_bytes(&mut random_bytes); + [ + Self::from_random_bytes(<[u8; 128]>::try_from(&random_bytes[..128]).unwrap()), + Self::from_random_bytes(<[u8; 128]>::try_from(&random_bytes[128..]).unwrap()), + ] + } + + #[cfg(feature = "hashing")] + pub(crate) fn encode(msg: &[u8], dst: &[u8]) -> Self + where + X: for<'a> ExpandMsg<'a>, + { + let dst = [dst]; + let mut random_bytes = [0u8; 128]; + let mut expander = X::expand_message(&[msg], &dst, random_bytes.len()).unwrap(); + expander.fill_bytes(&mut random_bytes); + Self::from_random_bytes(random_bytes) + } } #[test] @@ -718,7 +781,7 @@ fn test_sqrt() { 0x9fb4_e61d_1e83_eac5, 0x005c_b922_afe8_4dc7, ]), - c1: Fp::zero(), + c1: Fp::ZERO, }; assert_eq!(b.sqrt().unwrap().square(), b); @@ -734,7 +797,7 @@ fn test_sqrt() { 0xd36c_d6db_5547_e905, 0x02f8_c8ec_bf18_67bb, ]), - c1: Fp::zero(), + c1: Fp::ZERO, }; assert_eq!(c.sqrt().unwrap().square(), c); @@ -807,13 +870,13 @@ fn test_inversion() { assert_eq!(a.invert().unwrap(), b); - assert!(bool::from(Fp2::zero().invert().is_none())); + assert!(bool::from(Fp2::ZERO.invert().is_none())); } #[test] fn test_lexicographic_largest() { - assert!(!bool::from(Fp2::zero().lexicographically_largest())); - assert!(!bool::from(Fp2::one().lexicographically_largest())); + assert!(!bool::from(Fp2::ZERO.lexicographically_largest())); + assert!(!bool::from(Fp2::ONE.lexicographically_largest())); assert!(bool::from( Fp2 { c0: Fp::from_raw_unchecked([ @@ -866,7 +929,7 @@ fn test_lexicographic_largest() { 0x736c_3a59_232d_511d, 0x10ac_d42d_29cf_cbb6, ]), - c1: Fp::zero(), + c1: Fp::ZERO, } .lexicographically_largest() )); @@ -880,7 +943,7 @@ fn test_lexicographic_largest() { 0x736c_3a59_232d_511d, 0x10ac_d42d_29cf_cbb6, ]), - c1: Fp::zero(), + c1: Fp::ZERO, } .lexicographically_largest() )); @@ -891,7 +954,7 @@ fn test_lexicographic_largest() { fn test_zeroize() { use zeroize::Zeroize; - let mut a = Fp2::one(); + let mut a = Fp2::ONE; a.zeroize(); assert!(bool::from(a.is_zero())); } diff --git a/src/fp6.rs b/src/fp6.rs index 55420422..f0d85920 100644 --- a/src/fp6.rs +++ b/src/fp6.rs @@ -19,8 +19,8 @@ impl From for Fp6 { fn from(f: Fp) -> Fp6 { Fp6 { c0: Fp2::from(f), - c1: Fp2::zero(), - c2: Fp2::zero(), + c1: Fp2::ZERO, + c2: Fp2::ZERO, } } } @@ -29,8 +29,8 @@ impl From for Fp6 { fn from(f: Fp2) -> Fp6 { Fp6 { c0: f, - c1: Fp2::zero(), - c2: Fp2::zero(), + c1: Fp2::ZERO, + c2: Fp2::ZERO, } } } @@ -51,7 +51,7 @@ impl Clone for Fp6 { impl Default for Fp6 { fn default() -> Self { - Fp6::zero() + Fp6::ZERO } } @@ -83,21 +83,32 @@ impl ConstantTimeEq for Fp6 { } impl Fp6 { + pub const ZERO: Fp6 = Fp6 { + c0: Fp2::ZERO, + c1: Fp2::ZERO, + c2: Fp2::ZERO, + }; + pub const ONE: Fp6 = Fp6 { + c0: Fp2::ONE, + c1: Fp2::ZERO, + c2: Fp2::ZERO, + }; + #[inline] pub fn zero() -> Self { Fp6 { - c0: Fp2::zero(), - c1: Fp2::zero(), - c2: Fp2::zero(), + c0: Fp2::ZERO, + c1: Fp2::ZERO, + c2: Fp2::ZERO, } } #[inline] pub fn one() -> Self { Fp6 { - c0: Fp2::one(), - c1: Fp2::zero(), - c2: Fp2::zero(), + c0: Fp2::ONE, + c1: Fp2::ZERO, + c2: Fp2::ZERO, } } @@ -159,7 +170,7 @@ impl Fp6 { // c1 = c1 * (u + 1)^((p - 1) / 3) let c1 = c1 * Fp2 { - c0: Fp::zero(), + c0: Fp::ZERO, c1: Fp::from_raw_unchecked([ 0xcd03_c9e4_8671_f071, 0x5dab_2246_1fcd_a5d2, @@ -181,7 +192,7 @@ impl Fp6 { 0x14e4_f04f_e2db_9068, 0x14e5_6d3f_1564_853a, ]), - c1: Fp::zero(), + c1: Fp::ZERO, }; Fp6 { c0, c1, c2 } @@ -557,7 +568,7 @@ fn test_arithmetic() { a.invert().unwrap() * b.invert().unwrap(), (a * b).invert().unwrap() ); - assert_eq!(a.invert().unwrap() * a, Fp6::one()); + assert_eq!(a.invert().unwrap() * a, Fp6::ONE); } #[cfg(feature = "zeroize")] @@ -565,7 +576,7 @@ fn test_arithmetic() { fn test_zeroize() { use zeroize::Zeroize; - let mut a = Fp6::one(); + let mut a = Fp6::ONE; a.zeroize(); assert!(bool::from(a.is_zero())); } diff --git a/src/g1.rs b/src/g1.rs index b7951008..3bc944b1 100644 --- a/src/g1.rs +++ b/src/g1.rs @@ -1,7 +1,7 @@ //! This module provides an implementation of the $\mathbb{G}_1$ group of BLS12-381. use core::borrow::Borrow; -use core::fmt; +use core::fmt::{self, Formatter}; use core::iter::Sum; use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use group::{ @@ -15,7 +15,13 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; use group::WnafGroup; use crate::fp::Fp; +use crate::util::decode_hex_into_slice; use crate::Scalar; +#[cfg(feature = "hashing")] +use elliptic_curve::{ + group::cofactor::CofactorGroup, + hash2curve::{ExpandMsg, MapToCurve}, +}; /// This is an element of $\mathbb{G}_1$ represented in the affine coordinate space. /// It is ideal to keep elements in this representation to reduce memory usage and @@ -46,9 +52,29 @@ impl fmt::Display for G1Affine { } } +impl fmt::LowerHex for G1Affine { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let bytes = self.to_compressed(); + for &b in bytes.iter() { + write!(f, "{:02x}", b)?; + } + Ok(()) + } +} + +impl fmt::UpperHex for G1Affine { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let bytes = self.to_compressed(); + for &b in bytes.iter() { + write!(f, "{:02X}", b)?; + } + Ok(()) + } +} + impl<'a> From<&'a G1Projective> for G1Affine { fn from(p: &'a G1Projective) -> G1Affine { - let zinv = p.z.invert().unwrap_or(Fp::zero()); + let zinv = p.z.invert().unwrap_or(Fp::ZERO); let x = p.x * zinv; let y = p.y * zinv; @@ -107,7 +133,7 @@ impl<'a> Neg for &'a G1Affine { fn neg(self) -> G1Affine { G1Affine { x: self.x, - y: Fp::conditional_select(&-self.y, &Fp::one(), self.infinity), + y: Fp::conditional_select(&-self.y, &Fp::ONE, self.infinity), infinity: self.infinity, } } @@ -166,7 +192,7 @@ where where I: Iterator, { - iter.fold(Self::identity(), |acc, item| acc + item.borrow()) + iter.fold(Self::IDENTITY, |acc, item| acc + item.borrow()) } } @@ -183,11 +209,15 @@ const B: Fp = Fp::from_raw_unchecked([ ]); impl G1Affine { + /// Bytes to represent this point compressed + pub const COMPRESSED_BYTES: usize = 48; + /// Bytes to represent this point uncompressed + pub const UNCOMPRESSED_BYTES: usize = 96; /// Returns the identity of the group: the point at infinity. pub fn identity() -> G1Affine { G1Affine { - x: Fp::zero(), - y: Fp::one(), + x: Fp::ZERO, + y: Fp::ONE, infinity: Choice::from(1u8), } } @@ -221,7 +251,7 @@ impl G1Affine { pub fn to_compressed(&self) -> [u8; 48] { // Strictly speaking, self.x is zero already when self.infinity is true, but // to guard against implementation mistakes we do not assume this. - let mut res = Fp::conditional_select(&self.x, &Fp::zero(), self.infinity).to_bytes(); + let mut res = Fp::conditional_select(&self.x, &Fp::ZERO, self.infinity).to_bytes(); // This point is in compressed form, so we set the most significant bit. res[0] |= 1u8 << 7; @@ -247,10 +277,10 @@ impl G1Affine { let mut res = [0; 96]; res[0..48].copy_from_slice( - &Fp::conditional_select(&self.x, &Fp::zero(), self.infinity).to_bytes()[..], + &Fp::conditional_select(&self.x, &Fp::ZERO, self.infinity).to_bytes()[..], ); res[48..96].copy_from_slice( - &Fp::conditional_select(&self.y, &Fp::zero(), self.infinity).to_bytes()[..], + &Fp::conditional_select(&self.y, &Fp::ZERO, self.infinity).to_bytes()[..], ); // Is this point at infinity? If so, set the second-most significant bit. @@ -389,6 +419,22 @@ impl G1Affine { }) } + /// Attempts to deserialize a compressed element hex string. See [`notes::serialization`](crate::notes::serialization) + /// for details about how group elements are serialized. + pub fn from_compressed_hex(hex: &str) -> CtOption { + let mut buf = [0u8; Self::COMPRESSED_BYTES]; + decode_hex_into_slice(&mut buf, hex.as_bytes()); + Self::from_compressed(&buf) + } + + /// Attempts to deserialize a uncompressed element hex string. See [`notes::serialization`](crate::notes::serialization) + /// for details about how group elements are serialized. + pub fn from_uncompressed_hex(hex: &str) -> CtOption { + let mut buf = [0u8; Self::UNCOMPRESSED_BYTES]; + decode_hex_into_slice(&mut buf, hex.as_bytes()); + Self::from_uncompressed(&buf) + } + /// Returns true if this element is the identity (the point at infinity). #[inline] pub fn is_identity(&self) -> Choice { @@ -447,7 +493,7 @@ pub struct G1Projective { impl Default for G1Projective { fn default() -> G1Projective { - G1Projective::identity() + G1Projective::IDENTITY } } @@ -465,7 +511,7 @@ impl<'a> From<&'a G1Affine> for G1Projective { G1Projective { x: p.x, y: p.y, - z: Fp::conditional_select(&Fp::one(), &Fp::zero(), p.infinity), + z: Fp::conditional_select(&Fp::ONE, &Fp::ZERO, p.infinity), } } } @@ -557,7 +603,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a G1Projective { type Output = G1Projective; fn mul(self, other: &'b Scalar) -> Self::Output { - self.multiply(&other.to_bytes()) + self.multiply(&other.to_le_bytes()) } } @@ -574,7 +620,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a G1Affine { type Output = G1Projective; fn mul(self, other: &'b Scalar) -> Self::Output { - G1Projective::from(self).multiply(&other.to_bytes()) + G1Projective::from(self).multiply(&other.to_le_bytes()) } } @@ -593,6 +639,38 @@ impl_binops_multiplicative_mixed!(G1Affine, Scalar, G1Projective); impl_binops_multiplicative_mixed!(Scalar, G1Affine, G1Projective); impl_binops_multiplicative_mixed!(Scalar, G1Projective, G1Projective); +impl fmt::LowerHex for G1Projective { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{:x}", self.to_affine()) + } +} + +impl fmt::UpperHex for G1Projective { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{:X}", self.to_affine()) + } +} + +#[cfg(feature = "hashing")] +impl CofactorGroup for G1Projective { + type Subgroup = G1Projective; + + /// Multiplies by $(1 - z)$, where $z$ is the parameter of BLS12-381, which + /// [suffices to clear](https://ia.cr/2019/403) the cofactor and map + /// elliptic curve points to elements of $\mathbb{G}\_1$. + fn clear_cofactor(&self) -> Self::Subgroup { + self - self.mul_by_x() + } + + fn into_subgroup(self) -> CtOption { + CtOption::new(self, 1.into()) + } + + fn is_torsion_free(&self) -> Choice { + self.is_on_curve() + } +} + #[inline(always)] fn mul_by_3b(a: Fp) -> Fp { let a = a + a; // 2 @@ -601,38 +679,39 @@ fn mul_by_3b(a: Fp) -> Fp { } impl G1Projective { - /// Returns the identity of the group: the point at infinity. - pub fn identity() -> G1Projective { - G1Projective { - x: Fp::zero(), - y: Fp::one(), - z: Fp::zero(), - } - } + /// Bytes to represent this point compressed + pub const COMPRESSED_BYTES: usize = 48; + /// Bytes to represent this point uncompressed + pub const UNCOMPRESSED_BYTES: usize = 96; + + /// The identity of the group: the point at infinity. + pub const IDENTITY: Self = Self { + x: Fp::ZERO, + y: Fp::ONE, + z: Fp::ZERO, + }; - /// Returns a fixed generator of the group. See [`notes::design`](notes/design/index.html#fixed-generators) + /// The fixed generator of the group. See [`notes::design`](notes/design/index.html#fixed-generators) /// for how this generator is chosen. - pub fn generator() -> G1Projective { - G1Projective { - x: Fp::from_raw_unchecked([ - 0x5cb3_8790_fd53_0c16, - 0x7817_fc67_9976_fff5, - 0x154f_95c7_143b_a1c1, - 0xf0ae_6acd_f3d0_e747, - 0xedce_6ecc_21db_f440, - 0x1201_7741_9e0b_fb75, - ]), - y: Fp::from_raw_unchecked([ - 0xbaac_93d5_0ce7_2271, - 0x8c22_631a_7918_fd8e, - 0xdd59_5f13_5707_25ce, - 0x51ac_5829_5040_5194, - 0x0e1c_8c3f_ad00_59c0, - 0x0bbc_3efc_5008_a26a, - ]), - z: Fp::one(), - } - } + pub const GENERATOR: Self = Self { + x: Fp::from_raw_unchecked([ + 0x5cb3_8790_fd53_0c16, + 0x7817_fc67_9976_fff5, + 0x154f_95c7_143b_a1c1, + 0xf0ae_6acd_f3d0_e747, + 0xedce_6ecc_21db_f440, + 0x1201_7741_9e0b_fb75, + ]), + y: Fp::from_raw_unchecked([ + 0xbaac_93d5_0ce7_2271, + 0x8c22_631a_7918_fd8e, + 0xdd59_5f13_5707_25ce, + 0x51ac_5829_5040_5194, + 0x0e1c_8c3f_ad00_59c0, + 0x0bbc_3efc_5008_a26a, + ]), + z: Fp::ONE, + }; /// Computes the doubling of this point. pub fn double(&self) -> G1Projective { @@ -663,7 +742,7 @@ impl G1Projective { z: z3, }; - G1Projective::conditional_select(&tmp, &G1Projective::identity(), self.is_identity()) + G1Projective::conditional_select(&tmp, &G1Projective::IDENTITY, self.is_identity()) } /// Adds this point to another point. @@ -752,7 +831,7 @@ impl G1Projective { } fn multiply(&self, by: &[u8; 32]) -> G1Projective { - let mut acc = G1Projective::identity(); + let mut acc = G1Projective::IDENTITY; // This is a simple double-and-add implementation of point // multiplication, moving from most significant to least @@ -775,7 +854,7 @@ impl G1Projective { /// Multiply `self` by `crate::BLS_X`, using double and add. fn mul_by_x(&self) -> G1Projective { - let mut xself = G1Projective::identity(); + let mut xself = G1Projective::IDENTITY; // NOTE: in BLS12-381 we can just skip the first bit. let mut x = crate::BLS_X >> 1; let mut tmp = *self; @@ -794,19 +873,12 @@ impl G1Projective { xself } - /// Multiplies by $(1 - z)$, where $z$ is the parameter of BLS12-381, which - /// [suffices to clear](https://ia.cr/2019/403) the cofactor and map - /// elliptic curve points to elements of $\mathbb{G}\_1$. - pub fn clear_cofactor(&self) -> G1Projective { - self - self.mul_by_x() - } - /// Converts a batch of `G1Projective` elements into `G1Affine` elements. This /// function will panic if `p.len() != q.len()`. pub fn batch_normalize(p: &[Self], q: &mut [G1Affine]) { assert_eq!(p.len(), q.len()); - let mut acc = Fp::one(); + let mut acc = Fp::ONE; for (p, q) in p.iter().zip(q.iter_mut()) { // We use the `x` field of `G1Affine` to store the product // of previous z-coordinates seen. @@ -852,6 +924,31 @@ impl G1Projective { (self.y.square() * self.z).ct_eq(&(self.x.square() * self.x + self.z.square() * self.z * B)) | self.z.is_zero() } + + #[cfg(feature = "hashing")] + /// Use a random oracle to map a value to a curve point + pub fn hash(msg: &[u8], dst: &[u8]) -> Self + where + X: for<'a> ExpandMsg<'a>, + { + { + let u = Fp::hash::(msg, dst); + u[0].map_to_curve() + u[1].map_to_curve() + } + .clear_cofactor() + } + + #[cfg(feature = "hashing")] + /// Use injective encoding to map a value to a curve point + pub fn encode(msg: &[u8], dst: &[u8]) -> Self + where + X: for<'a> ExpandMsg<'a>, + { + let u = Fp::encode::(msg, dst); + u.map_to_curve().clear_cofactor() + } + + impl_pippenger_sum_of_products!(); } #[derive(Clone, Copy)] @@ -968,11 +1065,11 @@ impl Group for G1Projective { } fn identity() -> Self { - Self::identity() + Self::IDENTITY } fn generator() -> Self { - Self::generator() + Self::GENERATOR } fn is_identity(&self) -> Choice { @@ -1103,16 +1200,16 @@ fn test_beta() { ]) .unwrap() ); - assert_ne!(BETA, Fp::one()); - assert_ne!(BETA * BETA, Fp::one()); - assert_eq!(BETA * BETA * BETA, Fp::one()); + assert_ne!(BETA, Fp::ONE); + assert_ne!(BETA * BETA, Fp::ONE); + assert_eq!(BETA * BETA * BETA, Fp::ONE); } #[test] fn test_is_on_curve() { assert!(bool::from(G1Affine::identity().is_on_curve())); assert!(bool::from(G1Affine::generator().is_on_curve())); - assert!(bool::from(G1Projective::identity().is_on_curve())); - assert!(bool::from(G1Projective::generator().is_on_curve())); + assert!(bool::from(G1Projective::IDENTITY.is_on_curve())); + assert!(bool::from(G1Projective::GENERATOR.is_on_curve())); let z = Fp::from_raw_unchecked([ 0xba7a_fa1f_9a6f_e250, @@ -1151,8 +1248,8 @@ fn test_affine_point_equality() { #[test] #[allow(clippy::eq_op)] fn test_projective_point_equality() { - let a = G1Projective::generator(); - let b = G1Projective::identity(); + let a = G1Projective::GENERATOR; + let b = G1Projective::IDENTITY; assert!(a == a); assert!(b == b); @@ -1207,8 +1304,8 @@ fn test_conditionally_select_affine() { #[test] fn test_conditionally_select_projective() { - let a = G1Projective::generator(); - let b = G1Projective::identity(); + let a = G1Projective::GENERATOR; + let b = G1Projective::IDENTITY; assert_eq!( G1Projective::conditional_select(&a, &b, Choice::from(0u8)), @@ -1222,8 +1319,8 @@ fn test_conditionally_select_projective() { #[test] fn test_projective_to_affine() { - let a = G1Projective::generator(); - let b = G1Projective::identity(); + let a = G1Projective::GENERATOR; + let b = G1Projective::IDENTITY; assert!(bool::from(G1Affine::from(a).is_on_curve())); assert!(!bool::from(G1Affine::from(a).is_identity())); @@ -1262,12 +1359,12 @@ fn test_affine_to_projective() { #[test] fn test_doubling() { { - let tmp = G1Projective::identity().double(); + let tmp = G1Projective::IDENTITY.double(); assert!(bool::from(tmp.is_identity())); assert!(bool::from(tmp.is_on_curve())); } { - let tmp = G1Projective::generator().double(); + let tmp = G1Projective::GENERATOR.double(); assert!(!bool::from(tmp.is_identity())); assert!(bool::from(tmp.is_on_curve())); @@ -1299,15 +1396,15 @@ fn test_doubling() { #[test] fn test_projective_addition() { { - let a = G1Projective::identity(); - let b = G1Projective::identity(); + let a = G1Projective::IDENTITY; + let b = G1Projective::IDENTITY; let c = a + b; assert!(bool::from(c.is_identity())); assert!(bool::from(c.is_on_curve())); } { - let a = G1Projective::identity(); - let mut b = G1Projective::generator(); + let a = G1Projective::IDENTITY; + let mut b = G1Projective::GENERATOR; { let z = Fp::from_raw_unchecked([ 0xba7a_fa1f_9a6f_e250, @@ -1327,11 +1424,11 @@ fn test_projective_addition() { let c = a + b; assert!(!bool::from(c.is_identity())); assert!(bool::from(c.is_on_curve())); - assert!(c == G1Projective::generator()); + assert!(c == G1Projective::GENERATOR); } { - let a = G1Projective::identity(); - let mut b = G1Projective::generator(); + let a = G1Projective::IDENTITY; + let mut b = G1Projective::GENERATOR; { let z = Fp::from_raw_unchecked([ 0xba7a_fa1f_9a6f_e250, @@ -1351,16 +1448,16 @@ fn test_projective_addition() { let c = b + a; assert!(!bool::from(c.is_identity())); assert!(bool::from(c.is_on_curve())); - assert!(c == G1Projective::generator()); + assert!(c == G1Projective::GENERATOR); } { - let a = G1Projective::generator().double().double(); // 4P - let b = G1Projective::generator().double(); // 2P + let a = G1Projective::GENERATOR.double().double(); // 4P + let b = G1Projective::GENERATOR.double(); // 2P let c = a + b; - let mut d = G1Projective::generator(); + let mut d = G1Projective::GENERATOR; for _ in 0..5 { - d += G1Projective::generator(); + d += G1Projective::GENERATOR; } assert!(!bool::from(c.is_identity())); assert!(bool::from(c.is_on_curve())); @@ -1380,7 +1477,7 @@ fn test_projective_addition() { 0x18f0_2065_5463_8741, ]); let beta = beta.square(); - let a = G1Projective::generator().double().double(); + let a = G1Projective::GENERATOR.double().double(); let b = G1Projective { x: a.x * beta, y: -a.y, @@ -1409,7 +1506,7 @@ fn test_projective_addition() { 0x0bc3_b8d5_fb04_47f7, 0x07bf_a4c7_210f_4f44, ]), - z: Fp::one() + z: Fp::ONE }) ); assert!(!bool::from(c.is_identity())); @@ -1421,14 +1518,14 @@ fn test_projective_addition() { fn test_mixed_addition() { { let a = G1Affine::identity(); - let b = G1Projective::identity(); + let b = G1Projective::IDENTITY; let c = a + b; assert!(bool::from(c.is_identity())); assert!(bool::from(c.is_on_curve())); } { let a = G1Affine::identity(); - let mut b = G1Projective::generator(); + let mut b = G1Projective::GENERATOR; { let z = Fp::from_raw_unchecked([ 0xba7a_fa1f_9a6f_e250, @@ -1448,11 +1545,11 @@ fn test_mixed_addition() { let c = a + b; assert!(!bool::from(c.is_identity())); assert!(bool::from(c.is_on_curve())); - assert!(c == G1Projective::generator()); + assert!(c == G1Projective::GENERATOR); } { let a = G1Affine::identity(); - let mut b = G1Projective::generator(); + let mut b = G1Projective::GENERATOR; { let z = Fp::from_raw_unchecked([ 0xba7a_fa1f_9a6f_e250, @@ -1472,14 +1569,14 @@ fn test_mixed_addition() { let c = b + a; assert!(!bool::from(c.is_identity())); assert!(bool::from(c.is_on_curve())); - assert!(c == G1Projective::generator()); + assert!(c == G1Projective::GENERATOR); } { - let a = G1Projective::generator().double().double(); // 4P - let b = G1Projective::generator().double(); // 2P + let a = G1Projective::GENERATOR.double().double(); // 4P + let b = G1Projective::GENERATOR.double(); // 2P let c = a + b; - let mut d = G1Projective::generator(); + let mut d = G1Projective::GENERATOR; for _ in 0..5 { d += G1Affine::generator(); } @@ -1501,7 +1598,7 @@ fn test_mixed_addition() { 0x18f0_2065_5463_8741, ]); let beta = beta.square(); - let a = G1Projective::generator().double().double(); + let a = G1Projective::GENERATOR.double().double(); let b = G1Projective { x: a.x * beta, y: -a.y, @@ -1531,7 +1628,7 @@ fn test_mixed_addition() { 0x0bc3_b8d5_fb04_47f7, 0x07bf_a4c7_210f_4f44, ]), - z: Fp::one() + z: Fp::ONE }) ); assert!(!bool::from(c.is_identity())); @@ -1542,21 +1639,21 @@ fn test_mixed_addition() { #[test] #[allow(clippy::eq_op)] fn test_projective_negation_and_subtraction() { - let a = G1Projective::generator().double(); - assert_eq!(a + (-a), G1Projective::identity()); + let a = G1Projective::GENERATOR.double(); + assert_eq!(a + (-a), G1Projective::IDENTITY); assert_eq!(a + (-a), a - a); } #[test] fn test_affine_negation_and_subtraction() { let a = G1Affine::generator(); - assert_eq!(G1Projective::from(a) + (-a), G1Projective::identity()); + assert_eq!(G1Projective::from(a) + (-a), G1Projective::IDENTITY); assert_eq!(G1Projective::from(a) + (-a), G1Projective::from(a) - a); } #[test] fn test_projective_scalar_multiplication() { - let g = G1Projective::generator(); + let g = G1Projective::GENERATOR; let a = Scalar::from_raw([ 0x2b56_8297_a56d_a71c, 0xd8c3_9ecb_0ef3_75d1, @@ -1625,7 +1722,7 @@ fn test_is_torsion_free() { fn test_mul_by_x() { // multiplying by `x` a point in G1 is the same as multiplying by // the equivalent scalar. - let generator = G1Projective::generator(); + let generator = G1Projective::GENERATOR; let x = if crate::BLS_X_IS_NEGATIVE { -Scalar::from(crate::BLS_X) } else { @@ -1633,7 +1730,7 @@ fn test_mul_by_x() { }; assert_eq!(generator.mul_by_x(), generator * x); - let point = G1Projective::generator() * Scalar::from(42); + let point = G1Projective::GENERATOR * Scalar::from(42); assert_eq!(point.mul_by_x(), point * x); } @@ -1641,9 +1738,9 @@ fn test_mul_by_x() { fn test_clear_cofactor() { // the generator (and the identity) are always on the curve, // even after clearing the cofactor - let generator = G1Projective::generator(); + let generator = G1Projective::GENERATOR; assert!(bool::from(generator.clear_cofactor().is_on_curve())); - let id = G1Projective::identity(); + let id = G1Projective::IDENTITY; assert!(bool::from(id.clear_cofactor().is_on_curve())); let z = Fp::from_raw_unchecked([ @@ -1689,7 +1786,7 @@ fn test_clear_cofactor() { #[test] fn test_batch_normalize() { - let a = G1Projective::generator().double(); + let a = G1Projective::GENERATOR.double(); let b = a.double(); let c = b.double(); @@ -1698,13 +1795,13 @@ fn test_batch_normalize() { for c_identity in (0..=1).map(|n| n == 1) { let mut v = [a, b, c]; if a_identity { - v[0] = G1Projective::identity() + v[0] = G1Projective::IDENTITY } if b_identity { - v[1] = G1Projective::identity() + v[1] = G1Projective::IDENTITY } if c_identity { - v[2] = G1Projective::identity() + v[2] = G1Projective::IDENTITY } let mut t = [ @@ -1735,7 +1832,7 @@ fn test_zeroize() { a.zeroize(); assert!(bool::from(a.is_identity())); - let mut a = G1Projective::generator(); + let mut a = G1Projective::GENERATOR; a.zeroize(); assert!(bool::from(a.is_identity())); @@ -1758,7 +1855,7 @@ fn test_commutative_scalar_subgroup_multiplication() { ]); let g1_a = G1Affine::generator(); - let g1_p = G1Projective::generator(); + let g1_p = G1Projective::GENERATOR; // By reference. assert_eq!(&g1_a * &a, &a * &g1_a); @@ -1774,3 +1871,112 @@ fn test_commutative_scalar_subgroup_multiplication() { assert_eq!(g1_p * a, a * g1_p); assert_eq!(g1_a * a, a * g1_a); } + +#[test] +fn test_sum_of_products() { + use ff::Field; + use rand_core::SeedableRng; + use rand_xorshift::XorShiftRng; + + let seed = [1u8; 16]; + let mut rng = XorShiftRng::from_seed(seed); + + let h0 = G1Projective::random(&mut rng); + + let s = Scalar::random(&mut rng); + let s_tilde = Scalar::random(&mut rng); + let c = Scalar::random(&mut rng); + + assert_eq!( + h0 * s, + G1Projective::sum_of_products_in_place(&[h0], &mut [s]) + ); + assert_eq!( + h0 * s_tilde, + G1Projective::sum_of_products_in_place(&[h0], &mut [s_tilde]) + ); + + // test schnorr proof + let u = h0 * s; + let u_tilde = h0 * s_tilde; + let s_hat = s_tilde - c * s; + assert_eq!(u_tilde, u * c + h0 * s_hat); + assert_eq!( + u_tilde, + G1Projective::sum_of_products_in_place(&[u, h0], &mut [c, s_hat]) + ); +} + +#[cfg(feature = "alloc")] +#[test] +fn test_sum_of_products_alloc() { + use ff::Field; + use rand_core::SeedableRng; + use rand_xorshift::XorShiftRng; + + let seed = [1u8; 16]; + let mut rng = XorShiftRng::from_seed(seed); + + let h0 = G1Projective::random(&mut rng); + + let s = Scalar::random(&mut rng); + let s_clone = s.clone(); + let s_tilde = Scalar::random(&mut rng); + let c = Scalar::random(&mut rng); + + assert_eq!( + h0 * s, + G1Projective::sum_of_products_in_place(&[h0], &mut [s]) + ); + assert_eq!(s, s_clone); + assert_eq!( + h0 * s_tilde, + G1Projective::sum_of_products(&[h0], &mut [s_tilde]) + ); + + // test schnorr proof + let u = h0 * s; + let u_tilde = h0 * s_tilde; + let s_hat = s_tilde - c * s; + assert_eq!(u_tilde, u * c + h0 * s_hat); + assert_eq!( + u_tilde, + G1Projective::sum_of_products(&[u, h0], &mut [c, s_hat]) + ); +} + +#[cfg(feature = "hashing")] +#[test] +fn test_hash() { + use elliptic_curve::hash2curve::ExpandMsgXmd; + use std::convert::TryFrom; + const DST: &'static [u8] = b"QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_"; + + let tests: [(&'static [u8], &'static str); 5] = [ + (b"", "052926add2207b76ca4fa57a8734416c8dc95e24501772c814278700eed6d1e4e8cf62d9c09db0fac349612b759e79a108ba738453bfed09cb546dbb0783dbb3a5f1f566ed67bb6be0e8c67e2e81a4cc68ee29813bb7994998f3eae0c9c6a265"), + (b"abc", "03567bc5ef9c690c2ab2ecdf6a96ef1c139cc0b2f284dca0a9a7943388a49a3aee664ba5379a7655d3c68900be2f69030b9c15f3fe6e5cf4211f346271d7b01c8f3b28be689c8429c85b67af215533311f0b8dfaaa154fa6b88176c229f2885d"), + (b"abcdef0123456789", "11e0b079dea29a68f0383ee94fed1b940995272407e3bb916bbf268c263ddd57a6a27200a784cbc248e84f357ce82d9803a87ae2caf14e8ee52e51fa2ed8eefe80f02457004ba4d486d6aa1f517c0889501dc7413753f9599b099ebcbbd2d709"), + (b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", "15f68eaa693b95ccb85215dc65fa81038d69629f70aeee0d0f677cf22285e7bf58d7cb86eefe8f2e9bc3f8cb84fac4881807a1d50c29f430b8cafc4f8638dfeeadf51211e1602a5f184443076715f91bb90a48ba1e370edce6ae1062f5e6dd38"), + (b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "082aabae8b7dedb0e78aeb619ad3bfd9277a2f77ba7fad20ef6aabdc6c31d19ba5a6d12283553294c1825c4b3ca2dcfe05b84ae5a942248eea39e1d91030458c40153f3b654ab7872d779ad1e942856a20c438e8d99bc8abfbf74729ce1f7ac8"), + ]; + + for (msg, exp) in &tests { + let a = G1Projective::hash::>(msg, DST); + let d = <[u8; 96]>::try_from(hex::decode(exp).unwrap().as_slice()).unwrap(); + let e = G1Affine::from_uncompressed(&d).unwrap(); + assert_eq!(a.to_affine(), e); + } +} + +#[test] +fn test_hex() { + let g1 = G1Projective::GENERATOR; + let hex = format!("{:x}", g1); + let g2 = G1Affine::from_compressed_hex(&hex).map(G1Projective::from); + assert_eq!(g2.is_some().unwrap_u8(), 1u8); + assert_eq!(g1, g2.unwrap()); + let hex = hex::encode(g1.to_affine().to_uncompressed().as_ref()); + let g2 = G1Affine::from_uncompressed_hex(&hex).map(G1Projective::from); + assert_eq!(g2.is_some().unwrap_u8(), 1u8); + assert_eq!(g1, g2.unwrap()); +} diff --git a/src/g2.rs b/src/g2.rs index e96c3eaa..6c2851d8 100644 --- a/src/g2.rs +++ b/src/g2.rs @@ -1,7 +1,7 @@ //! This module provides an implementation of the $\mathbb{G}_2$ group of BLS12-381. use core::borrow::Borrow; -use core::fmt; +use core::fmt::{self, Formatter}; use core::iter::Sum; use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use group::{ @@ -9,14 +9,20 @@ use group::{ Curve, Group, GroupEncoding, UncompressedEncoding, }; use rand_core::RngCore; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +use subtle::{Choice, ConditionallyNegatable, ConditionallySelectable, ConstantTimeEq, CtOption}; #[cfg(feature = "alloc")] use group::WnafGroup; use crate::fp::Fp; use crate::fp2::Fp2; +use crate::util::decode_hex_into_slice; use crate::Scalar; +#[cfg(feature = "hashing")] +use elliptic_curve::{ + group::cofactor::CofactorGroup, + hash2curve::{ExpandMsg, Sgn0}, +}; /// This is an element of $\mathbb{G}_2$ represented in the affine coordinate space. /// It is ideal to keep elements in this representation to reduce memory usage and @@ -41,6 +47,26 @@ impl Default for G2Affine { #[cfg(feature = "zeroize")] impl zeroize::DefaultIsZeroes for G2Affine {} +impl fmt::LowerHex for G2Affine { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let bytes = self.to_compressed(); + for &b in bytes.iter() { + write!(f, "{:02x}", b)?; + } + Ok(()) + } +} + +impl fmt::UpperHex for G2Affine { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let bytes = self.to_compressed(); + for &b in bytes.iter() { + write!(f, "{:02X}", b)?; + } + Ok(()) + } +} + impl fmt::Display for G2Affine { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}", self) @@ -49,7 +75,7 @@ impl fmt::Display for G2Affine { impl<'a> From<&'a G2Projective> for G2Affine { fn from(p: &'a G2Projective) -> G2Affine { - let zinv = p.z.invert().unwrap_or(Fp2::zero()); + let zinv = p.z.invert().unwrap_or(Fp2::ZERO); let x = p.x * zinv; let y = p.y * zinv; @@ -108,7 +134,7 @@ impl<'a> Neg for &'a G2Affine { fn neg(self) -> G2Affine { G2Affine { x: self.x, - y: Fp2::conditional_select(&-self.y, &Fp2::one(), self.infinity), + y: Fp2::conditional_select(&-self.y, &Fp2::ONE, self.infinity), infinity: self.infinity, } } @@ -167,7 +193,7 @@ where where I: Iterator, { - iter.fold(Self::identity(), |acc, item| acc + item.borrow()) + iter.fold(Self::IDENTITY, |acc, item| acc + item.borrow()) } } @@ -196,11 +222,15 @@ const B: Fp2 = Fp2 { const B3: Fp2 = Fp2::add(&Fp2::add(&B, &B), &B); impl G2Affine { + /// Bytes to represent this point compressed + pub const COMPRESSED_BYTES: usize = 96; + /// Bytes to represent this point uncompressed + pub const UNCOMPRESSED_BYTES: usize = 192; /// Returns the identity of the group: the point at infinity. pub fn identity() -> G2Affine { G2Affine { - x: Fp2::zero(), - y: Fp2::one(), + x: Fp2::ZERO, + y: Fp2::ONE, infinity: Choice::from(1u8), } } @@ -254,12 +284,12 @@ impl G2Affine { pub fn to_compressed(&self) -> [u8; 96] { // Strictly speaking, self.x is zero already when self.infinity is true, but // to guard against implementation mistakes we do not assume this. - let x = Fp2::conditional_select(&self.x, &Fp2::zero(), self.infinity); + let x = Fp2::conditional_select(&self.x, &Fp2::ZERO, self.infinity); let mut res = [0; 96]; - (&mut res[0..48]).copy_from_slice(&x.c1.to_bytes()[..]); - (&mut res[48..96]).copy_from_slice(&x.c0.to_bytes()[..]); + res[0..48].copy_from_slice(&x.c1.to_bytes()[..]); + res[48..96].copy_from_slice(&x.c0.to_bytes()[..]); // This point is in compressed form, so we set the most significant bit. res[0] |= 1u8 << 7; @@ -284,8 +314,8 @@ impl G2Affine { pub fn to_uncompressed(&self) -> [u8; 192] { let mut res = [0; 192]; - let x = Fp2::conditional_select(&self.x, &Fp2::zero(), self.infinity); - let y = Fp2::conditional_select(&self.y, &Fp2::zero(), self.infinity); + let x = Fp2::conditional_select(&self.x, &Fp2::ZERO, self.infinity); + let y = Fp2::conditional_select(&self.y, &Fp2::ZERO, self.infinity); res[0..48].copy_from_slice(&x.c1.to_bytes()[..]); res[48..96].copy_from_slice(&x.c0.to_bytes()[..]); @@ -463,6 +493,22 @@ impl G2Affine { }) } + /// Attempts to deserialize a compressed element hex string. See [`notes::serialization`](crate::notes::serialization) + /// for details about how group elements are serialized. + pub fn from_compressed_hex(hex: &str) -> CtOption { + let mut buf = [0u8; Self::COMPRESSED_BYTES]; + decode_hex_into_slice(&mut buf, hex.as_bytes()); + Self::from_compressed(&buf) + } + + /// Attempts to deserialize a uncompressed element hex string. See [`notes::serialization`](crate::notes::serialization) + /// for details about how group elements are serialized. + pub fn from_uncompressed_hex(hex: &str) -> CtOption { + let mut buf = [0u8; Self::UNCOMPRESSED_BYTES]; + decode_hex_into_slice(&mut buf, hex.as_bytes()); + Self::from_uncompressed(&buf) + } + /// Returns true if this element is the identity (the point at infinity). #[inline] pub fn is_identity(&self) -> Choice { @@ -500,7 +546,7 @@ pub struct G2Projective { impl Default for G2Projective { fn default() -> G2Projective { - G2Projective::identity() + G2Projective::IDENTITY } } @@ -518,7 +564,7 @@ impl<'a> From<&'a G2Affine> for G2Projective { G2Projective { x: p.x, y: p.y, - z: Fp2::conditional_select(&Fp2::one(), &Fp2::zero(), p.infinity), + z: Fp2::conditional_select(&Fp2::ONE, &Fp2::ZERO, p.infinity), } } } @@ -610,7 +656,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a G2Projective { type Output = G2Projective; fn mul(self, other: &'b Scalar) -> Self::Output { - self.multiply(&other.to_bytes()) + self.multiply(&other.to_le_bytes()) } } @@ -627,7 +673,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a G2Affine { type Output = G2Projective; fn mul(self, other: &'b Scalar) -> Self::Output { - G2Projective::from(self).multiply(&other.to_bytes()) + G2Projective::from(self).multiply(&other.to_le_bytes()) } } @@ -652,57 +698,69 @@ fn mul_by_3b(x: Fp2) -> Fp2 { } impl G2Projective { + /// Bytes to represent this point compressed + pub const COMPRESSED_BYTES: usize = 96; + /// Bytes to represent this point uncompressed + pub const UNCOMPRESSED_BYTES: usize = 192; + /// The identity of the group: the point at infinity. + pub const IDENTITY: Self = Self { + x: Fp2::ZERO, + y: Fp2::ONE, + z: Fp2::ZERO, + }; + /// Returns the identity of the group: the point at infinity. pub fn identity() -> G2Projective { - G2Projective { - x: Fp2::zero(), - y: Fp2::one(), - z: Fp2::zero(), - } + Self::IDENTITY } + /// The fixed generator of the group. See [`notes::design`](notes/design/index.html#fixed-generators) + /// for how this generator is chosen. + pub const GENERATOR: Self = Self { + x: Fp2 { + c0: Fp::from_raw_unchecked([ + 0xf5f2_8fa2_0294_0a10, + 0xb3f5_fb26_87b4_961a, + 0xa1a8_93b5_3e2a_e580, + 0x9894_999d_1a3c_aee9, + 0x6f67_b763_1863_366b, + 0x0581_9192_4350_bcd7, + ]), + c1: Fp::from_raw_unchecked([ + 0xa5a9_c075_9e23_f606, + 0xaaa0_c59d_bccd_60c3, + 0x3bb1_7e18_e286_7806, + 0x1b1a_b6cc_8541_b367, + 0xc2b6_ed0e_f215_8547, + 0x1192_2a09_7360_edf3, + ]), + }, + y: Fp2 { + c0: Fp::from_raw_unchecked([ + 0x4c73_0af8_6049_4c4a, + 0x597c_fa1f_5e36_9c5a, + 0xe7e6_856c_aa0a_635a, + 0xbbef_b5e9_6e0d_495f, + 0x07d3_a975_f0ef_25a2, + 0x0083_fd8e_7e80_dae5, + ]), + c1: Fp::from_raw_unchecked([ + 0xadc0_fc92_df64_b05d, + 0x18aa_270a_2b14_61dc, + 0x86ad_ac6a_3be4_eba0, + 0x7949_5c4e_c93d_a33a, + 0xe717_5850_a43c_caed, + 0x0b2b_c2a1_63de_1bf2, + ]), + }, + z: Fp2::ONE, + }; + /// Returns a fixed generator of the group. See [`notes::design`](notes/design/index.html#fixed-generators) /// for how this generator is chosen. + #[deprecated(since = "0.5.5", note = "Use GENERATOR instead.")] pub fn generator() -> G2Projective { - G2Projective { - x: Fp2 { - c0: Fp::from_raw_unchecked([ - 0xf5f2_8fa2_0294_0a10, - 0xb3f5_fb26_87b4_961a, - 0xa1a8_93b5_3e2a_e580, - 0x9894_999d_1a3c_aee9, - 0x6f67_b763_1863_366b, - 0x0581_9192_4350_bcd7, - ]), - c1: Fp::from_raw_unchecked([ - 0xa5a9_c075_9e23_f606, - 0xaaa0_c59d_bccd_60c3, - 0x3bb1_7e18_e286_7806, - 0x1b1a_b6cc_8541_b367, - 0xc2b6_ed0e_f215_8547, - 0x1192_2a09_7360_edf3, - ]), - }, - y: Fp2 { - c0: Fp::from_raw_unchecked([ - 0x4c73_0af8_6049_4c4a, - 0x597c_fa1f_5e36_9c5a, - 0xe7e6_856c_aa0a_635a, - 0xbbef_b5e9_6e0d_495f, - 0x07d3_a975_f0ef_25a2, - 0x0083_fd8e_7e80_dae5, - ]), - c1: Fp::from_raw_unchecked([ - 0xadc0_fc92_df64_b05d, - 0x18aa_270a_2b14_61dc, - 0x86ad_ac6a_3be4_eba0, - 0x7949_5c4e_c93d_a33a, - 0xe717_5850_a43c_caed, - 0x0b2b_c2a1_63de_1bf2, - ]), - }, - z: Fp2::one(), - } + Self::GENERATOR } /// Computes the doubling of this point. @@ -734,7 +792,7 @@ impl G2Projective { z: z3, }; - G2Projective::conditional_select(&tmp, &G2Projective::identity(), self.is_identity()) + G2Projective::conditional_select(&tmp, &G2Projective::IDENTITY, self.is_identity()) } /// Adds this point to another point. @@ -823,7 +881,7 @@ impl G2Projective { } fn multiply(&self, by: &[u8]) -> G2Projective { - let mut acc = G2Projective::identity(); + let mut acc = G2Projective::IDENTITY; // This is a simple double-and-add implementation of point // multiplication, moving from most significant to least @@ -847,7 +905,7 @@ impl G2Projective { fn psi(&self) -> G2Projective { // 1 / ((u+1) ^ ((q-1)/3)) let psi_coeff_x = Fp2 { - c0: Fp::zero(), + c0: Fp::ZERO, c1: Fp::from_raw_unchecked([ 0x890dc9e4867545c3, 0x2af322533285a5d5, @@ -898,7 +956,7 @@ impl G2Projective { 0x03f97d6e83d050d2, 0x18f0206554638741, ]), - c1: Fp::zero(), + c1: Fp::ZERO, }; G2Projective { @@ -913,7 +971,7 @@ impl G2Projective { /// Multiply `self` by `crate::BLS_X`, using double and add. fn mul_by_x(&self) -> G2Projective { - let mut xself = G2Projective::identity(); + let mut xself = G2Projective::IDENTITY; // NOTE: in BLS12-381 we can just skip the first bit. let mut x = crate::BLS_X >> 1; let mut acc = *self; @@ -931,27 +989,12 @@ impl G2Projective { xself } - /// Clears the cofactor, using [Budroni-Pintore](https://ia.cr/2017/419). - /// This is equivalent to multiplying by $h\_\textrm{eff} = 3(z^2 - 1) \cdot - /// h_2$, where $h_2$ is the cofactor of $\mathbb{G}\_2$ and $z$ is the - /// parameter of BLS12-381. - pub fn clear_cofactor(&self) -> G2Projective { - let t1 = self.mul_by_x(); // [x] P - let t2 = self.psi(); // psi(P) - - self.double().psi2() // psi^2(2P) - + (t1 + t2).mul_by_x() // psi^2(2P) + [x^2] P + [x] psi(P) - - t1 // psi^2(2P) + [x^2 - x] P + [x] psi(P) - - t2 // psi^2(2P) + [x^2 - x] P + [x - 1] psi(P) - - self // psi^2(2P) + [x^2 - x - 1] P + [x - 1] psi(P) - } - /// Converts a batch of `G2Projective` elements into `G2Affine` elements. This /// function will panic if `p.len() != q.len()`. pub fn batch_normalize(p: &[Self], q: &mut [G2Affine]) { assert_eq!(p.len(), q.len()); - let mut acc = Fp2::one(); + let mut acc = Fp2::ONE; for (p, q) in p.iter().zip(q.iter_mut()) { // We use the `x` field of `G2Affine` to store the product // of previous z-coordinates seen. @@ -997,8 +1040,170 @@ impl G2Projective { (self.y.square() * self.z).ct_eq(&(self.x.square() * self.x + self.z.square() * self.z * B)) | self.z.is_zero() } + + #[cfg(feature = "hashing")] + /// Use a random oracle to map a value to a curve point + pub fn hash(msg: &[u8], dst: &[u8]) -> Self + where + X: for<'a> ExpandMsg<'a>, + { + { + let u = Fp2::hash::(msg, dst); + let q0 = Self::sswu_map(&u[0]).isogeny_map(); + let q1 = Self::sswu_map(&u[1]).isogeny_map(); + q0 + q1 + } + .clear_cofactor() + } + + #[cfg(feature = "hashing")] + /// Use injective encoding to map a value to a curve point + pub fn encode(msg: &[u8], dst: &[u8]) -> Self + where + X: for<'a> ExpandMsg<'a>, + { + let u = Fp2::encode::(msg, dst); + Self::sswu_map(&u).isogeny_map().clear_cofactor() + } + + #[cfg(feature = "hashing")] + /// simplified swu map for q = 9 mod 16 where AB == 0 + fn sswu_map(u: &Fp2) -> Self { + const A: Fp2 = Fp2 { + c0: Fp::ZERO, + c1: Fp([ + 0xe53a000003135242u64, + 0x01080c0fdef80285u64, + 0xe7889edbe340f6bdu64, + 0x0b51375126310601u64, + 0x02d6985717c744abu64, + 0x1220b4e979ea5467u64, + ]), + }; + const B: Fp2 = Fp2 { + c0: Fp([ + 0x22ea00000cf89db2u64, + 0x6ec832df71380aa4u64, + 0x6e1b94403db5a66eu64, + 0x75bf3c53a79473bau64, + 0x3dd3a569412c0a34u64, + 0x125cdb5e74dc4fd1u64, + ]), + c1: Fp([ + 0x22ea00000cf89db2u64, + 0x6ec832df71380aa4u64, + 0x6e1b94403db5a66eu64, + 0x75bf3c53a79473bau64, + 0x3dd3a569412c0a34u64, + 0x125cdb5e74dc4fd1u64, + ]), + }; + const Z: Fp2 = Fp2 { + c0: Fp([ + 0x87ebfffffff9555cu64, + 0x656fffe5da8ffffau64, + 0x0fd0749345d33ad2u64, + 0xd951e663066576f4u64, + 0xde291a3d41e980d3u64, + 0x0815664c7dfe040du64, + ]), + c1: Fp([ + 0x43f5fffffffcaaaeu64, + 0x32b7fff2ed47fffdu64, + 0x07e83a49a2e99d69u64, + 0xeca8f3318332bb7au64, + 0xef148d1ea0f4c069u64, + 0x040ab3263eff0206u64, + ]), + }; + const Z_INV: Fp2 = Fp2 { + c0: Fp([ + 0xacd0000000011110u64, + 0x9dd9999dc88ccccdu64, + 0xb5ca2ac9b76352bfu64, + 0xf1b574bcf4bc90ceu64, + 0x42dab41f28a77081u64, + 0x132fc6ac14cd1e12u64, + ]), + c1: Fp([ + 0xe396ffffffff2223u64, + 0x4fbf332fcd0d9998u64, + 0x0c4bbd3c1aff4cc4u64, + 0x6b9c91267926ca58u64, + 0x29ae4da6aef7f496u64, + 0x10692e942f195791u64, + ]), + }; + const M_B_OVER_A: Fp2 = Fp2 { + c0: Fp([ + 0x903c555555474fb3u64, + 0x5f98cc95ce451105u64, + 0x9f8e582eefe0fadeu64, + 0xc68946b6aebbd062u64, + 0x467a4ad10ee6de53u64, + 0x0e7146f483e23a05u64, + ]), + c1: Fp([ + 0x29c2aaaaaab85af8u64, + 0xbf133368e30eeefau64, + 0xc7a27a7206cffb45u64, + 0x9dee04ce44c9425cu64, + 0x04a15ce53464ce83u64, + 0x0b8fcaf5b59dac95u64, + ]), + }; + + let tv1 = Z * u.square(); + let mut tv2 = tv1.square(); + let mut x1 = (tv1 + tv2).invert().unwrap(); + x1 += Fp2::ONE; + x1.conditional_assign(&Z_INV, x1.is_zero()); + x1 *= M_B_OVER_A; + let gx1 = ((x1.square() + A) * x1) + B; + let x2 = tv1 * x1; + tv2 *= tv1; + let gx2 = gx1 * tv2; + let e2 = gx1.sqrt(); + let x = Fp2::conditional_select(&x2, &x1, e2.is_some()); + let y2 = Fp2::conditional_select(&gx2, &gx1, e2.is_some()); + let mut y = y2.sqrt().unwrap(); + let e9 = u.sgn0() ^ y.sgn0(); + y.conditional_negate(e9); + Self { x, y, z: Fp2::ONE } + } + + #[cfg(feature = "hashing")] + /// Computes the isogeny map for this point + fn isogeny_map(&self) -> Self { + use crate::isogeny::g2::*; + + fn compute(xxs: &[Fp2], k: &[Fp2]) -> Fp2 { + let mut xx = Fp2::ZERO; + for i in 0..k.len() { + xx += xxs[i] * k[i]; + } + xx + } + + let mut xs = [Fp2::ONE; 4]; + xs[1] = self.x; + xs[2] = self.x.square(); + xs[3] = xs[2] * self.x; + + let x_num = compute(&xs, &XNUM); + let x_den = compute(&xs, &XDEN); + let y_num = compute(&xs, &YNUM); + let y_den = compute(&xs, &YDEN); + + let x = x_num * x_den.invert().unwrap(); + let y = self.y * y_num * y_den.invert().unwrap(); + Self { x, y, z: Fp2::ONE } + } + + impl_pippenger_sum_of_products!(); } +/// The compressed form of a G2 point #[derive(Clone, Copy)] pub struct G2Compressed([u8; 96]); @@ -1113,11 +1318,11 @@ impl Group for G2Projective { } fn identity() -> Self { - Self::identity() + Self::IDENTITY } fn generator() -> Self { - Self::generator() + Self::GENERATOR } fn is_identity(&self) -> Choice { @@ -1235,12 +1440,52 @@ impl UncompressedEncoding for G2Affine { } } +impl fmt::LowerHex for G2Projective { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{:x}", self.to_affine()) + } +} + +impl fmt::UpperHex for G2Projective { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{:X}", self.to_affine()) + } +} + +#[cfg(feature = "hashing")] +impl CofactorGroup for G2Projective { + type Subgroup = G2Projective; + + /// Clears the cofactor, using [Budroni-Pintore](https://ia.cr/2017/419). + /// This is equivalent to multiplying by $h\_\textrm{eff} = 3(z^2 - 1) \cdot + /// h_2$, where $h_2$ is the cofactor of $\mathbb{G}\_2$ and $z$ is the + /// parameter of BLS12-381. + fn clear_cofactor(&self) -> Self::Subgroup { + let t1 = self.mul_by_x(); // [x] P + let t2 = self.psi(); // psi(P) + + self.double().psi2() // psi^2(2P) + + (t1 + t2).mul_by_x() // psi^2(2P) + [x^2] P + [x] psi(P) + - t1 // psi^2(2P) + [x^2 - x] P + [x] psi(P) + - t2 // psi^2(2P) + [x^2 - x] P + [x - 1] psi(P) + - self // psi^2(2P) + [x^2 - x - 1] P + [x - 1] psi(P) + } + + fn into_subgroup(self) -> CtOption { + CtOption::new(self, 1.into()) + } + + fn is_torsion_free(&self) -> Choice { + self.is_on_curve() + } +} + #[test] fn test_is_on_curve() { assert!(bool::from(G2Affine::identity().is_on_curve())); assert!(bool::from(G2Affine::generator().is_on_curve())); - assert!(bool::from(G2Projective::identity().is_on_curve())); - assert!(bool::from(G2Projective::generator().is_on_curve())); + assert!(bool::from(G2Projective::IDENTITY.is_on_curve())); + assert!(bool::from(G2Projective::GENERATOR.is_on_curve())); let z = Fp2 { c0: Fp::from_raw_unchecked([ @@ -1289,8 +1534,8 @@ fn test_affine_point_equality() { #[test] #[allow(clippy::eq_op)] fn test_projective_point_equality() { - let a = G2Projective::generator(); - let b = G2Projective::identity(); + let a = G2Projective::GENERATOR; + let b = G2Projective::IDENTITY; assert!(a == a); assert!(b == b); @@ -1355,8 +1600,8 @@ fn test_conditionally_select_affine() { #[test] fn test_conditionally_select_projective() { - let a = G2Projective::generator(); - let b = G2Projective::identity(); + let a = G2Projective::GENERATOR; + let b = G2Projective::IDENTITY; assert_eq!( G2Projective::conditional_select(&a, &b, Choice::from(0u8)), @@ -1370,8 +1615,8 @@ fn test_conditionally_select_projective() { #[test] fn test_projective_to_affine() { - let a = G2Projective::generator(); - let b = G2Projective::identity(); + let a = G2Projective::GENERATOR; + let b = G2Projective::IDENTITY; assert!(bool::from(G2Affine::from(a).is_on_curve())); assert!(!bool::from(G2Affine::from(a).is_identity())); @@ -1420,12 +1665,12 @@ fn test_affine_to_projective() { #[test] fn test_doubling() { { - let tmp = G2Projective::identity().double(); + let tmp = G2Projective::IDENTITY.double(); assert!(bool::from(tmp.is_identity())); assert!(bool::from(tmp.is_on_curve())); } { - let tmp = G2Projective::generator().double(); + let tmp = G2Projective::GENERATOR.double(); assert!(!bool::from(tmp.is_identity())); assert!(bool::from(tmp.is_on_curve())); @@ -1477,15 +1722,15 @@ fn test_doubling() { #[test] fn test_projective_addition() { { - let a = G2Projective::identity(); - let b = G2Projective::identity(); + let a = G2Projective::IDENTITY; + let b = G2Projective::IDENTITY; let c = a + b; assert!(bool::from(c.is_identity())); assert!(bool::from(c.is_on_curve())); } { - let a = G2Projective::identity(); - let mut b = G2Projective::generator(); + let a = G2Projective::IDENTITY; + let mut b = G2Projective::GENERATOR; { let z = Fp2 { c0: Fp::from_raw_unchecked([ @@ -1515,11 +1760,11 @@ fn test_projective_addition() { let c = a + b; assert!(!bool::from(c.is_identity())); assert!(bool::from(c.is_on_curve())); - assert!(c == G2Projective::generator()); + assert!(c == G2Projective::GENERATOR); } { - let a = G2Projective::identity(); - let mut b = G2Projective::generator(); + let a = G2Projective::IDENTITY; + let mut b = G2Projective::GENERATOR; { let z = Fp2 { c0: Fp::from_raw_unchecked([ @@ -1549,16 +1794,16 @@ fn test_projective_addition() { let c = b + a; assert!(!bool::from(c.is_identity())); assert!(bool::from(c.is_on_curve())); - assert!(c == G2Projective::generator()); + assert!(c == G2Projective::GENERATOR); } { - let a = G2Projective::generator().double().double(); // 4P - let b = G2Projective::generator().double(); // 2P + let a = G2Projective::GENERATOR.double().double(); // 4P + let b = G2Projective::GENERATOR.double(); // 2P let c = a + b; - let mut d = G2Projective::generator(); + let mut d = G2Projective::GENERATOR; for _ in 0..5 { - d += G2Projective::generator(); + d += G2Projective::GENERATOR; } assert!(!bool::from(c.is_identity())); assert!(bool::from(c.is_on_curve())); @@ -1578,10 +1823,10 @@ fn test_projective_addition() { 0x03f9_7d6e_83d0_50d2, 0x18f0_2065_5463_8741, ]), - c1: Fp::zero(), + c1: Fp::ZERO, }; let beta = beta.square(); - let a = G2Projective::generator().double().double(); + let a = G2Projective::GENERATOR.double().double(); let b = G2Projective { x: a.x * beta, y: -a.y, @@ -1630,7 +1875,7 @@ fn test_projective_addition() { 0x11f9_5c16_d14c_3bbe, ]) }, - z: Fp2::one() + z: Fp2::ONE }) ); assert!(!bool::from(c.is_identity())); @@ -1642,14 +1887,14 @@ fn test_projective_addition() { fn test_mixed_addition() { { let a = G2Affine::identity(); - let b = G2Projective::identity(); + let b = G2Projective::IDENTITY; let c = a + b; assert!(bool::from(c.is_identity())); assert!(bool::from(c.is_on_curve())); } { let a = G2Affine::identity(); - let mut b = G2Projective::generator(); + let mut b = G2Projective::GENERATOR; { let z = Fp2 { c0: Fp::from_raw_unchecked([ @@ -1679,11 +1924,11 @@ fn test_mixed_addition() { let c = a + b; assert!(!bool::from(c.is_identity())); assert!(bool::from(c.is_on_curve())); - assert!(c == G2Projective::generator()); + assert!(c == G2Projective::GENERATOR); } { let a = G2Affine::identity(); - let mut b = G2Projective::generator(); + let mut b = G2Projective::GENERATOR; { let z = Fp2 { c0: Fp::from_raw_unchecked([ @@ -1713,14 +1958,14 @@ fn test_mixed_addition() { let c = b + a; assert!(!bool::from(c.is_identity())); assert!(bool::from(c.is_on_curve())); - assert!(c == G2Projective::generator()); + assert!(c == G2Projective::GENERATOR); } { - let a = G2Projective::generator().double().double(); // 4P - let b = G2Projective::generator().double(); // 2P + let a = G2Projective::GENERATOR.double().double(); // 4P + let b = G2Projective::GENERATOR.double(); // 2P let c = a + b; - let mut d = G2Projective::generator(); + let mut d = G2Projective::GENERATOR; for _ in 0..5 { d += G2Affine::generator(); } @@ -1742,10 +1987,10 @@ fn test_mixed_addition() { 0x03f9_7d6e_83d0_50d2, 0x18f0_2065_5463_8741, ]), - c1: Fp::zero(), + c1: Fp::ZERO, }; let beta = beta.square(); - let a = G2Projective::generator().double().double(); + let a = G2Projective::GENERATOR.double().double(); let b = G2Projective { x: a.x * beta, y: -a.y, @@ -1795,7 +2040,7 @@ fn test_mixed_addition() { 0x11f9_5c16_d14c_3bbe, ]) }, - z: Fp2::one() + z: Fp2::ONE }) ); assert!(!bool::from(c.is_identity())); @@ -1806,21 +2051,21 @@ fn test_mixed_addition() { #[test] #[allow(clippy::eq_op)] fn test_projective_negation_and_subtraction() { - let a = G2Projective::generator().double(); - assert_eq!(a + (-a), G2Projective::identity()); + let a = G2Projective::GENERATOR.double(); + assert_eq!(a + (-a), G2Projective::IDENTITY); assert_eq!(a + (-a), a - a); } #[test] fn test_affine_negation_and_subtraction() { let a = G2Affine::generator(); - assert_eq!(G2Projective::from(a) + (-a), G2Projective::identity()); + assert_eq!(G2Projective::from(a) + (-a), G2Projective::IDENTITY); assert_eq!(G2Projective::from(a) + (-a), G2Projective::from(a) - a); } #[test] fn test_projective_scalar_multiplication() { - let g = G2Projective::generator(); + let g = G2Projective::GENERATOR; let a = Scalar::from_raw([ 0x2b56_8297_a56d_a71c, 0xd8c3_9ecb_0ef3_75d1, @@ -1909,7 +2154,7 @@ fn test_is_torsion_free() { fn test_mul_by_x() { // multiplying by `x` a point in G2 is the same as multiplying by // the equivalent scalar. - let generator = G2Projective::generator(); + let generator = G2Projective::GENERATOR; let x = if crate::BLS_X_IS_NEGATIVE { -Scalar::from(crate::BLS_X) } else { @@ -1917,13 +2162,13 @@ fn test_mul_by_x() { }; assert_eq!(generator.mul_by_x(), generator * x); - let point = G2Projective::generator() * Scalar::from(42); + let point = G2Projective::GENERATOR * Scalar::from(42); assert_eq!(point.mul_by_x(), point * x); } #[test] fn test_psi() { - let generator = G2Projective::generator(); + let generator = G2Projective::GENERATOR; let z = Fp2 { c0: Fp::from_raw_unchecked([ @@ -2071,9 +2316,9 @@ fn test_clear_cofactor() { // the generator (and the identity) are always on the curve, // even after clearing the cofactor - let generator = G2Projective::generator(); + let generator = G2Projective::GENERATOR; assert!(bool::from(generator.clear_cofactor().is_on_curve())); - let id = G2Projective::identity(); + let id = G2Projective::IDENTITY; assert!(bool::from(id.clear_cofactor().is_on_curve())); // test the effect on q-torsion points multiplying by h_eff modulo |Scalar| @@ -2092,7 +2337,7 @@ fn test_clear_cofactor() { #[test] fn test_batch_normalize() { - let a = G2Projective::generator().double(); + let a = G2Projective::GENERATOR.double(); let b = a.double(); let c = b.double(); @@ -2101,13 +2346,13 @@ fn test_batch_normalize() { for c_identity in (0..=1).map(|n| n == 1) { let mut v = [a, b, c]; if a_identity { - v[0] = G2Projective::identity() + v[0] = G2Projective::IDENTITY } if b_identity { - v[1] = G2Projective::identity() + v[1] = G2Projective::IDENTITY } if c_identity { - v[2] = G2Projective::identity() + v[2] = G2Projective::IDENTITY } let mut t = [ @@ -2138,7 +2383,7 @@ fn test_zeroize() { a.zeroize(); assert!(bool::from(a.is_identity())); - let mut a = G2Projective::generator(); + let mut a = G2Projective::GENERATOR; a.zeroize(); assert!(bool::from(a.is_identity())); @@ -2161,7 +2406,7 @@ fn test_commutative_scalar_subgroup_multiplication() { ]); let g2_a = G2Affine::generator(); - let g2_p = G2Projective::generator(); + let g2_p = G2Projective::GENERATOR; // By reference. assert_eq!(&g2_a * &a, &a * &g2_a); @@ -2177,3 +2422,107 @@ fn test_commutative_scalar_subgroup_multiplication() { assert_eq!(g2_p * a, a * g2_p); assert_eq!(g2_a * a, a * g2_a); } + +#[cfg(feature = "hashing")] +#[test] +fn test_hash() { + use elliptic_curve::hash2curve::ExpandMsgXmd; + use std::convert::TryFrom; + const DST: &'static [u8] = b"QUUX-V01-CS02-with-BLS12381G2_XMD:SHA-256_SSWU_RO_"; + + let tests: [(&[u8], &str); 5] = [ + (b"", "05cb8437535e20ecffaef7752baddf98034139c38452458baeefab379ba13dff5bf5dd71b72418717047f5b0f37da03d0141ebfbdca40eb85b87142e130ab689c673cf60f1a3e98d69335266f30d9b8d4ac44c1038e9dcdd5393faf5c41fb78a12424ac32561493f3fe3c260708a12b7c620e7be00099a974e259ddc7d1f6395c3c811cdd19f1e8dbf3e9ecfdcbab8d60503921d7f6a12805e72940b963c0cf3471c7b2a524950ca195d11062ee75ec076daf2d4bc358c4b190c0c98064fdd92"), + (b"abc", "139cddbccdc5e91b9623efd38c49f81a6f83f175e80b06fc374de9eb4b41dfe4ca3a230ed250fbe3a2acf73a41177fd802c2d18e033b960562aae3cab37a27ce00d80ccd5ba4b7fe0e7a210245129dbec7780ccc7954725f4168aff2787776e600aa65dae3c8d732d10ecd2c50f8a1baf3001578f71c694e03866e9f3d49ac1e1ce70dd94a733534f106d4cec0eddd161787327b68159716a37440985269cf584bcb1e621d3a7202be6ea05c4cfe244aeb197642555a0645fb87bf7466b2ba48"), + (b"abcdef0123456789", "190d119345b94fbd15497bcba94ecf7db2cbfd1e1fe7da034d26cbba169fb3968288b3fafb265f9ebd380512a71c3f2c121982811d2491fde9ba7ed31ef9ca474f0e1501297f68c298e9f4c0028add35aea8bb83d53c08cfc007c1e005723cd00bb5e7572275c567462d91807de765611490205a941a5a6af3b1691bfe596c31225d3aabdf15faff860cb4ef17c7c3be05571a0f8d3c08d094576981f4a3b8eda0a8e771fcdcc8ecceaf1356a6acf17574518acb506e435b639353c2e14827c8"), + (b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", "0934aba516a52d8ae479939a91998299c76d39cc0c035cd18813bec433f587e2d7a4fef038260eef0cef4d02aae3eb9119a84dd7248a1066f737cc34502ee5555bd3c19f2ecdb3c7d9e24dc65d4e25e50d83f0f77105e955d78f4762d33c17da09bcccfa036b4847c9950780733633f13619994394c23ff0b32fa6b795844f4a0673e20282d07bc69641cee04f5e566214f81cd421617428bc3b9fe25afbb751d934a00493524bc4e065635b0555084dd54679df1536101b2c979c0152d09192"), + (b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "11fca2ff525572795a801eed17eb12785887c7b63fb77a42be46ce4a34131d71f7a73e95fee3f812aea3de78b4d0156901a6ba2f9a11fa5598b2d8ace0fbe0a0eacb65deceb476fbbcb64fd24557c2f4b18ecfc5663e54ae16a84f5ab7f6253403a47f8e6d1763ba0cad63d6114c0accbef65707825a511b251a660a9b3994249ae4e63fac38b23da0c398689ee2ab520b6798718c8aed24bc19cb27f866f1c9effcdbf92397ad6448b5c9db90d2b9da6cbabf48adc1adf59a1a28344e79d57e") + ]; + + for (msg, exp) in &tests { + let a = G2Projective::hash::>(msg, DST); + let d = <[u8; 192]>::try_from(hex::decode(exp).unwrap().as_slice()).unwrap(); + let e = G2Affine::from_uncompressed(&d).unwrap(); + assert_eq!(a.to_affine(), e); + } +} + +#[test] +fn test_sum_of_products() { + use ff::Field; + use rand_core::SeedableRng; + use rand_xorshift::XorShiftRng; + + let seed = [1u8; 16]; + let mut rng = XorShiftRng::from_seed(seed); + + let h0 = G2Projective::random(&mut rng); + + let s = Scalar::random(&mut rng); + let s_tilde = Scalar::random(&mut rng); + let c = Scalar::random(&mut rng); + + assert_eq!( + h0 * s, + G2Projective::sum_of_products_in_place(&[h0], &mut [s]) + ); + assert_eq!( + h0 * s_tilde, + G2Projective::sum_of_products_in_place(&[h0], &mut [s_tilde]) + ); + + // test schnorr proof + let u = h0 * s; + let u_tilde = h0 * s_tilde; + let s_hat = s_tilde - c * s; + assert_eq!(u_tilde, u * c + h0 * s_hat); + assert_eq!( + u_tilde, + G2Projective::sum_of_products_in_place(&[u, h0], &mut [c, s_hat]) + ); +} + +#[cfg(feature = "alloc")] +#[test] +fn test_sum_of_products_alloc() { + use ff::Field; + use rand_core::SeedableRng; + use rand_xorshift::XorShiftRng; + + let seed = [1u8; 16]; + let mut rng = XorShiftRng::from_seed(seed); + + let h0 = G2Projective::random(&mut rng); + + let s = Scalar::random(&mut rng); + let s_tilde = Scalar::random(&mut rng); + let c = Scalar::random(&mut rng); + + assert_eq!(h0 * s, G2Projective::sum_of_products(&[h0], &mut [s])); + assert_eq!( + h0 * s_tilde, + G2Projective::sum_of_products(&[h0], &mut [s_tilde]) + ); + + // test schnorr proof + let u = h0 * s; + let u_tilde = h0 * s_tilde; + let s_hat = s_tilde - c * s; + assert_eq!(u_tilde, u * c + h0 * s_hat); + assert_eq!( + u_tilde, + G2Projective::sum_of_products(&[u, h0], &mut [c, s_hat]) + ); +} + +#[test] +fn test_hex() { + let g1 = G2Projective::GENERATOR; + let hex = format!("{:x}", g1); + let g2 = G2Affine::from_compressed_hex(&hex).map(G2Projective::from); + assert_eq!(g2.is_some().unwrap_u8(), 1u8); + assert_eq!(g1, g2.unwrap()); + let hex = hex::encode(g1.to_affine().to_uncompressed().as_ref()); + let g2 = G2Affine::from_uncompressed_hex(&hex).map(G2Projective::from); + assert_eq!(g2.is_some().unwrap_u8(), 1u8); + assert_eq!(g1, g2.unwrap()); +} diff --git a/src/hash_to_curve/chain.rs b/src/hash_to_curve/chain.rs deleted file mode 100644 index c9d2352f..00000000 --- a/src/hash_to_curve/chain.rs +++ /dev/null @@ -1,920 +0,0 @@ -//! Addition chains for computing square roots. -//! chain_pm3div4: input x, output x^((p-3)//4). -//! chain_p2m9div16: input x, output x^((p**2 - 9) // 16). - -use core::ops::MulAssign; - -use crate::{fp::Fp, fp2::Fp2}; - -macro_rules! square { - ($var:expr, $n:expr) => { - for _ in 0..$n { - $var = $var.square(); - } - }; -} - -#[allow(clippy::cognitive_complexity)] -/// addchain for 1000602388805416848354447456433976039139220704984751971333014534031007912622709466110671907282253916009473568139946 -/// Bos-Coster (win=4) : 458 links, 16 variables */ -/// Addition chain implementing exponentiation by (p - 3) // 4. -pub fn chain_pm3div4(var0: &Fp) -> Fp { - let mut var1 = var0.square(); - //Self::sqr(var1, var0); /* 0 : 2 */ - let var9 = var1 * var0; - //Self::mul(&mut var9, var1, var0); /* 1 : 3 */ - let var5 = var1.square(); - //Self::sqr(&mut var5, var1); /* 2 : 4 */ - let var2 = var9 * var1; - //Self::mul(&mut var2, &var9, var1); /* 3 : 5 */ - let var7 = var5 * var9; - //Self::mul(&mut var7, &var5, &var9); /* 4 : 7 */ - let var10 = var2 * var5; - //Self::mul(&mut var10, &var2, &var5); /* 5 : 9 */ - let var13 = var7 * var5; - //Self::mul(&mut var13, &var7, &var5); /* 6 : 11 */ - let var4 = var10 * var5; - //Self::mul(&mut var4, &var10, &var5); /* 7 : 13 */ - let var8 = var13 * var5; - //Self::mul(&mut var8, &var13, &var5); /* 8 : 15 */ - let var15 = var4 * var5; - //Self::mul(&mut var15, &var4, &var5); /* 9 : 17 */ - let var11 = var8 * var5; - //Self::mul(&mut var11, &var8, &var5); /* 10 : 19 */ - let var3 = var15 * var5; - //Self::mul(&mut var3, &var15, &var5); /* 11 : 21 */ - let var12 = var11 * var5; - //Self::mul(&mut var12, &var11, &var5); /* 12 : 23 */ - var1 = var4.square(); - //Self::sqr(var1, &var4); /* 13 : 26 */ - let var14 = var12 * var5; - //Self::mul(&mut var14, &var12, &var5); /* 14 : 27 */ - let var6 = var1 * var9; - //Self::mul(&mut var6, var1, &var9); /* 15 : 29 */ - let var5 = var1 * var2; - //Self::mul(&mut var5, var1, &var2); /* 16 : 31 */ - // 17 : 106496 - square!(var1, 12); - // 29 : 106513 - var1.mul_assign(&var15); - // 30 : 13633664 - square!(var1, 7); - // 37 : 13633679 - var1.mul_assign(&var8); - // 38 : 218138864 - square!(var1, 4); - // 42 : 218138869 - var1.mul_assign(&var2); - // 43 : 13960887616 - square!(var1, 6); - // 49 : 13960887623 - var1.mul_assign(&var7); - // 50 : 1786993615744 - square!(var1, 7); - // 57 : 1786993615767 - var1.mul_assign(&var12); - // 58 : 57183795704544 - square!(var1, 5); - // 63 : 57183795704575 - var1.mul_assign(&var5); - // 64 : 228735182818300 - square!(var1, 2); - // 66 : 228735182818303 - var1.mul_assign(&var9); - // 67 : 14639051700371392 - square!(var1, 6); - // 73 : 14639051700371405 - var1.mul_assign(&var4); - // 74 : 936899308823769920 - square!(var1, 6); - // 80 : 936899308823769933 - var1.mul_assign(&var4); - // 81 : 59961555764721275712 - square!(var1, 6); - // 87 : 59961555764721275721 - var1.mul_assign(&var10); - // 88 : 479692446117770205768 - square!(var1, 3); - // 91 : 479692446117770205771 - var1.mul_assign(&var9); - // 92 : 61400633103074586338688 - square!(var1, 7); - // 99 : 61400633103074586338701 - var1.mul_assign(&var4); - // 100 : 982410129649193381419216 - square!(var1, 4); - // 104 : 982410129649193381419229 - var1.mul_assign(&var4); - // 105 : 62874248297548376410830656 - square!(var1, 6); - // 111 : 62874248297548376410830671 - var1.mul_assign(&var8); - // 112 : 4023951891043096090293162944 - square!(var1, 6); - // 118 : 4023951891043096090293162971 - var1.mul_assign(&var14); - // 119 : 32191615128344768722345303768 - square!(var1, 3); - // 122 : 32191615128344768722345303769 - var1.mul_assign(var0); - // 123 : 8241053472856260792920397764864 - square!(var1, 8); - // 131 : 8241053472856260792920397764877 - var1.mul_assign(&var4); - // 132 : 1054854844525601381493810913904256 - square!(var1, 7); - // 139 : 1054854844525601381493810913904279 - var1.mul_assign(&var12); - // 140 : 33755355024819244207801949244936928 - square!(var1, 5); - // 145 : 33755355024819244207801949244936939 - var1.mul_assign(&var13); - // 146 : 2160342721588431629299324751675964096 - square!(var1, 6); - // 152 : 2160342721588431629299324751675964109 - var1.mul_assign(&var4); - // 153 : 138261934181659624275156784107261702976 - square!(var1, 6); - // 159 : 138261934181659624275156784107261703005 - var1.mul_assign(&var6); - // 160 : 2212190946906553988402508545716187248080 - square!(var1, 4); - // 164 : 2212190946906553988402508545716187248089 - var1.mul_assign(&var10); - // 165 : 566320882408077821031042187703343935510784 - square!(var1, 8); - // 173 : 566320882408077821031042187703343935510813 - var1.mul_assign(&var6); - // 174 : 9061134118529245136496675003253502968173008 - square!(var1, 4); - // 178 : 9061134118529245136496675003253502968173021 - var1.mul_assign(&var4); - // 179 : 1159825167171743377471574400416448379926146688 - square!(var1, 7); - // 186 : 1159825167171743377471574400416448379926146711 - var1.mul_assign(&var12); - // 187 : 593830485591932609265446093013221570522187116032 - square!(var1, 9); - // 196 : 593830485591932609265446093013221570522187116051 - var1.mul_assign(&var11); - // 197 : 2375321942367730437061784372052886282088748464204 - square!(var1, 2); - // 199 : 2375321942367730437061784372052886282088748464207 - var1.mul_assign(&var9); - // 200 : 76010302155767373985977099905692361026839950854624 - square!(var1, 5); - // 205 : 76010302155767373985977099905692361026839950854631 - var1.mul_assign(&var7); - // 206 : 9729318675938223870205068787928622211435513709392768 - square!(var1, 7); - // 213 : 9729318675938223870205068787928622211435513709392773 - var1.mul_assign(&var2); - // 214 : 1245352790520092655386248804854863643063745754802274944 - square!(var1, 7); - // 221 : 1245352790520092655386248804854863643063745754802274953 - var1.mul_assign(&var10); - // 222 : 79702578593285929944719923510711273156079728307345596992 - square!(var1, 6); - // 228 : 79702578593285929944719923510711273156079728307345597015 - var1.mul_assign(&var12); - // 229 : 2550482514985149758231037552342760740994551305835059104480 - square!(var1, 5); - // 234 : 2550482514985149758231037552342760740994551305835059104509 - var1.mul_assign(&var6); - // 235 : 81615440479524792263393201674968343711825641786721891344288 - square!(var1, 5); - // 240 : 81615440479524792263393201674968343711825641786721891344307 - var1.mul_assign(&var11); - // 241 : 2611694095344793352428582453598986998778420537175100523017824 - square!(var1, 5); - // 246 : 2611694095344793352428582453598986998778420537175100523017843 - var1.mul_assign(&var11); - // 247 : 668593688408267098221717108121340671687275657516825733892567808 - square!(var1, 8); - // 255 : 668593688408267098221717108121340671687275657516825733892567821 - var1.mul_assign(&var4); - // 256 : 85579992116258188572379789839531605975971284162153693938248681088 - square!(var1, 7); - // 263 : 85579992116258188572379789839531605975971284162153693938248681109 - var1.mul_assign(&var3); - // 264 : 43816955963524192549058452397840182259697297491022691296383324727808 - square!(var1, 9); - // 273 : 43816955963524192549058452397840182259697297491022691296383324727823 - var1.mul_assign(&var8); - // 274 : 1402142590832774161569870476730885832310313519712726121484266391290336 - square!(var1, 5); - // 279 : 1402142590832774161569870476730885832310313519712726121484266391290349 - var1.mul_assign(&var4); - // 280 : 11217140726662193292558963813847086658482508157701808971874131130322792 - square!(var1, 3); - // 283 : 11217140726662193292558963813847086658482508157701808971874131130322795 - var1.mul_assign(&var9); - // 284 : 2871588026025521482895094736344854184571522088371663096799777569362635520 - square!(var1, 8); - // 292 : 2871588026025521482895094736344854184571522088371663096799777569362635535 - var1.mul_assign(&var8); - // 293 : 22972704208204171863160757890758833476572176706973304774398220554901084280 - square!(var1, 3); - // 296 : 22972704208204171863160757890758833476572176706973304774398220554901084283 - var1.mul_assign(&var9); - // 297 : 2940506138650133998484577010017130685001238618492583011122972231027338788224 - square!(var1, 7); - // 304 : 2940506138650133998484577010017130685001238618492583011122972231027338788233 - var1.mul_assign(&var10); - // 305 : 1505539142988868607224103429128770910720634172668202501694961782285997459575296 - square!(var1, 9); - // 314 : 1505539142988868607224103429128770910720634172668202501694961782285997459575311 - var1.mul_assign(&var8); - // 315 : 96354505151287590862342619464241338286120587050764960108477554066303837412819904 - square!(var1, 6); - // 321 : 96354505151287590862342619464241338286120587050764960108477554066303837412819925 - var1.mul_assign(&var3); - // 322 : 6166688329682405815189927645711445650311717571248957446942563460243445594420475200 - square!(var1, 6); - // 328 : 6166688329682405815189927645711445650311717571248957446942563460243445594420475231 - var1.mul_assign(&var5); - // 329 : 197334026549836986086077684662766260809974962279966638302162030727790259021455207392 - square!(var1, 5); - // 334 : 197334026549836986086077684662766260809974962279966638302162030727790259021455207423 - var1.mul_assign(&var5); - // 335 : 6314688849594783554754485909208520345919198792958932425669184983289288288686566637536 - square!(var1, 5); - // 340 : 6314688849594783554754485909208520345919198792958932425669184983289288288686566637567 - var1.mul_assign(&var5); - // 341 : 101035021593516536876071774547336325534707180687342918810706959732628612618985066201072 - square!(var1, 4); - // 345 : 101035021593516536876071774547336325534707180687342918810706959732628612618985066201085 - var1.mul_assign(&var4); - // 346 : 808280172748132295008574196378690604277657445498743350485655677861028900951880529608680 - square!(var1, 3); - // 349 : 808280172748132295008574196378690604277657445498743350485655677861028900951880529608683 - var1.mul_assign(&var9); - // 350 : 206919724223521867522194994272944794695080306047678297724327853532423398643681415579822848 - square!(var1, 8); - // 358 : 206919724223521867522194994272944794695080306047678297724327853532423398643681415579822869 - var1.mul_assign(&var3); - // 359 : 26485724700610799042840959266936933720970279174102822108713965252150195026391221194217327232 - square!(var1, 7); - // 366 : 26485724700610799042840959266936933720970279174102822108713965252150195026391221194217327263 - var1.mul_assign(&var5); - // 367 : 847543190419545569370910696541981879071048933571290307478846888068806240844519078214954472416 - square!(var1, 5); - // 372 : 847543190419545569370910696541981879071048933571290307478846888068806240844519078214954472447 - var1.mul_assign(&var5); - // 373 : 27121382093425458219869142289343420130273565874281289839323100418201799707024610502878543118304 - square!(var1, 5); - // 378 : 27121382093425458219869142289343420130273565874281289839323100418201799707024610502878543118335 - var1.mul_assign(&var5); - // 379 : 433942113494807331517906276629494722084377053988500637429169606691228795312393768046056689893360 - square!(var1, 4); - // 383 : 433942113494807331517906276629494722084377053988500637429169606691228795312393768046056689893375 - var1.mul_assign(&var8); - // 384 : 6943073815916917304286500426071915553350032863816010198866713707059660724998300288736907038294000 - square!(var1, 4); - // 388 : 6943073815916917304286500426071915553350032863816010198866713707059660724998300288736907038294007 - var1.mul_assign(&var7); - // 389 : 888713448437365414948672054537205190828804206568449305454939354503636572799782436958324100901632896 - square!(var1, 7); - // 396 : 888713448437365414948672054537205190828804206568449305454939354503636572799782436958324100901632927 - var1.mul_assign(&var5); - // 397 : 28438830349995693278357505745190566106521734610190377774558059344116370329593037982666371228852253664 - square!(var1, 5); - // 402 : 28438830349995693278357505745190566106521734610190377774558059344116370329593037982666371228852253693 - var1.mul_assign(&var6); - // 403 : 910042571199862184907440183846098115408695507526092088785857899011723850546977215445323879323272118176 - square!(var1, 5); - // 408 : 910042571199862184907440183846098115408695507526092088785857899011723850546977215445323879323272118207 - var1.mul_assign(&var5); - // 409 : 29121362278395589917038085883075139693078256240834946841147452768375163217503270894250364138344707782624 - square!(var1, 5); - // 414 : 29121362278395589917038085883075139693078256240834946841147452768375163217503270894250364138344707782655 - var1.mul_assign(&var5); - // 415 : 931883592908658877345218748258404470178504199706718298916718488588005222960104668616011652427030649044960 - square!(var1, 5); - // 420 : 931883592908658877345218748258404470178504199706718298916718488588005222960104668616011652427030649044991 - var1.mul_assign(&var5); - // 421 : 29820274973077084075046999944268943045712134390614985565334991634816167134723349395712372877664980769439712 - square!(var1, 5); - // 426 : 29820274973077084075046999944268943045712134390614985565334991634816167134723349395712372877664980769439743 - var1.mul_assign(&var5); - // 427 : 954248799138466690401503998216606177462788300499679538090719732314117348311147180662795932085279384622071776 - square!(var1, 5); - // 432 : 954248799138466690401503998216606177462788300499679538090719732314117348311147180662795932085279384622071807 - var1.mul_assign(&var5); - // 433 : 30535961572430934092848127942931397678809225615989745218903031434051755145956709781209469826728940307906297824 - square!(var1, 5); - // 438 : 30535961572430934092848127942931397678809225615989745218903031434051755145956709781209469826728940307906297855 - var1.mul_assign(&var5); - // 439 : 488575385158894945485570047086902362860947609855835923502448502944828082335307356499351517227663044926500765680 - square!(var1, 4); - // 443 : 488575385158894945485570047086902362860947609855835923502448502944828082335307356499351517227663044926500765693 - var1.mul_assign(&var4); - // 444 : 31268824650169276511076483013561751223100647030773499104156704188468997269459670815958497102570434875296049004352 - square!(var1, 6); - // 450 : 31268824650169276511076483013561751223100647030773499104156704188468997269459670815958497102570434875296049004373 - var1.mul_assign(&var3); - // 451 : 500301194402708424177223728216988019569610352492375985666507267015503956311354733055335953641126958004736784069968 - square!(var1, 4); - // 455 : 500301194402708424177223728216988019569610352492375985666507267015503956311354733055335953641126958004736784069973 - var1.mul_assign(&var2); - // 456 : 1000602388805416848354447456433976039139220704984751971333014534031007912622709466110671907282253916009473568139946 - var1.square() -} - -#[allow(clippy::cognitive_complexity)] -/// addchain for 1001205140483106588246484290269935788605945006208159541241399033561623546780709821462541004956387089373434649096260670658193992783731681621012512651314777238193313314641988297376025498093520728838658813979860931248214124593092835 -/// Bos-Coster (win=4) : 895 links, 17 variables -/// Addition chain implementing exponentiation by (p**2 - 9) // 16. -pub fn chain_p2m9div16(var0: &Fp2) -> Fp2 { - let mut var1 = var0.square(); - //Self::sqr(var1, var0); /* 0 : 2 */ - let var2 = var1 * var0; - //Self::mul(&mut var2, var1, var0); /* 1 : 3 */ - let var15 = var2 * var1; - //Self::mul(&mut var15, &var2, var1); /* 2 : 5 */ - let var3 = var15 * var1; - //Self::mul(&mut var3, &var15, var1); /* 3 : 7 */ - let var14 = var3 * var1; - //Self::mul(&mut var14, &var3, var1); /* 4 : 9 */ - let var13 = var14 * var1; - //Self::mul(&mut var13, &var14, var1); /* 5 : 11 */ - let var5 = var13 * var1; - //Self::mul(&mut var5, &var13, var1); /* 6 : 13 */ - let var10 = var5 * var1; - //Self::mul(&mut var10, &var5, var1); /* 7 : 15 */ - let var9 = var10 * var1; - //Self::mul(&mut var9, &var10, var1); /* 8 : 17 */ - let var16 = var9 * var1; - //Self::mul(&mut var16, &var9, var1); /* 9 : 19 */ - let var4 = var16 * var1; - //Self::mul(&mut var4, &var16, var1); /* 10 : 21 */ - let var7 = var4 * var1; - //Self::mul(&mut var7, &var4, var1); /* 11 : 23 */ - let var6 = var7 * var1; - //Self::mul(&mut var6, &var7, var1); /* 12 : 25 */ - let var12 = var6 * var1; - //Self::mul(&mut var12, &var6, var1); /* 13 : 27 */ - let var8 = var12 * var1; - //Self::mul(&mut var8, &var12, var1); /* 14 : 29 */ - let var11 = var8 * var1; - //Self::mul(&mut var11, &var8, var1); /* 15 : 31 */ - var1 = var4.square(); - //Self::sqr(var1, &var4); /* 16 : 42 */ - // 17 : 168 - square!(var1, 2); - // 19 : 169 - var1.mul_assign(var0); - // 20 : 86528 - square!(var1, 9); - // 29 : 86555 - var1.mul_assign(&var12); - // 30 : 1384880 - square!(var1, 4); - // 34 : 1384893 - var1.mul_assign(&var5); - // 35 : 88633152 - square!(var1, 6); - // 41 : 88633161 - var1.mul_assign(&var14); - // 42 : 1418130576 - square!(var1, 4); - // 46 : 1418130583 - var1.mul_assign(&var3); - // 47 : 45380178656 - square!(var1, 5); - // 52 : 45380178659 - var1.mul_assign(&var2); - // 53 : 11617325736704 - square!(var1, 8); - // 61 : 11617325736717 - var1.mul_assign(&var5); - // 62 : 185877211787472 - square!(var1, 4); - // 66 : 185877211787479 - var1.mul_assign(&var3); - // 67 : 2974035388599664 - square!(var1, 4); - // 71 : 2974035388599679 - var1.mul_assign(&var10); - // 72 : 761353059481517824 - square!(var1, 8); - // 80 : 761353059481517853 - var1.mul_assign(&var8); - // 81 : 48726595806817142592 - square!(var1, 6); - // 87 : 48726595806817142603 - var1.mul_assign(&var13); - // 88 : 779625532909074281648 - square!(var1, 4); - // 92 : 779625532909074281661 - var1.mul_assign(&var5); - // 93 : 6237004263272594253288 - square!(var1, 3); - // 96 : 6237004263272594253289 - var1.mul_assign(var0); - // 97 : 399168272849446032210496 - square!(var1, 6); - // 103 : 399168272849446032210511 - var1.mul_assign(&var10); - // 104 : 102187077849458184245890816 - square!(var1, 8); - // 112 : 102187077849458184245890845 - var1.mul_assign(&var8); - // 113 : 6539972982365323791737014080 - square!(var1, 6); - // 119 : 6539972982365323791737014101 - var1.mul_assign(&var4); - // 120 : 1674233083485522890684675609856 - square!(var1, 8); - // 128 : 1674233083485522890684675609873 - var1.mul_assign(&var9); - // 129 : 53575458671536732501909619515936 - square!(var1, 5); - // 134 : 53575458671536732501909619515951 - var1.mul_assign(&var10); - // 135 : 3428829354978350880122215649020864 - square!(var1, 6); - // 141 : 3428829354978350880122215649020873 - var1.mul_assign(&var14); - // 142 : 109722539359307228163910900768667936 - square!(var1, 5); - // 147 : 109722539359307228163910900768667951 - var1.mul_assign(&var10); - // 148 : 438890157437228912655643603074671804 - square!(var1, 2); - // 150 : 438890157437228912655643603074671805 - var1.mul_assign(var0); - // 151 : 28088970075982650409961190596778995520 - square!(var1, 6); - // 157 : 28088970075982650409961190596778995535 - var1.mul_assign(&var10); - // 158 : 3595388169725779252475032396387711428480 - square!(var1, 7); - // 165 : 3595388169725779252475032396387711428491 - var1.mul_assign(&var13); - // 166 : 57526210715612468039600518342203382855856 - square!(var1, 4); - // 170 : 57526210715612468039600518342203382855863 - var1.mul_assign(&var3); - // 171 : 3681677485799197954534433173901016502775232 - square!(var1, 6); - // 177 : 3681677485799197954534433173901016502775241 - var1.mul_assign(&var14); - // 178 : 471254718182297338180407446259330112355230848 - square!(var1, 7); - // 185 : 471254718182297338180407446259330112355230855 - var1.mul_assign(&var3); - // 186 : 15080150981833514821773038280298563595367387360 - square!(var1, 5); - // 191 : 15080150981833514821773038280298563595367387365 - var1.mul_assign(&var15); - // 192 : 1930259325674689897186948899878216140207025582720 - square!(var1, 7); - // 199 : 1930259325674689897186948899878216140207025582727 - var1.mul_assign(&var3); - // 200 : 61768298421590076709982364796102916486624818647264 - square!(var1, 5); - // 205 : 61768298421590076709982364796102916486624818647271 - var1.mul_assign(&var3); - // 206 : 63250737583708238551021941551209386482303814294805504 - square!(var1, 10); - // 216 : 63250737583708238551021941551209386482303814294805521 - var1.mul_assign(&var9); - // 217 : 506005900669665908408175532409675091858430514358444168 - square!(var1, 3); - // 220 : 506005900669665908408175532409675091858430514358444173 - var1.mul_assign(&var15); - // 221 : 16192188821429309069061617037109602939469776459470213536 - square!(var1, 5); - // 226 : 16192188821429309069061617037109602939469776459470213549 - var1.mul_assign(&var5); - // 227 : 4145200338285903121679773961500058352504262773624374668544 - square!(var1, 8); - // 235 : 4145200338285903121679773961500058352504262773624374668569 - var1.mul_assign(&var6); - // 236 : 132646410825148899893752766768001867280136408755979989394208 - square!(var1, 5); - // 241 : 132646410825148899893752766768001867280136408755979989394231 - var1.mul_assign(&var7); - // 242 : 8489370292809529593200177073152119505928730160382719321230784 - square!(var1, 6); - // 248 : 8489370292809529593200177073152119505928730160382719321230795 - var1.mul_assign(&var13); - // 249 : 543319698739809893964811332681735648379438730264494036558770880 - square!(var1, 6); - // 255 : 543319698739809893964811332681735648379438730264494036558770895 - var1.mul_assign(&var10); - // 256 : 34772460719347833213747925291631081496284078736927618339761337280 - square!(var1, 6); - // 262 : 34772460719347833213747925291631081496284078736927618339761337289 - var1.mul_assign(&var14); - // 263 : 4450874972076522651359734437328778431524362078326735147489451172992 - square!(var1, 7); - // 270 : 4450874972076522651359734437328778431524362078326735147489451173011 - var1.mul_assign(&var16); - // 271 : 142427999106448724843511501994520909808779586506455524719662437536352 - square!(var1, 5); - // 276 : 142427999106448724843511501994520909808779586506455524719662437536361 - var1.mul_assign(&var14); - // 277 : 9115391942812718389984736127649338227761893536413153582058396002327104 - square!(var1, 6); - // 283 : 9115391942812718389984736127649338227761893536413153582058396002327119 - var1.mul_assign(&var10); - // 284 : 583385084340013976959023112169557646576761186330441829251737344148935616 - square!(var1, 6); - // 290 : 583385084340013976959023112169557646576761186330441829251737344148935633 - var1.mul_assign(&var9); - // 291 : 18668322698880447262688739589425844690456357962574138536055595012765940256 - square!(var1, 5); - // 296 : 18668322698880447262688739589425844690456357962574138536055595012765940271 - var1.mul_assign(&var10); - // 297 : 74673290795521789050754958357703378761825431850296554144222380051063761084 - square!(var1, 2); - // 299 : 74673290795521789050754958357703378761825431850296554144222380051063761085 - var1.mul_assign(var0); - // 300 : 19116362443653577996993269339572064963027310553675917860920929293072322837760 - square!(var1, 8); - // 308 : 19116362443653577996993269339572064963027310553675917860920929293072322837765 - var1.mul_assign(&var15); - // 309 : 2446894392787657983615138475465224315267495750870517486197878949513257323233920 - square!(var1, 7); - // 316 : 2446894392787657983615138475465224315267495750870517486197878949513257323233925 - var1.mul_assign(&var15); - // 317 : 39150310284602527737842215607443589044279932013928279779166063192212117171742800 - square!(var1, 4); - // 321 : 39150310284602527737842215607443589044279932013928279779166063192212117171742803 - var1.mul_assign(&var2); - // 322 : 5011239716429123550443803597752779397667831297782819811733256088603150997983078784 - square!(var1, 7); - // 329 : 5011239716429123550443803597752779397667831297782819811733256088603150997983078795 - var1.mul_assign(&var13); - // 330 : 320719341851463907228403430256177881450741203058100467950928389670601663870917042880 - square!(var1, 6); - // 336 : 320719341851463907228403430256177881450741203058100467950928389670601663870917042895 - var1.mul_assign(&var10); - // 337 : 5131509469623422515654454884098846103211859248929607487214854234729626621934672686320 - square!(var1, 4); - // 341 : 5131509469623422515654454884098846103211859248929607487214854234729626621934672686333 - var1.mul_assign(&var5); - // 342 : 656833212111798082003770225164652301211117983862989758363501342045392207607638103850624 - square!(var1, 7); - // 349 : 656833212111798082003770225164652301211117983862989758363501342045392207607638103850635 - var1.mul_assign(&var13); - // 350 : 42037325575155077248241294410537747277511550967231344535264085890905101286888838646440640 - square!(var1, 6); - // 356 : 42037325575155077248241294410537747277511550967231344535264085890905101286888838646440667 - var1.mul_assign(&var12); - // 357 : 1345194418404962471943721421137207912880369630951403025128450748508963241180442836686101344 - square!(var1, 5); - // 362 : 1345194418404962471943721421137207912880369630951403025128450748508963241180442836686101367 - var1.mul_assign(&var7); - // 363 : 43046221388958799102199085476390653212171828190444896804110423952286823717774170773955243744 - square!(var1, 5); - // 368 : 43046221388958799102199085476390653212171828190444896804110423952286823717774170773955243749 - var1.mul_assign(&var15); - // 369 : 5509916337786726285081482940978003611157994008376946790926134265892713435875093859066271199872 - square!(var1, 7); - // 376 : 5509916337786726285081482940978003611157994008376946790926134265892713435875093859066271199899 - var1.mul_assign(&var12); - // 377 : 176317322809175241122607454111296115557055808268062297309636296508566829948003003490120678396768 - square!(var1, 5); - // 382 : 176317322809175241122607454111296115557055808268062297309636296508566829948003003490120678396791 - var1.mul_assign(&var7); - // 383 : 5642154329893607715923438531561475697825785864577993513908361488274138558336096111683861708697312 - square!(var1, 5); - // 388 : 5642154329893607715923438531561475697825785864577993513908361488274138558336096111683861708697333 - var1.mul_assign(&var4); - // 389 : 90274469278297723454775016504983611165212573833247896222533783812386216933377537786941787339157328 - square!(var1, 4); - // 393 : 90274469278297723454775016504983611165212573833247896222533783812386216933377537786941787339157331 - var1.mul_assign(&var2); - // 394 : 5777566033811054301105601056318951114573604725327865358242162163992717883736162418364274389706069184 - square!(var1, 6); - // 400 : 5777566033811054301105601056318951114573604725327865358242162163992717883736162418364274389706069189 - var1.mul_assign(&var15); - // 401 : 369764226163907475270758467604412871332710702420983382927498378495533944559114394775313560941188428096 - square!(var1, 6); - // 407 : 369764226163907475270758467604412871332710702420983382927498378495533944559114394775313560941188428105 - var1.mul_assign(&var14); - // 408 : 5916227618622519604332135481670605941323371238735734126839974055928543112945830316405016975059014849680 - square!(var1, 4); - // 412 : 5916227618622519604332135481670605941323371238735734126839974055928543112945830316405016975059014849683 - var1.mul_assign(&var2); - // 413 : 94659641897960313669314167706729695061173939819771746029439584894856689807133285062480271600944237594928 - square!(var1, 4); - // 417 : 94659641897960313669314167706729695061173939819771746029439584894856689807133285062480271600944237594931 - var1.mul_assign(&var2); - // 418 : 24232868325877840299344426932922801935660528593861566983536533733083312590626120975994949529841724824302336 - square!(var1, 8); - // 426 : 24232868325877840299344426932922801935660528593861566983536533733083312590626120975994949529841724824302345 - var1.mul_assign(&var14); - // 427 : 775451786428090889579021661853529661941136915003570143473169079458666002900035871231838384954935194377675040 - square!(var1, 5); - // 432 : 775451786428090889579021661853529661941136915003570143473169079458666002900035871231838384954935194377675055 - var1.mul_assign(&var10); - // 433 : 49628914331397816933057386358625898364232762560228489182282821085354624185602295758837656637115852440171203520 - square!(var1, 6); - // 439 : 49628914331397816933057386358625898364232762560228489182282821085354624185602295758837656637115852440171203527 - var1.mul_assign(&var3); - // 440 : 1588125258604730141857836363476028747655448401927311653833050274731347973939273464282805012387707278085478512864 - square!(var1, 5); - // 445 : 1588125258604730141857836363476028747655448401927311653833050274731347973939273464282805012387707278085478512879 - var1.mul_assign(&var10); - // 446 : 6504961059244974661049697744797813750396716654294268534100173925299601301255264109702369330740049011038119988752384 - square!(var1, 12); - // 458 : 6504961059244974661049697744797813750396716654294268534100173925299601301255264109702369330740049011038119988752401 - var1.mul_assign(&var9); - // 459 : 104079376947919594576795163916765020006347466468708296545602782804793620820084225755237909291840784176609919820038416 - square!(var1, 4); - // 463 : 104079376947919594576795163916765020006347466468708296545602782804793620820084225755237909291840784176609919820038429 - var1.mul_assign(&var5); - // 464 : 3330540062333427026457445245336480640203118926998665489459289049753395866242695224167613097338905093651517434241229728 - square!(var1, 5); - // 469 : 3330540062333427026457445245336480640203118926998665489459289049753395866242695224167613097338905093651517434241229741 - var1.mul_assign(&var5); - // 470 : 213154563989339329693276495701534760972999611327914591325394499184217335439532494346727238229689925993697115791438703424 - square!(var1, 6); - // 476 : 213154563989339329693276495701534760972999611327914591325394499184217335439532494346727238229689925993697115791438703427 - var1.mul_assign(&var2); - // 477 : 109135136762541736802957565799185797618175800999892270758601983582319275745040637105524345973601242108772923285216616154624 - square!(var1, 9); - // 486 : 109135136762541736802957565799185797618175800999892270758601983582319275745040637105524345973601242108772923285216616154649 - var1.mul_assign(&var6); - // 487 : 3492324376401335577694642105573945523781625631996552664275263474634216823841300387376779071155239747480733545126931716948768 - square!(var1, 5); - // 492 : 3492324376401335577694642105573945523781625631996552664275263474634216823841300387376779071155239747480733545126931716948793 - var1.mul_assign(&var6); - // 493 : 223508760089685476972457094756732513522024040447779370513616862376589876725843224792113860553935343838766946888123629884722752 - square!(var1, 6); - // 499 : 223508760089685476972457094756732513522024040447779370513616862376589876725843224792113860553935343838766946888123629884722755 - var1.mul_assign(&var2); - // 500 : 14304560645739870526237254064430880865409538588657879712871479192101752110453966386695287075451862005681084600839912312622256320 - square!(var1, 6); - // 506 : 14304560645739870526237254064430880865409538588657879712871479192101752110453966386695287075451862005681084600839912312622256323 - var1.mul_assign(&var2); - // 507 : 7323935050618813709433474080988611003089683757392834412990197346356097080552430789987986982631353346908715315630035104062595237376 - square!(var1, 9); - // 516 : 7323935050618813709433474080988611003089683757392834412990197346356097080552430789987986982631353346908715315630035104062595237399 - var1.mul_assign(&var7); - // 517 : 937463686479208154807484682366542208395479520946282804862745260333580426310711141118462333776813228404315560400644493320012190387072 - square!(var1, 7); - // 524 : 937463686479208154807484682366542208395479520946282804862745260333580426310711141118462333776813228404315560400644493320012190387087 - var1.mul_assign(&var10); - // 525 : 59997675934669321907679019671458701337310689340562099511215696661349147283885513031581589361716046617876195865641247572480780184773568 - square!(var1, 6); - // 531 : 59997675934669321907679019671458701337310689340562099511215696661349147283885513031581589361716046617876195865641247572480780184773593 - var1.mul_assign(&var6); - // 532 : 1919925629909418301045728629486678442793942058897987184358902293163172713084336417010610859574913491772038267700519922319384965912754976 - square!(var1, 5); - // 537 : 1919925629909418301045728629486678442793942058897987184358902293163172713084336417010610859574913491772038267700519922319384965912754985 - var1.mul_assign(&var14); - // 538 : 245750480628405542533853264574294840677624583538942359597939493524886107274795061377358190025588926946820898265666550056881275636832638080 - square!(var1, 7); - // 545 : 245750480628405542533853264574294840677624583538942359597939493524886107274795061377358190025588926946820898265666550056881275636832638103 - var1.mul_assign(&var7); - // 546 : 983001922513622170135413058297179362710498334155769438391757974099544429099180245509432760102355707787283593062666200227525102547330552412 - square!(var1, 2); - // 548 : 983001922513622170135413058297179362710498334155769438391757974099544429099180245509432760102355707787283593062666200227525102547330552413 - var1.mul_assign(var0); - // 549 : 251648492163487275554665742924077916853887573543876976228290041369483373849390142850414786586203061193544599824042547258246426252116621417728 - square!(var1, 8); - // 557 : 251648492163487275554665742924077916853887573543876976228290041369483373849390142850414786586203061193544599824042547258246426252116621417739 - var1.mul_assign(&var13); - // 558 : 4026375874615796408874651886785246669662201176702031619652640661911733981590242285606636585379248979096713597184680756131942820033865942683824 - square!(var1, 4); - // 562 : 4026375874615796408874651886785246669662201176702031619652640661911733981590242285606636585379248979096713597184680756131942820033865942683829 - var1.mul_assign(&var15); - // 563 : 515376111950821940335955441508511573716761750617860047315538004724701949643551012557649482928543869324379340439639136784888680964334840663530112 - square!(var1, 7); - // 570 : 515376111950821940335955441508511573716761750617860047315538004724701949643551012557649482928543869324379340439639136784888680964334840663530119 - var1.mul_assign(&var3); - // 571 : 131936284659410416726004593026178962871491008158172172112777729209523699108749059214758267629707230547041111152547619016931502326869719209863710464 - square!(var1, 8); - // 579 : 131936284659410416726004593026178962871491008158172172112777729209523699108749059214758267629707230547041111152547619016931502326869719209863710473 - var1.mul_assign(&var14); - // 580 : 16887844436404533340928587907350907247550849044246038030435549338819033485919879579489058256602525510021262227526095234167232297839324058862554940544 - square!(var1, 7); - // 587 : 16887844436404533340928587907350907247550849044246038030435549338819033485919879579489058256602525510021262227526095234167232297839324058862554940557 - var1.mul_assign(&var5); - // 588 : 17293152702878242141110874017127329021492069421307942943166002522950690289581956689396795654760986122261772520986721519787245872987467836275256259130368 - square!(var1, 10); - // 598 : 17293152702878242141110874017127329021492069421307942943166002522950690289581956689396795654760986122261772520986721519787245872987467836275256259130377 - var1.mul_assign(&var14); - // 599 : 1106761772984207497031095937096149057375492442963708348362624161468844178533245228121394921904703111824753441343150177266383735871197941521616400584344128 - square!(var1, 6); - // 605 : 1106761772984207497031095937096149057375492442963708348362624161468844178533245228121394921904703111824753441343150177266383735871197941521616400584344139 - var1.mul_assign(&var13); - // 606 : 70832753470989279809990139974153539672031516349677334295207946334006027426127694599769275001900999156784220245961611345048559095756668257383449637398024896 - square!(var1, 6); - // 612 : 70832753470989279809990139974153539672031516349677334295207946334006027426127694599769275001900999156784220245961611345048559095756668257383449637398024909 - var1.mul_assign(&var5); - // 613 : 4533296222143313907839368958345826539010017046379349394893308565376385755272172454385233600121663946034190095741543126083107782128426768472540776793473594176 - square!(var1, 6); - // 619 : 4533296222143313907839368958345826539010017046379349394893308565376385755272172454385233600121663946034190095741543126083107782128426768472540776793473594207 - var1.mul_assign(&var11); - // 620 : 145065479108586045050859806667066449248320545484139180636585874092044344168709518540327475203893246273094083063729380034659449028109656591121304857391155014624 - square!(var1, 5); - // 625 : 145065479108586045050859806667066449248320545484139180636585874092044344168709518540327475203893246273094083063729380034659449028109656591121304857391155014649 - var1.mul_assign(&var6); - // 626 : 18568381325899013766510055253384505503785029821969815121482991883781676053594818373161916826098335522956042632157360644436409475598036043663527021746067841875072 - square!(var1, 7); - // 633 : 18568381325899013766510055253384505503785029821969815121482991883781676053594818373161916826098335522956042632157360644436409475598036043663527021746067841875087 - var1.mul_assign(&var10); - // 634 : 594188202428768440528321768108304176121120954303034083887455740281013633715034187941181338435146736734593364229035540621965103219137153397232864695874170940002784 - square!(var1, 5); - // 639 : 594188202428768440528321768108304176121120954303034083887455740281013633715034187941181338435146736734593364229035540621965103219137153397232864695874170940002797 - var1.mul_assign(&var5); - // 640 : 76056089910882360387625186317862934543503482150788362737594334755969745115524376056471211319698782302027950621316549199611533212049555634845806681071893880320358016 - square!(var1, 7); - // 647 : 76056089910882360387625186317862934543503482150788362737594334755969745115524376056471211319698782302027950621316549199611533212049555634845806681071893880320358047 - var1.mul_assign(&var11); - // 648 : 2433794877148235532404005962171613905392111428825227607603018712191031843696780033807078762230361033664894419882129574387569062785585780315065813794300604170251457504 - square!(var1, 5); - // 653 : 2433794877148235532404005962171613905392111428825227607603018712191031843696780033807078762230361033664894419882129574387569062785585780315065813794300604170251457511 - var1.mul_assign(&var3); - // 654 : 623051488549948296295425526315933159780380525779258267546372790320904151986375688654612163130972424618212971489825171043217680073109959760656848331340954667584373122816 - square!(var1, 8); - // 662 : 623051488549948296295425526315933159780380525779258267546372790320904151986375688654612163130972424618212971489825171043217680073109959760656848331340954667584373122843 - var1.mul_assign(&var12); - // 663 : 39875295267196690962907233684219722225944353649872529122967858580537865727128044073895178440382235175565630175348810946765931524679037424682038293205821098725399879861952 - square!(var1, 6); - // 669 : 39875295267196690962907233684219722225944353649872529122967858580537865727128044073895178440382235175565630175348810946765931524679037424682038293205821098725399879861981 - var1.mul_assign(&var8); - // 670 : 2552018897100588221626062955790062222460438633591841863869942949154423406536194820729291420184463051236200331222323900593019617579458395179650450765172550318425592311166784 - square!(var1, 6); - // 676 : 2552018897100588221626062955790062222460438633591841863869942949154423406536194820729291420184463051236200331222323900593019617579458395179650450765172550318425592311166787 - var1.mul_assign(&var2); - // 677 : 326658418828875292368136058341127964474936145099755758575352697491766196036632937053349301783611270558233642396457459275906511050170674582995257697942086440758475815829348736 - square!(var1, 7); - // 684 : 326658418828875292368136058341127964474936145099755758575352697491766196036632937053349301783611270558233642396457459275906511050170674582995257697942086440758475815829348747 - var1.mul_assign(&var13); - // 685 : 41812277610096037423121415467664379452791826572768737097645145278946073092689015942828710628302242631453906226746554787316033414421846346623392985336587064417084904426156639616 - square!(var1, 7); - // 692 : 41812277610096037423121415467664379452791826572768737097645145278946073092689015942828710628302242631453906226746554787316033414421846346623392985336587064417084904426156639627 - var1.mul_assign(&var13); - // 693 : 2675985767046146395079770589930520284978676900657199174249289297852548677932097020341037480211343528413049998511779506388226138522998166183897151061541572122693433883274024936128 - square!(var1, 6); - // 699 : 2675985767046146395079770589930520284978676900657199174249289297852548677932097020341037480211343528413049998511779506388226138522998166183897151061541572122693433883274024936131 - var1.mul_assign(&var2); - // 700 : 85631544545476684642552658877776649119317660821030373575977257531281557693827104650913199366762992909217599952376944204423236432735941317884708833969330307926189884264768797956192 - square!(var1, 5); - // 705 : 85631544545476684642552658877776649119317660821030373575977257531281557693827104650913199366762992909217599952376944204423236432735941317884708833969330307926189884264768797956199 - var1.mul_assign(&var3); - // 706 : 87686701614568125073973922690843288698181284680735102541800711712032315078478955162535116151565304739038822351233990865329394107121603909513941845984594235316418441487123249107147776 - square!(var1, 10); - // 716 : 87686701614568125073973922690843288698181284680735102541800711712032315078478955162535116151565304739038822351233990865329394107121603909513941845984594235316418441487123249107147803 - var1.mul_assign(&var12); - // 717 : 1402987225833090001183582763053492619170900554891761640668811387392517041255663282600561858425044875824621157619743853845270305713945662552223069535753507765062695063793971985714364848 - square!(var1, 4); - // 721 : 1402987225833090001183582763053492619170900554891761640668811387392517041255663282600561858425044875824621157619743853845270305713945662552223069535753507765062695063793971985714364849 - var1.mul_assign(var0); - // 722 : 718329459626542080605994374683388221015501084104581960022431430344968725122899600691487671513622976422206032701308853168778396525540179226738211602305795975712099872662513656685754802688 - square!(var1, 9); - // 731 : 718329459626542080605994374683388221015501084104581960022431430344968725122899600691487671513622976422206032701308853168778396525540179226738211602305795975712099872662513656685754802705 - var1.mul_assign(&var9); - // 732 : 45973085416098693158783639979736846144992069382693245441435611542077998407865574444255210976871870491021186092883766602801817377634571470511245542547570942445574391850400874027888307373120 - square!(var1, 6); - // 738 : 45973085416098693158783639979736846144992069382693245441435611542077998407865574444255210976871870491021186092883766602801817377634571470511245542547570942445574391850400874027888307373135 - var1.mul_assign(&var10); - // 739 : 5884554933260632724324305917406316306558984880984735416503758277385983796206793528864667005039599422850711819889122125158632624337225148225439429446089080633033522156851311875569703343761280 - square!(var1, 7); - // 746 : 5884554933260632724324305917406316306558984880984735416503758277385983796206793528864667005039599422850711819889122125158632624337225148225439429446089080633033522156851311875569703343761311 - var1.mul_assign(&var11); - // 747 : 188305757864340247178377789357002121809887516191511533328120264876351481478617392923669344161267181531222778236451908005076243978791204743214061742274850580257072709019241980018230507000361952 - square!(var1, 5); - // 752 : 188305757864340247178377789357002121809887516191511533328120264876351481478617392923669344161267181531222778236451908005076243978791204743214061742274850580257072709019241980018230507000361973 - var1.mul_assign(&var4); - // 753 : 3012892125829443954854044629712033948958200259064184533249924238021623703657878286778709506580274904499564451783230528081219903660659275891424987876397609284113163344307871680291688112005791568 - square!(var1, 4); - // 757 : 3012892125829443954854044629712033948958200259064184533249924238021623703657878286778709506580274904499564451783230528081219903660659275891424987876397609284113163344307871680291688112005791583 - var1.mul_assign(&var10); - // 758 : 385650192106168826221317712603140345466649633160215620255990302466767834068208420707674816842275187775944249828253507594396147668564387314102398448178893988366484908071407575077336078336741322624 - square!(var1, 7); - // 765 : 385650192106168826221317712603140345466649633160215620255990302466767834068208420707674816842275187775944249828253507594396147668564387314102398448178893988366484908071407575077336078336741322653 - var1.mul_assign(&var8); - // 766 : 12340806147397402439082166803300491054932788261126899848191689678936570690182669462645594138952806008830215994504112243020676725394060394051276750341724607627727517058285042402474754506775722324896 - square!(var1, 5); - // 771 : 12340806147397402439082166803300491054932788261126899848191689678936570690182669462645594138952806008830215994504112243020676725394060394051276750341724607627727517058285042402474754506775722324917 - var1.mul_assign(&var4); - // 772 : 394905796716716878050629337705615713757849224356060795142134069725970262085845422804659012446489792282566911824131591776661655212609932609640856010935187444087280545865121356879192144216823114397344 - square!(var1, 5); - // 777 : 394905796716716878050629337705615713757849224356060795142134069725970262085845422804659012446489792282566911824131591776661655212609932609640856010935187444087280545865121356879192144216823114397365 - var1.mul_assign(&var4); - // 778 : 12636985494934940097620138806579702840251175179393945444548290231231048386747053529749088398287673353042141178372210936853172966803517843508507392349925998210792977467683883420134148614938339660715680 - square!(var1, 5); - // 783 : 12636985494934940097620138806579702840251175179393945444548290231231048386747053529749088398287673353042141178372210936853172966803517843508507392349925998210792977467683883420134148614938339660715697 - var1.mul_assign(&var9); - // 784 : 202191767918959041561922220905275245444018802870303127112772643699696774187952856475985414372602773648674258853955374989650767468856285496136118277598815971372687639482942134722146377839013434571451152 - square!(var1, 4); - // 788 : 202191767918959041561922220905275245444018802870303127112772643699696774187952856475985414372602773648674258853955374989650767468856285496136118277598815971372687639482942134722146377839013434571451165 - var1.mul_assign(&var5); - // 789 : 12940273146813378659963022137937615708417203383699400135217449196780593548028982814463066519846577513515152566653143999337649118006802271752711569766324222167852008926908296622217368181696859812572874560 - square!(var1, 6); - // 795 : 12940273146813378659963022137937615708417203383699400135217449196780593548028982814463066519846577513515152566653143999337649118006802271752711569766324222167852008926908296622217368181696859812572874589 - var1.mul_assign(&var8); - // 796 : 25880546293626757319926044275875231416834406767398800270434898393561187096057965628926133039693155027030305133306287998675298236013604543505423139532648444335704017853816593244434736363393719625145749178 - var1 = var1.square(); - // 797 : 25880546293626757319926044275875231416834406767398800270434898393561187096057965628926133039693155027030305133306287998675298236013604543505423139532648444335704017853816593244434736363393719625145749179 - var1.mul_assign(var0); - // 798 : 1656354962792112468475266833656014810677402033113523217307833497187915974147709800251272514540361921729939528531602431915219087104870690784347080930089500437485057142644261967643823127257198056009327947456 - square!(var1, 6); - // 804 : 1656354962792112468475266833656014810677402033113523217307833497187915974147709800251272514540361921729939528531602431915219087104870690784347080930089500437485057142644261967643823127257198056009327947463 - var1.mul_assign(&var3); - // 805 : 1696107481899123167718673237663759166133659681908247774523221501120425957527254835457303054889330607851458077216360890281184345195387587363171410872411648447984698514067724254867274882311370809353551818202112 - square!(var1, 10); - // 815 : 1696107481899123167718673237663759166133659681908247774523221501120425957527254835457303054889330607851458077216360890281184345195387587363171410872411648447984698514067724254867274882311370809353551818202135 - var1.mul_assign(&var7); - // 816 : 108550878841543882733995087210480586632554219642127857569486176071707261281744309469267395512917158902493316941847096977995798092504805591242970295834345500671020704900334352311505592467927731798627316364936640 - square!(var1, 6); - // 822 : 108550878841543882733995087210480586632554219642127857569486176071707261281744309469267395512917158902493316941847096977995798092504805591242970295834345500671020704900334352311505592467927731798627316364936661 - var1.mul_assign(&var4); - // 823 : 6947256245858808494975685581470757544483470057096182884447115268589264722031635806033113312826698169759572284278214206591731077920307557839550098933398112042945325113621398547936357917947374835112148247355946304 - square!(var1, 6); - // 829 : 6947256245858808494975685581470757544483470057096182884447115268589264722031635806033113312826698169759572284278214206591731077920307557839550098933398112042945325113621398547936357917947374835112148247355946329 - var1.mul_assign(&var6); - // 830 : 444624399734963743678443877214128482846942083654155704604615377189712942210024691586119252020908682864612626193805709221870788986899683701731206331737479170748500807271769507067926906748631989447177487830780565056 - square!(var1, 6); - // 836 : 444624399734963743678443877214128482846942083654155704604615377189712942210024691586119252020908682864612626193805709221870788986899683701731206331737479170748500807271769507067926906748631989447177487830780565069 - var1.mul_assign(&var5); - // 837 : 28455961583037679595420408141704222902204293353865965094695384140141628301441580261511632129338155703335208076403565390199730495161579756910797205231198666927904051665393248452347322031912447324619359221169956164416 - square!(var1, 6); - // 843 : 28455961583037679595420408141704222902204293353865965094695384140141628301441580261511632129338155703335208076403565390199730495161579756910797205231198666927904051665393248452347322031912447324619359221169956164437 - var1.mul_assign(&var4); - // 844 : 238705906983162543355580399100765177871214152862586865721082456961065184302499251714358569373223087638243353151383559860752580829556389241459968722180074986980751351032731127113348364375477010926880553717580063640645533696 - square!(var1, 23); - // 867 : 238705906983162543355580399100765177871214152862586865721082456961065184302499251714358569373223087638243353151383559860752580829556389241459968722180074986980751351032731127113348364375477010926880553717580063640645533703 - var1.mul_assign(&var3); - // 868 : 15277178046922402774757145542448971383757705783205559406149277245508171795359952109718948439886277608847574601688547831088165173091608911453437998219524799166768086466094792135254295320030528699320355437925124073001314156992 - square!(var1, 6); - // 874 : 15277178046922402774757145542448971383757705783205559406149277245508171795359952109718948439886277608847574601688547831088165173091608911453437998219524799166768086466094792135254295320030528699320355437925124073001314156999 - var1.mul_assign(&var3); - // 875 : 488869697501516888792228657358367084280246585062577900996776871856261497451518467511006350076360883483122387254033530594821285538931485166510015943024793573336578766915033348328137450240976918378251374013603970336042053023968 - square!(var1, 5); - // 880 : 488869697501516888792228657358367084280246585062577900996776871856261497451518467511006350076360883483122387254033530594821285538931485166510015943024793573336578766915033348328137450240976918378251374013603970336042053023971 - var1.mul_assign(&var2); - // 881 : 31287660640097080882702634070935493393935781444004985663793719798800735836897181920704406404887096542919832784258145958068562274491615050656641020353586788693541041082562134293000796815422522776208087936870654101506691393534144 - square!(var1, 6); - // 887 : 31287660640097080882702634070935493393935781444004985663793719798800735836897181920704406404887096542919832784258145958068562274491615050656641020353586788693541041082562134293000796815422522776208087936870654101506691393534151 - var1.mul_assign(&var3); - // 888 : 1001205140483106588246484290269935788605945006208159541241399033561623546780709821462541004956387089373434649096260670658193992783731681621012512651314777238193313314641988297376025498093520728838658813979860931248214124593092832 - square!(var1, 5); - // 893 : 1001205140483106588246484290269935788605945006208159541241399033561623546780709821462541004956387089373434649096260670658193992783731681621012512651314777238193313314641988297376025498093520728838658813979860931248214124593092835 - var1 * var2 -} - -/// Tests for addition chains -#[cfg(test)] -mod tests { - use super::*; - use rand_core::SeedableRng; - - const SEED: [u8; 16] = [ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]; - - #[test] - fn test_fp_chain() { - let mut rng = rand_xorshift::XorShiftRng::from_seed(SEED); - let p_m3_over4 = [ - 0xee7f_bfff_ffff_eaaa, - 0x07aa_ffff_ac54_ffff, - 0xd9cc_34a8_3dac_3d89, - 0xd91d_d2e1_3ce1_44af, - 0x92c6_e9ed_90d2_eb35, - 0x0680_447a_8e5f_f9a6, - ]; - - for _ in 0..32 { - let input = Fp::random(&mut rng); - assert_eq!(chain_pm3div4(&input), input.pow_vartime(&p_m3_over4)); - } - } - - #[test] - fn test_fp2_chain() { - let mut rng = rand_xorshift::XorShiftRng::from_seed(SEED); - let p_sq_m9_over16 = [ - 0xb26a_a000_01c7_18e3, - 0xd7ce_d6b1_d763_82ea, - 0x3162_c338_3621_13cf, - 0x966b_f91e_d3e7_1b74, - 0xb292_e85a_8709_1a04, - 0x11d6_8619_c861_85c7, - 0xef53_1493_3097_8ef0, - 0x050a_62cf_d16d_dca6, - 0x466e_59e4_9349_e8bd, - 0x9e2d_c90e_50e7_046b, - 0x74bd_278e_aa22_f25e, - 0x002a_437a_4b8c_35fc, - ]; - - for _ in 0..32 { - let input = Fp2::random(&mut rng); - assert_eq!( - chain_p2m9div16(&input), - input.pow_vartime_extended(&p_sq_m9_over16[..]), - ); - } - } -} diff --git a/src/hash_to_curve/expand_msg.rs b/src/hash_to_curve/expand_msg.rs deleted file mode 100644 index 7187d46b..00000000 --- a/src/hash_to_curve/expand_msg.rs +++ /dev/null @@ -1,1282 +0,0 @@ -//! This module implements message expansion consistent with the -//! hash-to-curve RFC drafts 7 through 10 - -use core::{ - fmt::{self, Debug, Formatter}, - marker::PhantomData, -}; - -use digest::{BlockInput, Digest, ExtendableOutputDirty, Update, XofReader}; - -use crate::generic_array::{ - typenum::{Unsigned, U32}, - ArrayLength, GenericArray, -}; - -#[cfg(feature = "alloc")] -use alloc::vec::Vec; - -const OVERSIZE_DST_SALT: &[u8] = b"H2C-OVERSIZE-DST-"; - -/// The domain separation tag for a message expansion. -/// -/// Implements [section 5.4.3 of `draft-irtf-cfrg-hash-to-curve-12`][dst]. -/// -/// [dst]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-12#section-5.4.3 -#[derive(Debug)] -enum ExpandMsgDst<'x, L: ArrayLength> { - /// DST produced by hashing a very long (> 255 chars) input DST. - Hashed(GenericArray), - /// A raw input DST (<= 255 chars). - Raw(&'x [u8]), -} - -impl<'x, L: ArrayLength> ExpandMsgDst<'x, L> { - /// Produces a DST for use with `expand_message_xof`. - pub fn process_xof(dst: &'x [u8]) -> Self - where - H: Default + Update + ExtendableOutputDirty, - { - if dst.len() > 255 { - let mut data = GenericArray::::default(); - H::default() - .chain(OVERSIZE_DST_SALT) - .chain(&dst) - .finalize_xof_dirty() - .read(&mut data); - Self::Hashed(data) - } else { - Self::Raw(dst) - } - } - - /// Produces a DST for use with `expand_message_xmd`. - pub fn process_xmd(dst: &'x [u8]) -> Self - where - H: Digest, - { - if dst.len() > 255 { - Self::Hashed(H::new().chain(OVERSIZE_DST_SALT).chain(&dst).finalize()) - } else { - Self::Raw(dst) - } - } - - /// Returns the raw bytes of the DST. - pub fn data(&'x self) -> &'x [u8] { - match self { - Self::Hashed(arr) => &arr[..], - Self::Raw(buf) => buf, - } - } - - /// Returns the length of the DST. - pub fn len(&'x self) -> usize { - match self { - Self::Hashed(_) => L::to_usize(), - Self::Raw(buf) => buf.len(), - } - } -} - -/// A trait for message expansion methods supported by hash-to-curve. -pub trait ExpandMessage: for<'x> InitExpandMessage<'x> { - // This intermediate is likely only necessary until GATs allow - // associated types with lifetimes. -} - -/// Trait for constructing a new message expander. -pub trait InitExpandMessage<'x> { - /// The state object used during message expansion. - type Expander: ExpandMessageState<'x>; - - /// Initializes a message expander. - fn init_expand(message: &[u8], dst: &'x [u8], len_in_bytes: usize) -> Self::Expander; -} - -// Automatically derive trait -impl InitExpandMessage<'x>> ExpandMessage for X {} - -/// Trait for types implementing the `expand_message` interface for `hash_to_field`. -pub trait ExpandMessageState<'x> { - /// Reads bytes from the generated output. - fn read_into(&mut self, output: &mut [u8]) -> usize; - - /// Retrieves the number of bytes remaining in the generator. - fn remain(&self) -> usize; - - #[cfg(feature = "alloc")] - /// Constructs a `Vec` containing the remaining bytes of the output. - fn into_vec(mut self) -> Vec - where - Self: Sized, - { - let mut result = alloc::vec![0u8; self.remain()]; - self.read_into(&mut result[..]); - result - } -} - -/// A generator for the output of `expand_message_xof` for a given -/// extendable hash function, message, DST, and output length. -/// -/// Implements [section 5.4.2 of `draft-irtf-cfrg-hash-to-curve-12`][expand_message_xof] -/// with `k = 128`. -/// -/// [expand_message_xof]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-12#section-5.4.2 -pub struct ExpandMsgXof { - hash: ::Reader, - remain: usize, -} - -impl Debug for ExpandMsgXof { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("ExpandMsgXof") - .field("remain", &self.remain) - .finish() - } -} - -impl<'x, H> ExpandMessageState<'x> for ExpandMsgXof -where - H: ExtendableOutputDirty, -{ - fn read_into(&mut self, output: &mut [u8]) -> usize { - let len = self.remain.min(output.len()); - self.hash.read(&mut output[..len]); - self.remain -= len; - len - } - - fn remain(&self) -> usize { - self.remain - } -} - -impl<'x, H> InitExpandMessage<'x> for ExpandMsgXof -where - H: Default + Update + ExtendableOutputDirty, -{ - type Expander = Self; - - fn init_expand(message: &[u8], dst: &[u8], len_in_bytes: usize) -> Self { - // Use U32 here for k = 128. - let dst = ExpandMsgDst::::process_xof::(dst); - let hash = H::default() - .chain(message) - .chain((len_in_bytes as u16).to_be_bytes()) - .chain(dst.data()) - .chain([dst.len() as u8]) - .finalize_xof_dirty(); - Self { - hash, - remain: len_in_bytes, - } - } -} - -/// Constructor for `expand_message_xmd` for a given digest hash function, message, DST, -/// and output length. -/// -/// Implements [section 5.4.1 of `draft-irtf-cfrg-hash-to-curve-12`][expand_message_xmd]. -/// -/// [expand_message_xmd]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-12#section-5.4.1 -#[derive(Debug)] -pub struct ExpandMsgXmd(PhantomData); - -/// A generator for the output of `expand_message_xmd` for a given -/// digest hash function, message, DST, and output length. -/// -/// Implements [section 5.4.1 of `draft-irtf-cfrg-hash-to-curve-12`][expand_message_xmd]. -/// -/// [expand_message_xmd]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-12#section-5.4.1 -pub struct ExpandMsgXmdState<'x, H: Digest> { - dst: ExpandMsgDst<'x, H::OutputSize>, - b_0: GenericArray, - b_i: GenericArray, - i: usize, - b_offs: usize, - remain: usize, -} - -impl Debug for ExpandMsgXmdState<'_, H> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("ExpandMsgXmdState") - .field("remain", &self.remain) - .finish() - } -} - -impl<'x, H> InitExpandMessage<'x> for ExpandMsgXmd -where - H: Digest + BlockInput, -{ - type Expander = ExpandMsgXmdState<'x, H>; - - fn init_expand(message: &[u8], dst: &'x [u8], len_in_bytes: usize) -> Self::Expander { - let hash_size = ::OutputSize::to_usize(); - let ell = (len_in_bytes + hash_size - 1) / hash_size; - if ell > 255 { - panic!("Invalid ExpandMsgXmd usage: ell > 255"); - } - let dst = ExpandMsgDst::process_xmd::(dst); - let b_0 = H::new() - .chain(GenericArray::::BlockSize>::default()) - .chain(message) - .chain((len_in_bytes as u16).to_be_bytes()) - .chain([0u8]) - .chain(dst.data()) - .chain([dst.len() as u8]) - .finalize(); - // init with b_1 - let b_i = H::new() - .chain(&b_0) - .chain([1u8]) - .chain(dst.data()) - .chain([dst.len() as u8]) - .finalize(); - ExpandMsgXmdState { - dst, - b_0, - b_i, - i: 2, - b_offs: 0, - remain: len_in_bytes, - } - } -} - -impl<'x, H> ExpandMessageState<'x> for ExpandMsgXmdState<'x, H> -where - H: Digest + BlockInput, -{ - fn read_into(&mut self, output: &mut [u8]) -> usize { - let read_len = self.remain.min(output.len()); - let mut offs = 0; - let hash_size = H::OutputSize::to_usize(); - while offs < read_len { - let b_offs = self.b_offs; - let mut copy_len = hash_size - b_offs; - if copy_len > 0 { - copy_len = copy_len.min(read_len - offs); - output[offs..(offs + copy_len)] - .copy_from_slice(&self.b_i[b_offs..(b_offs + copy_len)]); - offs += copy_len; - self.b_offs = b_offs + copy_len; - } else { - let mut b_prev_xor = self.b_0.clone(); - for j in 0..hash_size { - b_prev_xor[j] ^= self.b_i[j]; - } - self.b_i = H::new() - .chain(b_prev_xor) - .chain([self.i as u8]) - .chain(self.dst.data()) - .chain([self.dst.len() as u8]) - .finalize(); - self.b_offs = 0; - self.i += 1; - } - } - self.remain -= read_len; - read_len - } - - fn remain(&self) -> usize { - self.remain - } -} - -#[cfg(feature = "alloc")] -#[cfg(test)] -mod tests { - use super::*; - use sha2::{Sha256, Sha512}; - use sha3::{Shake128, Shake256}; - - /// From - #[test] - fn expand_message_xmd_works_for_draft12_testvectors_sha256() { - let dst = b"QUUX-V01-CS02-with-expander-SHA256-128"; - - let msg = b""; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "68a985b87eb6b46952128911f2a4412bbc302a9d759667f8\ - 7f7a21d803f07235", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abc"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "d8ccab23b5985ccea865c6c97b6e5b8350e794e603b4b979\ - 02f53a8a0d605615", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abcdef0123456789"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "eff31487c770a893cfb36f912fbfcbff40d5661771ca4b2c\ - b4eafe524333f5c1", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqq"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "b23a1d2b4d97b2ef7785562a7e8bac7eed54ed6e97e29aa5\ - 1bfe3f12ddad1ff9", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "4623227bcc01293b8c130bf771da8c298dede7383243dc09\ - 93d2d94823958c4c", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b""; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "af84c27ccfd45d41914fdff5df25293e221afc53d8ad2ac0\ - 6d5e3e29485dadbee0d121587713a3e0dd4d5e69e93eb7cd4f5df4\ - cd103e188cf60cb02edc3edf18eda8576c412b18ffb658e3dd6ec8\ - 49469b979d444cf7b26911a08e63cf31f9dcc541708d3491184472\ - c2c29bb749d4286b004ceb5ee6b9a7fa5b646c993f0ced", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abc"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "abba86a6129e366fc877aab32fc4ffc70120d8996c88aee2\ - fe4b32d6c7b6437a647e6c3163d40b76a73cf6a5674ef1d890f95b\ - 664ee0afa5359a5c4e07985635bbecbac65d747d3d2da7ec2b8221\ - b17b0ca9dc8a1ac1c07ea6a1e60583e2cb00058e77b7b72a298425\ - cd1b941ad4ec65e8afc50303a22c0f99b0509b4c895f40", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abcdef0123456789"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "ef904a29bffc4cf9ee82832451c946ac3c8f8058ae97d8d6\ - 29831a74c6572bd9ebd0df635cd1f208e2038e760c4994984ce73f\ - 0d55ea9f22af83ba4734569d4bc95e18350f740c07eef653cbb9f8\ - 7910d833751825f0ebefa1abe5420bb52be14cf489b37fe1a72f7d\ - e2d10be453b2c9d9eb20c7e3f6edc5a60629178d9478df", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqq"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "80be107d0884f0d881bb460322f0443d38bd222db8bd0b0a\ - 5312a6fedb49c1bbd88fd75d8b9a09486c60123dfa1d73c1cc3169\ - 761b17476d3c6b7cbbd727acd0e2c942f4dd96ae3da5de368d26b3\ - 2286e32de7e5a8cb2949f866a0b80c58116b29fa7fabb3ea7d520e\ - e603e0c25bcaf0b9a5e92ec6a1fe4e0391d1cdbce8c68a", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "546aff5444b5b79aa6148bd81728704c32decb73a3ba76e9\ - e75885cad9def1d06d6792f8a7d12794e90efed817d96920d72889\ - 6a4510864370c207f99bd4a608ea121700ef01ed879745ee3e4cee\ - f777eda6d9e5e38b90c86ea6fb0b36504ba4a45d22e86f6db5dd43\ - d98a294bebb9125d5b794e9d2a81181066eb954966a487", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - } - - /// From - #[test] - fn expand_message_xmd_works_for_draft12_testvectors_sha256_long_dst() { - let dst = b"QUUX-V01-CS02-with-expander-SHA256-128-long-DST-111111\ - 111111111111111111111111111111111111111111111111111111\ - 111111111111111111111111111111111111111111111111111111\ - 111111111111111111111111111111111111111111111111111111\ - 1111111111111111111111111111111111111111"; - - let msg = b""; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "e8dc0c8b686b7ef2074086fbdd2f30e3f8bfbd3bdf177f73\ - f04b97ce618a3ed3", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abc"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "52dbf4f36cf560fca57dedec2ad924ee9c266341d8f3d6af\ - e5171733b16bbb12", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abcdef0123456789"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "35387dcf22618f3728e6c686490f8b431f76550b0b2c61cb\ - c1ce7001536f4521", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqq"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "01b637612bb18e840028be900a833a74414140dde0c4754c\ - 198532c3a0ba42bc", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "20cce7033cabc5460743180be6fa8aac5a103f56d481cf36\ - 9a8accc0c374431b", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b""; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "14604d85432c68b757e485c8894db3117992fc57e0e136f7\ - 1ad987f789a0abc287c47876978e2388a02af86b1e8d1342e5ce4f\ - 7aaa07a87321e691f6fba7e0072eecc1218aebb89fb14a0662322d\ - 5edbd873f0eb35260145cd4e64f748c5dfe60567e126604bcab1a3\ - ee2dc0778102ae8a5cfd1429ebc0fa6bf1a53c36f55dfc", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abc"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "1a30a5e36fbdb87077552b9d18b9f0aee16e80181d5b951d\ - 0471d55b66684914aef87dbb3626eaabf5ded8cd0686567e503853\ - e5c84c259ba0efc37f71c839da2129fe81afdaec7fbdc0ccd4c794\ - 727a17c0d20ff0ea55e1389d6982d1241cb8d165762dbc39fb0cee\ - 4474d2cbbd468a835ae5b2f20e4f959f56ab24cd6fe267", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abcdef0123456789"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "d2ecef3635d2397f34a9f86438d772db19ffe9924e28a1ca\ - f6f1c8f15603d4028f40891044e5c7e39ebb9b31339979ff33a424\ - 9206f67d4a1e7c765410bcd249ad78d407e303675918f20f26ce6d\ - 7027ed3774512ef5b00d816e51bfcc96c3539601fa48ef1c07e494\ - bdc37054ba96ecb9dbd666417e3de289d4f424f502a982", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqq"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "ed6e8c036df90111410431431a232d41a32c86e296c05d42\ - 6e5f44e75b9a50d335b2412bc6c91e0a6dc131de09c43110d9180d\ - 0a70f0d6289cb4e43b05f7ee5e9b3f42a1fad0f31bac6a625b3b5c\ - 50e3a83316783b649e5ecc9d3b1d9471cb5024b7ccf40d41d1751a\ - 04ca0356548bc6e703fca02ab521b505e8e45600508d32", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "78b53f2413f3c688f07732c10e5ced29a17c6a16f717179f\ - fbe38d92d6c9ec296502eb9889af83a1928cd162e845b0d3c5424e\ - 83280fed3d10cffb2f8431f14e7a23f4c68819d40617589e4c4116\ - 9d0b56e0e3535be1fd71fbb08bb70c5b5ffed953d6c14bf7618b35\ - fc1f4c4b30538236b4b08c9fbf90462447a8ada60be495", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - } - - /// From - #[test] - fn expand_message_xmd_works_for_draft12_testvectors_sha512() { - let dst = b"QUUX-V01-CS02-with-expander-SHA512-256"; - - let msg = b""; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "6b9a7312411d92f921c6f68ca0b6380730a1a4d982c50721\ - 1a90964c394179ba", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abc"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "0da749f12fbe5483eb066a5f595055679b976e93abe9be6f\ - 0f6318bce7aca8dc", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abcdef0123456789"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "087e45a86e2939ee8b91100af1583c4938e0f5fc6c9db4b1\ - 07b83346bc967f58", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqq"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "7336234ee9983902440f6bc35b348352013becd88938d2af\ - ec44311caf8356b3", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "57b5f7e766d5be68a6bfe1768e3c2b7f1228b3e4b3134956\ - dd73a59b954c66f4", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b""; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "41b037d1734a5f8df225dd8c7de38f851efdb45c372887be\ - 655212d07251b921b052b62eaed99b46f72f2ef4cc96bfaf254ebb\ - bec091e1a3b9e4fb5e5b619d2e0c5414800a1d882b62bb5cd1778f\ - 098b8eb6cb399d5d9d18f5d5842cf5d13d7eb00a7cff859b605da6\ - 78b318bd0e65ebff70bec88c753b159a805d2c89c55961", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abc"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "7f1dddd13c08b543f2e2037b14cefb255b44c83cc397c178\ - 6d975653e36a6b11bdd7732d8b38adb4a0edc26a0cef4bb4521713\ - 5456e58fbca1703cd6032cb1347ee720b87972d63fbf232587043e\ - d2901bce7f22610c0419751c065922b488431851041310ad659e4b\ - 23520e1772ab29dcdeb2002222a363f0c2b1c972b3efe1", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abcdef0123456789"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "3f721f208e6199fe903545abc26c837ce59ac6fa45733f1b\ - aaf0222f8b7acb0424814fcb5eecf6c1d38f06e9d0a6ccfbf85ae6\ - 12ab8735dfdf9ce84c372a77c8f9e1c1e952c3a61b7567dd069301\ - 6af51d2745822663d0c2367e3f4f0bed827feecc2aaf98c949b5ed\ - 0d35c3f1023d64ad1407924288d366ea159f46287e61ac", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqq"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "b799b045a58c8d2b4334cf54b78260b45eec544f9f2fb5bd\ - 12fb603eaee70db7317bf807c406e26373922b7b8920fa29142703\ - dd52bdf280084fb7ef69da78afdf80b3586395b433dc66cde048a2\ - 58e476a561e9deba7060af40adf30c64249ca7ddea79806ee5beb9\ - a1422949471d267b21bc88e688e4014087a0b592b695ed", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "05b0bfef265dcee87654372777b7c44177e2ae4c13a27f10\ - 3340d9cd11c86cb2426ffcad5bd964080c2aee97f03be1ca18e30a\ - 1f14e27bc11ebbd650f305269cc9fb1db08bf90bfc79b42a952b46\ - daf810359e7bc36452684784a64952c343c52e5124cd1f71d474d5\ - 197fefc571a92929c9084ffe1112cf5eea5192ebff330b", - ) - .unwrap(); - assert_eq!( - ExpandMsgXmd::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - } - - /// From - #[test] - fn expand_message_xof_works_for_draft12_testvectors_shake128() { - let dst = b"QUUX-V01-CS02-with-expander-SHAKE128"; - - let msg = b""; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "86518c9cd86581486e9485aa74ab35ba150d1c75c88e26b7\ - 043e44e2acd735a2", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abc"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "8696af52a4d862417c0763556073f47bc9b9ba43c99b5053\ - 05cb1ec04a9ab468", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abcdef0123456789"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "912c58deac4821c3509dbefa094df54b34b8f5d01a191d1d\ - 3108a2c89077acca", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqq"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "1adbcc448aef2a0cebc71dac9f756b22e51839d348e031e6\ - 3b33ebb50faeaf3f", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "df3447cc5f3e9a77da10f819218ddf31342c310778e0e4ef\ - 72bbaecee786a4fe", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b""; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "7314ff1a155a2fb99a0171dc71b89ab6e3b2b7d59e38e644\ - 19b8b6294d03ffee42491f11370261f436220ef787f8f76f5b26bd\ - cd850071920ce023f3ac46847744f4612b8714db8f5db83205b2e6\ - 25d95afd7d7b4d3094d3bdde815f52850bb41ead9822e08f22cf41\ - d615a303b0d9dde73263c049a7b9898208003a739a2e57", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abc"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "c952f0c8e529ca8824acc6a4cab0e782fc3648c563ddb00d\ - a7399f2ae35654f4860ec671db2356ba7baa55a34a9d7f79197b60\ - ddae6e64768a37d699a78323496db3878c8d64d909d0f8a7de4927\ - dcab0d3dbbc26cb20a49eceb0530b431cdf47bc8c0fa3e0d88f53b\ - 318b6739fbed7d7634974f1b5c386d6230c76260d5337a", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abcdef0123456789"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "19b65ee7afec6ac06a144f2d6134f08eeec185f1a890fe34\ - e68f0e377b7d0312883c048d9b8a1d6ecc3b541cb4987c26f45e0c\ - 82691ea299b5e6889bbfe589153016d8131717ba26f07c3c14ffbe\ - f1f3eff9752e5b6183f43871a78219a75e7000fbac6a7072e2b83c\ - 790a3a5aecd9d14be79f9fd4fb180960a3772e08680495", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqq"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "ca1b56861482b16eae0f4a26212112362fcc2d76dcc80c93\ - c4182ed66c5113fe41733ed68be2942a3487394317f3379856f482\ - 2a611735e50528a60e7ade8ec8c71670fec6661e2c59a09ed36386\ - 513221688b35dc47e3c3111ee8c67ff49579089d661caa29db1ef1\ - 0eb6eace575bf3dc9806e7c4016bd50f3c0e2a6481ee6d", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "9d763a5ce58f65c91531b4100c7266d479a5d9777ba76169\ - 3d052acd37d149e7ac91c796a10b919cd74a591a1e38719fb91b72\ - 03e2af31eac3bff7ead2c195af7d88b8bc0a8adf3d1e90ab9bed6d\ - dc2b7f655dd86c730bdeaea884e73741097142c92f0e3fc1811b69\ - 9ba593c7fbd81da288a29d423df831652e3a01a9374999", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - } - - /// From - #[test] - fn expand_message_xof_works_for_draft12_testvectors_shake128_long_dst() { - let dst = b"QUUX-V01-CS02-with-expander-SHAKE128-long-DST-11111111\ - 111111111111111111111111111111111111111111111111111111\ - 111111111111111111111111111111111111111111111111111111\ - 111111111111111111111111111111111111111111111111111111\ - 1111111111111111111111111111111111111111"; - - let msg = b""; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "827c6216330a122352312bccc0c8d6e7a146c5257a776dbd\ - 9ad9d75cd880fc53", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abc"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "690c8d82c7213b4282c6cb41c00e31ea1d3e2005f93ad19b\ - bf6da40f15790c5c", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abcdef0123456789"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "979e3a15064afbbcf99f62cc09fa9c85028afcf3f825eb07\ - 11894dcfc2f57057", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqq"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "c5a9220962d9edc212c063f4f65b609755a1ed96e62f9db5\ - d1fd6adb5a8dc52b", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "f7b96a5901af5d78ce1d071d9c383cac66a1dfadb508300e\ - c6aeaea0d62d5d62", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b""; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "3890dbab00a2830be398524b71c2713bbef5f4884ac2e6f0\ - 70b092effdb19208c7df943dc5dcbaee3094a78c267ef276632ee2\ - c8ea0c05363c94b6348500fae4208345dd3475fe0c834c2beac7fa\ - 7bc181692fb728c0a53d809fc8111495222ce0f38468b11becb15b\ - 32060218e285c57a60162c2c8bb5b6bded13973cd41819", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abc"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "41b7ffa7a301b5c1441495ebb9774e2a53dbbf4e54b9a1af\ - 6a20fd41eafd69ef7b9418599c5545b1ee422f363642b01d4a5344\ - 9313f68da3e49dddb9cd25b97465170537d45dcbdf92391b5bdff3\ - 44db4bd06311a05bca7dcd360b6caec849c299133e5c9194f4e15e\ - 3e23cfaab4003fab776f6ac0bfae9144c6e2e1c62e7d57", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abcdef0123456789"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "55317e4a21318472cd2290c3082957e1242241d9e0d04f47\ - 026f03401643131401071f01aa03038b2783e795bdfa8a3541c194\ - ad5de7cb9c225133e24af6c86e748deb52e560569bd54ef4dac034\ - 65111a3a44b0ea490fb36777ff8ea9f1a8a3e8e0de3cf0880b4b2f\ - 8dd37d3a85a8b82375aee4fa0e909f9763319b55778e71", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqq"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "19fdd2639f082e31c77717ac9bb032a22ff0958382b2dbb3\ - 9020cdc78f0da43305414806abf9a561cb2d0067eb2f7bc544482f\ - 75623438ed4b4e39dd9e6e2909dd858bd8f1d57cd0fce2d3150d90\ - aa67b4498bdf2df98c0100dd1a173436ba5d0df6be1defb0b2ce55\ - ccd2f4fc05eb7cb2c019c35d5398b85adc676da4238bc7", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "945373f0b3431a103333ba6a0a34f1efab2702efde41754c\ - 4cb1d5216d5b0a92a67458d968562bde7fa6310a83f53dda138368\ - 0a276a283438d58ceebfa7ab7ba72499d4a3eddc860595f63c93b1\ - c5e823ea41fc490d938398a26db28f61857698553e93f0574eb8c5\ - 017bfed6249491f9976aaa8d23d9485339cc85ca329308", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - } - - /// From - #[test] - fn expand_message_xof_works_for_draft12_testvectors_shake256() { - let dst = b"QUUX-V01-CS02-with-expander-SHAKE256"; - - let msg = b""; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "2ffc05c48ed32b95d72e807f6eab9f7530dd1c2f013914c8\ - fed38c5ccc15ad76", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abc"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "b39e493867e2767216792abce1f2676c197c0692aed06156\ - 0ead251821808e07", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abcdef0123456789"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "245389cf44a13f0e70af8665fe5337ec2dcd138890bb7901\ - c4ad9cfceb054b65", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqq"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "719b3911821e6428a5ed9b8e600f2866bcf23c8f0515e52d\ - 6c6c019a03f16f0e", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - let len_in_bytes = 0x20; - let uniform_bytes = hex::decode( - "9181ead5220b1963f1b5951f35547a5ea86a820562287d6c\ - a4723633d17ccbbc", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b""; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "7a1361d2d7d82d79e035b8880c5a3c86c5afa719478c007d\ - 96e6c88737a3f631dd74a2c88df79a4cb5e5d9f7504957c70d669e\ - c6bfedc31e01e2bacc4ff3fdf9b6a00b17cc18d9d72ace7d6b81c2\ - e481b4f73f34f9a7505dccbe8f5485f3d20c5409b0310093d5d649\ - 2dea4e18aa6979c23c8ea5de01582e9689612afbb353df", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abc"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "a54303e6b172909783353ab05ef08dd435a558c3197db0c1\ - 32134649708e0b9b4e34fb99b92a9e9e28fc1f1d8860d85897a8e0\ - 21e6382f3eea10577f968ff6df6c45fe624ce65ca25932f679a42a\ - 404bc3681efe03fcd45ef73bb3a8f79ba784f80f55ea8a3c367408\ - f30381299617f50c8cf8fbb21d0f1e1d70b0131a7b6fbe", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"abcdef0123456789"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "e42e4d9538a189316e3154b821c1bafb390f78b2f010ea40\ - 4e6ac063deb8c0852fcd412e098e231e43427bd2be1330bb47b403\ - 9ad57b30ae1fc94e34993b162ff4d695e42d59d9777ea18d3848d9\ - d336c25d2acb93adcad009bcfb9cde12286df267ada283063de0bb\ - 1505565b2eb6c90e31c48798ecdc71a71756a9110ff373", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqq"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "4ac054dda0a38a65d0ecf7afd3c2812300027c8789655e47\ - aecf1ecc1a2426b17444c7482c99e5907afd9c25b991990490bb9c\ - 686f43e79b4471a23a703d4b02f23c669737a886a7ec28bddb92c3\ - a98de63ebf878aa363a501a60055c048bea11840c4717beae7eee2\ - 8c3cfa42857b3d130188571943a7bd747de831bd6444e0", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - - let msg = b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - let len_in_bytes = 0x80; - let uniform_bytes = hex::decode( - "09afc76d51c2cccbc129c2315df66c2be7295a231203b8ab\ - 2dd7f95c2772c68e500bc72e20c602abc9964663b7a03a389be128\ - c56971ce81001a0b875e7fd17822db9d69792ddf6a23a151bf4700\ - 79c518279aef3e75611f8f828994a9988f4a8a256ddb8bae161e65\ - 8d5a2a09bcfe839c6396dc06ee5c8ff3c22d3b1f9deb7e", - ) - .unwrap(); - assert_eq!( - ExpandMsgXof::::init_expand(msg, dst, len_in_bytes).into_vec(), - uniform_bytes - ); - } -} diff --git a/src/hash_to_curve/map_g1.rs b/src/hash_to_curve/map_g1.rs deleted file mode 100644 index 0f2c94e6..00000000 --- a/src/hash_to_curve/map_g1.rs +++ /dev/null @@ -1,961 +0,0 @@ -//! Implementation of hash-to-curve for the G1 group. - -use subtle::{Choice, ConditionallyNegatable, ConditionallySelectable, ConstantTimeEq}; - -use super::chain::chain_pm3div4; -use super::{HashToField, MapToCurve, Sgn0}; -use crate::fp::Fp; -use crate::g1::G1Projective; -use crate::generic_array::{typenum::U64, GenericArray}; - -/// Coefficients of the 11-isogeny x map's numerator -const ISO11_XNUM: [Fp; 12] = [ - Fp::from_raw_unchecked([ - 0x4d18_b6f3_af00_131c, - 0x19fa_2197_93fe_e28c, - 0x3f28_85f1_467f_19ae, - 0x23dc_ea34_f2ff_b304, - 0xd15b_58d2_ffc0_0054, - 0x0913_be20_0a20_bef4, - ]), - Fp::from_raw_unchecked([ - 0x8989_8538_5cdb_bd8b, - 0x3c79_e43c_c7d9_66aa, - 0x1597_e193_f4cd_233a, - 0x8637_ef1e_4d66_23ad, - 0x11b2_2dee_d20d_827b, - 0x0709_7bc5_9987_84ad, - ]), - Fp::from_raw_unchecked([ - 0xa542_583a_480b_664b, - 0xfc71_69c0_26e5_68c6, - 0x5ba2_ef31_4ed8_b5a6, - 0x5b54_91c0_5102_f0e7, - 0xdf6e_9970_7d2a_0079, - 0x0784_151e_d760_5524, - ]), - Fp::from_raw_unchecked([ - 0x494e_2128_70f7_2741, - 0xab9b_e52f_bda4_3021, - 0x26f5_5779_94e3_4c3d, - 0x049d_fee8_2aef_bd60, - 0x65da_dd78_2850_5289, - 0x0e93_d431_ea01_1aeb, - ]), - Fp::from_raw_unchecked([ - 0x90ee_774b_d6a7_4d45, - 0x7ada_1c8a_41bf_b185, - 0x0f1a_8953_b325_f464, - 0x104c_2421_1be4_805c, - 0x1691_39d3_19ea_7a8f, - 0x09f2_0ead_8e53_2bf6, - ]), - Fp::from_raw_unchecked([ - 0x6ddd_93e2_f436_26b7, - 0xa548_2c9a_a1cc_d7bd, - 0x1432_4563_1883_f4bd, - 0x2e0a_94cc_f77e_c0db, - 0xb028_2d48_0e56_489f, - 0x18f4_bfcb_b436_8929, - ]), - Fp::from_raw_unchecked([ - 0x23c5_f0c9_5340_2dfd, - 0x7a43_ff69_58ce_4fe9, - 0x2c39_0d3d_2da5_df63, - 0xd0df_5c98_e1f9_d70f, - 0xffd8_9869_a572_b297, - 0x1277_ffc7_2f25_e8fe, - ]), - Fp::from_raw_unchecked([ - 0x79f4_f049_0f06_a8a6, - 0x85f8_94a8_8030_fd81, - 0x12da_3054_b18b_6410, - 0xe2a5_7f65_0588_0d65, - 0xbba0_74f2_60e4_00f1, - 0x08b7_6279_f621_d028, - ]), - Fp::from_raw_unchecked([ - 0xe672_45ba_78d5_b00b, - 0x8456_ba9a_1f18_6475, - 0x7888_bff6_e6b3_3bb4, - 0xe215_85b9_a30f_86cb, - 0x05a6_9cdc_ef55_feee, - 0x09e6_99dd_9adf_a5ac, - ]), - Fp::from_raw_unchecked([ - 0x0de5_c357_bff5_7107, - 0x0a0d_b4ae_6b1a_10b2, - 0xe256_bb67_b3b3_cd8d, - 0x8ad4_5657_4e9d_b24f, - 0x0443_915f_50fd_4179, - 0x098c_4bf7_de8b_6375, - ]), - Fp::from_raw_unchecked([ - 0xe6b0_617e_7dd9_29c7, - 0xfe6e_37d4_4253_7375, - 0x1daf_deda_137a_489e, - 0xe4ef_d1ad_3f76_7ceb, - 0x4a51_d866_7f0f_e1cf, - 0x054f_df4b_bf1d_821c, - ]), - Fp::from_raw_unchecked([ - 0x72db_2a50_658d_767b, - 0x8abf_91fa_a257_b3d5, - 0xe969_d683_3764_ab47, - 0x4641_7014_2a10_09eb, - 0xb14f_01aa_db30_be2f, - 0x18ae_6a85_6f40_715d, - ]), -]; - -/// Coefficients of the 11-isogeny x map's denominator -const ISO11_XDEN: [Fp; 11] = [ - Fp::from_raw_unchecked([ - 0xb962_a077_fdb0_f945, - 0xa6a9_740f_efda_13a0, - 0xc14d_568c_3ed6_c544, - 0xb43f_c37b_908b_133e, - 0x9c0b_3ac9_2959_9016, - 0x0165_aa6c_93ad_115f, - ]), - Fp::from_raw_unchecked([ - 0x2327_9a3b_a506_c1d9, - 0x92cf_ca0a_9465_176a, - 0x3b29_4ab1_3755_f0ff, - 0x116d_da1c_5070_ae93, - 0xed45_3092_4cec_2045, - 0x0833_83d6_ed81_f1ce, - ]), - Fp::from_raw_unchecked([ - 0x9885_c2a6_449f_ecfc, - 0x4a2b_54cc_d377_33f0, - 0x17da_9ffd_8738_c142, - 0xa0fb_a727_32b3_fafd, - 0xff36_4f36_e54b_6812, - 0x0f29_c13c_6605_23e2, - ]), - Fp::from_raw_unchecked([ - 0xe349_cc11_8278_f041, - 0xd487_228f_2f32_04fb, - 0xc9d3_2584_9ade_5150, - 0x43a9_2bd6_9c15_c2df, - 0x1c2c_7844_bc41_7be4, - 0x1202_5184_f407_440c, - ]), - Fp::from_raw_unchecked([ - 0x587f_65ae_6acb_057b, - 0x1444_ef32_5140_201f, - 0xfbf9_95e7_1270_da49, - 0xccda_0660_7243_6a42, - 0x7408_904f_0f18_6bb2, - 0x13b9_3c63_edf6_c015, - ]), - Fp::from_raw_unchecked([ - 0xfb91_8622_cd14_1920, - 0x4a4c_6442_3eca_ddb4, - 0x0beb_2329_27f7_fb26, - 0x30f9_4df6_f83a_3dc2, - 0xaeed_d424_d780_f388, - 0x06cc_402d_d594_bbeb, - ]), - Fp::from_raw_unchecked([ - 0xd41f_7611_51b2_3f8f, - 0x32a9_2465_4357_19b3, - 0x64f4_36e8_88c6_2cb9, - 0xdf70_a9a1_f757_c6e4, - 0x6933_a38d_5b59_4c81, - 0x0c6f_7f72_37b4_6606, - ]), - Fp::from_raw_unchecked([ - 0x693c_0874_7876_c8f7, - 0x22c9_850b_f9cf_80f0, - 0x8e90_71da_b950_c124, - 0x89bc_62d6_1c7b_af23, - 0xbc6b_e2d8_dad5_7c23, - 0x1791_6987_aa14_a122, - ]), - Fp::from_raw_unchecked([ - 0x1be3_ff43_9c13_16fd, - 0x9965_243a_7571_dfa7, - 0xc7f7_f629_62f5_cd81, - 0x32c6_aa9a_f394_361c, - 0xbbc2_ee18_e1c2_27f4, - 0x0c10_2cba_c531_bb34, - ]), - Fp::from_raw_unchecked([ - 0x9976_14c9_7bac_bf07, - 0x61f8_6372_b991_92c0, - 0x5b8c_95fc_1435_3fc3, - 0xca2b_066c_2a87_492f, - 0x1617_8f5b_bf69_8711, - 0x12a6_dcd7_f0f4_e0e8, - ]), - Fp::from_raw_unchecked([ - 0x7609_0000_0002_fffd, - 0xebf4_000b_c40c_0002, - 0x5f48_9857_53c7_58ba, - 0x77ce_5853_7052_5745, - 0x5c07_1a97_a256_ec6d, - 0x15f6_5ec3_fa80_e493, - ]), -]; - -/// Coefficients of the 11-isogeny y map's numerator -const ISO11_YNUM: [Fp; 16] = [ - Fp::from_raw_unchecked([ - 0x2b56_7ff3_e283_7267, - 0x1d4d_9e57_b958_a767, - 0xce02_8fea_04bd_7373, - 0xcc31_a30a_0b6c_d3df, - 0x7d7b_18a6_8269_2693, - 0x0d30_0744_d42a_0310, - ]), - Fp::from_raw_unchecked([ - 0x99c2_555f_a542_493f, - 0xfe7f_53cc_4874_f878, - 0x5df0_608b_8f97_608a, - 0x14e0_3832_052b_49c8, - 0x7063_26a6_957d_d5a4, - 0x0a8d_add9_c241_4555, - ]), - Fp::from_raw_unchecked([ - 0x13d9_4292_2a5c_f63a, - 0x357e_33e3_6e26_1e7d, - 0xcf05_a27c_8456_088d, - 0x0000_bd1d_e7ba_50f0, - 0x83d0_c753_2f8c_1fde, - 0x13f7_0bf3_8bbf_2905, - ]), - Fp::from_raw_unchecked([ - 0x5c57_fd95_bfaf_bdbb, - 0x28a3_59a6_5e54_1707, - 0x3983_ceb4_f636_0b6d, - 0xafe1_9ff6_f97e_6d53, - 0xb346_8f45_5019_2bf7, - 0x0bb6_cde4_9d8b_a257, - ]), - Fp::from_raw_unchecked([ - 0x590b_62c7_ff8a_513f, - 0x314b_4ce3_72ca_cefd, - 0x6bef_32ce_94b8_a800, - 0x6ddf_84a0_9571_3d5f, - 0x64ea_ce4c_b098_2191, - 0x0386_213c_651b_888d, - ]), - Fp::from_raw_unchecked([ - 0xa531_0a31_111b_bcdd, - 0xa14a_c0f5_da14_8982, - 0xf9ad_9cc9_5423_d2e9, - 0xaa6e_c095_283e_e4a7, - 0xcf5b_1f02_2e1c_9107, - 0x01fd_df5a_ed88_1793, - ]), - Fp::from_raw_unchecked([ - 0x65a5_72b0_d7a7_d950, - 0xe25c_2d81_8347_3a19, - 0xc2fc_ebe7_cb87_7dbd, - 0x05b2_d36c_769a_89b0, - 0xba12_961b_e86e_9efb, - 0x07eb_1b29_c1df_de1f, - ]), - Fp::from_raw_unchecked([ - 0x93e0_9572_f7c4_cd24, - 0x364e_9290_7679_5091, - 0x8569_467e_68af_51b5, - 0xa47d_a894_39f5_340f, - 0xf4fa_9180_82e4_4d64, - 0x0ad5_2ba3_e669_5a79, - ]), - Fp::from_raw_unchecked([ - 0x9114_2984_4e0d_5f54, - 0xd03f_51a3_516b_b233, - 0x3d58_7e56_4053_6e66, - 0xfa86_d2a3_a9a7_3482, - 0xa90e_d5ad_f1ed_5537, - 0x149c_9c32_6a5e_7393, - ]), - Fp::from_raw_unchecked([ - 0x462b_beb0_3c12_921a, - 0xdc9a_f5fa_0a27_4a17, - 0x9a55_8ebd_e836_ebed, - 0x649e_f8f1_1a4f_ae46, - 0x8100_e165_2b3c_dc62, - 0x1862_bd62_c291_dacb, - ]), - Fp::from_raw_unchecked([ - 0x05c9_b8ca_89f1_2c26, - 0x0194_160f_a9b9_ac4f, - 0x6a64_3d5a_6879_fa2c, - 0x1466_5bdd_8846_e19d, - 0xbb1d_0d53_af3f_f6bf, - 0x12c7_e1c3_b289_62e5, - ]), - Fp::from_raw_unchecked([ - 0xb55e_bf90_0b8a_3e17, - 0xfedc_77ec_1a92_01c4, - 0x1f07_db10_ea1a_4df4, - 0x0dfb_d15d_c41a_594d, - 0x3895_47f2_334a_5391, - 0x0241_9f98_1658_71a4, - ]), - Fp::from_raw_unchecked([ - 0xb416_af00_0745_fc20, - 0x8e56_3e9d_1ea6_d0f5, - 0x7c76_3e17_763a_0652, - 0x0145_8ef0_159e_bbef, - 0x8346_fe42_1f96_bb13, - 0x0d2d_7b82_9ce3_24d2, - ]), - Fp::from_raw_unchecked([ - 0x9309_6bb5_38d6_4615, - 0x6f2a_2619_951d_823a, - 0x8f66_b3ea_5951_4fa4, - 0xf563_e637_04f7_092f, - 0x724b_136c_4cf2_d9fa, - 0x0469_59cf_cfd0_bf49, - ]), - Fp::from_raw_unchecked([ - 0xea74_8d4b_6e40_5346, - 0x91e9_079c_2c02_d58f, - 0x4106_4965_946d_9b59, - 0xa067_31f1_d2bb_e1ee, - 0x07f8_97e2_67a3_3f1b, - 0x1017_2909_1921_0e5f, - ]), - Fp::from_raw_unchecked([ - 0x872a_a6c1_7d98_5097, - 0xeecc_5316_1264_562a, - 0x07af_e37a_fff5_5002, - 0x5475_9078_e5be_6838, - 0xc4b9_2d15_db8a_cca8, - 0x106d_87d1_b51d_13b9, - ]), -]; - -/// Coefficients of the 11-isogeny y map's denominator -const ISO11_YDEN: [Fp; 16] = [ - Fp::from_raw_unchecked([ - 0xeb6c_359d_47e5_2b1c, - 0x18ef_5f8a_1063_4d60, - 0xddfa_71a0_889d_5b7e, - 0x723e_71dc_c5fc_1323, - 0x52f4_5700_b70d_5c69, - 0x0a8b_981e_e476_91f1, - ]), - Fp::from_raw_unchecked([ - 0x616a_3c4f_5535_b9fb, - 0x6f5f_0373_95db_d911, - 0xf25f_4cc5_e35c_65da, - 0x3e50_dffe_a3c6_2658, - 0x6a33_dca5_2356_0776, - 0x0fad_eff7_7b6b_fe3e, - ]), - Fp::from_raw_unchecked([ - 0x2be9_b66d_f470_059c, - 0x24a2_c159_a3d3_6742, - 0x115d_be7a_d10c_2a37, - 0xb663_4a65_2ee5_884d, - 0x04fe_8bb2_b8d8_1af4, - 0x01c2_a7a2_56fe_9c41, - ]), - Fp::from_raw_unchecked([ - 0xf27b_f8ef_3b75_a386, - 0x898b_3674_76c9_073f, - 0x2448_2e6b_8c2f_4e5f, - 0xc8e0_bbd6_fe11_0806, - 0x59b0_c17f_7631_448a, - 0x1103_7cd5_8b3d_bfbd, - ]), - Fp::from_raw_unchecked([ - 0x31c7_912e_a267_eec6, - 0x1dbf_6f1c_5fcd_b700, - 0xd30d_4fe3_ba86_fdb1, - 0x3cae_528f_bee9_a2a4, - 0xb1cc_e69b_6aa9_ad9a, - 0x0443_93bb_632d_94fb, - ]), - Fp::from_raw_unchecked([ - 0xc66e_f6ef_eeb5_c7e8, - 0x9824_c289_dd72_bb55, - 0x71b1_a4d2_f119_981d, - 0x104f_c1aa_fb09_19cc, - 0x0e49_df01_d942_a628, - 0x096c_3a09_7732_72d4, - ]), - Fp::from_raw_unchecked([ - 0x9abc_11eb_5fad_eff4, - 0x32dc_a50a_8857_28f0, - 0xfb1f_a372_1569_734c, - 0xc4b7_6271_ea65_06b3, - 0xd466_a755_99ce_728e, - 0x0c81_d464_5f4c_b6ed, - ]), - Fp::from_raw_unchecked([ - 0x4199_f10e_5b8b_e45b, - 0xda64_e495_b1e8_7930, - 0xcb35_3efe_9b33_e4ff, - 0x9e9e_fb24_aa64_24c6, - 0xf08d_3368_0a23_7465, - 0x0d33_7802_3e4c_7406, - ]), - Fp::from_raw_unchecked([ - 0x7eb4_ae92_ec74_d3a5, - 0xc341_b4aa_9fac_3497, - 0x5be6_0389_9e90_7687, - 0x03bf_d9cc_a75c_bdeb, - 0x564c_2935_a96b_fa93, - 0x0ef3_c333_71e2_fdb5, - ]), - Fp::from_raw_unchecked([ - 0x7ee9_1fd4_49f6_ac2e, - 0xe5d5_bd5c_b935_7a30, - 0x773a_8ca5_196b_1380, - 0xd0fd_a172_174e_d023, - 0x6cb9_5e0f_a776_aead, - 0x0d22_d5a4_0cec_7cff, - ]), - Fp::from_raw_unchecked([ - 0xf727_e092_85fd_8519, - 0xdc9d_55a8_3017_897b, - 0x7549_d8bd_0578_94ae, - 0x1784_1961_3d90_d8f8, - 0xfce9_5ebd_eb5b_490a, - 0x0467_ffae_f23f_c49e, - ]), - Fp::from_raw_unchecked([ - 0xc176_9e6a_7c38_5f1b, - 0x79bc_930d_eac0_1c03, - 0x5461_c75a_23ed_e3b5, - 0x6e20_829e_5c23_0c45, - 0x828e_0f1e_772a_53cd, - 0x116a_efa7_4912_7bff, - ]), - Fp::from_raw_unchecked([ - 0x101c_10bf_2744_c10a, - 0xbbf1_8d05_3a6a_3154, - 0xa0ec_f39e_f026_f602, - 0xfc00_9d49_96dc_5153, - 0xb900_0209_d5bd_08d3, - 0x189e_5fe4_470c_d73c, - ]), - Fp::from_raw_unchecked([ - 0x7ebd_546c_a157_5ed2, - 0xe47d_5a98_1d08_1b55, - 0x57b2_b625_b6d4_ca21, - 0xb0a1_ba04_2285_20cc, - 0x9873_8983_c210_7ff3, - 0x13dd_dbc4_799d_81d6, - ]), - Fp::from_raw_unchecked([ - 0x0931_9f2e_3983_4935, - 0x039e_952c_bdb0_5c21, - 0x55ba_77a9_a2f7_6493, - 0xfd04_e3df_c608_6467, - 0xfb95_832e_7d78_742e, - 0x0ef9_c24e_ccaf_5e0e, - ]), - Fp::from_raw_unchecked([ - 0x7609_0000_0002_fffd, - 0xebf4_000b_c40c_0002, - 0x5f48_9857_53c7_58ba, - 0x77ce_5853_7052_5745, - 0x5c07_1a97_a256_ec6d, - 0x15f6_5ec3_fa80_e493, - ]), -]; - -const SSWU_ELLP_A: Fp = Fp::from_raw_unchecked([ - 0x2f65_aa0e_9af5_aa51, - 0x8646_4c2d_1e84_16c3, - 0xb85c_e591_b7bd_31e2, - 0x27e1_1c91_b5f2_4e7c, - 0x2837_6eda_6bfc_1835, - 0x1554_55c3_e507_1d85, -]); - -const SSWU_ELLP_B: Fp = Fp::from_raw_unchecked([ - 0xfb99_6971_fe22_a1e0, - 0x9aa9_3eb3_5b74_2d6f, - 0x8c47_6013_de99_c5c4, - 0x873e_27c3_a221_e571, - 0xca72_b5e4_5a52_d888, - 0x0682_4061_418a_386b, -]); - -const SSWU_XI: Fp = Fp::from_raw_unchecked([ - 0x886c_0000_0023_ffdc, - 0x0f70_008d_3090_001d, - 0x7767_2417_ed58_28c3, - 0x9dac_23e9_43dc_1740, - 0x5055_3f1b_9c13_1521, - 0x078c_712f_be0a_b6e8, -]); - -const SQRT_M_XI_CUBED: Fp = Fp::from_raw_unchecked([ - 0x43b5_71ca_d321_5f1f, - 0xccb4_60ef_1c70_2dc2, - 0x742d_884f_4f97_100b, - 0xdb2c_3e32_38a3_382b, - 0xe40f_3fa1_3fce_8f88, - 0x0073_a2af_9892_a2ff, -]); - -impl HashToField for Fp { - // ceil(log2(p)) = 381, m = 1, k = 128. - type InputLength = U64; - - fn from_okm(okm: &GenericArray) -> Fp { - const F_2_256: Fp = Fp::from_raw_unchecked([ - 0x075b_3cd7_c5ce_820f, - 0x3ec6_ba62_1c3e_db0b, - 0x168a_13d8_2bff_6bce, - 0x8766_3c4b_f8c4_49d2, - 0x15f3_4c83_ddc8_d830, - 0x0f96_28b4_9caa_2e85, - ]); - - let mut bs = [0u8; 48]; - bs[16..].copy_from_slice(&okm[..32]); - let db = Fp::from_bytes(&bs).unwrap(); - - bs[16..].copy_from_slice(&okm[32..]); - let da = Fp::from_bytes(&bs).unwrap(); - - db * F_2_256 + da - } -} - -impl Sgn0 for Fp { - fn sgn0(&self) -> Choice { - // Turn into canonical form by computing - // (a.R) / R = a - let tmp = Fp::montgomery_reduce( - self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], 0, 0, 0, 0, 0, 0, - ); - Choice::from((tmp.0[0] & 1) as u8) - } -} - -/// Maps an element of [`Fp`] to a point on iso-G1. -/// -/// Implements [section 6.6.2 of `draft-irtf-cfrg-hash-to-curve-12`][sswu]. -/// -/// [sswu]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-12#section-6.6.2 -fn map_to_curve_simple_swu(u: &Fp) -> G1Projective { - let usq = u.square(); - let xi_usq = SSWU_XI * usq; - let xisq_u4 = xi_usq.square(); - let nd_common = xisq_u4 + xi_usq; // XI^2 * u^4 + XI * u^2 - let x_den = SSWU_ELLP_A * Fp::conditional_select(&(-nd_common), &SSWU_XI, nd_common.is_zero()); - let x0_num = SSWU_ELLP_B * (Fp::one() + nd_common); // B * (1 + (XI^2 * u^4 + XI * u^2)) - - // compute g(x0(u)) - let x_densq = x_den.square(); - let gx_den = x_densq * x_den; - // x0_num^3 + A * x0_num * x_den^2 + B * x_den^3 - let gx0_num = (x0_num.square() + SSWU_ELLP_A * x_densq) * x0_num + SSWU_ELLP_B * gx_den; - - // compute g(X0(u)) ^ ((p - 3) // 4) - let sqrt_candidate = { - let u_v = gx0_num * gx_den; // u*v - let vsq = gx_den.square(); // v^2 - u_v * chain_pm3div4(&(u_v * vsq)) // u v (u v^3) ^ ((p - 3) // 4) - }; - - let gx0_square = (sqrt_candidate.square() * gx_den).ct_eq(&gx0_num); // g(x0) is square - let x1_num = x0_num * xi_usq; - // sqrt(-XI**3) * u^3 g(x0) ^ ((p - 3) // 4) - let y1 = SQRT_M_XI_CUBED * usq * u * sqrt_candidate; - - let x_num = Fp::conditional_select(&x1_num, &x0_num, gx0_square); - let mut y = Fp::conditional_select(&y1, &sqrt_candidate, gx0_square); - // ensure sign of y and sign of u agree - y.conditional_negate(y.sgn0() ^ u.sgn0()); - - G1Projective { - x: x_num, - y: y * x_den, - z: x_den, - } -} - -/// Maps an iso-G1 point to a G1 point. -fn iso_map(u: &G1Projective) -> G1Projective { - const COEFFS: [&[Fp]; 4] = [&ISO11_XNUM, &ISO11_XDEN, &ISO11_YNUM, &ISO11_YDEN]; - - // unpack input point - let G1Projective { x, y, z } = *u; - - // xnum, xden, ynum, yden - let mut mapvals = [Fp::zero(); 4]; - - // pre-compute powers of z - let zpows = { - let mut zpows = [Fp::zero(); 15]; - zpows[0] = z; - for idx in 1..zpows.len() { - zpows[idx] = zpows[idx - 1] * z; - } - zpows - }; - - // compute map value by Horner's rule - for idx in 0..4 { - let coeff = COEFFS[idx]; - let clast = coeff.len() - 1; - mapvals[idx] = coeff[clast]; - for jdx in 0..clast { - mapvals[idx] = mapvals[idx] * x + zpows[jdx] * coeff[clast - 1 - jdx]; - } - } - - // x denominator is order 1 less than x numerator, so we need an extra factor of z - mapvals[1] *= z; - - // multiply result of Y map by the y-coord, y / z - mapvals[2] *= y; - mapvals[3] *= z; - - G1Projective { - x: mapvals[0] * mapvals[3], // xnum * yden, - y: mapvals[2] * mapvals[1], // ynum * xden, - z: mapvals[1] * mapvals[3], // xden * yden - } -} - -impl MapToCurve for G1Projective { - type Field = Fp; - - fn map_to_curve(u: &Fp) -> G1Projective { - let pt = map_to_curve_simple_swu(u); - iso_map(&pt) - } - - fn clear_h(&self) -> Self { - self.clear_cofactor() - } -} - -#[cfg(test)] -fn check_g1_prime(pt: &G1Projective) -> bool { - // (X : Y : Z)==(X/Z, Y/Z) is on E': y^2 = x^3 + A * x + B. - // y^2 z = (x^3) + A (x z^2) + B z^3 - let zsq = pt.z.square(); - (pt.y.square() * pt.z) - == (pt.x.square() * pt.x + SSWU_ELLP_A * pt.x * zsq + SSWU_ELLP_B * zsq * pt.z) -} - -#[test] -fn test_simple_swu_expected() { - // exceptional case: zero - let p = map_to_curve_simple_swu(&Fp::zero()); - let G1Projective { x, y, z } = &p; - let xo = Fp::from_raw_unchecked([ - 0xfb99_6971_fe22_a1e0, - 0x9aa9_3eb3_5b74_2d6f, - 0x8c47_6013_de99_c5c4, - 0x873e_27c3_a221_e571, - 0xca72_b5e4_5a52_d888, - 0x0682_4061_418a_386b, - ]); - let yo = Fp::from_raw_unchecked([ - 0xfd6f_ced8_7a7f_11a3, - 0x9a6b_314b_03c8_db31, - 0x41f8_5416_e0ea_b593, - 0xfeeb_089f_7e6e_c4d7, - 0x85a1_34c3_7ed1_278f, - 0x0575_c525_bb9f_74bb, - ]); - let zo = Fp::from_raw_unchecked([ - 0x7f67_4ea0_a891_5178, - 0xb0f9_45fc_13b8_fa65, - 0x4b46_759a_38e8_7d76, - 0x2e7a_9296_41bb_b6a1, - 0x1668_ddfa_462b_f6b6, - 0x0096_0e2e_d1cf_294c, - ]); - assert_eq!(x, &xo); - assert_eq!(y, &yo); - assert_eq!(z, &zo); - assert!(check_g1_prime(&p)); - - // exceptional case: sqrt(-1/XI) (positive) - let excp = Fp::from_raw_unchecked([ - 0x00f3_d047_7e91_edbf, - 0x08d6_621e_4ca8_dc69, - 0xb9cf_7927_b19b_9726, - 0xba13_3c99_6caf_a2ec, - 0xed2a_5ccd_5ca7_bb68, - 0x19cb_022f_8ee9_d73b, - ]); - let p = map_to_curve_simple_swu(&excp); - let G1Projective { x, y, z } = &p; - assert_eq!(x, &xo); - assert_eq!(y, &yo); - assert_eq!(z, &zo); - assert!(check_g1_prime(&p)); - - // exceptional case: sqrt(-1/XI) (negative) - let excp = Fp::from_raw_unchecked([ - 0xb90b_2fb8_816d_bcec, - 0x15d5_9de0_64ab_2396, - 0xad61_5979_4515_5efe, - 0xaa64_0eeb_86d5_6fd2, - 0x5df1_4ae8_e6a3_f16e, - 0x0036_0fba_aa96_0f5e, - ]); - let p = map_to_curve_simple_swu(&excp); - let G1Projective { x, y, z } = &p; - let myo = -yo; - assert_eq!(x, &xo); - assert_eq!(y, &myo); - assert_eq!(z, &zo); - assert!(check_g1_prime(&p)); - - let u = Fp::from_raw_unchecked([ - 0xa618_fa19_f7e2_eadc, - 0x93c7_f1fc_876b_a245, - 0xe2ed_4cc4_7b5c_0ae0, - 0xd49e_fa74_e4a8_d000, - 0xa0b2_3ba6_92b5_431c, - 0x0d15_51f2_d7d8_d193, - ]); - let xo = Fp::from_raw_unchecked([ - 0x2197_ca55_fab3_ba48, - 0x591d_eb39_f434_949a, - 0xf9df_7fb4_f1fa_6a08, - 0x59e3_c16a_9dfa_8fa5, - 0xe592_9b19_4aad_5f7a, - 0x130a_46a4_c61b_44ed, - ]); - let yo = Fp::from_raw_unchecked([ - 0xf721_5b58_c720_0ad0, - 0x8905_1631_3a4e_66bf, - 0xc903_1acc_8a36_19a8, - 0xea1f_9978_fde3_ffec, - 0x0548_f02d_6cfb_f472, - 0x1693_7557_3529_163f, - ]); - let zo = Fp::from_raw_unchecked([ - 0xf36f_eb2e_1128_ade0, - 0x42e2_2214_250b_cd94, - 0xb94f_6ba2_dddf_62d6, - 0xf56d_4392_782b_f0a2, - 0xb2d7_ce1e_c263_09e7, - 0x182b_57ed_6b99_f0a1, - ]); - let p = map_to_curve_simple_swu(&u); - let G1Projective { x, y, z } = &p; - assert_eq!(x, &xo); - assert_eq!(y, &yo); - assert_eq!(z, &zo); - assert!(check_g1_prime(&p)); -} - -#[test] -fn test_osswu_semirandom() { - use rand_core::SeedableRng; - let mut rng = rand_xorshift::XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - for _ in 0..32 { - let input = Fp::random(&mut rng); - let p = map_to_curve_simple_swu(&input); - assert!(check_g1_prime(&p)); - - let p_iso = iso_map(&p); - assert!(bool::from(p_iso.is_on_curve())); - } -} - -// test vectors from the draft 10 RFC -#[test] -fn test_encode_to_curve_10() { - use crate::{ - g1::G1Affine, - hash_to_curve::{ExpandMsgXmd, HashToCurve}, - }; - use std::string::{String, ToString}; - - struct TestCase { - msg: &'static [u8], - expected: [&'static str; 2], - } - impl TestCase { - fn expected(&self) -> String { - self.expected[0].to_string() + self.expected[1] - } - } - - const DOMAIN: &[u8] = b"QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_NU_"; - - let cases = vec![ - TestCase { - msg: b"", - expected: [ - "184bb665c37ff561a89ec2122dd343f20e0f4cbcaec84e3c3052ea81d1834e192c426074b02ed3dca4e7676ce4ce48ba", - "04407b8d35af4dacc809927071fc0405218f1401a6d15af775810e4e460064bcc9468beeba82fdc751be70476c888bf3", - ], - }, - TestCase { - msg: b"abc", - expected: [ - "009769f3ab59bfd551d53a5f846b9984c59b97d6842b20a2c565baa167945e3d026a3755b6345df8ec7e6acb6868ae6d", - "1532c00cf61aa3d0ce3e5aa20c3b531a2abd2c770a790a2613818303c6b830ffc0ecf6c357af3317b9575c567f11cd2c", - ], - }, - TestCase { - msg: b"abcdef0123456789", - expected: [ - "1974dbb8e6b5d20b84df7e625e2fbfecb2cdb5f77d5eae5fb2955e5ce7313cae8364bc2fff520a6c25619739c6bdcb6a", - "15f9897e11c6441eaa676de141c8d83c37aab8667173cbe1dfd6de74d11861b961dccebcd9d289ac633455dfcc7013a3", - ] - }, - TestCase { - msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqq", - expected: [ - "0a7a047c4a8397b3446450642c2ac64d7239b61872c9ae7a59707a8f4f950f101e766afe58223b3bff3a19a7f754027c", - "1383aebba1e4327ccff7cf9912bda0dbc77de048b71ef8c8a81111d71dc33c5e3aa6edee9cf6f5fe525d50cc50b77cc9", - ] - }, - TestCase { - msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - expected: [ - "0e7a16a975904f131682edbb03d9560d3e48214c9986bd50417a77108d13dc957500edf96462a3d01e62dc6cd468ef11", - "0ae89e677711d05c30a48d6d75e76ca9fb70fe06c6dd6ff988683d89ccde29ac7d46c53bb97a59b1901abf1db66052db", - ] - } - ]; - - for case in cases { - let g = >>::encode_to_curve( - &case.msg, DOMAIN, - ); - let aff = G1Affine::from(g); - let g_uncompressed = aff.to_uncompressed(); - - assert_eq!(case.expected(), hex::encode(&g_uncompressed[..])); - } -} - -// test vectors from the draft 10 RFC -#[test] -fn test_hash_to_curve_10() { - use crate::{ - g1::G1Affine, - hash_to_curve::{ExpandMsgXmd, HashToCurve}, - }; - use std::string::{String, ToString}; - - struct TestCase { - msg: &'static [u8], - expected: [&'static str; 2], - } - impl TestCase { - fn expected(&self) -> String { - self.expected[0].to_string() + self.expected[1] - } - } - - const DOMAIN: &[u8] = b"QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_"; - - let cases = vec![ - TestCase { - msg: b"", - expected: [ - "052926add2207b76ca4fa57a8734416c8dc95e24501772c814278700eed6d1e4e8cf62d9c09db0fac349612b759e79a1", - "08ba738453bfed09cb546dbb0783dbb3a5f1f566ed67bb6be0e8c67e2e81a4cc68ee29813bb7994998f3eae0c9c6a265", - ], - }, - TestCase { - msg: b"abc", - expected: [ - "03567bc5ef9c690c2ab2ecdf6a96ef1c139cc0b2f284dca0a9a7943388a49a3aee664ba5379a7655d3c68900be2f6903", - "0b9c15f3fe6e5cf4211f346271d7b01c8f3b28be689c8429c85b67af215533311f0b8dfaaa154fa6b88176c229f2885d" - ], - }, - TestCase { - msg: b"abcdef0123456789", - expected: [ - "11e0b079dea29a68f0383ee94fed1b940995272407e3bb916bbf268c263ddd57a6a27200a784cbc248e84f357ce82d98", - "03a87ae2caf14e8ee52e51fa2ed8eefe80f02457004ba4d486d6aa1f517c0889501dc7413753f9599b099ebcbbd2d709" - ] - }, - TestCase { - msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqq", - expected: [ - "15f68eaa693b95ccb85215dc65fa81038d69629f70aeee0d0f677cf22285e7bf58d7cb86eefe8f2e9bc3f8cb84fac488", - "1807a1d50c29f430b8cafc4f8638dfeeadf51211e1602a5f184443076715f91bb90a48ba1e370edce6ae1062f5e6dd38" - ] - }, - TestCase { - msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - expected: [ - "082aabae8b7dedb0e78aeb619ad3bfd9277a2f77ba7fad20ef6aabdc6c31d19ba5a6d12283553294c1825c4b3ca2dcfe", - "05b84ae5a942248eea39e1d91030458c40153f3b654ab7872d779ad1e942856a20c438e8d99bc8abfbf74729ce1f7ac8" - ] - } - ]; - - for case in cases { - let g = >>::hash_to_curve( - &case.msg, DOMAIN, - ); - let g_uncompressed = G1Affine::from(g).to_uncompressed(); - - assert_eq!(case.expected(), hex::encode(&g_uncompressed[..])); - } -} - -#[cfg(test)] -// p-1 / 2 -pub const P_M1_OVER2: Fp = Fp::from_raw_unchecked([ - 0xa1fa_ffff_fffe_5557, - 0x995b_fff9_76a3_fffe, - 0x03f4_1d24_d174_ceb4, - 0xf654_7998_c199_5dbd, - 0x778a_468f_507a_6034, - 0x0205_5993_1f7f_8103, -]); - -#[test] -fn test_sgn0() { - assert_eq!(bool::from(Fp::zero().sgn0()), false); - assert_eq!(bool::from(Fp::one().sgn0()), true); - assert_eq!(bool::from((-Fp::one()).sgn0()), false); - assert_eq!(bool::from((-Fp::zero()).sgn0()), false); - assert_eq!(bool::from(P_M1_OVER2.sgn0()), true); - - let p_p1_over2 = P_M1_OVER2 + Fp::one(); - assert_eq!(bool::from(p_p1_over2.sgn0()), false); - - let neg_p_p1_over2 = { - let mut tmp = p_p1_over2; - tmp.conditional_negate(Choice::from(1u8)); - tmp - }; - assert_eq!(neg_p_p1_over2, P_M1_OVER2); -} diff --git a/src/hash_to_curve/map_g2.rs b/src/hash_to_curve/map_g2.rs deleted file mode 100644 index b2cdb956..00000000 --- a/src/hash_to_curve/map_g2.rs +++ /dev/null @@ -1,900 +0,0 @@ -//! Implementation of hash-to-curve for the G2 group - -use subtle::{Choice, ConditionallyNegatable, ConditionallySelectable, ConstantTimeEq}; - -use super::chain::chain_p2m9div16; -use super::{HashToField, MapToCurve, Sgn0}; -use crate::generic_array::{ - typenum::{U128, U64}, - GenericArray, -}; -use crate::{fp::Fp, fp2::Fp2, g2::G2Projective}; - -/// Coefficients of the 3-isogeny x map's numerator -const ISO3_XNUM: [Fp2; 4] = [ - Fp2 { - c0: Fp::from_raw_unchecked([ - 0x47f6_71c7_1ce0_5e62, - 0x06dd_5707_1206_393e, - 0x7c80_cd2a_f3fd_71a2, - 0x0481_03ea_9e6c_d062, - 0xc545_16ac_c8d0_37f6, - 0x1380_8f55_0920_ea41, - ]), - c1: Fp::from_raw_unchecked([ - 0x47f6_71c7_1ce0_5e62, - 0x06dd_5707_1206_393e, - 0x7c80_cd2a_f3fd_71a2, - 0x0481_03ea_9e6c_d062, - 0xc545_16ac_c8d0_37f6, - 0x1380_8f55_0920_ea41, - ]), - }, - Fp2 { - c0: Fp::zero(), - c1: Fp::from_raw_unchecked([ - 0x5fe5_5555_554c_71d0, - 0x873f_ffdd_236a_aaa3, - 0x6a6b_4619_b26e_f918, - 0x21c2_8884_0887_4945, - 0x2836_cda7_028c_abc5, - 0x0ac7_3310_a7fd_5abd, - ]), - }, - Fp2 { - c0: Fp::from_raw_unchecked([ - 0x0a0c_5555_5559_71c3, - 0xdb0c_0010_1f9e_aaae, - 0xb1fb_2f94_1d79_7997, - 0xd396_0742_ef41_6e1c, - 0xb700_40e2_c205_56f4, - 0x149d_7861_e581_393b, - ]), - c1: Fp::from_raw_unchecked([ - 0xaff2_aaaa_aaa6_38e8, - 0x439f_ffee_91b5_5551, - 0xb535_a30c_d937_7c8c, - 0x90e1_4442_0443_a4a2, - 0x941b_66d3_8146_55e2, - 0x0563_9988_53fe_ad5e, - ]), - }, - Fp2 { - c0: Fp::from_raw_unchecked([ - 0x40aa_c71c_71c7_25ed, - 0x1909_5555_7a84_e38e, - 0xd817_050a_8f41_abc3, - 0xd864_85d4_c87f_6fb1, - 0x696e_b479_f885_d059, - 0x198e_1a74_3280_02d2, - ]), - c1: Fp::zero(), - }, -]; - -/// Coefficients of the 3-isogeny x map's denominator -const ISO3_XDEN: [Fp2; 3] = [ - Fp2 { - c0: Fp::zero(), - c1: Fp::from_raw_unchecked([ - 0x1f3a_ffff_ff13_ab97, - 0xf25b_fc61_1da3_ff3e, - 0xca37_57cb_3819_b208, - 0x3e64_2736_6f8c_ec18, - 0x0397_7bc8_6095_b089, - 0x04f6_9db1_3f39_a952, - ]), - }, - Fp2 { - c0: Fp::from_raw_unchecked([ - 0x4476_0000_0027_552e, - 0xdcb8_009a_4348_0020, - 0x6f7e_e9ce_4a6e_8b59, - 0xb103_30b7_c0a9_5bc6, - 0x6140_b1fc_fb1e_54b7, - 0x0381_be09_7f0b_b4e1, - ]), - c1: Fp::from_raw_unchecked([ - 0x7588_ffff_ffd8_557d, - 0x41f3_ff64_6e0b_ffdf, - 0xf7b1_e8d2_ac42_6aca, - 0xb374_1acd_32db_b6f8, - 0xe9da_f5b9_482d_581f, - 0x167f_53e0_ba74_31b8, - ]), - }, - Fp2::one(), -]; - -/// Coefficients of the 3-isogeny y map's numerator -const ISO3_YNUM: [Fp2; 4] = [ - Fp2 { - c0: Fp::from_raw_unchecked([ - 0x96d8_f684_bdfc_77be, - 0xb530_e4f4_3b66_d0e2, - 0x184a_88ff_3796_52fd, - 0x57cb_23ec_fae8_04e1, - 0x0fd2_e39e_ada3_eba9, - 0x08c8_055e_31c5_d5c3, - ]), - c1: Fp::from_raw_unchecked([ - 0x96d8_f684_bdfc_77be, - 0xb530_e4f4_3b66_d0e2, - 0x184a_88ff_3796_52fd, - 0x57cb_23ec_fae8_04e1, - 0x0fd2_e39e_ada3_eba9, - 0x08c8_055e_31c5_d5c3, - ]), - }, - Fp2 { - c0: Fp::zero(), - c1: Fp::from_raw_unchecked([ - 0xbf0a_71c7_1c91_b406, - 0x4d6d_55d2_8b76_38fd, - 0x9d82_f98e_5f20_5aee, - 0xa27a_a27b_1d1a_18d5, - 0x02c3_b2b2_d293_8e86, - 0x0c7d_1342_0b09_807f, - ]), - }, - Fp2 { - c0: Fp::from_raw_unchecked([ - 0xd7f9_5555_5553_1c74, - 0x21cf_fff7_48da_aaa8, - 0x5a9a_d186_6c9b_be46, - 0x4870_a221_0221_d251, - 0x4a0d_b369_c0a3_2af1, - 0x02b1_ccc4_29ff_56af, - ]), - c1: Fp::from_raw_unchecked([ - 0xe205_aaaa_aaac_8e37, - 0xfcdc_0007_6879_5556, - 0x0c96_011a_8a15_37dd, - 0x1c06_a963_f163_406e, - 0x010d_f44c_82a8_81e6, - 0x174f_4526_0f80_8feb, - ]), - }, - Fp2 { - c0: Fp::from_raw_unchecked([ - 0xa470_bda1_2f67_f35c, - 0xc0fe_38e2_3327_b425, - 0xc9d3_d0f2_c6f0_678d, - 0x1c55_c993_5b5a_982e, - 0x27f6_c0e2_f074_6764, - 0x117c_5e6e_28aa_9054, - ]), - c1: Fp::zero(), - }, -]; - -/// Coefficients of the 3-isogeny y map's denominator -const ISO3_YDEN: [Fp2; 4] = [ - Fp2 { - c0: Fp::from_raw_unchecked([ - 0x0162_ffff_fa76_5adf, - 0x8f7b_ea48_0083_fb75, - 0x561b_3c22_59e9_3611, - 0x11e1_9fc1_a9c8_75d5, - 0xca71_3efc_0036_7660, - 0x03c6_a03d_41da_1151, - ]), - c1: Fp::from_raw_unchecked([ - 0x0162_ffff_fa76_5adf, - 0x8f7b_ea48_0083_fb75, - 0x561b_3c22_59e9_3611, - 0x11e1_9fc1_a9c8_75d5, - 0xca71_3efc_0036_7660, - 0x03c6_a03d_41da_1151, - ]), - }, - Fp2 { - c0: Fp::zero(), - c1: Fp::from_raw_unchecked([ - 0x5db0_ffff_fd3b_02c5, - 0xd713_f523_58eb_fdba, - 0x5ea6_0761_a84d_161a, - 0xbb2c_75a3_4ea6_c44a, - 0x0ac6_7359_21c1_119b, - 0x0ee3_d913_bdac_fbf6, - ]), - }, - Fp2 { - c0: Fp::from_raw_unchecked([ - 0x66b1_0000_003a_ffc5, - 0xcb14_00e7_64ec_0030, - 0xa73e_5eb5_6fa5_d106, - 0x8984_c913_a0fe_09a9, - 0x11e1_0afb_78ad_7f13, - 0x0542_9d0e_3e91_8f52, - ]), - c1: Fp::from_raw_unchecked([ - 0x534d_ffff_ffc4_aae6, - 0x5397_ff17_4c67_ffcf, - 0xbff2_73eb_870b_251d, - 0xdaf2_8271_5287_0915, - 0x393a_9cba_ca9e_2dc3, - 0x14be_74db_faee_5748, - ]), - }, - Fp2::one(), -]; - -const SSWU_ELLP_A: Fp2 = Fp2 { - c0: Fp::zero(), - c1: Fp::from_raw_unchecked([ - 0xe53a_0000_0313_5242, - 0x0108_0c0f_def8_0285, - 0xe788_9edb_e340_f6bd, - 0x0b51_3751_2631_0601, - 0x02d6_9857_17c7_44ab, - 0x1220_b4e9_79ea_5467, - ]), -}; - -const SSWU_ELLP_B: Fp2 = Fp2 { - c0: Fp::from_raw_unchecked([ - 0x22ea_0000_0cf8_9db2, - 0x6ec8_32df_7138_0aa4, - 0x6e1b_9440_3db5_a66e, - 0x75bf_3c53_a794_73ba, - 0x3dd3_a569_412c_0a34, - 0x125c_db5e_74dc_4fd1, - ]), - c1: Fp::from_raw_unchecked([ - 0x22ea_0000_0cf8_9db2, - 0x6ec8_32df_7138_0aa4, - 0x6e1b_9440_3db5_a66e, - 0x75bf_3c53_a794_73ba, - 0x3dd3_a569_412c_0a34, - 0x125c_db5e_74dc_4fd1, - ]), -}; - -const SSWU_XI: Fp2 = Fp2 { - c0: Fp::from_raw_unchecked([ - 0x87eb_ffff_fff9_555c, - 0x656f_ffe5_da8f_fffa, - 0x0fd0_7493_45d3_3ad2, - 0xd951_e663_0665_76f4, - 0xde29_1a3d_41e9_80d3, - 0x0815_664c_7dfe_040d, - ]), - c1: Fp::from_raw_unchecked([ - 0x43f5_ffff_fffc_aaae, - 0x32b7_fff2_ed47_fffd, - 0x07e8_3a49_a2e9_9d69, - 0xeca8_f331_8332_bb7a, - 0xef14_8d1e_a0f4_c069, - 0x040a_b326_3eff_0206, - ]), -}; - -const SSWU_ETAS: [Fp2; 4] = [ - Fp2 { - c0: Fp::from_raw_unchecked([ - 0x05e5_1466_8ac7_36d2, - 0x9089_b4d6_b84f_3ea5, - 0x603c_384c_224a_8b32, - 0xf325_7909_536a_fea6, - 0x5c5c_dbab_ae65_6d81, - 0x075b_fa08_63c9_87e9, - ]), - c1: Fp::from_raw_unchecked([ - 0x338d_9bfe_0808_7330, - 0x7b8e_48b2_bd83_cefe, - 0x530d_ad5d_306b_5be7, - 0x5a4d_7e8e_6c40_8b6d, - 0x6258_f7a6_232c_ab9b, - 0x0b98_5811_cce1_4db5, - ]), - }, - Fp2 { - c0: Fp::from_raw_unchecked([ - 0x8671_6401_f7f7_377b, - 0xa31d_b74b_f3d0_3101, - 0x1423_2543_c645_9a3c, - 0x0a29_ccf6_8744_8752, - 0xe8c2_b010_201f_013c, - 0x0e68_b9d8_6c9e_98e4, - ]), - c1: Fp::from_raw_unchecked([ - 0x05e5_1466_8ac7_36d2, - 0x9089_b4d6_b84f_3ea5, - 0x603c_384c_224a_8b32, - 0xf325_7909_536a_fea6, - 0x5c5c_dbab_ae65_6d81, - 0x075b_fa08_63c9_87e9, - ]), - }, - Fp2 { - c0: Fp::from_raw_unchecked([ - 0x718f_dad2_4ee1_d90f, - 0xa58c_025b_ed82_76af, - 0x0c3a_1023_0ab7_976f, - 0xf0c5_4df5_c8f2_75e1, - 0x4ec2_478c_28ba_f465, - 0x1129_373a_90c5_08e6, - ]), - c1: Fp::from_raw_unchecked([ - 0x019a_f5f9_80a3_680c, - 0x4ed7_da0e_6606_3afa, - 0x6003_5472_3b5d_9972, - 0x8b2f_958b_20d0_9d72, - 0x0474_938f_02d4_61db, - 0x0dcf_8b9e_0684_ab1c, - ]), - }, - Fp2 { - c0: Fp::from_raw_unchecked([ - 0xb864_0a06_7f5c_429f, - 0xcfd4_25f0_4b4d_c505, - 0x072d_7e2e_bb53_5cb1, - 0xd947_b5f9_d2b4_754d, - 0x46a7_1427_4077_4afb, - 0x0c31_864c_32fb_3b7e, - ]), - c1: Fp::from_raw_unchecked([ - 0x718f_dad2_4ee1_d90f, - 0xa58c_025b_ed82_76af, - 0x0c3a_1023_0ab7_976f, - 0xf0c5_4df5_c8f2_75e1, - 0x4ec2_478c_28ba_f465, - 0x1129_373a_90c5_08e6, - ]), - }, -]; - -const SSWU_RV1: Fp2 = Fp2 { - c0: Fp::from_raw_unchecked([ - 0x7bcf_a7a2_5aa3_0fda, - 0xdc17_dec1_2a92_7e7c, - 0x2f08_8dd8_6b4e_bef1, - 0xd1ca_2087_da74_d4a7, - 0x2da2_5966_96ce_bc1d, - 0x0e2b_7eed_bbfd_87d2, - ]), - c1: Fp::from_raw_unchecked([ - 0x7bcf_a7a2_5aa3_0fda, - 0xdc17_dec1_2a92_7e7c, - 0x2f08_8dd8_6b4e_bef1, - 0xd1ca_2087_da74_d4a7, - 0x2da2_5966_96ce_bc1d, - 0x0e2b_7eed_bbfd_87d2, - ]), -}; - -impl HashToField for Fp2 { - // ceil(log2(p)) = 381, m = 2, k = 128. - type InputLength = U128; - - fn from_okm(okm: &GenericArray) -> Fp2 { - let c0 = ::from_okm(GenericArray::::from_slice(&okm[..64])); - let c1 = ::from_okm(GenericArray::::from_slice(&okm[64..])); - Fp2 { c0, c1 } - } -} - -impl Sgn0 for Fp2 { - fn sgn0(&self) -> Choice { - let sign_0 = self.c0.sgn0(); - let zero_0 = self.c0.is_zero(); - let sign_1 = self.c1.sgn0(); - sign_0 | (zero_0 & sign_1) - } -} - -/// Maps from an [`Fp2]` element to a point on iso-G2. -fn map_to_curve_simple_swu(u: &Fp2) -> G2Projective { - let usq = u.square(); - let xi_usq = SSWU_XI * usq; - let xisq_u4 = xi_usq.square(); - let nd_common = xisq_u4 + xi_usq; // XI^2 * u^4 + XI * u^2 - let x_den = SSWU_ELLP_A * Fp2::conditional_select(&(-nd_common), &SSWU_XI, nd_common.is_zero()); - let x0_num = SSWU_ELLP_B * (Fp2::one() + nd_common); // B * (1 + (XI^2 * u^4 + XI * u^2)) - - // compute g(x0(u)) - let x_densq = x_den.square(); - let gx_den = x_densq * x_den; - // x0_num^3 + A * x0_num * x_den^2 + B * x_den^3 - let gx0_num = (x0_num.square() + SSWU_ELLP_A * x_densq) * x0_num + SSWU_ELLP_B * gx_den; - - // compute g(x0(u)) ^ ((p^2 - 9) // 16) - let sqrt_candidate = { - let vsq = gx_den.square(); // v^2 - let v_3 = vsq * gx_den; // v^3 - let v_4 = vsq.square(); // v^4 - let uv_7 = gx0_num * v_3 * v_4; // u v^7 - let uv_15 = uv_7 * v_4.square(); // u v^15 - uv_7 * chain_p2m9div16(&uv_15) // u v^7 (u v^15) ^ ((p^2 - 9) // 16) - }; - - // set y = sqrt_candidate * Fp2::one(), check candidate against other roots of unity - let mut y = sqrt_candidate; - // check Fp2(0, 1) - let tmp = Fp2 { - c0: -sqrt_candidate.c1, - c1: sqrt_candidate.c0, - }; - y.conditional_assign(&tmp, (tmp.square() * gx_den).ct_eq(&gx0_num)); - // check Fp2(RV1, RV1) - let tmp = sqrt_candidate * SSWU_RV1; - y.conditional_assign(&tmp, (tmp.square() * gx_den).ct_eq(&gx0_num)); - // check Fp2(RV1, -RV1) - let tmp = Fp2 { - c0: tmp.c1, - c1: -tmp.c0, - }; - y.conditional_assign(&tmp, (tmp.square() * gx_den).ct_eq(&gx0_num)); - - // compute g(x1(u)) = g(x0(u)) * XI^3 * u^6 - let gx1_num = gx0_num * xi_usq * xisq_u4; - // compute g(x1(u)) * u^3 - let sqrt_candidate = sqrt_candidate * usq * u; - let mut eta_found = Choice::from(0u8); - for eta in &SSWU_ETAS[..] { - let tmp = sqrt_candidate * eta; - let found = (tmp.square() * gx_den).ct_eq(&gx1_num); - y.conditional_assign(&tmp, found); - eta_found |= found; - } - - let x_num = Fp2::conditional_select(&x0_num, &(x0_num * xi_usq), eta_found); - // ensure sign of y and sign of u agree - y.conditional_negate(u.sgn0() ^ y.sgn0()); - - G2Projective { - x: x_num, - y: y * x_den, - z: x_den, - } -} - -/// Maps from an iso-G2 point to a G2 point. -fn iso_map(u: &G2Projective) -> G2Projective { - const COEFFS: [&[Fp2]; 4] = [&ISO3_XNUM, &ISO3_XDEN, &ISO3_YNUM, &ISO3_YDEN]; - - // unpack input point - let G2Projective { x, y, z } = *u; - - // xnum, xden, ynum, yden - let mut mapvals = [Fp2::zero(); 4]; - - // compute powers of z - let zsq = z.square(); - let zpows = [z, zsq, zsq * z]; - - // compute map value by Horner's rule - for idx in 0..4 { - let coeff = COEFFS[idx]; - let clast = coeff.len() - 1; - mapvals[idx] = coeff[clast]; - for jdx in 0..clast { - mapvals[idx] = mapvals[idx] * x + zpows[jdx] * coeff[clast - 1 - jdx]; - } - } - - // x denominator is order 1 less than x numerator, so we need an extra factor of z - mapvals[1] *= z; - - // multiply result of Y map by the y-coord, y / z - mapvals[2] *= y; - mapvals[3] *= z; - - G2Projective { - x: mapvals[0] * mapvals[3], // xnum * yden, - y: mapvals[2] * mapvals[1], // ynum * xden, - z: mapvals[1] * mapvals[3], // xden * yden - } -} - -impl MapToCurve for G2Projective { - type Field = Fp2; - - fn map_to_curve(u: &Fp2) -> G2Projective { - let pt = map_to_curve_simple_swu(u); - iso_map(&pt) - } - - fn clear_h(&self) -> Self { - self.clear_cofactor() - } -} - -#[cfg(test)] -fn check_g2_prime(pt: &G2Projective) -> bool { - // (X : Y : Z)==(X/Z, Y/Z) is on E': y^2 = x^3 + A * x + B. - // y^2 z = (x^3) + A (x z^2) + B z^3 - let zsq = pt.z.square(); - (pt.y.square() * pt.z) - == (pt.x.square() * pt.x + SSWU_ELLP_A * pt.x * zsq + SSWU_ELLP_B * zsq * pt.z) -} - -#[test] -fn test_osswu_semirandom() { - use rand_core::SeedableRng; - let mut rng = rand_xorshift::XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - for _ in 0..32 { - let input = Fp2::random(&mut rng); - let p = map_to_curve_simple_swu(&input); - assert!(check_g2_prime(&p)); - - let p_iso = iso_map(&p); - assert!(bool::from(p_iso.is_on_curve())); - } -} - -// test vectors from the draft 10 RFC -#[test] -fn test_encode_to_curve_10() { - use crate::{ - g2::G2Affine, - hash_to_curve::{ExpandMsgXmd, HashToCurve}, - }; - use std::string::{String, ToString}; - - struct TestCase { - msg: &'static [u8], - expected: [&'static str; 4], - } - impl TestCase { - fn expected(&self) -> String { - self.expected[0].to_string() + self.expected[1] + self.expected[2] + self.expected[3] - } - } - - const DOMAIN: &[u8] = b"QUUX-V01-CS02-with-BLS12381G2_XMD:SHA-256_SSWU_NU_"; - - let cases = vec![ - TestCase { - msg: b"", - expected: [ - "126b855e9e69b1f691f816e48ac6977664d24d99f8724868a184186469ddfd4617367e94527d4b74fc86413483afb35b", - "00e7f4568a82b4b7dc1f14c6aaa055edf51502319c723c4dc2688c7fe5944c213f510328082396515734b6612c4e7bb7", - "1498aadcf7ae2b345243e281ae076df6de84455d766ab6fcdaad71fab60abb2e8b980a440043cd305db09d283c895e3d", - "0caead0fd7b6176c01436833c79d305c78be307da5f6af6c133c47311def6ff1e0babf57a0fb5539fce7ee12407b0a42", - ], - }, - TestCase { - msg: b"abc", - expected: [ - "0296238ea82c6d4adb3c838ee3cb2346049c90b96d602d7bb1b469b905c9228be25c627bffee872def773d5b2a2eb57d", - "108ed59fd9fae381abfd1d6bce2fd2fa220990f0f837fa30e0f27914ed6e1454db0d1ee957b219f61da6ff8be0d6441f", - "153606c417e59fb331b7ae6bce4fbf7c5190c33ce9402b5ebe2b70e44fca614f3f1382a3625ed5493843d0b0a652fc3f", - "033f90f6057aadacae7963b0a0b379dd46750c1c94a6357c99b65f63b79e321ff50fe3053330911c56b6ceea08fee656", - ], - }, - TestCase { - msg: b"abcdef0123456789", - expected: [ - "0da75be60fb6aa0e9e3143e40c42796edf15685cafe0279afd2a67c3dff1c82341f17effd402e4f1af240ea90f4b659b", - "038af300ef34c7759a6caaa4e69363cafeed218a1f207e93b2c70d91a1263d375d6730bd6b6509dcac3ba5b567e85bf3", - "0492f4fed741b073e5a82580f7c663f9b79e036b70ab3e51162359cec4e77c78086fe879b65ca7a47d34374c8315ac5e", - "19b148cbdf163cf0894f29660d2e7bfb2b68e37d54cc83fd4e6e62c020eaa48709302ef8e746736c0e19342cc1ce3df4", - ] - }, - TestCase { - msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqq", - expected: [ - "12c8c05c1d5fc7bfa847f4d7d81e294e66b9a78bc9953990c358945e1f042eedafce608b67fdd3ab0cb2e6e263b9b1ad", - "0c5ae723be00e6c3f0efe184fdc0702b64588fe77dda152ab13099a3bacd3876767fa7bbad6d6fd90b3642e902b208f9", - "11c624c56dbe154d759d021eec60fab3d8b852395a89de497e48504366feedd4662d023af447d66926a28076813dd646", - "04e77ddb3ede41b5ec4396b7421dd916efc68a358a0d7425bddd253547f2fb4830522358491827265dfc5bcc1928a569", - ] - }, - TestCase { - msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - expected: [ - "1565c2f625032d232f13121d3cfb476f45275c303a037faa255f9da62000c2c864ea881e2bcddd111edc4a3c0da3e88d", - "0ea4e7c33d43e17cc516a72f76437c4bf81d8f4eac69ac355d3bf9b71b8138d55dc10fd458be115afa798b55dac34be1", - "0f8991d2a1ad662e7b6f58ab787947f1fa607fce12dde171bc17903b012091b657e15333e11701edcf5b63ba2a561247", - "043b6f5fe4e52c839148dc66f2b3751e69a0f6ebb3d056d6465d50d4108543ecd956e10fa1640dfd9bc0030cc2558d28", - ] - } - ]; - - for case in cases { - let g = >>::encode_to_curve( - &case.msg, DOMAIN, - ); - let g_uncompressed = G2Affine::from(g).to_uncompressed(); - - assert_eq!(case.expected(), hex::encode(&g_uncompressed[..])); - } -} - -// test vectors from the draft 10 RFC -#[test] -fn test_hash_to_curve_10() { - use crate::{ - g2::G2Affine, - hash_to_curve::{ExpandMsgXmd, HashToCurve}, - }; - use std::string::{String, ToString}; - - struct TestCase { - msg: &'static [u8], - expected: [&'static str; 4], - } - impl TestCase { - fn expected(&self) -> String { - self.expected[0].to_string() + self.expected[1] + self.expected[2] + self.expected[3] - } - } - - const DOMAIN: &[u8] = b"QUUX-V01-CS02-with-BLS12381G2_XMD:SHA-256_SSWU_RO_"; - - let cases = vec![ - TestCase { - msg: b"", - expected: [ - "05cb8437535e20ecffaef7752baddf98034139c38452458baeefab379ba13dff5bf5dd71b72418717047f5b0f37da03d", - "0141ebfbdca40eb85b87142e130ab689c673cf60f1a3e98d69335266f30d9b8d4ac44c1038e9dcdd5393faf5c41fb78a", - "12424ac32561493f3fe3c260708a12b7c620e7be00099a974e259ddc7d1f6395c3c811cdd19f1e8dbf3e9ecfdcbab8d6", - "0503921d7f6a12805e72940b963c0cf3471c7b2a524950ca195d11062ee75ec076daf2d4bc358c4b190c0c98064fdd92", - ], - }, - TestCase { - msg: b"abc", - expected: [ - "139cddbccdc5e91b9623efd38c49f81a6f83f175e80b06fc374de9eb4b41dfe4ca3a230ed250fbe3a2acf73a41177fd8", - "02c2d18e033b960562aae3cab37a27ce00d80ccd5ba4b7fe0e7a210245129dbec7780ccc7954725f4168aff2787776e6", - "00aa65dae3c8d732d10ecd2c50f8a1baf3001578f71c694e03866e9f3d49ac1e1ce70dd94a733534f106d4cec0eddd16", - "1787327b68159716a37440985269cf584bcb1e621d3a7202be6ea05c4cfe244aeb197642555a0645fb87bf7466b2ba48", - ], - }, - TestCase { - msg: b"abcdef0123456789", - expected: [ - "190d119345b94fbd15497bcba94ecf7db2cbfd1e1fe7da034d26cbba169fb3968288b3fafb265f9ebd380512a71c3f2c", - "121982811d2491fde9ba7ed31ef9ca474f0e1501297f68c298e9f4c0028add35aea8bb83d53c08cfc007c1e005723cd0", - "0bb5e7572275c567462d91807de765611490205a941a5a6af3b1691bfe596c31225d3aabdf15faff860cb4ef17c7c3be", - "05571a0f8d3c08d094576981f4a3b8eda0a8e771fcdcc8ecceaf1356a6acf17574518acb506e435b639353c2e14827c8", - ] - }, - TestCase { - msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\ - qqqqqqqqqqqqqqqqqqqqqqqqq", - expected: [ - "0934aba516a52d8ae479939a91998299c76d39cc0c035cd18813bec433f587e2d7a4fef038260eef0cef4d02aae3eb91", - "19a84dd7248a1066f737cc34502ee5555bd3c19f2ecdb3c7d9e24dc65d4e25e50d83f0f77105e955d78f4762d33c17da", - "09bcccfa036b4847c9950780733633f13619994394c23ff0b32fa6b795844f4a0673e20282d07bc69641cee04f5e5662", - "14f81cd421617428bc3b9fe25afbb751d934a00493524bc4e065635b0555084dd54679df1536101b2c979c0152d09192", - ] - }, - TestCase { - msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - expected: [ - "11fca2ff525572795a801eed17eb12785887c7b63fb77a42be46ce4a34131d71f7a73e95fee3f812aea3de78b4d01569", - "01a6ba2f9a11fa5598b2d8ace0fbe0a0eacb65deceb476fbbcb64fd24557c2f4b18ecfc5663e54ae16a84f5ab7f62534", - "03a47f8e6d1763ba0cad63d6114c0accbef65707825a511b251a660a9b3994249ae4e63fac38b23da0c398689ee2ab52", - "0b6798718c8aed24bc19cb27f866f1c9effcdbf92397ad6448b5c9db90d2b9da6cbabf48adc1adf59a1a28344e79d57e", - ] - } - ]; - - for case in cases { - let g = >>::hash_to_curve( - &case.msg, DOMAIN, - ); - let g_uncompressed = G2Affine::from(g).to_uncompressed(); - - assert_eq!(case.expected(), hex::encode(&g_uncompressed[..])); - } -} - -#[test] -fn test_sgn0() { - use super::map_g1::P_M1_OVER2; - - assert_eq!(bool::from(Fp2::zero().sgn0()), false); - assert_eq!(bool::from(Fp2::one().sgn0()), true); - assert_eq!( - bool::from( - Fp2 { - c0: P_M1_OVER2, - c1: Fp::zero() - } - .sgn0() - ), - true - ); - assert_eq!( - bool::from( - Fp2 { - c0: P_M1_OVER2, - c1: Fp::one() - } - .sgn0() - ), - true - ); - assert_eq!( - bool::from( - Fp2 { - c0: Fp::zero(), - c1: P_M1_OVER2, - } - .sgn0() - ), - true - ); - assert_eq!( - bool::from( - Fp2 { - c0: Fp::one(), - c1: P_M1_OVER2, - } - .sgn0() - ), - true - ); - - let p_p1_over2 = P_M1_OVER2 + Fp::one(); - assert_eq!( - bool::from( - Fp2 { - c0: p_p1_over2, - c1: Fp::zero() - } - .sgn0() - ), - false - ); - assert_eq!( - bool::from( - Fp2 { - c0: p_p1_over2, - c1: Fp::one() - } - .sgn0() - ), - false - ); - assert_eq!( - bool::from( - Fp2 { - c0: Fp::zero(), - c1: p_p1_over2, - } - .sgn0() - ), - false - ); - assert_eq!( - bool::from( - Fp2 { - c0: Fp::one(), - c1: p_p1_over2, - } - .sgn0() - ), - true - ); - - assert_eq!( - bool::from( - Fp2 { - c0: P_M1_OVER2, - c1: -Fp::one() - } - .sgn0() - ), - true - ); - assert_eq!( - bool::from( - Fp2 { - c0: p_p1_over2, - c1: -Fp::one() - } - .sgn0() - ), - false - ); - assert_eq!( - bool::from( - Fp2 { - c0: Fp::zero(), - c1: -Fp::one() - } - .sgn0() - ), - false - ); - assert_eq!( - bool::from( - Fp2 { - c0: P_M1_OVER2, - c1: p_p1_over2 - } - .sgn0() - ), - true - ); - assert_eq!( - bool::from( - Fp2 { - c0: p_p1_over2, - c1: P_M1_OVER2 - } - .sgn0() - ), - false - ); - - assert_eq!( - bool::from( - Fp2 { - c0: -Fp::one(), - c1: P_M1_OVER2, - } - .sgn0() - ), - false - ); - assert_eq!( - bool::from( - Fp2 { - c0: -Fp::one(), - c1: p_p1_over2, - } - .sgn0() - ), - false - ); - assert_eq!( - bool::from( - Fp2 { - c0: -Fp::one(), - c1: Fp::zero(), - } - .sgn0() - ), - false - ); - assert_eq!( - bool::from( - Fp2 { - c0: p_p1_over2, - c1: P_M1_OVER2, - } - .sgn0() - ), - false - ); - assert_eq!( - bool::from( - Fp2 { - c0: P_M1_OVER2, - c1: p_p1_over2, - } - .sgn0() - ), - true - ); -} diff --git a/src/hash_to_curve/map_scalar.rs b/src/hash_to_curve/map_scalar.rs deleted file mode 100644 index ec4bb9e0..00000000 --- a/src/hash_to_curve/map_scalar.rs +++ /dev/null @@ -1,39 +0,0 @@ -//! Implementation of hash-to-field for Scalar values - -use super::HashToField; -use crate::generic_array::{typenum::U48, GenericArray}; -use crate::scalar::Scalar; - -impl HashToField for Scalar { - // ceil(log2(p)) = 255, m = 1, k = 128. - type InputLength = U48; - - fn from_okm(okm: &GenericArray) -> Scalar { - let mut bs = [0u8; 64]; - bs[16..].copy_from_slice(okm); - bs.reverse(); // into little endian - Scalar::from_bytes_wide(&bs) - } -} - -#[test] -fn test_hash_to_scalar() { - let tests: &[(&[u8], &str)] = &[ - ( - &[0u8; 48], - "0x0000000000000000000000000000000000000000000000000000000000000000", - ), - ( - b"aaaaaabbbbbbccccccddddddeeeeeeffffffgggggghhhhhh", - "0x2228450bf55d8fe62395161bd3677ff6fc28e45b89bc87e02a818eda11a8c5da", - ), - ( - b"111111222222333333444444555555666666777777888888", - "0x4aa543cbd2f0c8f37f8a375ce2e383eb343e7e3405f61e438b0a15fb8899d1ae", - ), - ]; - for (input, expected) in tests { - let output = format!("{:?}", Scalar::from_okm(GenericArray::from_slice(input))); - assert_eq!(&output, expected); - } -} diff --git a/src/hash_to_curve/mod.rs b/src/hash_to_curve/mod.rs deleted file mode 100644 index 4c15a498..00000000 --- a/src/hash_to_curve/mod.rs +++ /dev/null @@ -1,113 +0,0 @@ -//! This module implements hash_to_curve, hash_to_field and related -//! hashing primitives for use with BLS signatures. - -use core::ops::Add; - -use subtle::Choice; - -pub(crate) mod chain; - -mod expand_msg; -pub use self::expand_msg::{ - ExpandMessage, ExpandMessageState, ExpandMsgXmd, ExpandMsgXof, InitExpandMessage, -}; - -mod map_g1; -mod map_g2; -mod map_scalar; - -use crate::generic_array::{typenum::Unsigned, ArrayLength, GenericArray}; - -/// Enables a byte string to be hashed into one or more field elements for a given curve. -/// -/// Implements [section 5 of `draft-irtf-cfrg-hash-to-curve-12`][hash_to_field]. -/// -/// [hash_to_field]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-12#section-5 -pub trait HashToField: Sized { - /// The length of the data used to produce an individual field element. - /// - /// This must be set to `m * L = m * ceil((ceil(log2(p)) + k) / 8)`, where `p` is the - /// characteristic of `Self`, `m` is the extension degree of `Self`, and `k` is the - /// security parameter. - type InputLength: ArrayLength; - - /// Interprets the given output keying material as a big endian integer, and reduces - /// it into a field element. - fn from_okm(okm: &GenericArray) -> Self; - - /// Hashes a byte string of arbitrary length into one or more elements of `Self`, - /// using [`ExpandMessage`] variant `X`. - /// - /// Implements [section 5.3 of `draft-irtf-cfrg-hash-to-curve-12`][hash_to_field]. - /// - /// [hash_to_field]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-12#section-5.3 - fn hash_to_field(message: &[u8], dst: &[u8], output: &mut [Self]) { - let len_per_elm = Self::InputLength::to_usize(); - let len_in_bytes = output.len() * len_per_elm; - let mut expander = X::init_expand(message, dst, len_in_bytes); - - let mut buf = GenericArray::::default(); - output.iter_mut().for_each(|item| { - expander.read_into(&mut buf[..]); - *item = Self::from_okm(&buf); - }); - } -} - -/// Allow conversion from the output of hashed or encoded input into points on the curve -pub trait MapToCurve: Sized { - /// The field element type. - type Field: Copy + Default + HashToField; - - /// Maps an element of the finite field `Self::Field` to a point on the curve `Self`. - fn map_to_curve(elt: &Self::Field) -> Self; - - /// Clears the cofactor, sending a point on curve E to the target group (G1/G2). - fn clear_h(&self) -> Self; -} - -/// Implementation of random oracle maps to the curve. -pub trait HashToCurve: MapToCurve + for<'a> Add<&'a Self, Output = Self> { - /// Implements a uniform encoding from byte strings to elements of `Self`. - /// - /// This function is suitable for most applications requiring a random - /// oracle returning points in `Self`. - fn hash_to_curve(message: impl AsRef<[u8]>, dst: &[u8]) -> Self { - let mut u = [Self::Field::default(); 2]; - Self::Field::hash_to_field::(message.as_ref(), dst, &mut u); - let p1 = Self::map_to_curve(&u[0]); - let p2 = Self::map_to_curve(&u[1]); - (p1 + &p2).clear_h() - } - - /// Implements a **non-uniform** encoding from byte strings to elements of `Self`. - /// - /// The distribution of its output is not uniformly random in `Self`: the set of - /// possible outputs of this function is only a fraction of the points in `Self`, and - /// some elements of this set are more likely to be output than others. See - /// [section 10.1 of `draft-irtf-cfrg-hash-to-curve-12`][encode_to_curve-distribution] - /// for a more precise definition of `encode_to_curve`'s output distribution. - /// - /// [encode_to_curve-distribution]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-12#section-10.1 - fn encode_to_curve(message: impl AsRef<[u8]>, dst: &[u8]) -> Self { - let mut u = [Self::Field::default(); 1]; - Self::Field::hash_to_field::(message.as_ref(), dst, &mut u); - let p = Self::map_to_curve(&u[0]); - p.clear_h() - } -} - -impl HashToCurve for G -where - G: MapToCurve + for<'a> Add<&'a Self, Output = Self>, - X: ExpandMessage, -{ -} - -pub(crate) trait Sgn0 { - /// Returns either 0 or 1 indicating the "sign" of x, where sgn0(x) == 1 - /// just when x is "negative". (In other words, this function always considers 0 to be positive.) - /// - /// The equivalent for draft 6 would be `lexicographically_largest`. - fn sgn0(&self) -> Choice; -} diff --git a/src/isogeny.rs b/src/isogeny.rs new file mode 100644 index 00000000..499afde5 --- /dev/null +++ b/src/isogeny.rs @@ -0,0 +1,743 @@ +pub(crate) mod g1 { + use crate::fp::Fp; + + /// Coefficients of the 11-isogeny x map's numerator + pub const XNUM: [Fp; 12] = [ + Fp([ + 0x4d18_b6f3_af00_131cu64, + 0x19fa_2197_93fe_e28cu64, + 0x3f28_85f1_467f_19aeu64, + 0x23dc_ea34_f2ff_b304u64, + 0xd15b_58d2_ffc0_0054u64, + 0x0913_be20_0a20_bef4u64, + ]), + Fp([ + 0x8989_8538_5cdb_bd8bu64, + 0x3c79_e43c_c7d9_66aau64, + 0x1597_e193_f4cd_233au64, + 0x8637_ef1e_4d66_23adu64, + 0x11b2_2dee_d20d_827bu64, + 0x0709_7bc5_9987_84adu64, + ]), + Fp([ + 0xa542_583a_480b_664bu64, + 0xfc71_69c0_26e5_68c6u64, + 0x5ba2_ef31_4ed8_b5a6u64, + 0x5b54_91c0_5102_f0e7u64, + 0xdf6e_9970_7d2a_0079u64, + 0x0784_151e_d760_5524u64, + ]), + Fp([ + 0x494e_2128_70f7_2741u64, + 0xab9b_e52f_bda4_3021u64, + 0x26f5_5779_94e3_4c3du64, + 0x049d_fee8_2aef_bd60u64, + 0x65da_dd78_2850_5289u64, + 0x0e93_d431_ea01_1aebu64, + ]), + Fp([ + 0x90ee_774b_d6a7_4d45u64, + 0x7ada_1c8a_41bf_b185u64, + 0x0f1a_8953_b325_f464u64, + 0x104c_2421_1be4_805cu64, + 0x1691_39d3_19ea_7a8fu64, + 0x09f2_0ead_8e53_2bf6u64, + ]), + Fp([ + 0x6ddd_93e2_f436_26b7u64, + 0xa548_2c9a_a1cc_d7bdu64, + 0x1432_4563_1883_f4bdu64, + 0x2e0a_94cc_f77e_c0dbu64, + 0xb028_2d48_0e56_489fu64, + 0x18f4_bfcb_b436_8929u64, + ]), + Fp([ + 0x23c5_f0c9_5340_2dfdu64, + 0x7a43_ff69_58ce_4fe9u64, + 0x2c39_0d3d_2da5_df63u64, + 0xd0df_5c98_e1f9_d70fu64, + 0xffd8_9869_a572_b297u64, + 0x1277_ffc7_2f25_e8feu64, + ]), + Fp([ + 0x79f4_f049_0f06_a8a6u64, + 0x85f8_94a8_8030_fd81u64, + 0x12da_3054_b18b_6410u64, + 0xe2a5_7f65_0588_0d65u64, + 0xbba0_74f2_60e4_00f1u64, + 0x08b7_6279_f621_d028u64, + ]), + Fp([ + 0xe672_45ba_78d5_b00bu64, + 0x8456_ba9a_1f18_6475u64, + 0x7888_bff6_e6b3_3bb4u64, + 0xe215_85b9_a30f_86cbu64, + 0x05a6_9cdc_ef55_feeeu64, + 0x09e6_99dd_9adf_a5acu64, + ]), + Fp([ + 0x0de5_c357_bff5_7107u64, + 0x0a0d_b4ae_6b1a_10b2u64, + 0xe256_bb67_b3b3_cd8du64, + 0x8ad4_5657_4e9d_b24fu64, + 0x0443_915f_50fd_4179u64, + 0x098c_4bf7_de8b_6375u64, + ]), + Fp([ + 0xe6b0_617e_7dd9_29c7u64, + 0xfe6e_37d4_4253_7375u64, + 0x1daf_deda_137a_489eu64, + 0xe4ef_d1ad_3f76_7cebu64, + 0x4a51_d866_7f0f_e1cfu64, + 0x054f_df4b_bf1d_821cu64, + ]), + Fp([ + 0x72db_2a50_658d_767bu64, + 0x8abf_91fa_a257_b3d5u64, + 0xe969_d683_3764_ab47u64, + 0x4641_7014_2a10_09ebu64, + 0xb14f_01aa_db30_be2fu64, + 0x18ae_6a85_6f40_715du64, + ]), + ]; + /// Coefficients of the 11-isogeny x map's denominator + pub const XDEN: [Fp; 11] = [ + Fp([ + 0xb962_a077_fdb0_f945u64, + 0xa6a9_740f_efda_13a0u64, + 0xc14d_568c_3ed6_c544u64, + 0xb43f_c37b_908b_133eu64, + 0x9c0b_3ac9_2959_9016u64, + 0x0165_aa6c_93ad_115fu64, + ]), + Fp([ + 0x2327_9a3b_a506_c1d9u64, + 0x92cf_ca0a_9465_176au64, + 0x3b29_4ab1_3755_f0ffu64, + 0x116d_da1c_5070_ae93u64, + 0xed45_3092_4cec_2045u64, + 0x0833_83d6_ed81_f1ceu64, + ]), + Fp([ + 0x9885_c2a6_449f_ecfcu64, + 0x4a2b_54cc_d377_33f0u64, + 0x17da_9ffd_8738_c142u64, + 0xa0fb_a727_32b3_fafdu64, + 0xff36_4f36_e54b_6812u64, + 0x0f29_c13c_6605_23e2u64, + ]), + Fp([ + 0xe349_cc11_8278_f041u64, + 0xd487_228f_2f32_04fbu64, + 0xc9d3_2584_9ade_5150u64, + 0x43a9_2bd6_9c15_c2dfu64, + 0x1c2c_7844_bc41_7be4u64, + 0x1202_5184_f407_440cu64, + ]), + Fp([ + 0x587f_65ae_6acb_057bu64, + 0x1444_ef32_5140_201fu64, + 0xfbf9_95e7_1270_da49u64, + 0xccda_0660_7243_6a42u64, + 0x7408_904f_0f18_6bb2u64, + 0x13b9_3c63_edf6_c015u64, + ]), + Fp([ + 0xfb91_8622_cd14_1920u64, + 0x4a4c_6442_3eca_ddb4u64, + 0x0beb_2329_27f7_fb26u64, + 0x30f9_4df6_f83a_3dc2u64, + 0xaeed_d424_d780_f388u64, + 0x06cc_402d_d594_bbebu64, + ]), + Fp([ + 0xd41f_7611_51b2_3f8fu64, + 0x32a9_2465_4357_19b3u64, + 0x64f4_36e8_88c6_2cb9u64, + 0xdf70_a9a1_f757_c6e4u64, + 0x6933_a38d_5b59_4c81u64, + 0x0c6f_7f72_37b4_6606u64, + ]), + Fp([ + 0x693c_0874_7876_c8f7u64, + 0x22c9_850b_f9cf_80f0u64, + 0x8e90_71da_b950_c124u64, + 0x89bc_62d6_1c7b_af23u64, + 0xbc6b_e2d8_dad5_7c23u64, + 0x1791_6987_aa14_a122u64, + ]), + Fp([ + 0x1be3_ff43_9c13_16fdu64, + 0x9965_243a_7571_dfa7u64, + 0xc7f7_f629_62f5_cd81u64, + 0x32c6_aa9a_f394_361cu64, + 0xbbc2_ee18_e1c2_27f4u64, + 0x0c10_2cba_c531_bb34u64, + ]), + Fp([ + 0x9976_14c9_7bac_bf07u64, + 0x61f8_6372_b991_92c0u64, + 0x5b8c_95fc_1435_3fc3u64, + 0xca2b_066c_2a87_492fu64, + 0x1617_8f5b_bf69_8711u64, + 0x12a6_dcd7_f0f4_e0e8u64, + ]), + Fp([ + 0x7609_0000_0002_fffdu64, + 0xebf4_000b_c40c_0002u64, + 0x5f48_9857_53c7_58bau64, + 0x77ce_5853_7052_5745u64, + 0x5c07_1a97_a256_ec6du64, + 0x15f6_5ec3_fa80_e493u64, + ]), + ]; + /// Coefficients of the 11-isogeny y map's numerator + pub const YNUM: [Fp; 16] = [ + Fp([ + 0x2b56_7ff3_e283_7267u64, + 0x1d4d_9e57_b958_a767u64, + 0xce02_8fea_04bd_7373u64, + 0xcc31_a30a_0b6c_d3dfu64, + 0x7d7b_18a6_8269_2693u64, + 0x0d30_0744_d42a_0310u64, + ]), + Fp([ + 0x99c2_555f_a542_493fu64, + 0xfe7f_53cc_4874_f878u64, + 0x5df0_608b_8f97_608au64, + 0x14e0_3832_052b_49c8u64, + 0x7063_26a6_957d_d5a4u64, + 0x0a8d_add9_c241_4555u64, + ]), + Fp([ + 0x13d9_4292_2a5c_f63au64, + 0x357e_33e3_6e26_1e7du64, + 0xcf05_a27c_8456_088du64, + 0x0000_bd1d_e7ba_50f0u64, + 0x83d0_c753_2f8c_1fdeu64, + 0x13f7_0bf3_8bbf_2905u64, + ]), + Fp([ + 0x5c57_fd95_bfaf_bdbbu64, + 0x28a3_59a6_5e54_1707u64, + 0x3983_ceb4_f636_0b6du64, + 0xafe1_9ff6_f97e_6d53u64, + 0xb346_8f45_5019_2bf7u64, + 0x0bb6_cde4_9d8b_a257u64, + ]), + Fp([ + 0x590b_62c7_ff8a_513fu64, + 0x314b_4ce3_72ca_cefdu64, + 0x6bef_32ce_94b8_a800u64, + 0x6ddf_84a0_9571_3d5fu64, + 0x64ea_ce4c_b098_2191u64, + 0x0386_213c_651b_888du64, + ]), + Fp([ + 0xa531_0a31_111b_bcddu64, + 0xa14a_c0f5_da14_8982u64, + 0xf9ad_9cc9_5423_d2e9u64, + 0xaa6e_c095_283e_e4a7u64, + 0xcf5b_1f02_2e1c_9107u64, + 0x01fd_df5a_ed88_1793u64, + ]), + Fp([ + 0x65a5_72b0_d7a7_d950u64, + 0xe25c_2d81_8347_3a19u64, + 0xc2fc_ebe7_cb87_7dbdu64, + 0x05b2_d36c_769a_89b0u64, + 0xba12_961b_e86e_9efbu64, + 0x07eb_1b29_c1df_de1fu64, + ]), + Fp([ + 0x93e0_9572_f7c4_cd24u64, + 0x364e_9290_7679_5091u64, + 0x8569_467e_68af_51b5u64, + 0xa47d_a894_39f5_340fu64, + 0xf4fa_9180_82e4_4d64u64, + 0x0ad5_2ba3_e669_5a79u64, + ]), + Fp([ + 0x9114_2984_4e0d_5f54u64, + 0xd03f_51a3_516b_b233u64, + 0x3d58_7e56_4053_6e66u64, + 0xfa86_d2a3_a9a7_3482u64, + 0xa90e_d5ad_f1ed_5537u64, + 0x149c_9c32_6a5e_7393u64, + ]), + Fp([ + 0x462b_beb0_3c12_921au64, + 0xdc9a_f5fa_0a27_4a17u64, + 0x9a55_8ebd_e836_ebedu64, + 0x649e_f8f1_1a4f_ae46u64, + 0x8100_e165_2b3c_dc62u64, + 0x1862_bd62_c291_dacbu64, + ]), + Fp([ + 0x05c9_b8ca_89f1_2c26u64, + 0x0194_160f_a9b9_ac4fu64, + 0x6a64_3d5a_6879_fa2cu64, + 0x1466_5bdd_8846_e19du64, + 0xbb1d_0d53_af3f_f6bfu64, + 0x12c7_e1c3_b289_62e5u64, + ]), + Fp([ + 0xb55e_bf90_0b8a_3e17u64, + 0xfedc_77ec_1a92_01c4u64, + 0x1f07_db10_ea1a_4df4u64, + 0x0dfb_d15d_c41a_594du64, + 0x3895_47f2_334a_5391u64, + 0x0241_9f98_1658_71a4u64, + ]), + Fp([ + 0xb416_af00_0745_fc20u64, + 0x8e56_3e9d_1ea6_d0f5u64, + 0x7c76_3e17_763a_0652u64, + 0x0145_8ef0_159e_bbefu64, + 0x8346_fe42_1f96_bb13u64, + 0x0d2d_7b82_9ce3_24d2u64, + ]), + Fp([ + 0x9309_6bb5_38d6_4615u64, + 0x6f2a_2619_951d_823au64, + 0x8f66_b3ea_5951_4fa4u64, + 0xf563_e637_04f7_092fu64, + 0x724b_136c_4cf2_d9fau64, + 0x0469_59cf_cfd0_bf49u64, + ]), + Fp([ + 0xea74_8d4b_6e40_5346u64, + 0x91e9_079c_2c02_d58fu64, + 0x4106_4965_946d_9b59u64, + 0xa067_31f1_d2bb_e1eeu64, + 0x07f8_97e2_67a3_3f1bu64, + 0x1017_2909_1921_0e5fu64, + ]), + Fp([ + 0x872a_a6c1_7d98_5097u64, + 0xeecc_5316_1264_562au64, + 0x07af_e37a_fff5_5002u64, + 0x5475_9078_e5be_6838u64, + 0xc4b9_2d15_db8a_cca8u64, + 0x106d_87d1_b51d_13b9u64, + ]), + ]; + /// Coefficients of the 11-isogeny y map's denominator + pub const YDEN: [Fp; 16] = [ + Fp([ + 0xeb6c_359d_47e5_2b1cu64, + 0x18ef_5f8a_1063_4d60u64, + 0xddfa_71a0_889d_5b7eu64, + 0x723e_71dc_c5fc_1323u64, + 0x52f4_5700_b70d_5c69u64, + 0x0a8b_981e_e476_91f1u64, + ]), + Fp([ + 0x616a_3c4f_5535_b9fbu64, + 0x6f5f_0373_95db_d911u64, + 0xf25f_4cc5_e35c_65dau64, + 0x3e50_dffe_a3c6_2658u64, + 0x6a33_dca5_2356_0776u64, + 0x0fad_eff7_7b6b_fe3eu64, + ]), + Fp([ + 0x2be9_b66d_f470_059cu64, + 0x24a2_c159_a3d3_6742u64, + 0x115d_be7a_d10c_2a37u64, + 0xb663_4a65_2ee5_884du64, + 0x04fe_8bb2_b8d8_1af4u64, + 0x01c2_a7a2_56fe_9c41u64, + ]), + Fp([ + 0xf27b_f8ef_3b75_a386u64, + 0x898b_3674_76c9_073fu64, + 0x2448_2e6b_8c2f_4e5fu64, + 0xc8e0_bbd6_fe11_0806u64, + 0x59b0_c17f_7631_448au64, + 0x1103_7cd5_8b3d_bfbdu64, + ]), + Fp([ + 0x31c7_912e_a267_eec6u64, + 0x1dbf_6f1c_5fcd_b700u64, + 0xd30d_4fe3_ba86_fdb1u64, + 0x3cae_528f_bee9_a2a4u64, + 0xb1cc_e69b_6aa9_ad9au64, + 0x0443_93bb_632d_94fbu64, + ]), + Fp([ + 0xc66e_f6ef_eeb5_c7e8u64, + 0x9824_c289_dd72_bb55u64, + 0x71b1_a4d2_f119_981du64, + 0x104f_c1aa_fb09_19ccu64, + 0x0e49_df01_d942_a628u64, + 0x096c_3a09_7732_72d4u64, + ]), + Fp([ + 0x9abc_11eb_5fad_eff4u64, + 0x32dc_a50a_8857_28f0u64, + 0xfb1f_a372_1569_734cu64, + 0xc4b7_6271_ea65_06b3u64, + 0xd466_a755_99ce_728eu64, + 0x0c81_d464_5f4c_b6edu64, + ]), + Fp([ + 0x4199_f10e_5b8b_e45bu64, + 0xda64_e495_b1e8_7930u64, + 0xcb35_3efe_9b33_e4ffu64, + 0x9e9e_fb24_aa64_24c6u64, + 0xf08d_3368_0a23_7465u64, + 0x0d33_7802_3e4c_7406u64, + ]), + Fp([ + 0x7eb4_ae92_ec74_d3a5u64, + 0xc341_b4aa_9fac_3497u64, + 0x5be6_0389_9e90_7687u64, + 0x03bf_d9cc_a75c_bdebu64, + 0x564c_2935_a96b_fa93u64, + 0x0ef3_c333_71e2_fdb5u64, + ]), + Fp([ + 0x7ee9_1fd4_49f6_ac2eu64, + 0xe5d5_bd5c_b935_7a30u64, + 0x773a_8ca5_196b_1380u64, + 0xd0fd_a172_174e_d023u64, + 0x6cb9_5e0f_a776_aeadu64, + 0x0d22_d5a4_0cec_7cffu64, + ]), + Fp([ + 0xf727_e092_85fd_8519u64, + 0xdc9d_55a8_3017_897bu64, + 0x7549_d8bd_0578_94aeu64, + 0x1784_1961_3d90_d8f8u64, + 0xfce9_5ebd_eb5b_490au64, + 0x0467_ffae_f23f_c49eu64, + ]), + Fp([ + 0xc176_9e6a_7c38_5f1bu64, + 0x79bc_930d_eac0_1c03u64, + 0x5461_c75a_23ed_e3b5u64, + 0x6e20_829e_5c23_0c45u64, + 0x828e_0f1e_772a_53cdu64, + 0x116a_efa7_4912_7bffu64, + ]), + Fp([ + 0x101c_10bf_2744_c10au64, + 0xbbf1_8d05_3a6a_3154u64, + 0xa0ec_f39e_f026_f602u64, + 0xfc00_9d49_96dc_5153u64, + 0xb900_0209_d5bd_08d3u64, + 0x189e_5fe4_470c_d73cu64, + ]), + Fp([ + 0x7ebd_546c_a157_5ed2u64, + 0xe47d_5a98_1d08_1b55u64, + 0x57b2_b625_b6d4_ca21u64, + 0xb0a1_ba04_2285_20ccu64, + 0x9873_8983_c210_7ff3u64, + 0x13dd_dbc4_799d_81d6u64, + ]), + Fp([ + 0x0931_9f2e_3983_4935u64, + 0x039e_952c_bdb0_5c21u64, + 0x55ba_77a9_a2f7_6493u64, + 0xfd04_e3df_c608_6467u64, + 0xfb95_832e_7d78_742eu64, + 0x0ef9_c24e_ccaf_5e0eu64, + ]), + Fp([ + 0x7609_0000_0002_fffdu64, + 0xebf4_000b_c40c_0002u64, + 0x5f48_9857_53c7_58bau64, + 0x77ce_5853_7052_5745u64, + 0x5c07_1a97_a256_ec6du64, + 0x15f6_5ec3_fa80_e493u64, + ]), + ]; +} + +pub(crate) mod g2 { + use crate::{fp::Fp, fp2::Fp2}; + + /// Coefficients of the 3-isogeny x map's numerator + pub const XNUM: [Fp2; 4] = [ + Fp2 { + c0: Fp([ + 0x47f671c71ce05e62u64, + 0x06dd57071206393eu64, + 0x7c80cd2af3fd71a2u64, + 0x048103ea9e6cd062u64, + 0xc54516acc8d037f6u64, + 0x13808f550920ea41u64, + ]), + c1: Fp([ + 0x47f671c71ce05e62u64, + 0x06dd57071206393eu64, + 0x7c80cd2af3fd71a2u64, + 0x048103ea9e6cd062u64, + 0xc54516acc8d037f6u64, + 0x13808f550920ea41u64, + ]), + }, + Fp2 { + c0: Fp([ + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + ]), + c1: Fp([ + 0x5fe55555554c71d0u64, + 0x873fffdd236aaaa3u64, + 0x6a6b4619b26ef918u64, + 0x21c2888408874945u64, + 0x2836cda7028cabc5u64, + 0x0ac73310a7fd5abdu64, + ]), + }, + Fp2 { + c0: Fp([ + 0x0a0c5555555971c3u64, + 0xdb0c00101f9eaaaeu64, + 0xb1fb2f941d797997u64, + 0xd3960742ef416e1cu64, + 0xb70040e2c20556f4u64, + 0x149d7861e581393bu64, + ]), + c1: Fp([ + 0xaff2aaaaaaa638e8u64, + 0x439fffee91b55551u64, + 0xb535a30cd9377c8cu64, + 0x90e144420443a4a2u64, + 0x941b66d3814655e2u64, + 0x0563998853fead5eu64, + ]), + }, + Fp2 { + c0: Fp([ + 0x40aac71c71c725edu64, + 0x190955557a84e38eu64, + 0xd817050a8f41abc3u64, + 0xd86485d4c87f6fb1u64, + 0x696eb479f885d059u64, + 0x198e1a74328002d2u64, + ]), + c1: Fp([ + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + ]), + }, + ]; + /// Coefficients of the 3-isogeny x map's denominator + pub const XDEN: [Fp2; 3] = [ + Fp2 { + c0: Fp([ + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + ]), + c1: Fp([ + 0x1f3affffff13ab97u64, + 0xf25bfc611da3ff3eu64, + 0xca3757cb3819b208u64, + 0x3e6427366f8cec18u64, + 0x03977bc86095b089u64, + 0x04f69db13f39a952u64, + ]), + }, + Fp2 { + c0: Fp([ + 0x447600000027552eu64, + 0xdcb8009a43480020u64, + 0x6f7ee9ce4a6e8b59u64, + 0xb10330b7c0a95bc6u64, + 0x6140b1fcfb1e54b7u64, + 0x0381be097f0bb4e1u64, + ]), + c1: Fp([ + 0x7588ffffffd8557du64, + 0x41f3ff646e0bffdfu64, + 0xf7b1e8d2ac426acau64, + 0xb3741acd32dbb6f8u64, + 0xe9daf5b9482d581fu64, + 0x167f53e0ba7431b8u64, + ]), + }, + Fp2 { + c0: Fp([ + 0x760900000002fffdu64, + 0xebf4000bc40c0002u64, + 0x5f48985753c758bau64, + 0x77ce585370525745u64, + 0x5c071a97a256ec6du64, + 0x15f65ec3fa80e493u64, + ]), + c1: Fp([ + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + ]), + }, + ]; + /// Coefficients of the 3-isogeny y map's numerator + pub const YNUM: [Fp2; 4] = [ + Fp2 { + c0: Fp([ + 0x96d8f684bdfc77beu64, + 0xb530e4f43b66d0e2u64, + 0x184a88ff379652fdu64, + 0x57cb23ecfae804e1u64, + 0x0fd2e39eada3eba9u64, + 0x08c8055e31c5d5c3u64, + ]), + c1: Fp([ + 0x96d8f684bdfc77beu64, + 0xb530e4f43b66d0e2u64, + 0x184a88ff379652fdu64, + 0x57cb23ecfae804e1u64, + 0x0fd2e39eada3eba9u64, + 0x08c8055e31c5d5c3u64, + ]), + }, + Fp2 { + c0: Fp([ + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + ]), + c1: Fp([ + 0xbf0a71c71c91b406u64, + 0x4d6d55d28b7638fdu64, + 0x9d82f98e5f205aeeu64, + 0xa27aa27b1d1a18d5u64, + 0x02c3b2b2d2938e86u64, + 0x0c7d13420b09807fu64, + ]), + }, + Fp2 { + c0: Fp([ + 0xd7f9555555531c74u64, + 0x21cffff748daaaa8u64, + 0x5a9ad1866c9bbe46u64, + 0x4870a2210221d251u64, + 0x4a0db369c0a32af1u64, + 0x02b1ccc429ff56afu64, + ]), + c1: Fp([ + 0xe205aaaaaaac8e37u64, + 0xfcdc000768795556u64, + 0x0c96011a8a1537ddu64, + 0x1c06a963f163406eu64, + 0x010df44c82a881e6u64, + 0x174f45260f808febu64, + ]), + }, + Fp2 { + c0: Fp([ + 0xa470bda12f67f35cu64, + 0xc0fe38e23327b425u64, + 0xc9d3d0f2c6f0678du64, + 0x1c55c9935b5a982eu64, + 0x27f6c0e2f0746764u64, + 0x117c5e6e28aa9054u64, + ]), + c1: Fp([ + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + ]), + }, + ]; + /// Coefficients of the 3-isogeny y map's denominator + pub const YDEN: [Fp2; 4] = [ + Fp2 { + c0: Fp([ + 0x0162fffffa765adfu64, + 0x8f7bea480083fb75u64, + 0x561b3c2259e93611u64, + 0x11e19fc1a9c875d5u64, + 0xca713efc00367660u64, + 0x03c6a03d41da1151u64, + ]), + c1: Fp([ + 0x0162fffffa765adfu64, + 0x8f7bea480083fb75u64, + 0x561b3c2259e93611u64, + 0x11e19fc1a9c875d5u64, + 0xca713efc00367660u64, + 0x03c6a03d41da1151u64, + ]), + }, + Fp2 { + c0: Fp([ + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + ]), + c1: Fp([ + 0x5db0fffffd3b02c5u64, + 0xd713f52358ebfdbau64, + 0x5ea60761a84d161au64, + 0xbb2c75a34ea6c44au64, + 0x0ac6735921c1119bu64, + 0x0ee3d913bdacfbf6u64, + ]), + }, + Fp2 { + c0: Fp([ + 0x66b10000003affc5u64, + 0xcb1400e764ec0030u64, + 0xa73e5eb56fa5d106u64, + 0x8984c913a0fe09a9u64, + 0x11e10afb78ad7f13u64, + 0x05429d0e3e918f52u64, + ]), + c1: Fp([ + 0x534dffffffc4aae6u64, + 0x5397ff174c67ffcfu64, + 0xbff273eb870b251du64, + 0xdaf2827152870915u64, + 0x393a9cbaca9e2dc3u64, + 0x14be74dbfaee5748u64, + ]), + }, + Fp2 { + c0: Fp([ + 0x760900000002fffdu64, + 0xebf4000bc40c0002u64, + 0x5f48985753c758bau64, + 0x77ce585370525745u64, + 0x5c071a97a256ec6du64, + 0x15f65ec3fa80e493u64, + ]), + c1: Fp([ + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + 0x0000000000000000u64, + ]), + }, + ]; +} diff --git a/src/lib.rs b/src/lib.rs index cfb6dcc3..18bc9b3d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,11 @@ extern crate alloc; #[macro_use] extern crate std; +pub use elliptic_curve; +pub use ff; +#[cfg(feature = "groups")] +pub use group; + #[cfg(test)] #[cfg(feature = "groups")] mod tests; @@ -79,12 +84,8 @@ mod pairings; #[cfg(feature = "pairings")] pub use pairings::{pairing, Bls12, Gt, MillerLoopResult}; -#[cfg(all(feature = "pairings", feature = "alloc"))] +#[cfg(feature = "pairings")] pub use pairings::{multi_miller_loop, G2Prepared}; -/// Use the generic_array re-exported by digest to avoid a version mismatch -#[cfg(feature = "experimental")] -pub(crate) use digest::generic_array; - -#[cfg(feature = "experimental")] -pub mod hash_to_curve; +#[cfg(feature = "hashing")] +mod isogeny; diff --git a/src/pairings.rs b/src/pairings.rs index 43992e3e..adbd37c3 100644 --- a/src/pairings.rs +++ b/src/pairings.rs @@ -2,20 +2,21 @@ use crate::fp::Fp; use crate::fp12::Fp12; use crate::fp2::Fp2; use crate::fp6::Fp6; +use crate::util::decode_hex_byte; use crate::{G1Affine, G1Projective, G2Affine, G2Projective, Scalar, BLS_X, BLS_X_IS_NEGATIVE}; -use core::borrow::Borrow; -use core::fmt; -use core::iter::Sum; -use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; -use group::Group; +use arrayref::array_ref; +use core::{ + borrow::Borrow, + fmt::{self, Display, Formatter, LowerHex, UpperHex}, + iter::Sum, + ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, +}; +use group::{Group, GroupEncoding}; use pairing::{Engine, PairingCurveAffine}; use rand_core::RngCore; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; -#[cfg(feature = "alloc")] -use alloc::vec::Vec; -#[cfg(feature = "alloc")] use pairing::MultiMillerLoop; /// Represents results of a Miller loop, one of the most expensive portions @@ -27,7 +28,7 @@ pub struct MillerLoopResult(pub(crate) Fp12); impl Default for MillerLoopResult { fn default() -> Self { - MillerLoopResult(Fp12::one()) + MillerLoopResult(Fp12::ONE) } } @@ -114,7 +115,7 @@ impl MillerLoopResult { #[must_use] fn cycolotomic_exp(f: Fp12) -> Fp12 { let x = BLS_X; - let mut tmp = Fp12::one(); + let mut tmp = Fp12::ONE; let mut found_one = false; for i in (0..64).rev().map(|b| ((x >> b) & 1) == 1) { if found_one { @@ -212,15 +213,35 @@ pub struct Gt(pub(crate) Fp12); impl Default for Gt { fn default() -> Self { - Self::identity() + Self::IDENTITY } } #[cfg(feature = "zeroize")] impl zeroize::DefaultIsZeroes for Gt {} -impl fmt::Display for Gt { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl LowerHex for Gt { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let bytes = self.to_bytes(); + for &b in bytes.iter() { + write!(f, "{:02x}", b)?; + } + Ok(()) + } +} + +impl UpperHex for Gt { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let bytes = self.to_bytes(); + for &b in bytes.iter() { + write!(f, "{:02X}", b)?; + } + Ok(()) + } +} + +impl Display for Gt { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self) } } @@ -246,15 +267,127 @@ impl PartialEq for Gt { } impl Gt { + /// The group identity, which is $1$. + pub const IDENTITY: Self = Self(Fp12::ONE); + + /// Bytes to represent this field + pub const BYTES: usize = 576; + /// Returns the group identity, which is $1$. pub fn identity() -> Gt { - Gt(Fp12::one()) + Gt(Fp12::ONE) } /// Doubles this group element. pub fn double(&self) -> Gt { Gt(self.0.square()) } + + /// Return the byte representation of this value in big-endian + pub fn to_bytes(&self) -> [u8; Self::BYTES] { + let mut output = [0u8; Self::BYTES]; + output[..48].copy_from_slice(&self.0.c0.c0.c0.to_bytes()); + output[48..96].copy_from_slice(&self.0.c0.c0.c1.to_bytes()); + output[96..144].copy_from_slice(&self.0.c0.c1.c0.to_bytes()); + output[144..192].copy_from_slice(&self.0.c0.c1.c1.to_bytes()); + output[192..240].copy_from_slice(&self.0.c0.c2.c0.to_bytes()); + output[240..288].copy_from_slice(&self.0.c0.c2.c1.to_bytes()); + output[288..336].copy_from_slice(&self.0.c1.c0.c0.to_bytes()); + output[336..384].copy_from_slice(&self.0.c1.c0.c1.to_bytes()); + output[384..432].copy_from_slice(&self.0.c1.c1.c0.to_bytes()); + output[432..480].copy_from_slice(&self.0.c1.c1.c1.to_bytes()); + output[480..528].copy_from_slice(&self.0.c1.c2.c0.to_bytes()); + output[528..Self::BYTES].copy_from_slice(&self.0.c1.c2.c1.to_bytes()); + output + } + + /// Attempts to convert a big-endian byte representation of + /// a scalar into a `Gt`, failing if the input is not canonical. + pub fn from_bytes(bytes: &[u8; Self::BYTES]) -> CtOption { + let c000 = Fp::from_bytes(array_ref![bytes, 0, 48]); + let c001 = Fp::from_bytes(array_ref![bytes, 48, 48]); + let c010 = Fp::from_bytes(array_ref![bytes, 96, 48]); + let c011 = Fp::from_bytes(array_ref![bytes, 144, 48]); + let c020 = Fp::from_bytes(array_ref![bytes, 192, 48]); + let c021 = Fp::from_bytes(array_ref![bytes, 240, 48]); + let c100 = Fp::from_bytes(array_ref![bytes, 288, 48]); + let c101 = Fp::from_bytes(array_ref![bytes, 336, 48]); + let c110 = Fp::from_bytes(array_ref![bytes, 384, 48]); + let c111 = Fp::from_bytes(array_ref![bytes, 432, 48]); + let c120 = Fp::from_bytes(array_ref![bytes, 480, 48]); + let c121 = Fp::from_bytes(array_ref![bytes, 528, 48]); + + c000.and_then(|cc000| { + c001.and_then(|cc001| { + c010.and_then(|cc010| { + c011.and_then(|cc011| { + c020.and_then(|cc020| { + c021.and_then(|cc021| { + c100.and_then(|cc100| { + c101.and_then(|cc101| { + c110.and_then(|cc110| { + c111.and_then(|cc111| { + c120.and_then(|cc120| { + c121.and_then(|cc121| { + CtOption::new( + Gt(Fp12 { + c0: Fp6 { + c0: Fp2 { + c0: cc000, + c1: cc001, + }, + c1: Fp2 { + c0: cc010, + c1: cc011, + }, + c2: Fp2 { + c0: cc020, + c1: cc021, + }, + }, + c1: Fp6 { + c0: Fp2 { + c0: cc100, + c1: cc101, + }, + c1: Fp2 { + c0: cc110, + c1: cc111, + }, + c2: Fp2 { + c0: cc120, + c1: cc121, + }, + }, + }), + Choice::from(1u8), + ) + }) + }) + }) + }) + }) + }) + }) + }) + }) + }) + }) + }) + } + + /// Attempts to convert a big-endian hex representation of + /// a scalar into a `Gt`, failing if the input is not canonical. + pub fn from_hex_be(hex: &str) -> CtOption { + let bytes = hex.as_bytes(); + let mut buf = [0u8; Self::BYTES]; + let mut i = 0; + while i < Self::BYTES { + buf[i] = decode_hex_byte([bytes[i * 2], bytes[i * 2 + 1]]); + i += 1; + } + Self::from_bytes(&buf) + } } impl<'a> Neg for &'a Gt { @@ -298,7 +431,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a Gt { type Output = Gt; fn mul(self, other: &'b Scalar) -> Self::Output { - let mut acc = Gt::identity(); + let mut acc = Gt::IDENTITY; // This is a simple double-and-add implementation of group element // multiplication, moving from most significant to least @@ -307,7 +440,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a Gt { // We skip the leading bit because it's always unset for Fq // elements. for bit in other - .to_bytes() + .to_le_bytes() .iter() .rev() .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8))) @@ -332,7 +465,7 @@ where where I: Iterator, { - iter.fold(Self::identity(), |acc, item| acc + item.borrow()) + iter.fold(Self::IDENTITY, |acc, item| acc + item.borrow()) } } @@ -353,7 +486,7 @@ impl Group for Gt { } fn identity() -> Self { - Self::identity() + Self::IDENTITY } fn generator() -> Self { @@ -475,7 +608,7 @@ impl Group for Gt { } fn is_identity(&self) -> Choice { - self.ct_eq(&Self::identity()) + self.ct_eq(&Self::IDENTITY) } #[must_use] @@ -484,8 +617,45 @@ impl Group for Gt { } } -#[cfg(feature = "alloc")] -#[cfg_attr(docsrs, doc(cfg(all(feature = "pairings", feature = "alloc"))))] +impl GroupEncoding for Gt { + type Repr = GtRepr; + + fn from_bytes(bytes: &Self::Repr) -> CtOption { + Self::from_bytes(&bytes.0) + } + + fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { + Self::from_bytes(&bytes.0) + } + + fn to_bytes(&self) -> Self::Repr { + GtRepr(self.to_bytes()) + } +} + +/// The representation of bytes for GT +#[derive(Copy, Clone, Debug)] +pub struct GtRepr([u8; Gt::BYTES]); + +impl Default for GtRepr { + fn default() -> Self { + Self([0u8; Gt::BYTES]) + } +} + +impl AsRef<[u8]> for GtRepr { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl AsMut<[u8]> for GtRepr { + fn as_mut(&mut self) -> &mut [u8] { + self.0.as_mut() + } +} + +#[cfg_attr(docsrs, doc(cfg(all(feature = "pairings"))))] #[derive(Clone, Debug)] /// This structure contains cached computations pertaining to a $\mathbb{G}_2$ /// element as part of the pairing function (specifically, the Miller loop) and @@ -494,19 +664,18 @@ impl Group for Gt { /// conjunction with the [`multi_miller_loop`](crate::multi_miller_loop) /// function provided by this crate. /// -/// Requires the `alloc` and `pairing` crate features to be enabled. +/// Requires the `pairing` crate features to be enabled. pub struct G2Prepared { infinity: Choice, - coeffs: Vec<(Fp2, Fp2, Fp2)>, + coeffs: PairingCoefficients, } -#[cfg(feature = "alloc")] impl From for G2Prepared { fn from(q: G2Affine) -> G2Prepared { struct Adder { cur: G2Projective, base: G2Affine, - coeffs: Vec<(Fp2, Fp2, Fp2)>, + coeffs: PairingCoefficients, } impl MillerLoopDriver for Adder { @@ -531,12 +700,12 @@ impl From for G2Prepared { let mut adder = Adder { cur: G2Projective::from(q), base: q, - coeffs: Vec::with_capacity(68), + coeffs: PairingCoefficients::default(), }; miller_loop(&mut adder); - assert_eq!(adder.coeffs.len(), 68); + debug_assert_eq!(adder.coeffs.len(), 68); G2Prepared { infinity: is_identity, @@ -545,12 +714,11 @@ impl From for G2Prepared { } } -#[cfg(feature = "alloc")] -#[cfg_attr(docsrs, doc(cfg(all(feature = "pairings", feature = "alloc"))))] +#[cfg_attr(docsrs, doc(cfg(all(feature = "pairings"))))] /// Computes $$\sum_{i=1}^n \textbf{ML}(a_i, b_i)$$ given a series of terms /// $$(a_1, b_1), (a_2, b_2), ..., (a_n, b_n).$$ /// -/// Requires the `alloc` and `pairing` crate features to be enabled. +/// Requires the `pairing` crate features to be enabled. pub fn multi_miller_loop(terms: &[(&G1Affine, &G2Prepared)]) -> MillerLoopResult { struct Adder<'a, 'b, 'c> { terms: &'c [(&'a G1Affine, &'b G2Prepared)], @@ -591,7 +759,7 @@ pub fn multi_miller_loop(terms: &[(&G1Affine, &G2Prepared)]) -> MillerLoopResult f.conjugate() } fn one() -> Self::Output { - Fp12::one() + Fp12::ONE } } @@ -629,7 +797,7 @@ pub fn pairing(p: &G1Affine, q: &G2Affine) -> Gt { f.conjugate() } fn one() -> Self::Output { - Fp12::one() + Fp12::ONE } } @@ -644,11 +812,7 @@ pub fn pairing(p: &G1Affine, q: &G2Affine) -> Gt { }; let tmp = miller_loop(&mut adder); - let tmp = MillerLoopResult(Fp12::conditional_select( - &tmp, - &Fp12::one(), - either_identity, - )); + let tmp = MillerLoopResult(Fp12::conditional_select(&tmp, &Fp12::ONE, either_identity)); tmp.final_exponentiation() } @@ -823,6 +987,40 @@ impl MultiMillerLoop for Bls12 { } } +#[derive(Clone, Debug)] +struct PairingCoefficients { + space: [(Fp2, Fp2, Fp2); 68], + length: usize, +} + +impl Default for PairingCoefficients { + fn default() -> Self { + Self { + space: [(Fp2::ZERO, Fp2::ZERO, Fp2::ZERO); 68], + length: 0, + } + } +} + +impl core::ops::Index for PairingCoefficients { + type Output = (Fp2, Fp2, Fp2); + + fn index(&self, index: usize) -> &Self::Output { + &self.space[index] + } +} + +impl PairingCoefficients { + pub fn push(&mut self, coeffs: (Fp2, Fp2, Fp2)) { + self.space[self.length] = coeffs; + self.length += 1; + } + + pub fn len(&self) -> usize { + self.length + } +} + #[test] fn test_gt_generator() { assert_eq!( @@ -843,7 +1041,7 @@ fn test_bilinearity() { let h = G2Affine::from(G2Affine::generator() * b); let p = pairing(&g, &h); - assert!(p != Gt::identity()); + assert_ne!(p, Gt::IDENTITY); let expected = G1Affine::from(G1Affine::generator() * c); @@ -866,7 +1064,6 @@ fn test_unitary() { assert_eq!(q, r); } -#[cfg(feature = "alloc")] #[test] fn test_multi_miller_loop() { let a1 = G1Affine::generator(); @@ -924,7 +1121,7 @@ fn test_multi_miller_loop() { fn test_miller_loop_result_default() { assert_eq!( MillerLoopResult::default().final_exponentiation(), - Gt::identity(), + Gt::IDENTITY, ); } @@ -945,11 +1142,11 @@ fn test_miller_loop_result_zeroize() { fn tricking_miller_loop_result() { assert_eq!( multi_miller_loop(&[(&G1Affine::identity(), &G2Affine::generator().into())]).0, - Fp12::one() + Fp12::ONE ); assert_eq!( multi_miller_loop(&[(&G1Affine::generator(), &G2Affine::identity().into())]).0, - Fp12::one() + Fp12::ONE ); assert_ne!( multi_miller_loop(&[ @@ -957,7 +1154,7 @@ fn tricking_miller_loop_result() { (&-G1Affine::generator(), &G2Affine::generator().into()) ]) .0, - Fp12::one() + Fp12::ONE ); assert_eq!( multi_miller_loop(&[ @@ -965,6 +1162,14 @@ fn tricking_miller_loop_result() { (&-G1Affine::generator(), &G2Affine::generator().into()) ]) .final_exponentiation(), - Gt::identity() + Gt::IDENTITY ); } +#[test] +fn test_hex() { + let s1 = Gt::generator(); + let hex = format!("{:x}", s1); + let s2 = Gt::from_hex_be(&hex); + assert_eq!(s2.is_some().unwrap_u8(), 1u8); + assert_eq!(s1, s2.unwrap()); +} diff --git a/src/scalar.rs b/src/scalar.rs index 59be5dca..6db0ff8a 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -1,7 +1,7 @@ //! This module provides an implementation of the BLS12-381 scalar field $\mathbb{F}_q$ //! where `q = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001` -use core::fmt; +use core::fmt::{self, Debug, Display, Formatter, LowerHex, UpperHex}; use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use rand_core::RngCore; @@ -11,7 +11,7 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; #[cfg(feature = "bits")] use ff::{FieldBits, PrimeFieldBits}; -use crate::util::{adc, mac, sbb}; +use crate::util::{adc, decode_hex_into_slice, mac, sbb}; /// Represents an element of the scalar field $\mathbb{F}_q$ of the BLS12-381 elliptic /// curve construction. @@ -21,23 +21,43 @@ use crate::util::{adc, mac, sbb}; #[derive(Clone, Copy, Eq)] pub struct Scalar(pub(crate) [u64; 4]); -impl fmt::Debug for Scalar { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let tmp = self.to_bytes(); +impl Debug for Scalar { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let tmp = self.to_be_bytes(); write!(f, "0x")?; - for &b in tmp.iter().rev() { + for &b in &tmp { write!(f, "{:02x}", b)?; } Ok(()) } } -impl fmt::Display for Scalar { +impl Display for Scalar { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?}", self) } } +impl LowerHex for Scalar { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let tmp = self.to_be_bytes(); + for &b in &tmp { + write!(f, "{:02x}", b)?; + } + Ok(()) + } +} + +impl UpperHex for Scalar { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let tmp = self.to_be_bytes(); + for &b in &tmp { + write!(f, "{:02X}", b)?; + } + Ok(()) + } +} + impl From for Scalar { fn from(val: u64) -> Scalar { Scalar([val, 0, 0, 0]) * R2 @@ -224,7 +244,7 @@ const DELTA: Scalar = Scalar([ impl Default for Scalar { #[inline] fn default() -> Self { - Self::zero() + Self::ZERO } } @@ -232,17 +252,12 @@ impl Default for Scalar { impl zeroize::DefaultIsZeroes for Scalar {} impl Scalar { - /// Returns zero, the additive identity. - #[inline] - pub const fn zero() -> Scalar { - Scalar([0, 0, 0, 0]) - } - - /// Returns one, the multiplicative identity. - #[inline] - pub const fn one() -> Scalar { - R - } + /// Bytes to represent this field + pub const BYTES: usize = 32; + /// The additive identity. + pub const ZERO: Scalar = Scalar([0, 0, 0, 0]); + /// The multiplicative identity. + pub const ONE: Scalar = R; /// Doubles this field element. #[inline] @@ -251,9 +266,18 @@ impl Scalar { self.add(self) } + /// Attempts to convert a big-endian byte representation of + /// a scalar into a `Scalar`, failing if the input is not canonical. + pub fn from_be_bytes(bytes: &[u8; 32]) -> CtOption { + let mut tmp = [0u8; 32]; + tmp.copy_from_slice(bytes); + tmp.reverse(); + Self::from_le_bytes(&tmp) + } + /// Attempts to convert a little-endian byte representation of /// a scalar into a `Scalar`, failing if the input is not canonical. - pub fn from_bytes(bytes: &[u8; 32]) -> CtOption { + pub fn from_le_bytes(bytes: &[u8; 32]) -> CtOption { let mut tmp = Scalar([0, 0, 0, 0]); tmp.0[0] = u64::from_le_bytes(<[u8; 8]>::try_from(&bytes[0..8]).unwrap()); @@ -279,9 +303,17 @@ impl Scalar { CtOption::new(tmp, Choice::from(is_some)) } + /// Converts an element of `Scalar` into a byte representation in + /// big-endian byte order. + pub fn to_be_bytes(&self) -> [u8; 32] { + let mut bytes = self.to_le_bytes(); + bytes.reverse(); + bytes + } + /// Converts an element of `Scalar` into a byte representation in /// little-endian byte order. - pub fn to_bytes(&self) -> [u8; 32] { + pub fn to_le_bytes(&self) -> [u8; 32] { // Turn into canonical form by computing // (a.R) / R = a let tmp = Scalar::montgomery_reduce(self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0); @@ -295,6 +327,20 @@ impl Scalar { res } + /// Create a new [`Scalar`] from the provided big endian hex string. + pub fn from_be_hex(hex: &str) -> CtOption { + let mut buf = [0u8; Self::BYTES]; + decode_hex_into_slice(&mut buf, hex.as_bytes()); + Self::from_be_bytes(&buf) + } + + /// Create a new [`Scalar`] from the provided little endian hex string. + pub fn from_le_hex(hex: &str) -> CtOption { + let mut buf = [0u8; Self::BYTES]; + decode_hex_into_slice(&mut buf, hex.as_bytes()); + Self::from_le_bytes(&buf) + } + /// Converts a 512-bit little endian integer into /// a `Scalar` by reducing by the modulus. pub fn from_bytes_wide(bytes: &[u8; 64]) -> Scalar { @@ -310,6 +356,29 @@ impl Scalar { ]) } + /// Read from output of a KDF + pub fn from_okm(bytes: &[u8; 48]) -> Scalar { + const F_2_192: Scalar = Scalar([ + 0x5947_6ebc_41b4_528fu64, + 0xc5a3_0cb2_43fc_c152u64, + 0x2b34_e639_40cc_bd72u64, + 0x1e17_9025_ca24_7088u64, + ]); + let d0 = Scalar([ + u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[16..24]).unwrap()), + u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[8..16]).unwrap()), + u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[0..8]).unwrap()), + 0, + ]); + let d1 = Scalar([ + u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[40..48]).unwrap()), + u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[32..40]).unwrap()), + u64::from_be_bytes(<[u8; 8]>::try_from(&bytes[24..32]).unwrap()), + 0, + ]); + (d0 * R2) * F_2_192 + d1 * R2 + } + fn from_u512(limbs: [u64; 8]) -> Scalar { // We reduce an arbitrary 512-bit number by decomposing it into two 256-bit digits // with the higher bits multiplied by 2^256. Thus, we perform two reductions @@ -371,7 +440,7 @@ impl Scalar { /// Exponentiates `self` by `by`, where `by` is a /// little-endian order integer exponent. pub fn pow(&self, by: &[u64; 4]) -> Self { - let mut res = Self::one(); + let mut res = Self::ONE; for e in by.iter().rev() { for i in (0..64).rev() { res = res.square(); @@ -390,7 +459,7 @@ impl Scalar { /// to the exponent.** If the exponent is fixed, /// this operation is effectively constant time. pub fn pow_vartime(&self, by: &[u64; 4]) -> Self { - let mut res = Self::one(); + let mut res = Self::ONE; for e in by.iter().rev() { for i in (0..64).rev() { res = res.square(); @@ -499,11 +568,11 @@ impl Scalar { square_assign_multi(&mut t0, 5); t0 *= &t1; - CtOption::new(t0, !self.ct_eq(&Self::zero())) + CtOption::new(t0, !self.ct_eq(&Self::ZERO)) } #[inline(always)] - const fn montgomery_reduce( + pub(crate) const fn montgomery_reduce( r0: u64, r1: u64, r2: u64, @@ -629,19 +698,19 @@ impl Scalar { impl From for [u8; 32] { fn from(value: Scalar) -> [u8; 32] { - value.to_bytes() + value.to_le_bytes() } } impl<'a> From<&'a Scalar> for [u8; 32] { fn from(value: &'a Scalar) -> [u8; 32] { - value.to_bytes() + value.to_le_bytes() } } impl Field for Scalar { - const ZERO: Self = Self::zero(); - const ONE: Self = Self::one(); + const ZERO: Self = Self::ZERO; + const ONE: Self = Self::ONE; fn random(mut rng: impl RngCore) -> Self { let mut buf = [0; 64]; @@ -681,7 +750,7 @@ impl Field for Scalar { } fn is_zero_vartime(&self) -> bool { - self.0 == Self::zero().0 + self.0 == Self::ZERO.0 } } @@ -689,15 +758,15 @@ impl PrimeField for Scalar { type Repr = [u8; 32]; fn from_repr(r: Self::Repr) -> CtOption { - Self::from_bytes(&r) + Self::from_le_bytes(&r) } fn to_repr(&self) -> Self::Repr { - self.to_bytes() + self.to_le_bytes() } fn is_odd(&self) -> Choice { - Choice::from(self.to_bytes()[0] & 1) + Choice::from(self.to_le_bytes()[0] & 1) } const MODULUS: &'static str = @@ -723,7 +792,7 @@ impl PrimeFieldBits for Scalar { type ReprBits = ReprBits; fn to_le_bits(&self) -> FieldBits { - let bytes = self.to_bytes(); + let bytes = self.to_le_bytes(); #[cfg(not(target_pointer_width = "64"))] let limbs = [ @@ -767,7 +836,7 @@ where where I: Iterator, { - iter.fold(Self::zero(), |acc, item| acc + item.borrow()) + iter.fold(Self::ZERO, |acc, item| acc + item.borrow()) } } @@ -779,7 +848,7 @@ where where I: Iterator, { - iter.fold(Self::one(), |acc, item| acc * item.borrow()) + iter.fold(Self::ONE, |acc, item| acc * item.borrow()) } } @@ -834,11 +903,11 @@ fn test_inv() { #[test] fn test_debug() { assert_eq!( - format!("{:?}", Scalar::zero()), + format!("{:?}", Scalar::ZERO), "0x0000000000000000000000000000000000000000000000000000000000000000" ); assert_eq!( - format!("{:?}", Scalar::one()), + format!("{:?}", Scalar::ONE), "0x0000000000000000000000000000000000000000000000000000000000000001" ); assert_eq!( @@ -849,18 +918,18 @@ fn test_debug() { #[test] fn test_equality() { - assert_eq!(Scalar::zero(), Scalar::zero()); - assert_eq!(Scalar::one(), Scalar::one()); + assert_eq!(Scalar::ZERO, Scalar::ZERO); + assert_eq!(Scalar::ONE, Scalar::ONE); assert_eq!(R2, R2); - assert!(Scalar::zero() != Scalar::one()); - assert!(Scalar::one() != R2); + assert!(Scalar::ZERO != Scalar::ONE); + assert!(Scalar::ONE != R2); } #[test] fn test_to_bytes() { assert_eq!( - Scalar::zero().to_bytes(), + Scalar::ZERO.to_le_bytes(), [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 @@ -868,7 +937,7 @@ fn test_to_bytes() { ); assert_eq!( - Scalar::one().to_bytes(), + Scalar::ONE.to_le_bytes(), [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 @@ -876,7 +945,7 @@ fn test_to_bytes() { ); assert_eq!( - R2.to_bytes(), + R2.to_le_bytes(), [ 254, 255, 255, 255, 1, 0, 0, 0, 2, 72, 3, 0, 250, 183, 132, 88, 245, 79, 188, 236, 239, 79, 140, 153, 111, 5, 197, 172, 89, 177, 36, 24 @@ -884,7 +953,7 @@ fn test_to_bytes() { ); assert_eq!( - (-&Scalar::one()).to_bytes(), + (-&Scalar::ONE).to_le_bytes(), [ 0, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115 @@ -895,25 +964,25 @@ fn test_to_bytes() { #[test] fn test_from_bytes() { assert_eq!( - Scalar::from_bytes(&[ + Scalar::from_le_bytes(&[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]) .unwrap(), - Scalar::zero() + Scalar::ZERO ); assert_eq!( - Scalar::from_bytes(&[ + Scalar::from_le_bytes(&[ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]) .unwrap(), - Scalar::one() + Scalar::ONE ); assert_eq!( - Scalar::from_bytes(&[ + Scalar::from_le_bytes(&[ 254, 255, 255, 255, 1, 0, 0, 0, 2, 72, 3, 0, 250, 183, 132, 88, 245, 79, 188, 236, 239, 79, 140, 153, 111, 5, 197, 172, 89, 177, 36, 24 ]) @@ -923,7 +992,7 @@ fn test_from_bytes() { // -1 should work assert!(bool::from( - Scalar::from_bytes(&[ + Scalar::from_le_bytes(&[ 0, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115 ]) @@ -932,7 +1001,7 @@ fn test_from_bytes() { // modulus is invalid assert!(bool::from( - Scalar::from_bytes(&[ + Scalar::from_le_bytes(&[ 1, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115 ]) @@ -941,21 +1010,21 @@ fn test_from_bytes() { // Anything larger than the modulus is invalid assert!(bool::from( - Scalar::from_bytes(&[ + Scalar::from_le_bytes(&[ 2, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115 ]) .is_none() )); assert!(bool::from( - Scalar::from_bytes(&[ + Scalar::from_le_bytes(&[ 1, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, 216, 58, 51, 72, 125, 157, 41, 83, 167, 237, 115 ]) .is_none() )); assert!(bool::from( - Scalar::from_bytes(&[ + Scalar::from_le_bytes(&[ 1, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 116 ]) @@ -966,7 +1035,7 @@ fn test_from_bytes() { #[test] fn test_from_u512_zero() { assert_eq!( - Scalar::zero(), + Scalar::ZERO, Scalar::from_u512([ MODULUS.0[0], MODULUS.0[1], @@ -1014,7 +1083,7 @@ fn test_from_bytes_wide_r2() { #[test] fn test_from_bytes_wide_negative_one() { assert_eq!( - -&Scalar::one(), + -&Scalar::ONE, Scalar::from_bytes_wide(&[ 0, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1038,10 +1107,10 @@ fn test_from_bytes_wide_maximum() { #[test] fn test_zero() { - assert_eq!(Scalar::zero(), -&Scalar::zero()); - assert_eq!(Scalar::zero(), Scalar::zero() + Scalar::zero()); - assert_eq!(Scalar::zero(), Scalar::zero() - Scalar::zero()); - assert_eq!(Scalar::zero(), Scalar::zero() * Scalar::zero()); + assert_eq!(Scalar::ZERO, -&Scalar::ZERO); + assert_eq!(Scalar::ZERO, Scalar::ZERO + Scalar::ZERO); + assert_eq!(Scalar::ZERO, Scalar::ZERO - Scalar::ZERO); + assert_eq!(Scalar::ZERO, Scalar::ZERO * Scalar::ZERO); } #[cfg(test)] @@ -1070,7 +1139,7 @@ fn test_addition() { let mut tmp = LARGEST; tmp += &Scalar([1, 0, 0, 0]); - assert_eq!(tmp, Scalar::zero()); + assert_eq!(tmp, Scalar::ZERO); } #[test] @@ -1079,8 +1148,8 @@ fn test_negation() { assert_eq!(tmp, Scalar([1, 0, 0, 0])); - let tmp = -&Scalar::zero(); - assert_eq!(tmp, Scalar::zero()); + let tmp = -&Scalar::ZERO; + assert_eq!(tmp, Scalar::ZERO); let tmp = -&Scalar([1, 0, 0, 0]); assert_eq!(tmp, LARGEST); } @@ -1090,9 +1159,9 @@ fn test_subtraction() { let mut tmp = LARGEST; tmp -= &LARGEST; - assert_eq!(tmp, Scalar::zero()); + assert_eq!(tmp, Scalar::ZERO); - let mut tmp = Scalar::zero(); + let mut tmp = Scalar::ZERO; tmp -= &LARGEST; let mut tmp2 = MODULUS; @@ -1109,9 +1178,9 @@ fn test_multiplication() { let mut tmp = cur; tmp *= &cur; - let mut tmp2 = Scalar::zero(); + let mut tmp2 = Scalar::ZERO; for b in cur - .to_bytes() + .to_le_bytes() .iter() .rev() .flat_map(|byte| (0..8).rev().map(move |i| ((byte >> i) & 1u8) == 1u8)) @@ -1138,9 +1207,9 @@ fn test_squaring() { let mut tmp = cur; tmp = tmp.square(); - let mut tmp2 = Scalar::zero(); + let mut tmp2 = Scalar::ZERO; for b in cur - .to_bytes() + .to_le_bytes() .iter() .rev() .flat_map(|byte| (0..8).rev().map(move |i| ((byte >> i) & 1u8) == 1u8)) @@ -1161,9 +1230,9 @@ fn test_squaring() { #[test] fn test_inversion() { - assert!(bool::from(Scalar::zero().invert().is_none())); - assert_eq!(Scalar::one().invert().unwrap(), Scalar::one()); - assert_eq!((-&Scalar::one()).invert().unwrap(), -&Scalar::one()); + assert!(bool::from(Scalar::ZERO.invert().is_none())); + assert_eq!(Scalar::ONE.invert().unwrap(), Scalar::ONE); + assert_eq!((-&Scalar::ONE).invert().unwrap(), -&Scalar::ONE); let mut tmp = R2; @@ -1171,7 +1240,7 @@ fn test_inversion() { let mut tmp2 = tmp.invert().unwrap(); tmp2.mul_assign(&tmp); - assert_eq!(tmp2, Scalar::one()); + assert_eq!(tmp2, Scalar::ONE); tmp.add_assign(&R2); } @@ -1207,7 +1276,7 @@ fn test_invert_is_pow() { #[test] fn test_sqrt() { { - assert_eq!(Scalar::zero().sqrt().unwrap(), Scalar::zero()); + assert_eq!(Scalar::ZERO.sqrt().unwrap(), Scalar::ZERO); } let mut square = Scalar([ @@ -1226,7 +1295,7 @@ fn test_sqrt() { } else { assert_eq!(square_root.unwrap() * square_root.unwrap(), square); } - square -= Scalar::one(); + square -= Scalar::ONE; } assert_eq!(49, none_count); @@ -1244,7 +1313,7 @@ fn test_from_raw() { Scalar::from_raw([0xffff_ffff_ffff_ffff; 4]) ); - assert_eq!(Scalar::from_raw(MODULUS.0), Scalar::zero()); + assert_eq!(Scalar::from_raw(MODULUS.0), Scalar::ZERO); assert_eq!(Scalar::from_raw([1, 0, 0, 0]), R); } @@ -1261,6 +1330,21 @@ fn test_double() { assert_eq!(a.double(), a + a); } +#[test] +fn test_from_okm() { + let okm = [ + 155, 244, 205, 103, 163, 209, 47, 21, 160, 157, 37, 214, 5, 190, 2, 104, 223, 213, 41, 196, + 96, 200, 48, 201, 176, 145, 160, 209, 98, 168, 107, 154, 167, 197, 41, 218, 168, 132, 185, + 95, 111, 233, 85, 102, 45, 243, 24, 145, + ]; + let expected = [ + 184, 141, 14, 25, 196, 12, 5, 65, 222, 229, 103, 132, 86, 28, 224, 249, 100, 61, 100, 238, + 234, 250, 153, 140, 126, 148, 80, 19, 66, 92, 178, 14, + ]; + let actual = Scalar::from_okm(&okm).to_le_bytes(); + assert_eq!(actual, expected) +} + #[cfg(feature = "zeroize")] #[test] fn test_zeroize() { @@ -1275,3 +1359,18 @@ fn test_zeroize() { a.zeroize(); assert!(bool::from(a.is_zero())); } + +#[test] +fn test_hex() { + let s1 = R2; + let hex = format!("{:x}", s1); + let s2 = Scalar::from_be_hex(&hex); + assert_eq!(s2.is_some().unwrap_u8(), 1u8); + let s2 = s2.unwrap(); + assert_eq!(s1, s2); + let hex = hex::encode(s1.to_le_bytes()); + let s2 = Scalar::from_le_hex(&hex); + assert_eq!(s2.is_some().unwrap_u8(), 1u8); + let s2 = s2.unwrap(); + assert_eq!(s1, s2); +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index e2b9d877..d262ec4a 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -2,7 +2,7 @@ use super::*; macro_rules! test_vectors { ($projective:ident, $affine:ident, $serialize:ident, $deserialize:ident, $expected:ident) => { - let mut e = $projective::identity(); + let mut e = $projective::IDENTITY; let mut v = vec![]; { @@ -19,7 +19,7 @@ macro_rules! test_vectors { let decoded = $affine::$deserialize(&decoded).unwrap(); assert_eq!(e_affine, decoded); - e = &e + &$projective::generator(); + e = &e + &$projective::GENERATOR; } } diff --git a/src/util.rs b/src/util.rs index bd25dd06..6d6e5a6c 100644 --- a/src/util.rs +++ b/src/util.rs @@ -19,6 +19,41 @@ pub const fn mac(a: u64, b: u64, c: u64, carry: u64) -> (u64, u64) { (ret as u64, (ret >> 64) as u64) } +pub fn decode_hex_into_slice(buffer: &mut [u8], bytes: &[u8]) { + debug_assert_eq!(buffer.len(), bytes.len() / 2); + let mut i = 0; + while i < buffer.len() { + buffer[i] = decode_hex_byte([bytes[2 * i], bytes[2 * i + 1]]); + i += 1; + } +} + +/// Decode a single byte encoded as two hexadecimal characters. +pub const fn decode_hex_byte(bytes: [u8; 2]) -> u8 { + let mut i = 0; + let mut result = 0u8; + + while i < 2 { + result <<= 4; + result |= match bytes[i] { + b @ b'0'..=b'9' => b - b'0', + b @ b'a'..=b'f' => 10 + b - b'a', + b @ b'A'..=b'F' => 10 + b - b'A', + b => { + assert!( + matches!(b, b'0'..=b'9' | b'a' ..= b'f' | b'A'..=b'F'), + "invalid hex byte" + ); + 0 + } + }; + + i += 1; + } + + result +} + macro_rules! impl_add_binop_specify_output { ($lhs:ident, $rhs:ident, $output:ident) => { impl<'b> Add<&'b $rhs> for $lhs { @@ -172,3 +207,145 @@ macro_rules! impl_binops_multiplicative { } }; } + +macro_rules! impl_pippenger_sum_of_products { + () => { + /// Use pippenger multi-exponentiation method to compute + /// the sum of multiple points raise to scalars. + /// This uses a fixed window of 4 to be constant time + #[cfg(feature = "alloc")] + pub fn sum_of_products(points: &[Self], scalars: &[Scalar]) -> Self { + use alloc::vec::Vec; + + let ss: Vec = scalars + .iter() + .map(|s| Scalar::montgomery_reduce(s.0[0], s.0[1], s.0[2], s.0[3], 0, 0, 0, 0)) + .collect(); + Self::sum_of_products_pippenger(points, ss.as_slice()) + } + + /// Use pippenger multi-exponentiation method to compute + /// the sum of multiple points raise to scalars. + /// This uses a fixed window of 4 to be constant time + /// The scalars are used as place holders for temporary computations + pub fn sum_of_products_in_place(points: &[Self], scalars: &mut [Scalar]) -> Self { + // Scalars are in montgomery form, hack them in place to be temporarily + // in canonical form, do the computation, then switch them back + for i in 0..scalars.len() { + // Turn into canonical form by computing (a.R) / R = a + scalars[i] = Scalar::montgomery_reduce( + scalars[i].0[0], + scalars[i].0[1], + scalars[i].0[2], + scalars[i].0[3], + 0, + 0, + 0, + 0, + ); + } + + let res = Self::sum_of_products_pippenger(points, scalars); + for i in 0..scalars.len() { + scalars[i] = Scalar::from_raw(scalars[i].0); + } + res + } + + /// Compute pippenger multi-exponentiation. + /// Pippenger relies on scalars in canonical form + /// This uses a fixed window of 4 to be constant time + fn sum_of_products_pippenger(points: &[Self], scalars: &[Scalar]) -> Self { + const WINDOW: usize = 4; + const NUM_BUCKETS: usize = 1 << WINDOW; + const EDGE: usize = WINDOW - 1; + const MASK: u64 = (NUM_BUCKETS - 1) as u64; + + let num_components = core::cmp::min(points.len(), scalars.len()); + let mut buckets = [Self::IDENTITY; NUM_BUCKETS]; + let mut res = Self::IDENTITY; + let mut num_doubles = 0; + let mut bit_sequence_index = 255usize; // point to top bit we need to process + + loop { + for _ in 0..num_doubles { + res = res.double(); + } + + let mut max_bucket = 0; + let word_index = bit_sequence_index >> 6; // divide by 64 to find word_index + let bit_index = bit_sequence_index & 63; // mod by 64 to find bit_index + + if bit_index < EDGE { + // we are on the edge of a word; have to look at the previous word, if it exists + if word_index == 0 { + // there is no word before + let smaller_mask = ((1 << (bit_index + 1)) - 1) as u64; + for i in 0..num_components { + let bucket_index: usize = + (scalars[i].0[word_index] & smaller_mask) as usize; + if bucket_index > 0 { + buckets[bucket_index] += points[i]; + if bucket_index > max_bucket { + max_bucket = bucket_index; + } + } + } + } else { + // there is a word before + let high_order_mask = ((1 << (bit_index + 1)) - 1) as u64; + let high_order_shift = EDGE - bit_index; + let low_order_mask = ((1 << high_order_shift) - 1) as u64; + let low_order_shift = 64 - high_order_shift; + let prev_word_index = word_index - 1; + for i in 0..num_components { + let mut bucket_index = ((scalars[i].0[word_index] & high_order_mask) + << high_order_shift) + as usize; + bucket_index |= ((scalars[i].0[prev_word_index] >> low_order_shift) + & low_order_mask) as usize; + if bucket_index > 0 { + buckets[bucket_index] += points[i]; + if bucket_index > max_bucket { + max_bucket = bucket_index; + } + } + } + } + } else { + let shift = bit_index - EDGE; + for i in 0..num_components { + let bucket_index: usize = + ((scalars[i].0[word_index] >> shift) & MASK) as usize; + assert!(bit_sequence_index != 255 || scalars[i].0[3] >> 63 == 0); + if bucket_index > 0 { + buckets[bucket_index] += points[i]; + if bucket_index > max_bucket { + max_bucket = bucket_index; + } + } + } + } + res += &buckets[max_bucket]; + for i in (1..max_bucket).rev() { + buckets[i] += buckets[i + 1]; + res += buckets[i]; + buckets[i + 1] = Self::IDENTITY; + } + buckets[1] = Self::IDENTITY; + if bit_sequence_index < WINDOW { + break; + } + bit_sequence_index -= WINDOW; + num_doubles = { + if bit_sequence_index < EDGE { + bit_sequence_index + 1 + } else { + WINDOW + } + }; + } + res + } + }; +}