Files
pirate-librustzcash/src/bls12_381/ec.rs

1694 lines
58 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

macro_rules! curve_impl {
(
$name:expr,
$projective:ident,
$affine:ident,
$prepared:ident,
$basefield:ident,
$scalarfield:ident,
$uncompressed:ident,
$compressed: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, Eq, Debug)]
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;
z1.square();
let mut z2 = other.z;
z2.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 is_on_curve(&self) -> bool {
if self.is_zero() {
true
} else {
// Check that the point is on the curve
let mut y2 = self.y;
y2.square();
let mut x3b = self.x;
x3b.square();
x3b.mul_assign(&self.x);
x3b.add_assign(&Self::get_coeff_b());
y2 == x3b
}
}
fn is_in_correct_subgroup(&self) -> bool {
self.mul($scalarfield::char()).is_zero()
}
}
impl CurveAffine for $affine {
type Scalar = $scalarfield;
type Base = $basefield;
type Prepared = $prepared;
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<S: Into<<Self::Scalar as PrimeField>::Repr>>(&self, by: S) -> $projective {
let mut res = $projective::zero();
for i in BitIterator::new(by.into())
{
res.double();
if i {
res.add_assign_mixed(self);
}
}
res
}
fn negate(&mut self) {
if !self.is_zero() {
self.y.negate();
}
}
fn prepare(&self) -> Self::Prepared {
$prepared::from_affine(*self)
}
fn into_projective(&self) -> $projective {
(*self).into()
}
}
impl Rand for $projective {
fn rand<R: Rng>(rng: &mut R) -> Self {
$affine::one().mul($scalarfield::rand(rng))
}
}
impl CurveProjective for $projective {
type Scalar = $scalarfield;
type Base = $basefield;
type Affine = $affine;
// 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])
{
// Montgomerys 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.inverse().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; // 1/z
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 mut a = self.x;
a.square();
// B = Y1^2
let mut b = self.y;
b.square();
// C = B^2
let mut c = b;
c.square();
// D = 2*((X1+B)2-A-C)
let mut d = self.x;
d.add_assign(&b);
d.square();
d.sub_assign(&a);
d.sub_assign(&c);
d.double();
// E = 3*A
let mut e = a;
e.double();
e.add_assign(&a);
// F = E^2
let mut f = e;
f.square();
// Z3 = 2*Y1*Z1
self.z.mul_assign(&self.y);
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.double();
c.double();
c.double();
self.y.sub_assign(&c);
}
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 mut z1z1 = self.z;
z1z1.square();
// Z2Z2 = Z2^2
let mut z2z2 = other.z;
z2z2.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 mut i = h;
i.double();
i.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.double();
// V = U1*I
let mut v = u1;
v.mul_assign(&i);
// X3 = r^2 - J - 2*V
self.x = r;
self.x.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.double();
self.y.sub_assign(&s1);
// Z3 = ((Z1+Z2)^2 - Z1Z1 - Z2Z2)*H
self.z.add_assign(&other.z);
self.z.square();
self.z.sub_assign(&z1z1);
self.z.sub_assign(&z2z2);
self.z.mul_assign(&h);
}
}
fn add_assign_mixed(&mut self, other: &Self::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 mut z1z1 = self.z;
z1z1.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 mut hh = h;
hh.square();
// I = 4*HH
let mut i = hh;
i.double();
i.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.double();
// V = X1*I
let mut v = self.x;
v.mul_assign(&i);
// X3 = r^2 - J - 2*V
self.x = r;
self.x.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.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.square();
self.z.sub_assign(&z1z1);
self.z.sub_assign(&hh);
}
}
fn negate(&mut self) {
if !self.is_zero() {
self.y.negate()
}
}
fn mul_assign<S: Into<<Self::Scalar as PrimeField>::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: <Self::Scalar as PrimeField>::Repr) -> Option<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.inverse().unwrap();
let mut zinv_powered = zinv;
zinv_powered.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 rand::{Rand, Rng};
use super::super::{Fq, Fr, FrRepr, FqRepr};
use ::{CurveProjective, CurveAffine, PrimeField, SqrtField, PrimeFieldRepr, Field, BitIterator, EncodedPoint, GroupDecodingError};
curve_impl!("E", G1, G1Affine, G1Prepared, Fq, Fr, G1Uncompressed, G1Compressed);
#[derive(Copy)]
pub struct G1Uncompressed([u8; 96]);
impl Clone for G1Uncompressed {
fn clone(&self) -> G1Uncompressed {
G1Uncompressed(self.0)
}
}
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 EncodedPoint for G1Uncompressed {
type Affine = G1Affine;
fn empty() -> Self { G1Uncompressed([0; 96]) }
fn size() -> usize { 96 }
fn into_affine(&self) -> Result<G1Affine, GroupDecodingError> {
let affine = self.into_affine_unchecked()?;
if !affine.is_on_curve() {
Err(GroupDecodingError::NotOnCurve)
} else if !affine.is_in_correct_subgroup() {
Err(GroupDecodingError::NotInSubgroup)
} else {
Ok(affine)
}
}
fn into_affine_unchecked(&self) -> Result<G1Affine, GroupDecodingError> {
// 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 = &copy[..];
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)]
pub struct G1Compressed([u8; 48]);
impl Clone for G1Compressed {
fn clone(&self) -> G1Compressed {
G1Compressed(self.0)
}
}
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 EncodedPoint for G1Compressed {
type Affine = G1Affine;
fn empty() -> Self { G1Compressed([0; 48]) }
fn size() -> usize { 48 }
fn into_affine(&self) -> Result<G1Affine, GroupDecodingError> {
let affine = self.into_affine_unchecked()?;
// NB: Decompression guarantees that it is on the curve already.
if !affine.is_in_correct_subgroup() {
Err(GroupDecodingError::NotInSubgroup)
} else {
Ok(affine)
}
}
fn into_affine_unchecked(&self) -> Result<G1Affine, GroupDecodingError> {
// 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 = &copy[..];
x.read_be(&mut reader).unwrap();
}
// Interpret as Fq element.
let x = Fq::from_repr(x).map_err(|e| GroupDecodingError::CoordinateDecodingError("x coordinate", e))?;
// Compute x^3 + b
let mut x3b = x;
x3b.square();
x3b.mul_assign(&x);
x3b.add_assign(&G1Affine::get_coeff_b());
// Attempt to compute y
match x3b.sqrt() {
Some(y) => {
let mut negy = y;
negy.negate();
// Get the parity of the sqrt we found.
let parity = y > negy;
Ok(G1Affine {
x: x,
y: if parity == greatest { y } else { negy },
infinity: false
})
},
None => {
// Point must not be on the curve.
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 mut negy = affine.y;
negy.negate();
// 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 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
}
}
impl G1 {
fn empirical_recommended_wnaf_for_scalar(scalar: FrRepr) -> Option<usize>
{
const RECOMMENDATIONS: [usize; 3] = [12, 34, 130];
let mut ret = None;
let num_bits = scalar.num_bits() as usize;
for (i, r) in RECOMMENDATIONS.iter().enumerate() {
if *r >= num_bits {
ret = Some(i + 2)
}
}
ret
}
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)]
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 ::SqrtField;
let mut x = Fq::zero();
let mut i = 0;
loop {
// y^2 = x^3 + b
let mut rhs = x;
rhs.square();
rhs.mul_assign(&x);
rhs.add_assign(&G1Affine::get_coeff_b());
if let Some(y) = rhs.sqrt() {
let yrepr = y.into_repr();
let mut negy = y;
negy.negate();
let negyrepr = negy.into_repr();
let p = G1Affine {
x: x,
y: if yrepr < negyrepr { y } else { negy },
infinity: false
};
assert!(!p.is_in_correct_subgroup());
let mut g1 = G1::zero();
// Cofactor of G1 is 76329603384216526031706109802092473003.
// Calculated by: ((x-1)**2) // 3
// where x is the BLS parameter.
for b in "111001011011001000110000000000010101010101010111100001010101101000110000000000101010101010101100000000000000001010101010101011"
.chars()
.map(|c| c == '1')
{
g1.double();
if b {
g1.add_assign_mixed(&p);
}
}
if !g1.is_zero() {
assert_eq!(i, 4);
let g1 = G1Affine::from(g1);
assert!(g1.is_in_correct_subgroup());
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());
}
// 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());
}
// 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());
}
}
#[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());
assert!(b.is_on_curve() && b.is_in_correct_subgroup());
assert!(c.is_on_curve() && c.is_in_correct_subgroup());
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_mixed(&b);
assert_eq!(tmp2.into_affine(), c);
assert_eq!(tmp2, c.into_projective());
}
#[test]
fn g1_curve_tests() {
::tests::curve::curve_tests::<G1>();
}
#[cfg(test)]
use rand::{SeedableRng, XorShiftRng};
#[bench]
fn bench_g1_mul_assign(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(G1, Fr)> = (0..SAMPLES).map(|_| (G1::rand(&mut rng), Fr::rand(&mut rng))).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_g1_add_assign(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(G1, G1)> = (0..SAMPLES).map(|_| (G1::rand(&mut rng), G1::rand(&mut rng))).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_g1_add_assign_mixed(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(G1, G1Affine)> = (0..SAMPLES).map(|_| (G1::rand(&mut rng), G1::rand(&mut rng).into())).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign_mixed(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
}
pub mod g2 {
use rand::{Rand, Rng};
use super::super::{Fq2, Fr, Fq, FrRepr, FqRepr};
use ::{CurveProjective, CurveAffine, PrimeField, SqrtField, PrimeFieldRepr, Field, BitIterator, EncodedPoint, GroupDecodingError};
curve_impl!("E'", G2, G2Affine, G2Prepared, Fq2, Fr, G2Uncompressed, G2Compressed);
#[derive(Copy)]
pub struct G2Uncompressed([u8; 192]);
impl Clone for G2Uncompressed {
fn clone(&self) -> G2Uncompressed {
G2Uncompressed(self.0)
}
}
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 EncodedPoint for G2Uncompressed {
type Affine = G2Affine;
fn empty() -> Self { G2Uncompressed([0; 192]) }
fn size() -> usize { 192 }
fn into_affine(&self) -> Result<G2Affine, GroupDecodingError> {
let affine = self.into_affine_unchecked()?;
if !affine.is_on_curve() {
Err(GroupDecodingError::NotOnCurve)
} else if !affine.is_in_correct_subgroup() {
Err(GroupDecodingError::NotInSubgroup)
} else {
Ok(affine)
}
}
fn into_affine_unchecked(&self) -> Result<G2Affine, GroupDecodingError> {
// 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 = &copy[..];
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)]
pub struct G2Compressed([u8; 96]);
impl Clone for G2Compressed {
fn clone(&self) -> G2Compressed {
G2Compressed(self.0)
}
}
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 EncodedPoint for G2Compressed {
type Affine = G2Affine;
fn empty() -> Self { G2Compressed([0; 96]) }
fn size() -> usize { 96 }
fn into_affine(&self) -> Result<G2Affine, GroupDecodingError> {
let affine = self.into_affine_unchecked()?;
// NB: Decompression guarantees that it is on the curve already.
if !affine.is_in_correct_subgroup() {
Err(GroupDecodingError::NotInSubgroup)
} else {
Ok(affine)
}
}
fn into_affine_unchecked(&self) -> Result<G2Affine, GroupDecodingError> {
// 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 = &copy[..];
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))?
};
// Compute x^3 + b
let mut x3b = x;
x3b.square();
x3b.mul_assign(&x);
x3b.add_assign(&G2Affine::get_coeff_b());
// Attempt to compute y
match x3b.sqrt() {
Some(y) => {
let mut negy = y;
negy.negate();
// Get the parity of the sqrt we found.
let parity = y > negy;
Ok(G2Affine {
x: x,
y: if parity == greatest { y } else { negy },
infinity: false
})
},
None => {
// Point must not be on the curve.
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 mut negy = affine.y;
negy.negate();
// 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
}
}
}
impl G2 {
fn empirical_recommended_wnaf_for_scalar(scalar: FrRepr) -> Option<usize>
{
const RECOMMENDATIONS: [usize; 3] = [13, 37, 103];
let mut ret = None;
let num_bits = scalar.num_bits() as usize;
for (i, r) in RECOMMENDATIONS.iter().enumerate() {
if *r >= num_bits {
ret = Some(i + 2)
}
}
ret
}
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)]
pub struct G2Prepared {
pub(crate) coeffs: Vec<(Fq2, Fq2, Fq2)>,
pub(crate) infinity: bool
}
#[test]
fn g2_generator() {
use ::SqrtField;
let mut x = Fq2::zero();
let mut i = 0;
loop {
// y^2 = x^3 + b
let mut rhs = x;
rhs.square();
rhs.mul_assign(&x);
rhs.add_assign(&G2Affine::get_coeff_b());
if let Some(y) = rhs.sqrt() {
let mut negy = y;
negy.negate();
let p = G2Affine {
x: x,
y: if y < negy { y } else { negy },
infinity: false
};
assert!(!p.is_in_correct_subgroup());
let mut g2 = G2::zero();
// Cofactor of G2 is 305502333931268344200999753193121504214466019254188142667664032982267604182971884026507427359259977847832272839041616661285803823378372096355777062779109.
// Calculated by: ((x**8) - (4 * (x**7)) + (5 * (x**6)) - (4 * (x**4)) + (6 * (x**3)) - (4 * (x**2)) - (4*x) + 13) // 9
// where x is the BLS parameter.
for b in "101110101010100001110101001010101000001010011100111111100010000100100011101010100000111100100101000011101101010001000000010110011011001000111011110010001010100011100001000010110101011101010100110100010100010000001011011001011100101101001111101110111111010011000101000111100011100101101001101100111101000001011101111001000010101001101111110001010010011101001100110100100011010111000010110000101101110110001101110011110000110111100001100011100001100111100011100001110001110001100011100011100100011100011100101"
.chars()
.map(|c| c == '1')
{
g2.double();
if b {
g2.add_assign_mixed(&p);
}
}
if !g2.is_zero() {
assert_eq!(i, 2);
let g2 = G2Affine::from(g2);
assert!(g2.is_in_correct_subgroup());
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());
}
// 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());
}
// 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());
}
}
#[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() {
::tests::curve::curve_tests::<G2>();
}
#[cfg(test)]
use rand::{SeedableRng, XorShiftRng};
#[bench]
fn bench_g2_mul_assign(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(G2, Fr)> = (0..SAMPLES).map(|_| (G2::rand(&mut rng), Fr::rand(&mut rng))).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_g2_add_assign(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(G2, G2)> = (0..SAMPLES).map(|_| (G2::rand(&mut rng), G2::rand(&mut rng))).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_g2_add_assign_mixed(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(G2, G2Affine)> = (0..SAMPLES).map(|_| (G2::rand(&mut rng), G2::rand(&mut rng).into())).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign_mixed(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
}
pub use self::g1::*;
pub use self::g2::*;