Files
pirate-librustzcash/pairing/src/bls12_381/ec.rs
Jack Grigg e924247e73 Add 'pairing/' from commit '09b6e6f9212020f385218e5cf5287e381ccd312b'
git-subtree-dir: pairing
git-subtree-mainline: ad16ba6a35
git-subtree-split: 09b6e6f921
2018-08-28 23:03:42 +01:00

2027 lines
64 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,
$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;
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 mul_bits<S: AsRef<[u64]>>(&self, bits: BitIterator<S>) -> $projective {
let mut res = $projective::zero();
for i in bits {
res.double();
if i { res.add_assign_mixed(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) -> Option<$affine> {
// Compute x^3 + b
let mut x3b = x;
x3b.square();
x3b.mul_assign(&x);
x3b.add_assign(&$affine::get_coeff_b());
x3b.sqrt().map(|y| {
let mut negy = y;
negy.negate();
$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 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_assuming_on_curve(&self) -> bool {
self.mul($scalarfield::char()).is_zero()
}
}
impl CurveAffine for $affine {
type Engine = Bls12;
type Scalar = $scalarfield;
type Base = $basefield;
type Prepared = $prepared;
type Projective = $projective;
type Uncompressed = $uncompressed;
type Compressed = $compressed;
type Pair = $pairing;
type PairingResult = Fq12;
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 bits = BitIterator::new(by.into());
self.mul_bits(bits)
}
fn negate(&mut self) {
if !self.is_zero() {
self.y.negate();
}
}
fn prepare(&self) -> Self::Prepared {
$prepared::from_affine(*self)
}
fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
self.perform_pairing(other)
}
fn into_projective(&self) -> $projective {
(*self).into()
}
}
impl Rand for $projective {
fn rand<R: Rng>(rng: &mut R) -> Self {
loop {
let x = rng.gen();
let greatest = rng.gen();
if let Some(p) = $affine::get_point_from_x(x, greatest) {
let p = p.scale_by_cofactor();
if !p.is_zero() {
return p;
}
}
}
}
}
impl CurveProjective for $projective {
type Engine = Bls12;
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) -> 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 super::super::{Bls12, Fq, Fq12, FqRepr, Fr, FrRepr};
use super::g2::G2Affine;
use rand::{Rand, Rng};
use std::fmt;
use {
BitIterator, CurveAffine, CurveProjective, EncodedPoint, Engine, Field, GroupDecodingError,
PrimeField, PrimeFieldRepr, SqrtField,
};
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<G1Affine, GroupDecodingError> {
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<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, 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<G1Affine, GroupDecodingError> {
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<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))?;
G1Affine::get_point_from_x(x, greatest).ok_or(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 scale_by_cofactor(&self) -> G1 {
// G1 cofactor = (x - 1)^2 / 3 = 76329603384216526031706109802092473003
let cofactor = BitIterator::new([0x8c00aaab0000aaab, 0x396c8c005555e156]);
self.mul_bits(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 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_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_mixed(&b);
assert_eq!(tmp2.into_affine(), c);
assert_eq!(tmp2, c.into_projective());
}
#[test]
fn g1_curve_tests() {
::tests::curve::curve_tests::<G1>();
}
}
pub mod g2 {
use super::super::{Bls12, Fq, Fq12, Fq2, FqRepr, Fr, FrRepr};
use super::g1::G1Affine;
use rand::{Rand, Rng};
use std::fmt;
use {
BitIterator, CurveAffine, CurveProjective, EncodedPoint, Engine, Field, GroupDecodingError,
PrimeField, PrimeFieldRepr, SqrtField,
};
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<G2Affine, GroupDecodingError> {
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<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, 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<G2Affine, GroupDecodingError> {
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<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)
})?,
};
G2Affine::get_point_from_x(x, greatest).ok_or(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,
}
}
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(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 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_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() {
::tests::curve::curve_tests::<G2>();
}
}
pub use self::g1::*;
pub use self::g2::*;