macro_rules! curve_impl { ( $name:expr, $projective:ident, $affine:ident, $prepared:ident, $basefield:ident, $scalarfield:ident, $uncompressed:ident, $compressed:ident, $pairing:ident ) => { #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct $affine { pub(crate) x: $basefield, pub(crate) y: $basefield, pub(crate) infinity: bool, } impl ::std::fmt::Display for $affine { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { if self.infinity { write!(f, "{}(Infinity)", $name) } else { write!(f, "{}(x={}, y={})", $name, self.x, self.y) } } } #[derive(Copy, Clone, Debug, Eq)] pub struct $projective { pub(crate) x: $basefield, pub(crate) y: $basefield, pub(crate) z: $basefield, } impl ::std::fmt::Display for $projective { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(f, "{}", self.into_affine()) } } impl PartialEq for $projective { fn eq(&self, other: &$projective) -> bool { if self.is_zero() { return other.is_zero(); } if other.is_zero() { return false; } // The points (X, Y, Z) and (X', Y', Z') // are equal when (X * Z^2) = (X' * Z'^2) // and (Y * Z^3) = (Y' * Z'^3). let mut z1 = self.z.square(); let mut z2 = other.z.square(); let mut tmp1 = self.x; tmp1.mul_assign(&z2); let mut tmp2 = other.x; tmp2.mul_assign(&z1); if tmp1 != tmp2 { return false; } z1.mul_assign(&self.z); z2.mul_assign(&other.z); z2.mul_assign(&self.y); z1.mul_assign(&other.y); if z1 != z2 { return false; } true } } impl $affine { fn mul_bits_u64>(&self, bits: BitIterator) -> $projective { let mut res = $projective::zero(); for i in bits { res.double(); if i { res.add_assign(self) } } res } fn mul_bits_u8>(&self, bits: BitIterator) -> $projective { let mut res = $projective::zero(); for i in bits { res.double(); if i { res.add_assign(self) } } res } /// Attempts to construct an affine point given an x-coordinate. The /// point is not guaranteed to be in the prime order subgroup. /// /// If and only if `greatest` is set will the lexicographically /// largest y-coordinate be selected. fn get_point_from_x(x: $basefield, greatest: bool) -> CtOption<$affine> { // Compute x^3 + b let mut x3b = x.square(); x3b.mul_assign(&x); x3b.add_assign(&$affine::get_coeff_b()); x3b.sqrt().map(|y| { let negy = y.neg(); $affine { x: x, y: if (y < negy) ^ greatest { y } else { negy }, infinity: false, } }) } fn is_on_curve(&self) -> bool { if self.is_zero() { true } else { // Check that the point is on the curve let y2 = self.y.square(); let mut x3b = self.x.square(); x3b.mul_assign(&self.x); x3b.add_assign(&Self::get_coeff_b()); y2 == x3b } } fn is_in_correct_subgroup_assuming_on_curve(&self) -> bool { self.mul($scalarfield::char()).is_zero() } } impl ::std::ops::Neg for $affine { type Output = Self; #[inline] fn neg(self) -> Self { let mut ret = self; if !ret.is_zero() { ret.y = ret.y.neg(); } ret } } impl CurveAffine for $affine { type Engine = Bls12; type Scalar = $scalarfield; type Base = $basefield; type Projective = $projective; type Uncompressed = $uncompressed; type Compressed = $compressed; fn zero() -> Self { $affine { x: $basefield::zero(), y: $basefield::one(), infinity: true, } } fn one() -> Self { Self::get_generator() } fn is_zero(&self) -> bool { self.infinity } fn mul::Repr>>(&self, by: S) -> $projective { let bits = BitIterator::::new(by.into()); self.mul_bits_u64(bits) } fn into_projective(&self) -> $projective { (*self).into() } } impl PairingCurveAffine for $affine { type Prepared = $prepared; type Pair = $pairing; type PairingResult = Fq12; fn prepare(&self) -> Self::Prepared { $prepared::from_affine(*self) } fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult { self.perform_pairing(other) } } impl ::std::ops::Neg for $projective { type Output = Self; #[inline] fn neg(self) -> Self { let mut ret = self; if !ret.is_zero() { ret.y = ret.y.neg(); } ret } } impl<'r> ::std::ops::Add<&'r $projective> for $projective { type Output = Self; #[inline] fn add(self, other: &Self) -> Self { let mut ret = self; ret.add_assign(other); ret } } impl ::std::ops::Add for $projective { type Output = Self; #[inline] fn add(self, other: Self) -> Self { self + &other } } impl<'r> ::std::ops::AddAssign<&'r $projective> for $projective { fn add_assign(&mut self, other: &Self) { if self.is_zero() { *self = *other; return; } if other.is_zero() { return; } // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl // Z1Z1 = Z1^2 let z1z1 = self.z.square(); // Z2Z2 = Z2^2 let z2z2 = other.z.square(); // U1 = X1*Z2Z2 let mut u1 = self.x; u1.mul_assign(&z2z2); // U2 = X2*Z1Z1 let mut u2 = other.x; u2.mul_assign(&z1z1); // S1 = Y1*Z2*Z2Z2 let mut s1 = self.y; s1.mul_assign(&other.z); s1.mul_assign(&z2z2); // S2 = Y2*Z1*Z1Z1 let mut s2 = other.y; s2.mul_assign(&self.z); s2.mul_assign(&z1z1); if u1 == u2 && s1 == s2 { // The two points are equal, so we double. self.double(); } else { // If we're adding -a and a together, self.z becomes zero as H becomes zero. // H = U2-U1 let mut h = u2; h.sub_assign(&u1); // I = (2*H)^2 let i = h.double().square(); // J = H*I let mut j = h; j.mul_assign(&i); // r = 2*(S2-S1) let mut r = s2; r.sub_assign(&s1); r = r.double(); // V = U1*I let mut v = u1; v.mul_assign(&i); // X3 = r^2 - J - 2*V self.x = r.square(); self.x.sub_assign(&j); self.x.sub_assign(&v); self.x.sub_assign(&v); // Y3 = r*(V - X3) - 2*S1*J self.y = v; self.y.sub_assign(&self.x); self.y.mul_assign(&r); s1.mul_assign(&j); // S1 = S1 * J * 2 s1 = s1.double(); self.y.sub_assign(&s1); // Z3 = ((Z1+Z2)^2 - Z1Z1 - Z2Z2)*H self.z.add_assign(&other.z); self.z = self.z.square(); self.z.sub_assign(&z1z1); self.z.sub_assign(&z2z2); self.z.mul_assign(&h); } } } impl ::std::ops::AddAssign for $projective { #[inline] fn add_assign(&mut self, other: Self) { self.add_assign(&other); } } impl<'r> ::std::ops::Sub<&'r $projective> for $projective { type Output = Self; #[inline] fn sub(self, other: &Self) -> Self { let mut ret = self; ret.sub_assign(other); ret } } impl ::std::ops::Sub for $projective { type Output = Self; #[inline] fn sub(self, other: Self) -> Self { self - &other } } impl<'r> ::std::ops::SubAssign<&'r $projective> for $projective { fn sub_assign(&mut self, other: &Self) { self.add_assign(&other.neg()); } } impl ::std::ops::SubAssign for $projective { #[inline] fn sub_assign(&mut self, other: Self) { self.sub_assign(&other); } } impl<'r> ::std::ops::Add<&'r <$projective as CurveProjective>::Affine> for $projective { type Output = Self; #[inline] fn add(self, other: &<$projective as CurveProjective>::Affine) -> Self { let mut ret = self; ret.add_assign(other); ret } } impl ::std::ops::Add<<$projective as CurveProjective>::Affine> for $projective { type Output = Self; #[inline] fn add(self, other: <$projective as CurveProjective>::Affine) -> Self { self + &other } } impl<'r> ::std::ops::AddAssign<&'r <$projective as CurveProjective>::Affine> for $projective { fn add_assign(&mut self, other: &<$projective as CurveProjective>::Affine) { if other.is_zero() { return; } if self.is_zero() { self.x = other.x; self.y = other.y; self.z = $basefield::one(); return; } // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl // Z1Z1 = Z1^2 let z1z1 = self.z.square(); // U2 = X2*Z1Z1 let mut u2 = other.x; u2.mul_assign(&z1z1); // S2 = Y2*Z1*Z1Z1 let mut s2 = other.y; s2.mul_assign(&self.z); s2.mul_assign(&z1z1); if self.x == u2 && self.y == s2 { // The two points are equal, so we double. self.double(); } else { // If we're adding -a and a together, self.z becomes zero as H becomes zero. // H = U2-X1 let mut h = u2; h.sub_assign(&self.x); // HH = H^2 let hh = h.square(); // I = 4*HH let i = hh.double().double(); // J = H*I let mut j = h; j.mul_assign(&i); // r = 2*(S2-Y1) let mut r = s2; r.sub_assign(&self.y); r = r.double(); // V = X1*I let mut v = self.x; v.mul_assign(&i); // X3 = r^2 - J - 2*V self.x = r.square(); self.x.sub_assign(&j); self.x.sub_assign(&v); self.x.sub_assign(&v); // Y3 = r*(V-X3)-2*Y1*J j.mul_assign(&self.y); // J = 2*Y1*J j = j.double(); self.y = v; self.y.sub_assign(&self.x); self.y.mul_assign(&r); self.y.sub_assign(&j); // Z3 = (Z1+H)^2-Z1Z1-HH self.z.add_assign(&h); self.z = self.z.square(); self.z.sub_assign(&z1z1); self.z.sub_assign(&hh); } } } impl ::std::ops::AddAssign<<$projective as CurveProjective>::Affine> for $projective { #[inline] fn add_assign(&mut self, other: <$projective as CurveProjective>::Affine) { self.add_assign(&other); } } impl<'r> ::std::ops::Sub<&'r <$projective as CurveProjective>::Affine> for $projective { type Output = Self; #[inline] fn sub(self, other: &<$projective as CurveProjective>::Affine) -> Self { let mut ret = self; ret.sub_assign(other); ret } } impl ::std::ops::Sub<<$projective as CurveProjective>::Affine> for $projective { type Output = Self; #[inline] fn sub(self, other: <$projective as CurveProjective>::Affine) -> Self { self - &other } } impl<'r> ::std::ops::SubAssign<&'r <$projective as CurveProjective>::Affine> for $projective { fn sub_assign(&mut self, other: &<$projective as CurveProjective>::Affine) { self.add_assign(&other.neg()); } } impl ::std::ops::SubAssign<<$projective as CurveProjective>::Affine> for $projective { #[inline] fn sub_assign(&mut self, other: <$projective as CurveProjective>::Affine) { self.sub_assign(&other); } } impl CurveProjective for $projective { type Engine = Bls12; type Scalar = $scalarfield; type Base = $basefield; type Affine = $affine; fn random(rng: &mut R) -> Self { loop { let x = $basefield::random(rng); let greatest = rng.next_u32() % 2 != 0; let p = $affine::get_point_from_x(x, greatest); if p.is_some().into() { let p = p.unwrap().scale_by_cofactor(); if !p.is_zero() { return p; } } } } // The point at infinity is always represented by // Z = 0. fn zero() -> Self { $projective { x: $basefield::zero(), y: $basefield::one(), z: $basefield::zero(), } } fn one() -> Self { $affine::one().into() } // The point at infinity is always represented by // Z = 0. fn is_zero(&self) -> bool { self.z.is_zero() } fn is_normalized(&self) -> bool { self.is_zero() || self.z == $basefield::one() } fn batch_normalization(v: &mut [Self]) { // Montgomery’s Trick and Fast Implementation of Masked AES // Genelle, Prouff and Quisquater // Section 3.2 // First pass: compute [a, ab, abc, ...] let mut prod = Vec::with_capacity(v.len()); let mut tmp = $basefield::one(); for g in v .iter_mut() // Ignore normalized elements .filter(|g| !g.is_normalized()) { tmp.mul_assign(&g.z); prod.push(tmp); } // Invert `tmp`. tmp = tmp.invert().unwrap(); // Guaranteed to be nonzero. // Second pass: iterate backwards to compute inverses for (g, s) in v .iter_mut() // Backwards .rev() // Ignore normalized elements .filter(|g| !g.is_normalized()) // Backwards, skip last element, fill in one for last term. .zip( prod.into_iter() .rev() .skip(1) .chain(Some($basefield::one())), ) { // tmp := tmp * g.z; g.z := tmp * s = 1/z let mut newtmp = tmp; newtmp.mul_assign(&g.z); g.z = tmp; g.z.mul_assign(&s); tmp = newtmp; } // Perform affine transformations for g in v.iter_mut().filter(|g| !g.is_normalized()) { let mut z = g.z.square(); // 1/z^2 g.x.mul_assign(&z); // x/z^2 z.mul_assign(&g.z); // 1/z^3 g.y.mul_assign(&z); // y/z^3 g.z = $basefield::one(); // z = 1 } } fn double(&mut self) { if self.is_zero() { return; } // Other than the point at infinity, no points on E or E' // can double to equal the point at infinity, as y=0 is // never true for points on the curve. (-4 and -4u-4 // are not cubic residue in their respective fields.) // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l // A = X1^2 let a = self.x.square(); // B = Y1^2 let b = self.y.square(); // C = B^2 let mut c = b.square(); // D = 2*((X1+B)2-A-C) let mut d = self.x; d.add_assign(&b); d = d.square(); d.sub_assign(&a); d.sub_assign(&c); d = d.double(); // E = 3*A let mut e = a.double(); e.add_assign(&a); // F = E^2 let f = e.square(); // Z3 = 2*Y1*Z1 self.z.mul_assign(&self.y); self.z = self.z.double(); // X3 = F-2*D self.x = f; self.x.sub_assign(&d); self.x.sub_assign(&d); // Y3 = E*(D-X3)-8*C self.y = d; self.y.sub_assign(&self.x); self.y.mul_assign(&e); c = c.double().double().double(); self.y.sub_assign(&c); } fn mul_assign::Repr>>(&mut self, other: S) { let mut res = Self::zero(); let mut found_one = false; for i in BitIterator::::new(other.into()) { if found_one { res.double(); } else { found_one = i; } if i { res.add_assign(&*self); } } *self = res; } fn into_affine(&self) -> $affine { (*self).into() } fn recommended_wnaf_for_scalar(scalar: &::Repr) -> usize { Self::empirical_recommended_wnaf_for_scalar(scalar) } fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize { Self::empirical_recommended_wnaf_for_num_scalars(num_scalars) } } // The affine point X, Y is represented in the jacobian // coordinates with Z = 1. impl From<$affine> for $projective { fn from(p: $affine) -> $projective { if p.is_zero() { $projective::zero() } else { $projective { x: p.x, y: p.y, z: $basefield::one(), } } } } // The projective point X, Y, Z is represented in the affine // coordinates as X/Z^2, Y/Z^3. impl From<$projective> for $affine { fn from(p: $projective) -> $affine { if p.is_zero() { $affine::zero() } else if p.z == $basefield::one() { // If Z is one, the point is already normalized. $affine { x: p.x, y: p.y, infinity: false, } } else { // Z is nonzero, so it must have an inverse in a field. let zinv = p.z.invert().unwrap(); let mut zinv_powered = zinv.square(); // X/Z^2 let mut x = p.x; x.mul_assign(&zinv_powered); // Y/Z^3 let mut y = p.y; zinv_powered.mul_assign(&zinv); y.mul_assign(&zinv_powered); $affine { x: x, y: y, infinity: false, } } } } }; } pub mod g1 { use super::super::{Bls12, Fq, Fq12, FqRepr, Fr, FrRepr}; use super::g2::G2Affine; use crate::{Engine, PairingCurveAffine}; use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use rand_core::RngCore; use std::fmt; use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; use subtle::CtOption; curve_impl!( "G1", G1, G1Affine, G1Prepared, Fq, Fr, G1Uncompressed, G1Compressed, G2Affine ); #[derive(Copy, Clone)] pub struct G1Uncompressed([u8; 96]); impl AsRef<[u8]> for G1Uncompressed { fn as_ref(&self) -> &[u8] { &self.0 } } impl AsMut<[u8]> for G1Uncompressed { fn as_mut(&mut self) -> &mut [u8] { &mut self.0 } } impl fmt::Debug for G1Uncompressed { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { self.0[..].fmt(formatter) } } impl EncodedPoint for G1Uncompressed { type Affine = G1Affine; fn empty() -> Self { G1Uncompressed([0; 96]) } fn size() -> usize { 96 } fn into_affine(&self) -> Result { let affine = self.into_affine_unchecked()?; if !affine.is_on_curve() { Err(GroupDecodingError::NotOnCurve) } else if !affine.is_in_correct_subgroup_assuming_on_curve() { Err(GroupDecodingError::NotInSubgroup) } else { Ok(affine) } } fn into_affine_unchecked(&self) -> Result { // Create a copy of this representation. let mut copy = self.0; if copy[0] & (1 << 7) != 0 { // Distinguisher bit is set, but this should be uncompressed! return Err(GroupDecodingError::UnexpectedCompressionMode); } if copy[0] & (1 << 6) != 0 { // This is the point at infinity, which means that if we mask away // the first two bits, the entire representation should consist // of zeroes. copy[0] &= 0x3f; if copy.iter().all(|b| *b == 0) { Ok(G1Affine::zero()) } else { Err(GroupDecodingError::UnexpectedInformation) } } else { if copy[0] & (1 << 5) != 0 { // The bit indicating the y-coordinate should be lexicographically // largest is set, but this is an uncompressed element. return Err(GroupDecodingError::UnexpectedInformation); } // Unset the three most significant bits. copy[0] &= 0x1f; let mut x = FqRepr([0; 6]); let mut y = FqRepr([0; 6]); { let mut reader = ©[..]; x.read_be(&mut reader).unwrap(); y.read_be(&mut reader).unwrap(); } Ok(G1Affine { x: Fq::from_repr(x).map_err(|e| { GroupDecodingError::CoordinateDecodingError("x coordinate", e) })?, y: Fq::from_repr(y).map_err(|e| { GroupDecodingError::CoordinateDecodingError("y coordinate", e) })?, infinity: false, }) } } fn from_affine(affine: G1Affine) -> Self { let mut res = Self::empty(); if affine.is_zero() { // Set the second-most significant bit to indicate this point // is at infinity. res.0[0] |= 1 << 6; } else { let mut writer = &mut res.0[..]; affine.x.into_repr().write_be(&mut writer).unwrap(); affine.y.into_repr().write_be(&mut writer).unwrap(); } res } } #[derive(Copy, Clone)] pub struct G1Compressed([u8; 48]); impl AsRef<[u8]> for G1Compressed { fn as_ref(&self) -> &[u8] { &self.0 } } impl AsMut<[u8]> for G1Compressed { fn as_mut(&mut self) -> &mut [u8] { &mut self.0 } } impl fmt::Debug for G1Compressed { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { self.0[..].fmt(formatter) } } impl EncodedPoint for G1Compressed { type Affine = G1Affine; fn empty() -> Self { G1Compressed([0; 48]) } fn size() -> usize { 48 } fn into_affine(&self) -> Result { let affine = self.into_affine_unchecked()?; // NB: Decompression guarantees that it is on the curve already. if !affine.is_in_correct_subgroup_assuming_on_curve() { Err(GroupDecodingError::NotInSubgroup) } else { Ok(affine) } } fn into_affine_unchecked(&self) -> Result { // Create a copy of this representation. let mut copy = self.0; if copy[0] & (1 << 7) == 0 { // Distinguisher bit isn't set. return Err(GroupDecodingError::UnexpectedCompressionMode); } if copy[0] & (1 << 6) != 0 { // This is the point at infinity, which means that if we mask away // the first two bits, the entire representation should consist // of zeroes. copy[0] &= 0x3f; if copy.iter().all(|b| *b == 0) { Ok(G1Affine::zero()) } else { Err(GroupDecodingError::UnexpectedInformation) } } else { // Determine if the intended y coordinate must be greater // lexicographically. let greatest = copy[0] & (1 << 5) != 0; // Unset the three most significant bits. copy[0] &= 0x1f; let mut x = FqRepr([0; 6]); { let mut reader = ©[..]; x.read_be(&mut reader).unwrap(); } // Interpret as Fq element. let x = Fq::from_repr(x) .map_err(|e| GroupDecodingError::CoordinateDecodingError("x coordinate", e))?; let ret = G1Affine::get_point_from_x(x, greatest); if ret.is_some().into() { Ok(ret.unwrap()) } else { Err(GroupDecodingError::NotOnCurve) } } } fn from_affine(affine: G1Affine) -> Self { let mut res = Self::empty(); if affine.is_zero() { // Set the second-most significant bit to indicate this point // is at infinity. res.0[0] |= 1 << 6; } else { { let mut writer = &mut res.0[..]; affine.x.into_repr().write_be(&mut writer).unwrap(); } let negy = affine.y.neg(); // Set the third most significant bit if the correct y-coordinate // is lexicographically largest. if affine.y > negy { res.0[0] |= 1 << 5; } } // Set highest bit to distinguish this as a compressed element. res.0[0] |= 1 << 7; res } } impl G1Affine { fn scale_by_cofactor(&self) -> G1 { // G1 cofactor = (x - 1)^2 / 3 = 76329603384216526031706109802092473003 let cofactor = BitIterator::::new([0x8c00aaab0000aaab, 0x396c8c005555e156]); self.mul_bits_u64(cofactor) } fn get_generator() -> Self { G1Affine { x: super::super::fq::G1_GENERATOR_X, y: super::super::fq::G1_GENERATOR_Y, infinity: false, } } fn get_coeff_b() -> Fq { super::super::fq::B_COEFF } fn perform_pairing(&self, other: &G2Affine) -> Fq12 { super::super::Bls12::pairing(*self, *other) } } impl G1 { fn empirical_recommended_wnaf_for_scalar(scalar: &FrRepr) -> usize { let num_bits = scalar.num_bits() as usize; if num_bits >= 130 { 4 } else if num_bits >= 34 { 3 } else { 2 } } fn empirical_recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize { const RECOMMENDATIONS: [usize; 12] = [1, 3, 7, 20, 43, 120, 273, 563, 1630, 3128, 7933, 62569]; let mut ret = 4; for r in &RECOMMENDATIONS { if num_scalars > *r { ret += 1; } else { break; } } ret } } #[derive(Clone, Debug)] pub struct G1Prepared(pub(crate) G1Affine); impl G1Prepared { pub fn is_zero(&self) -> bool { self.0.is_zero() } pub fn from_affine(p: G1Affine) -> Self { G1Prepared(p) } } #[test] fn g1_generator() { use crate::SqrtField; let mut x = Fq::zero(); let mut i = 0; loop { // y^2 = x^3 + b let mut rhs = x.square(); rhs.mul_assign(&x); rhs.add_assign(&G1Affine::get_coeff_b()); let y = rhs.sqrt(); if y.is_some().into() { let y = y.unwrap(); let yrepr = y.into_repr(); let negy = y.neg(); let negyrepr = negy.into_repr(); let p = G1Affine { x, y: if yrepr < negyrepr { y } else { negy }, infinity: false, }; assert!(!p.is_in_correct_subgroup_assuming_on_curve()); let g1 = p.scale_by_cofactor(); if !g1.is_zero() { assert_eq!(i, 4); let g1 = G1Affine::from(g1); assert!(g1.is_in_correct_subgroup_assuming_on_curve()); assert_eq!(g1, G1Affine::one()); break; } } i += 1; x.add_assign(&Fq::one()); } } #[test] fn g1_test_is_valid() { // Reject point on isomorphic twist (b = 24) { let p = G1Affine { x: Fq::from_repr(FqRepr([ 0xc58d887b66c035dc, 0x10cbfd301d553822, 0xaf23e064f1131ee5, 0x9fe83b1b4a5d648d, 0xf583cc5a508f6a40, 0xc3ad2aefde0bb13, ])) .unwrap(), y: Fq::from_repr(FqRepr([ 0x60aa6f9552f03aae, 0xecd01d5181300d35, 0x8af1cdb8aa8ce167, 0xe760f57922998c9d, 0x953703f5795a39e5, 0xfe3ae0922df702c, ])) .unwrap(), infinity: false, }; assert!(!p.is_on_curve()); assert!(p.is_in_correct_subgroup_assuming_on_curve()); } // Reject point on a twist (b = 3) { let p = G1Affine { x: Fq::from_repr(FqRepr([ 0xee6adf83511e15f5, 0x92ddd328f27a4ba6, 0xe305bd1ac65adba7, 0xea034ee2928b30a8, 0xbd8833dc7c79a7f7, 0xe45c9f0c0438675, ])) .unwrap(), y: Fq::from_repr(FqRepr([ 0x3b450eb1ab7b5dad, 0xa65cb81e975e8675, 0xaa548682b21726e5, 0x753ddf21a2601d20, 0x532d0b640bd3ff8b, 0x118d2c543f031102, ])) .unwrap(), infinity: false, }; assert!(!p.is_on_curve()); assert!(!p.is_in_correct_subgroup_assuming_on_curve()); } // Reject point in an invalid subgroup // There is only one r-order subgroup, as r does not divide the cofactor. { let p = G1Affine { x: Fq::from_repr(FqRepr([ 0x76e1c971c6db8fe8, 0xe37e1a610eff2f79, 0x88ae9c499f46f0c0, 0xf35de9ce0d6b4e84, 0x265bddd23d1dec54, 0x12a8778088458308, ])) .unwrap(), y: Fq::from_repr(FqRepr([ 0x8a22defa0d526256, 0xc57ca55456fcb9ae, 0x1ba194e89bab2610, 0x921beef89d4f29df, 0x5b6fda44ad85fa78, 0xed74ab9f302cbe0, ])) .unwrap(), infinity: false, }; assert!(p.is_on_curve()); assert!(!p.is_in_correct_subgroup_assuming_on_curve()); } } #[test] fn test_g1_addition_correctness() { let mut p = G1 { x: Fq::from_repr(FqRepr([ 0x47fd1f891d6e8bbf, 0x79a3b0448f31a2aa, 0x81f3339e5f9968f, 0x485e77d50a5df10d, 0x4c6fcac4b55fd479, 0x86ed4d9906fb064, ])) .unwrap(), y: Fq::from_repr(FqRepr([ 0xd25ee6461538c65, 0x9f3bbb2ecd3719b9, 0xa06fd3f1e540910d, 0xcefca68333c35288, 0x570c8005f8573fa6, 0x152ca696fe034442, ])) .unwrap(), z: Fq::one(), }; p.add_assign(&G1 { x: Fq::from_repr(FqRepr([ 0xeec78f3096213cbf, 0xa12beb1fea1056e6, 0xc286c0211c40dd54, 0x5f44314ec5e3fb03, 0x24e8538737c6e675, 0x8abd623a594fba8, ])) .unwrap(), y: Fq::from_repr(FqRepr([ 0x6b0528f088bb7044, 0x2fdeb5c82917ff9e, 0x9a5181f2fac226ad, 0xd65104c6f95a872a, 0x1f2998a5a9c61253, 0xe74846154a9e44, ])) .unwrap(), z: Fq::one(), }); let p = G1Affine::from(p); assert_eq!( p, G1Affine { x: Fq::from_repr(FqRepr([ 0x6dd3098f22235df, 0xe865d221c8090260, 0xeb96bb99fa50779f, 0xc4f9a52a428e23bb, 0xd178b28dd4f407ef, 0x17fb8905e9183c69 ])) .unwrap(), y: Fq::from_repr(FqRepr([ 0xd0de9d65292b7710, 0xf6a05f2bcf1d9ca7, 0x1040e27012f20b64, 0xeec8d1a5b7466c58, 0x4bc362649dce6376, 0x430cbdc5455b00a ])) .unwrap(), infinity: false, } ); } #[test] fn test_g1_doubling_correctness() { let mut p = G1 { x: Fq::from_repr(FqRepr([ 0x47fd1f891d6e8bbf, 0x79a3b0448f31a2aa, 0x81f3339e5f9968f, 0x485e77d50a5df10d, 0x4c6fcac4b55fd479, 0x86ed4d9906fb064, ])) .unwrap(), y: Fq::from_repr(FqRepr([ 0xd25ee6461538c65, 0x9f3bbb2ecd3719b9, 0xa06fd3f1e540910d, 0xcefca68333c35288, 0x570c8005f8573fa6, 0x152ca696fe034442, ])) .unwrap(), z: Fq::one(), }; p.double(); let p = G1Affine::from(p); assert_eq!( p, G1Affine { x: Fq::from_repr(FqRepr([ 0xf939ddfe0ead7018, 0x3b03942e732aecb, 0xce0e9c38fdb11851, 0x4b914c16687dcde0, 0x66c8baf177d20533, 0xaf960cff3d83833 ])) .unwrap(), y: Fq::from_repr(FqRepr([ 0x3f0675695f5177a8, 0x2b6d82ae178a1ba0, 0x9096380dd8e51b11, 0x1771a65b60572f4e, 0x8b547c1313b27555, 0x135075589a687b1e ])) .unwrap(), infinity: false, } ); } #[test] fn test_g1_same_y() { // Test the addition of two points with different x coordinates // but the same y coordinate. // x1 = 128100205326445210408953809171070606737678357140298133325128175840781723996595026100005714405541449960643523234125 // x2 = 3821408151224848222394078037104966877485040835569514006839342061575586899845797797516352881516922679872117658572470 // y = 2291134451313223670499022936083127939567618746216464377735567679979105510603740918204953301371880765657042046687078 let a = G1Affine { x: Fq::from_repr(FqRepr([ 0xea431f2cc38fc94d, 0x3ad2354a07f5472b, 0xfe669f133f16c26a, 0x71ffa8021531705, 0x7418d484386d267, 0xd5108d8ff1fbd6, ])) .unwrap(), y: Fq::from_repr(FqRepr([ 0xa776ccbfe9981766, 0x255632964ff40f4a, 0xc09744e650b00499, 0x520f74773e74c8c3, 0x484c8fc982008f0, 0xee2c3d922008cc6, ])) .unwrap(), infinity: false, }; let b = G1Affine { x: Fq::from_repr(FqRepr([ 0xe06cdb156b6356b6, 0xd9040b2d75448ad9, 0xe702f14bb0e2aca5, 0xc6e05201e5f83991, 0xf7c75910816f207c, 0x18d4043e78103106, ])) .unwrap(), y: Fq::from_repr(FqRepr([ 0xa776ccbfe9981766, 0x255632964ff40f4a, 0xc09744e650b00499, 0x520f74773e74c8c3, 0x484c8fc982008f0, 0xee2c3d922008cc6, ])) .unwrap(), infinity: false, }; // Expected // x = 52901198670373960614757979459866672334163627229195745167587898707663026648445040826329033206551534205133090753192 // y = 1711275103908443722918766889652776216989264073722543507596490456144926139887096946237734327757134898380852225872709 let c = G1Affine { x: Fq::from_repr(FqRepr([ 0xef4f05bdd10c8aa8, 0xad5bf87341a2df9, 0x81c7424206b78714, 0x9676ff02ec39c227, 0x4c12c15d7e55b9f3, 0x57fd1e317db9bd, ])) .unwrap(), y: Fq::from_repr(FqRepr([ 0x1288334016679345, 0xf955cd68615ff0b5, 0xa6998dbaa600f18a, 0x1267d70db51049fb, 0x4696deb9ab2ba3e7, 0xb1e4e11177f59d4, ])) .unwrap(), infinity: false, }; assert!(a.is_on_curve() && a.is_in_correct_subgroup_assuming_on_curve()); assert!(b.is_on_curve() && b.is_in_correct_subgroup_assuming_on_curve()); assert!(c.is_on_curve() && c.is_in_correct_subgroup_assuming_on_curve()); let mut tmp1 = a.into_projective(); tmp1.add_assign(&b.into_projective()); assert_eq!(tmp1.into_affine(), c); assert_eq!(tmp1, c.into_projective()); let mut tmp2 = a.into_projective(); tmp2.add_assign(&b); assert_eq!(tmp2.into_affine(), c); assert_eq!(tmp2, c.into_projective()); } #[test] fn g1_curve_tests() { use group::tests::curve_tests; curve_tests::(); } } pub mod g2 { use super::super::{Bls12, Fq, Fq12, Fq2, FqRepr, Fr, FrRepr}; use super::g1::G1Affine; use crate::{Engine, PairingCurveAffine}; use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField}; use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError}; use rand_core::RngCore; use std::fmt; use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; use subtle::CtOption; curve_impl!( "G2", G2, G2Affine, G2Prepared, Fq2, Fr, G2Uncompressed, G2Compressed, G1Affine ); #[derive(Copy, Clone)] pub struct G2Uncompressed([u8; 192]); impl AsRef<[u8]> for G2Uncompressed { fn as_ref(&self) -> &[u8] { &self.0 } } impl AsMut<[u8]> for G2Uncompressed { fn as_mut(&mut self) -> &mut [u8] { &mut self.0 } } impl fmt::Debug for G2Uncompressed { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { self.0[..].fmt(formatter) } } impl EncodedPoint for G2Uncompressed { type Affine = G2Affine; fn empty() -> Self { G2Uncompressed([0; 192]) } fn size() -> usize { 192 } fn into_affine(&self) -> Result { let affine = self.into_affine_unchecked()?; if !affine.is_on_curve() { Err(GroupDecodingError::NotOnCurve) } else if !affine.is_in_correct_subgroup_assuming_on_curve() { Err(GroupDecodingError::NotInSubgroup) } else { Ok(affine) } } fn into_affine_unchecked(&self) -> Result { // Create a copy of this representation. let mut copy = self.0; if copy[0] & (1 << 7) != 0 { // Distinguisher bit is set, but this should be uncompressed! return Err(GroupDecodingError::UnexpectedCompressionMode); } if copy[0] & (1 << 6) != 0 { // This is the point at infinity, which means that if we mask away // the first two bits, the entire representation should consist // of zeroes. copy[0] &= 0x3f; if copy.iter().all(|b| *b == 0) { Ok(G2Affine::zero()) } else { Err(GroupDecodingError::UnexpectedInformation) } } else { if copy[0] & (1 << 5) != 0 { // The bit indicating the y-coordinate should be lexicographically // largest is set, but this is an uncompressed element. return Err(GroupDecodingError::UnexpectedInformation); } // Unset the three most significant bits. copy[0] &= 0x1f; let mut x_c0 = FqRepr([0; 6]); let mut x_c1 = FqRepr([0; 6]); let mut y_c0 = FqRepr([0; 6]); let mut y_c1 = FqRepr([0; 6]); { let mut reader = ©[..]; x_c1.read_be(&mut reader).unwrap(); x_c0.read_be(&mut reader).unwrap(); y_c1.read_be(&mut reader).unwrap(); y_c0.read_be(&mut reader).unwrap(); } Ok(G2Affine { x: Fq2 { c0: Fq::from_repr(x_c0).map_err(|e| { GroupDecodingError::CoordinateDecodingError("x coordinate (c0)", e) })?, c1: Fq::from_repr(x_c1).map_err(|e| { GroupDecodingError::CoordinateDecodingError("x coordinate (c1)", e) })?, }, y: Fq2 { c0: Fq::from_repr(y_c0).map_err(|e| { GroupDecodingError::CoordinateDecodingError("y coordinate (c0)", e) })?, c1: Fq::from_repr(y_c1).map_err(|e| { GroupDecodingError::CoordinateDecodingError("y coordinate (c1)", e) })?, }, infinity: false, }) } } fn from_affine(affine: G2Affine) -> Self { let mut res = Self::empty(); if affine.is_zero() { // Set the second-most significant bit to indicate this point // is at infinity. res.0[0] |= 1 << 6; } else { let mut writer = &mut res.0[..]; affine.x.c1.into_repr().write_be(&mut writer).unwrap(); affine.x.c0.into_repr().write_be(&mut writer).unwrap(); affine.y.c1.into_repr().write_be(&mut writer).unwrap(); affine.y.c0.into_repr().write_be(&mut writer).unwrap(); } res } } #[derive(Copy, Clone)] pub struct G2Compressed([u8; 96]); impl AsRef<[u8]> for G2Compressed { fn as_ref(&self) -> &[u8] { &self.0 } } impl AsMut<[u8]> for G2Compressed { fn as_mut(&mut self) -> &mut [u8] { &mut self.0 } } impl fmt::Debug for G2Compressed { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { self.0[..].fmt(formatter) } } impl EncodedPoint for G2Compressed { type Affine = G2Affine; fn empty() -> Self { G2Compressed([0; 96]) } fn size() -> usize { 96 } fn into_affine(&self) -> Result { let affine = self.into_affine_unchecked()?; // NB: Decompression guarantees that it is on the curve already. if !affine.is_in_correct_subgroup_assuming_on_curve() { Err(GroupDecodingError::NotInSubgroup) } else { Ok(affine) } } fn into_affine_unchecked(&self) -> Result { // Create a copy of this representation. let mut copy = self.0; if copy[0] & (1 << 7) == 0 { // Distinguisher bit isn't set. return Err(GroupDecodingError::UnexpectedCompressionMode); } if copy[0] & (1 << 6) != 0 { // This is the point at infinity, which means that if we mask away // the first two bits, the entire representation should consist // of zeroes. copy[0] &= 0x3f; if copy.iter().all(|b| *b == 0) { Ok(G2Affine::zero()) } else { Err(GroupDecodingError::UnexpectedInformation) } } else { // Determine if the intended y coordinate must be greater // lexicographically. let greatest = copy[0] & (1 << 5) != 0; // Unset the three most significant bits. copy[0] &= 0x1f; let mut x_c1 = FqRepr([0; 6]); let mut x_c0 = FqRepr([0; 6]); { let mut reader = ©[..]; x_c1.read_be(&mut reader).unwrap(); x_c0.read_be(&mut reader).unwrap(); } // Interpret as Fq element. let x = Fq2 { c0: Fq::from_repr(x_c0).map_err(|e| { GroupDecodingError::CoordinateDecodingError("x coordinate (c0)", e) })?, c1: Fq::from_repr(x_c1).map_err(|e| { GroupDecodingError::CoordinateDecodingError("x coordinate (c1)", e) })?, }; let ret = G2Affine::get_point_from_x(x, greatest); if ret.is_some().into() { Ok(ret.unwrap()) } else { Err(GroupDecodingError::NotOnCurve) } } } fn from_affine(affine: G2Affine) -> Self { let mut res = Self::empty(); if affine.is_zero() { // Set the second-most significant bit to indicate this point // is at infinity. res.0[0] |= 1 << 6; } else { { let mut writer = &mut res.0[..]; affine.x.c1.into_repr().write_be(&mut writer).unwrap(); affine.x.c0.into_repr().write_be(&mut writer).unwrap(); } let negy = affine.y.neg(); // Set the third most significant bit if the correct y-coordinate // is lexicographically largest. if affine.y > negy { res.0[0] |= 1 << 5; } } // Set highest bit to distinguish this as a compressed element. res.0[0] |= 1 << 7; res } } impl G2Affine { fn get_generator() -> Self { G2Affine { x: Fq2 { c0: super::super::fq::G2_GENERATOR_X_C0, c1: super::super::fq::G2_GENERATOR_X_C1, }, y: Fq2 { c0: super::super::fq::G2_GENERATOR_Y_C0, c1: super::super::fq::G2_GENERATOR_Y_C1, }, infinity: false, } } fn get_coeff_b() -> Fq2 { Fq2 { c0: super::super::fq::B_COEFF, c1: super::super::fq::B_COEFF, } } fn scale_by_cofactor(&self) -> G2 { // G2 cofactor = (x^8 - 4 x^7 + 5 x^6) - (4 x^4 + 6 x^3 - 4 x^2 - 4 x + 13) // 9 // 0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5 let cofactor = BitIterator::::new([ 0xcf1c38e31c7238e5, 0x1616ec6e786f0c70, 0x21537e293a6691ae, 0xa628f1cb4d9e82ef, 0xa68a205b2e5a7ddf, 0xcd91de4547085aba, 0x91d50792876a202, 0x5d543a95414e7f1, ]); self.mul_bits_u64(cofactor) } fn perform_pairing(&self, other: &G1Affine) -> Fq12 { super::super::Bls12::pairing(*other, *self) } } impl G2 { fn empirical_recommended_wnaf_for_scalar(scalar: &FrRepr) -> usize { let num_bits = scalar.num_bits() as usize; if num_bits >= 103 { 4 } else if num_bits >= 37 { 3 } else { 2 } } fn empirical_recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize { const RECOMMENDATIONS: [usize; 11] = [1, 3, 8, 20, 47, 126, 260, 826, 1501, 4555, 84071]; let mut ret = 4; for r in &RECOMMENDATIONS { if num_scalars > *r { ret += 1; } else { break; } } ret } } #[derive(Clone, Debug)] pub struct G2Prepared { pub(crate) coeffs: Vec<(Fq2, Fq2, Fq2)>, pub(crate) infinity: bool, } #[test] fn g2_generator() { use crate::SqrtField; let mut x = Fq2::zero(); let mut i = 0; loop { // y^2 = x^3 + b let mut rhs = x.square(); rhs.mul_assign(&x); rhs.add_assign(&G2Affine::get_coeff_b()); let y = rhs.sqrt(); if y.is_some().into() { let y = y.unwrap(); let negy = y.neg(); let p = G2Affine { x, y: if y < negy { y } else { negy }, infinity: false, }; assert!(!p.is_in_correct_subgroup_assuming_on_curve()); let g2 = p.scale_by_cofactor(); if !g2.is_zero() { assert_eq!(i, 2); let g2 = G2Affine::from(g2); assert!(g2.is_in_correct_subgroup_assuming_on_curve()); assert_eq!(g2, G2Affine::one()); break; } } i += 1; x.add_assign(&Fq2::one()); } } #[test] fn g2_test_is_valid() { // Reject point on isomorphic twist (b = 3 * (u + 1)) { let p = G2Affine { x: Fq2 { c0: Fq::from_repr(FqRepr([ 0xa757072d9fa35ba9, 0xae3fb2fb418f6e8a, 0xc1598ec46faa0c7c, 0x7a17a004747e3dbe, 0xcc65406a7c2e5a73, 0x10b8c03d64db4d0c, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ 0xd30e70fe2f029778, 0xda30772df0f5212e, 0x5b47a9ff9a233a50, 0xfb777e5b9b568608, 0x789bac1fec71a2b9, 0x1342f02e2da54405, ])) .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ 0xfe0812043de54dca, 0xe455171a3d47a646, 0xa493f36bc20be98a, 0x663015d9410eb608, 0x78e82a79d829a544, 0x40a00545bb3c1e, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ 0x4709802348e79377, 0xb5ac4dc9204bcfbd, 0xda361c97d02f42b2, 0x15008b1dc399e8df, 0x68128fd0548a3829, 0x16a613db5c873aaa, ])) .unwrap(), }, infinity: false, }; assert!(!p.is_on_curve()); assert!(p.is_in_correct_subgroup_assuming_on_curve()); } // Reject point on a twist (b = 2 * (u + 1)) { let p = G2Affine { x: Fq2 { c0: Fq::from_repr(FqRepr([ 0xf4fdfe95a705f917, 0xc2914df688233238, 0x37c6b12cca35a34b, 0x41abba710d6c692c, 0xffcc4b2b62ce8484, 0x6993ec01b8934ed, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ 0xb94e92d5f874e26, 0x44516408bc115d95, 0xe93946b290caa591, 0xa5a0c2b7131f3555, 0x83800965822367e7, 0x10cf1d3ad8d90bfa, ])) .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ 0xbf00334c79701d97, 0x4fe714f9ff204f9a, 0xab70b28002f3d825, 0x5a9171720e73eb51, 0x38eb4fd8d658adb7, 0xb649051bbc1164d, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ 0x9225814253d7df75, 0xc196c2513477f887, 0xe05e2fbd15a804e0, 0x55f2b8efad953e04, 0x7379345eda55265e, 0x377f2e6208fd4cb, ])) .unwrap(), }, infinity: false, }; assert!(!p.is_on_curve()); assert!(!p.is_in_correct_subgroup_assuming_on_curve()); } // Reject point in an invalid subgroup // There is only one r-order subgroup, as r does not divide the cofactor. { let p = G2Affine { x: Fq2 { c0: Fq::from_repr(FqRepr([ 0x262cea73ea1906c, 0x2f08540770fabd6, 0x4ceb92d0a76057be, 0x2199bc19c48c393d, 0x4a151b732a6075bf, 0x17762a3b9108c4a7, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ 0x26f461e944bbd3d1, 0x298f3189a9cf6ed6, 0x74328ad8bc2aa150, 0x7e147f3f9e6e241, 0x72a9b63583963fff, 0x158b0083c000462, ])) .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ 0x91fb0b225ecf103b, 0x55d42edc1dc46ba0, 0x43939b11997b1943, 0x68cad19430706b4d, 0x3ccfb97b924dcea8, 0x1660f93434588f8d, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ 0xaaed3985b6dcb9c7, 0xc1e985d6d898d9f4, 0x618bd2ac3271ac42, 0x3940a2dbb914b529, 0xbeb88137cf34f3e7, 0x1699ee577c61b694, ])) .unwrap(), }, infinity: false, }; assert!(p.is_on_curve()); assert!(!p.is_in_correct_subgroup_assuming_on_curve()); } } #[test] fn test_g2_addition_correctness() { let mut p = G2 { x: Fq2 { c0: Fq::from_repr(FqRepr([ 0x6c994cc1e303094e, 0xf034642d2c9e85bd, 0x275094f1352123a9, 0x72556c999f3707ac, 0x4617f2e6774e9711, 0x100b2fe5bffe030b, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ 0x7a33555977ec608, 0xe23039d1fe9c0881, 0x19ce4678aed4fcb5, 0x4637c4f417667e2e, 0x93ebe7c3e41f6acc, 0xde884f89a9a371b, ])) .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ 0xe073119472e1eb62, 0x44fb3391fe3c9c30, 0xaa9b066d74694006, 0x25fd427b4122f231, 0xd83112aace35cae, 0x191b2432407cbb7f, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ 0xf68ae82fe97662f5, 0xe986057068b50b7d, 0x96c30f0411590b48, 0x9eaa6d19de569196, 0xf6a03d31e2ec2183, 0x3bdafaf7ca9b39b, ])) .unwrap(), }, z: Fq2::one(), }; p.add_assign(&G2 { x: Fq2 { c0: Fq::from_repr(FqRepr([ 0xa8c763d25910bdd3, 0x408777b30ca3add4, 0x6115fcc12e2769e, 0x8e73a96b329ad190, 0x27c546f75ee1f3ab, 0xa33d27add5e7e82, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ 0x93b1ebcd54870dfe, 0xf1578300e1342e11, 0x8270dca3a912407b, 0x2089faf462438296, 0x828e5848cd48ea66, 0x141ecbac1deb038b, ])) .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ 0xf5d2c28857229c3f, 0x8c1574228757ca23, 0xe8d8102175f5dc19, 0x2767032fc37cc31d, 0xd5ee2aba84fd10fe, 0x16576ccd3dd0a4e8, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ 0x4da9b6f6a96d1dd2, 0x9657f7da77f1650e, 0xbc150712f9ffe6da, 0x31898db63f87363a, 0xabab040ddbd097cc, 0x11ad236b9ba02990, ])) .unwrap(), }, z: Fq2::one(), }); let p = G2Affine::from(p); assert_eq!( p, G2Affine { x: Fq2 { c0: Fq::from_repr(FqRepr([ 0xcde7ee8a3f2ac8af, 0xfc642eb35975b069, 0xa7de72b7dd0e64b7, 0xf1273e6406eef9cc, 0xababd760ff05cb92, 0xd7c20456617e89 ])) .unwrap(), c1: Fq::from_repr(FqRepr([ 0xd1a50b8572cbd2b8, 0x238f0ac6119d07df, 0x4dbe924fe5fd6ac2, 0x8b203284c51edf6b, 0xc8a0b730bbb21f5e, 0x1a3b59d29a31274 ])) .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ 0x9e709e78a8eaa4c9, 0xd30921c93ec342f4, 0x6d1ef332486f5e34, 0x64528ab3863633dc, 0x159384333d7cba97, 0x4cb84741f3cafe8 ])) .unwrap(), c1: Fq::from_repr(FqRepr([ 0x242af0dc3640e1a4, 0xe90a73ad65c66919, 0x2bd7ca7f4346f9ec, 0x38528f92b689644d, 0xb6884deec59fb21f, 0x3c075d3ec52ba90 ])) .unwrap(), }, infinity: false, } ); } #[test] fn test_g2_doubling_correctness() { let mut p = G2 { x: Fq2 { c0: Fq::from_repr(FqRepr([ 0x6c994cc1e303094e, 0xf034642d2c9e85bd, 0x275094f1352123a9, 0x72556c999f3707ac, 0x4617f2e6774e9711, 0x100b2fe5bffe030b, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ 0x7a33555977ec608, 0xe23039d1fe9c0881, 0x19ce4678aed4fcb5, 0x4637c4f417667e2e, 0x93ebe7c3e41f6acc, 0xde884f89a9a371b, ])) .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ 0xe073119472e1eb62, 0x44fb3391fe3c9c30, 0xaa9b066d74694006, 0x25fd427b4122f231, 0xd83112aace35cae, 0x191b2432407cbb7f, ])) .unwrap(), c1: Fq::from_repr(FqRepr([ 0xf68ae82fe97662f5, 0xe986057068b50b7d, 0x96c30f0411590b48, 0x9eaa6d19de569196, 0xf6a03d31e2ec2183, 0x3bdafaf7ca9b39b, ])) .unwrap(), }, z: Fq2::one(), }; p.double(); let p = G2Affine::from(p); assert_eq!( p, G2Affine { x: Fq2 { c0: Fq::from_repr(FqRepr([ 0x91ccb1292727c404, 0x91a6cb182438fad7, 0x116aee59434de902, 0xbcedcfce1e52d986, 0x9755d4a3926e9862, 0x18bab73760fd8024 ])) .unwrap(), c1: Fq::from_repr(FqRepr([ 0x4e7c5e0a2ae5b99e, 0x96e582a27f028961, 0xc74d1cf4ef2d5926, 0xeb0cf5e610ef4fe7, 0x7b4c2bae8db6e70b, 0xf136e43909fca0 ])) .unwrap(), }, y: Fq2 { c0: Fq::from_repr(FqRepr([ 0x954d4466ab13e58, 0x3ee42eec614cf890, 0x853bb1d28877577e, 0xa5a2a51f7fde787b, 0x8b92866bc6384188, 0x81a53fe531d64ef ])) .unwrap(), c1: Fq::from_repr(FqRepr([ 0x4c5d607666239b34, 0xeddb5f48304d14b3, 0x337167ee6e8e3cb6, 0xb271f52f12ead742, 0x244e6c2015c83348, 0x19e2deae6eb9b441 ])) .unwrap(), }, infinity: false, } ); } #[test] fn g2_curve_tests() { use group::tests::curve_tests; curve_tests::(); } } pub use self::g1::*; pub use self::g2::*;