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;
}
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
}
fn get_point_from_x(x: $basefield, greatest: bool) -> Option<$affine> {
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 {
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 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 bits = BitIterator::new(by.into());
self.mul_bits(bits)
}
fn negate(&mut self) {
if !self.is_zero() {
self.y.negate();
}
}
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 CurveProjective for $projective {
type Engine = Bls12;
type Scalar = $scalarfield;
type Base = $basefield;
type Affine = $affine;
fn random<R: RngCore + ?std::marker::Sized>(rng: &mut R) -> Self {
loop {
let x = $basefield::random(rng);
let greatest = rng.next_u32() % 2 != 0;
if let Some(p) = $affine::get_point_from_x(x, greatest) {
let p = p.scale_by_cofactor();
if !p.is_zero() {
return p;
}
}
}
}
fn zero() -> Self {
$projective {
x: $basefield::zero(),
y: $basefield::one(),
z: $basefield::zero(),
}
}
fn one() -> Self {
$affine::one().into()
}
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]) {
let mut prod = Vec::with_capacity(v.len());
let mut tmp = $basefield::one();
for g in v
.iter_mut()
.filter(|g| !g.is_normalized())
{
tmp.mul_assign(&g.z);
prod.push(tmp);
}
tmp = tmp.inverse().unwrap();
for (g, s) in v
.iter_mut()
.rev()
.filter(|g| !g.is_normalized())
.zip(
prod.into_iter()
.rev()
.skip(1)
.chain(Some($basefield::one())),
)
{
let mut newtmp = tmp;
newtmp.mul_assign(&g.z);
g.z = tmp;
g.z.mul_assign(&s);
tmp = newtmp;
}
for g in v.iter_mut().filter(|g| !g.is_normalized()) {
let mut z = g.z;
z.square();
g.x.mul_assign(&z);
z.mul_assign(&g.z);
g.y.mul_assign(&z);
g.z = $basefield::one();
}
}
fn double(&mut self) {
if self.is_zero() {
return;
}
let mut a = self.x;
a.square();
let mut b = self.y;
b.square();
let mut c = b;
c.square();
let mut d = self.x;
d.add_assign(&b);
d.square();
d.sub_assign(&a);
d.sub_assign(&c);
d.double();
let mut e = a;
e.double();
e.add_assign(&a);
let mut f = e;
f.square();
self.z.mul_assign(&self.y);
self.z.double();
self.x = f;
self.x.sub_assign(&d);
self.x.sub_assign(&d);
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;
}
let mut z1z1 = self.z;
z1z1.square();
let mut z2z2 = other.z;
z2z2.square();
let mut u1 = self.x;
u1.mul_assign(&z2z2);
let mut u2 = other.x;
u2.mul_assign(&z1z1);
let mut s1 = self.y;
s1.mul_assign(&other.z);
s1.mul_assign(&z2z2);
let mut s2 = other.y;
s2.mul_assign(&self.z);
s2.mul_assign(&z1z1);
if u1 == u2 && s1 == s2 {
self.double();
} else {
let mut h = u2;
h.sub_assign(&u1);
let mut i = h;
i.double();
i.square();
let mut j = h;
j.mul_assign(&i);
let mut r = s2;
r.sub_assign(&s1);
r.double();
let mut v = u1;
v.mul_assign(&i);
self.x = r;
self.x.square();
self.x.sub_assign(&j);
self.x.sub_assign(&v);
self.x.sub_assign(&v);
self.y = v;
self.y.sub_assign(&self.x);
self.y.mul_assign(&r);
s1.mul_assign(&j);
s1.double();
self.y.sub_assign(&s1);
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;
}
let mut z1z1 = self.z;
z1z1.square();
let mut u2 = other.x;
u2.mul_assign(&z1z1);
let mut s2 = other.y;
s2.mul_assign(&self.z);
s2.mul_assign(&z1z1);
if self.x == u2 && self.y == s2 {
self.double();
} else {
let mut h = u2;
h.sub_assign(&self.x);
let mut hh = h;
hh.square();
let mut i = hh;
i.double();
i.double();
let mut j = h;
j.mul_assign(&i);
let mut r = s2;
r.sub_assign(&self.y);
r.double();
let mut v = self.x;
v.mul_assign(&i);
self.x = r;
self.x.square();
self.x.sub_assign(&j);
self.x.sub_assign(&v);
self.x.sub_assign(&v);
j.mul_assign(&self.y);
j.double();
self.y = v;
self.y.sub_assign(&self.x);
self.y.mul_assign(&r);
self.y.sub_assign(&j);
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)
}
}
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(),
}
}
}
}
impl From<$projective> for $affine {
fn from(p: $projective) -> $affine {
if p.is_zero() {
$affine::zero()
} else if p.z == $basefield::one() {
$affine {
x: p.x,
y: p.y,
infinity: false,
}
} else {
let zinv = p.z.inverse().unwrap();
let mut zinv_powered = zinv;
zinv_powered.square();
let mut x = p.x;
x.mul_assign(&zinv_powered);
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;
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> {
let mut copy = self.0;
if copy[0] & (1 << 7) != 0 {
return Err(GroupDecodingError::UnexpectedCompressionMode);
}
if copy[0] & (1 << 6) != 0 {
copy[0] &= 0x3f;
if copy.iter().all(|b| *b == 0) {
Ok(G1Affine::zero())
} else {
Err(GroupDecodingError::UnexpectedInformation)
}
} else {
if copy[0] & (1 << 5) != 0 {
return Err(GroupDecodingError::UnexpectedInformation);
}
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() {
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()?;
if !affine.is_in_correct_subgroup_assuming_on_curve() {
Err(GroupDecodingError::NotInSubgroup)
} else {
Ok(affine)
}
}
fn into_affine_unchecked(&self) -> Result<G1Affine, GroupDecodingError> {
let mut copy = self.0;
if copy[0] & (1 << 7) == 0 {
return Err(GroupDecodingError::UnexpectedCompressionMode);
}
if copy[0] & (1 << 6) != 0 {
copy[0] &= 0x3f;
if copy.iter().all(|b| *b == 0) {
Ok(G1Affine::zero())
} else {
Err(GroupDecodingError::UnexpectedInformation)
}
} else {
let greatest = copy[0] & (1 << 5) != 0;
copy[0] &= 0x1f;
let mut x = FqRepr([0; 6]);
{
let mut reader = ©[..];
x.read_be(&mut reader).unwrap();
}
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() {
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();
if affine.y > negy {
res.0[0] |= 1 << 5;
}
}
res.0[0] |= 1 << 7;
res
}
}
impl G1Affine {
fn scale_by_cofactor(&self) -> G1 {
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 crate::SqrtField;
let mut x = Fq::zero();
let mut i = 0;
loop {
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,
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() {
{
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());
}
{
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());
}
{
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() {
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,
};
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() {
use group::tests::curve_tests;
curve_tests::<G1>();
}
}
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;
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> {
let mut copy = self.0;
if copy[0] & (1 << 7) != 0 {
return Err(GroupDecodingError::UnexpectedCompressionMode);
}
if copy[0] & (1 << 6) != 0 {
copy[0] &= 0x3f;
if copy.iter().all(|b| *b == 0) {
Ok(G2Affine::zero())
} else {
Err(GroupDecodingError::UnexpectedInformation)
}
} else {
if copy[0] & (1 << 5) != 0 {
return Err(GroupDecodingError::UnexpectedInformation);
}
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() {
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()?;
if !affine.is_in_correct_subgroup_assuming_on_curve() {
Err(GroupDecodingError::NotInSubgroup)
} else {
Ok(affine)
}
}
fn into_affine_unchecked(&self) -> Result<G2Affine, GroupDecodingError> {
let mut copy = self.0;
if copy[0] & (1 << 7) == 0 {
return Err(GroupDecodingError::UnexpectedCompressionMode);
}
if copy[0] & (1 << 6) != 0 {
copy[0] &= 0x3f;
if copy.iter().all(|b| *b == 0) {
Ok(G2Affine::zero())
} else {
Err(GroupDecodingError::UnexpectedInformation)
}
} else {
let greatest = copy[0] & (1 << 5) != 0;
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();
}
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() {
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();
if affine.y > negy {
res.0[0] |= 1 << 5;
}
}
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 {
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 crate::SqrtField;
let mut x = Fq2::zero();
let mut i = 0;
loop {
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,
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() {
{
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());
}
{
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());
}
{
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::<G2>();
}
}
pub use self::g1::*;
pub use self::g2::*;