Merge branch 'develop'

This commit is contained in:
Jack Grigg
2020-03-14 10:36:58 +13:00
124 changed files with 15961 additions and 2084 deletions

View File

@@ -21,8 +21,10 @@ byteorder = "1"
ff = { version = "0.6", path = "../ff", features = ["derive"] }
group = { version = "0.6", path = "../group" }
rand_core = "0.5"
subtle = "2.2.1"
[dev-dependencies]
criterion = "0.3"
rand_xorshift = "0.2"
[features]
@@ -30,5 +32,9 @@ unstable-features = ["expose-arith"]
expose-arith = []
default = []
[[bench]]
name = "pairing_benches"
harness = false
[badges]
maintenance = { status = "actively-developed" }

View File

@@ -1,13 +1,14 @@
mod g1 {
pub(crate) mod g1 {
use criterion::{criterion_group, Criterion};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use std::ops::AddAssign;
use ff::Field;
use group::CurveProjective;
use pairing::bls12_381::*;
#[bench]
fn bench_g1_mul_assign(b: &mut ::test::Bencher) {
fn bench_g1_mul_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -20,16 +21,17 @@ mod g1 {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("G1::mul_assign", |b| {
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) {
fn bench_g1_add_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -42,16 +44,17 @@ mod g1 {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("G1::add_assign", |b| {
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) {
fn bench_g1_add_assign_mixed(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -64,25 +67,35 @@ mod g1 {
.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
c.bench_function("G1::add_assign_mixed", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
criterion_group!(
benches,
bench_g1_add_assign,
bench_g1_add_assign_mixed,
bench_g1_mul_assign,
);
}
mod g2 {
pub(crate) mod g2 {
use criterion::{criterion_group, Criterion};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use std::ops::AddAssign;
use ff::Field;
use group::CurveProjective;
use pairing::bls12_381::*;
#[bench]
fn bench_g2_mul_assign(b: &mut ::test::Bencher) {
fn bench_g2_mul_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -95,16 +108,17 @@ mod g2 {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("G2::mul_assign", |b| {
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) {
fn bench_g2_add_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -117,16 +131,17 @@ mod g2 {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("G2::add_assign", |b| {
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) {
fn bench_g2_add_assign_mixed(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -139,11 +154,20 @@ mod g2 {
.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
c.bench_function("G2::add_assign_mixed", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
criterion_group!(
benches,
bench_g2_add_assign,
bench_g2_add_assign_mixed,
bench_g2_mul_assign,
);
}

View File

@@ -1,11 +1,12 @@
use criterion::{criterion_group, Criterion};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField};
use pairing::bls12_381::*;
#[bench]
fn bench_fq_repr_add_nocarry(b: &mut ::test::Bencher) {
fn bench_fq_repr_add_nocarry(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -27,16 +28,17 @@ fn bench_fq_repr_add_nocarry(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_nocarry(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("FqRepr::add_nocarry", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_nocarry(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fq_repr_sub_noborrow(b: &mut ::test::Bencher) {
fn bench_fq_repr_sub_noborrow(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -57,16 +59,17 @@ fn bench_fq_repr_sub_noborrow(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.sub_noborrow(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("FqRepr::sub_noborrow", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.sub_noborrow(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fq_repr_num_bits(b: &mut ::test::Bencher) {
fn bench_fq_repr_num_bits(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -79,15 +82,16 @@ fn bench_fq_repr_num_bits(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let tmp = v[count].num_bits();
count = (count + 1) % SAMPLES;
tmp
c.bench_function("FqRepr::num_bits", |b| {
b.iter(|| {
let tmp = v[count].num_bits();
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fq_repr_mul2(b: &mut ::test::Bencher) {
fn bench_fq_repr_mul2(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -100,16 +104,17 @@ fn bench_fq_repr_mul2(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.mul2();
count = (count + 1) % SAMPLES;
tmp
c.bench_function("FqRepr::mul2", |b| {
b.iter(|| {
let mut tmp = v[count];
tmp.mul2();
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fq_repr_div2(b: &mut ::test::Bencher) {
fn bench_fq_repr_div2(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -122,16 +127,17 @@ fn bench_fq_repr_div2(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.div2();
count = (count + 1) % SAMPLES;
tmp
c.bench_function("FqRepr::div2", |b| {
b.iter(|| {
let mut tmp = v[count];
tmp.div2();
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fq_add_assign(b: &mut ::test::Bencher) {
fn bench_fq_add_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -144,16 +150,17 @@ fn bench_fq_add_assign(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fq::add_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fq_sub_assign(b: &mut ::test::Bencher) {
fn bench_fq_sub_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -166,16 +173,17 @@ fn bench_fq_sub_assign(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.sub_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fq::sub_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.sub_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fq_mul_assign(b: &mut ::test::Bencher) {
fn bench_fq_mul_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -188,16 +196,17 @@ fn bench_fq_mul_assign(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fq::mul_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fq_square(b: &mut ::test::Bencher) {
fn bench_fq_square(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -208,16 +217,16 @@ fn bench_fq_square(b: &mut ::test::Bencher) {
let v: Vec<Fq> = (0..SAMPLES).map(|_| Fq::random(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.square();
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fq::square", |b| {
b.iter(|| {
let tmp = v[count].square();
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fq_inverse(b: &mut ::test::Bencher) {
fn bench_fq_invert(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -228,14 +237,15 @@ fn bench_fq_inverse(b: &mut ::test::Bencher) {
let v: Vec<Fq> = (0..SAMPLES).map(|_| Fq::random(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].inverse()
c.bench_function("Fq::invert", |b| {
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].invert()
})
});
}
#[bench]
fn bench_fq_negate(b: &mut ::test::Bencher) {
fn bench_fq_neg(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -246,16 +256,16 @@ fn bench_fq_negate(b: &mut ::test::Bencher) {
let v: Vec<Fq> = (0..SAMPLES).map(|_| Fq::random(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.negate();
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fq::neg", |b| {
b.iter(|| {
let tmp = v[count].neg();
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fq_sqrt(b: &mut ::test::Bencher) {
fn bench_fq_sqrt(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -264,22 +274,19 @@ fn bench_fq_sqrt(b: &mut ::test::Bencher) {
]);
let v: Vec<Fq> = (0..SAMPLES)
.map(|_| {
let mut tmp = Fq::random(&mut rng);
tmp.square();
tmp
})
.map(|_| Fq::random(&mut rng).square())
.collect();
let mut count = 0;
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].sqrt()
c.bench_function("Fq::sqrt", |b| {
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].sqrt()
})
});
}
#[bench]
fn bench_fq_into_repr(b: &mut ::test::Bencher) {
fn bench_fq_into_repr(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -290,14 +297,15 @@ fn bench_fq_into_repr(b: &mut ::test::Bencher) {
let v: Vec<Fq> = (0..SAMPLES).map(|_| Fq::random(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].into_repr()
c.bench_function("Fq::into_repr", |b| {
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].into_repr()
})
});
}
#[bench]
fn bench_fq_from_repr(b: &mut ::test::Bencher) {
fn bench_fq_from_repr(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -310,8 +318,28 @@ fn bench_fq_from_repr(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
count = (count + 1) % SAMPLES;
Fq::from_repr(v[count])
c.bench_function("Fq::from_repr", |b| {
b.iter(|| {
count = (count + 1) % SAMPLES;
Fq::from_repr(v[count])
})
});
}
criterion_group!(
benches,
bench_fq_repr_add_nocarry,
bench_fq_repr_sub_noborrow,
bench_fq_repr_num_bits,
bench_fq_repr_mul2,
bench_fq_repr_div2,
bench_fq_add_assign,
bench_fq_sub_assign,
bench_fq_mul_assign,
bench_fq_square,
bench_fq_invert,
bench_fq_neg,
bench_fq_sqrt,
bench_fq_into_repr,
bench_fq_from_repr,
);

View File

@@ -1,11 +1,12 @@
use criterion::{criterion_group, Criterion};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use std::ops::{AddAssign, MulAssign, SubAssign};
use ff::Field;
use pairing::bls12_381::*;
#[bench]
fn bench_fq12_add_assign(b: &mut ::test::Bencher) {
fn bench_fq12_add_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -18,16 +19,17 @@ fn bench_fq12_add_assign(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fq12::add_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fq12_sub_assign(b: &mut ::test::Bencher) {
fn bench_fq12_sub_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -40,16 +42,17 @@ fn bench_fq12_sub_assign(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.sub_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fq12::sub_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.sub_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fq12_mul_assign(b: &mut ::test::Bencher) {
fn bench_fq12_mul_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -62,16 +65,17 @@ fn bench_fq12_mul_assign(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fq12::mul_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fq12_squaring(b: &mut ::test::Bencher) {
fn bench_fq12_squaring(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -82,16 +86,16 @@ fn bench_fq12_squaring(b: &mut ::test::Bencher) {
let v: Vec<Fq12> = (0..SAMPLES).map(|_| Fq12::random(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.square();
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fq12::square", |b| {
b.iter(|| {
let tmp = v[count].square();
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fq12_inverse(b: &mut ::test::Bencher) {
fn bench_fq12_invert(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -102,9 +106,20 @@ fn bench_fq12_inverse(b: &mut ::test::Bencher) {
let v: Vec<Fq12> = (0..SAMPLES).map(|_| Fq12::random(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let tmp = v[count].inverse();
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fq12::invert", |b| {
b.iter(|| {
let tmp = v[count].invert();
count = (count + 1) % SAMPLES;
tmp
})
});
}
criterion_group!(
benches,
bench_fq12_add_assign,
bench_fq12_sub_assign,
bench_fq12_mul_assign,
bench_fq12_squaring,
bench_fq12_invert,
);

View File

@@ -1,11 +1,12 @@
use criterion::{criterion_group, Criterion};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use std::ops::{AddAssign, MulAssign, SubAssign};
use ff::{Field, SqrtField};
use pairing::bls12_381::*;
#[bench]
fn bench_fq2_add_assign(b: &mut ::test::Bencher) {
fn bench_fq2_add_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -18,16 +19,17 @@ fn bench_fq2_add_assign(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fq2::add_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fq2_sub_assign(b: &mut ::test::Bencher) {
fn bench_fq2_sub_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -40,16 +42,17 @@ fn bench_fq2_sub_assign(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.sub_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fq2::sub_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.sub_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fq2_mul_assign(b: &mut ::test::Bencher) {
fn bench_fq2_mul_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -62,16 +65,17 @@ fn bench_fq2_mul_assign(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fq2::mul_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fq2_squaring(b: &mut ::test::Bencher) {
fn bench_fq2_squaring(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -82,16 +86,16 @@ fn bench_fq2_squaring(b: &mut ::test::Bencher) {
let v: Vec<Fq2> = (0..SAMPLES).map(|_| Fq2::random(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.square();
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fq2::square", |b| {
b.iter(|| {
let tmp = v[count].square();
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fq2_inverse(b: &mut ::test::Bencher) {
fn bench_fq2_invert(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -102,15 +106,16 @@ fn bench_fq2_inverse(b: &mut ::test::Bencher) {
let v: Vec<Fq2> = (0..SAMPLES).map(|_| Fq2::random(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let tmp = v[count].inverse();
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fq2::invert", |b| {
b.iter(|| {
let tmp = v[count].invert();
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fq2_sqrt(b: &mut ::test::Bencher) {
fn bench_fq2_sqrt(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -121,9 +126,21 @@ fn bench_fq2_sqrt(b: &mut ::test::Bencher) {
let v: Vec<Fq2> = (0..SAMPLES).map(|_| Fq2::random(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let tmp = v[count].sqrt();
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fq2::sqrt", |b| {
b.iter(|| {
let tmp = v[count].sqrt();
count = (count + 1) % SAMPLES;
tmp
})
});
}
criterion_group!(
benches,
bench_fq2_add_assign,
bench_fq2_sub_assign,
bench_fq2_mul_assign,
bench_fq2_squaring,
bench_fq2_invert,
bench_fq2_sqrt,
);

View File

@@ -1,11 +1,12 @@
use criterion::{criterion_group, Criterion};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField};
use pairing::bls12_381::*;
#[bench]
fn bench_fr_repr_add_nocarry(b: &mut ::test::Bencher) {
fn bench_fr_repr_add_nocarry(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -27,16 +28,17 @@ fn bench_fr_repr_add_nocarry(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_nocarry(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("FrRepr::add_nocarry", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_nocarry(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fr_repr_sub_noborrow(b: &mut ::test::Bencher) {
fn bench_fr_repr_sub_noborrow(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -57,16 +59,17 @@ fn bench_fr_repr_sub_noborrow(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.sub_noborrow(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("FrRepr::sub_noborrow", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.sub_noborrow(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fr_repr_num_bits(b: &mut ::test::Bencher) {
fn bench_fr_repr_num_bits(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -79,15 +82,16 @@ fn bench_fr_repr_num_bits(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let tmp = v[count].num_bits();
count = (count + 1) % SAMPLES;
tmp
c.bench_function("FrRepr::num_bits", |b| {
b.iter(|| {
let tmp = v[count].num_bits();
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fr_repr_mul2(b: &mut ::test::Bencher) {
fn bench_fr_repr_mul2(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -100,16 +104,17 @@ fn bench_fr_repr_mul2(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.mul2();
count = (count + 1) % SAMPLES;
tmp
c.bench_function("FrRepr::mul2", |b| {
b.iter(|| {
let mut tmp = v[count];
tmp.mul2();
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fr_repr_div2(b: &mut ::test::Bencher) {
fn bench_fr_repr_div2(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -122,16 +127,17 @@ fn bench_fr_repr_div2(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.div2();
count = (count + 1) % SAMPLES;
tmp
c.bench_function("FrRepr::div2", |b| {
b.iter(|| {
let mut tmp = v[count];
tmp.div2();
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fr_add_assign(b: &mut ::test::Bencher) {
fn bench_fr_add_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -144,16 +150,17 @@ fn bench_fr_add_assign(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fr::add_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fr_sub_assign(b: &mut ::test::Bencher) {
fn bench_fr_sub_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -166,16 +173,17 @@ fn bench_fr_sub_assign(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.sub_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fr::sub_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.sub_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fr_mul_assign(b: &mut ::test::Bencher) {
fn bench_fr_mul_assign(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -188,16 +196,17 @@ fn bench_fr_mul_assign(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fr::mul_assign", |b| {
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fr_square(b: &mut ::test::Bencher) {
fn bench_fr_square(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -208,16 +217,16 @@ fn bench_fr_square(b: &mut ::test::Bencher) {
let v: Vec<Fr> = (0..SAMPLES).map(|_| Fr::random(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.square();
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fr::square", |b| {
b.iter(|| {
let tmp = v[count].square();
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fr_inverse(b: &mut ::test::Bencher) {
fn bench_fr_invert(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -228,14 +237,15 @@ fn bench_fr_inverse(b: &mut ::test::Bencher) {
let v: Vec<Fr> = (0..SAMPLES).map(|_| Fr::random(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].inverse()
c.bench_function("Fr::invert", |b| {
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].invert()
})
});
}
#[bench]
fn bench_fr_negate(b: &mut ::test::Bencher) {
fn bench_fr_neg(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -246,16 +256,16 @@ fn bench_fr_negate(b: &mut ::test::Bencher) {
let v: Vec<Fr> = (0..SAMPLES).map(|_| Fr::random(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.negate();
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Fr::neg", |b| {
b.iter(|| {
let tmp = v[count].neg();
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_fr_sqrt(b: &mut ::test::Bencher) {
fn bench_fr_sqrt(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -264,22 +274,19 @@ fn bench_fr_sqrt(b: &mut ::test::Bencher) {
]);
let v: Vec<Fr> = (0..SAMPLES)
.map(|_| {
let mut tmp = Fr::random(&mut rng);
tmp.square();
tmp
})
.map(|_| Fr::random(&mut rng).square())
.collect();
let mut count = 0;
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].sqrt()
c.bench_function("Fr::sqrt", |b| {
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].sqrt()
})
});
}
#[bench]
fn bench_fr_into_repr(b: &mut ::test::Bencher) {
fn bench_fr_into_repr(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -290,14 +297,15 @@ fn bench_fr_into_repr(b: &mut ::test::Bencher) {
let v: Vec<Fr> = (0..SAMPLES).map(|_| Fr::random(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].into_repr()
c.bench_function("Fr::into_repr", |b| {
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].into_repr()
})
});
}
#[bench]
fn bench_fr_from_repr(b: &mut ::test::Bencher) {
fn bench_fr_from_repr(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -310,8 +318,28 @@ fn bench_fr_from_repr(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
count = (count + 1) % SAMPLES;
Fr::from_repr(v[count])
c.bench_function("Fr::from_repr", |b| {
b.iter(|| {
count = (count + 1) % SAMPLES;
Fr::from_repr(v[count])
})
});
}
criterion_group!(
benches,
bench_fr_repr_add_nocarry,
bench_fr_repr_sub_noborrow,
bench_fr_repr_num_bits,
bench_fr_repr_mul2,
bench_fr_repr_div2,
bench_fr_add_assign,
bench_fr_sub_assign,
bench_fr_mul_assign,
bench_fr_square,
bench_fr_invert,
bench_fr_neg,
bench_fr_sqrt,
bench_fr_into_repr,
bench_fr_from_repr,
);

View File

@@ -1,9 +1,10 @@
mod ec;
mod fq;
mod fq12;
mod fq2;
mod fr;
pub(crate) mod ec;
pub(crate) mod fq;
pub(crate) mod fq12;
pub(crate) mod fq2;
pub(crate) mod fr;
use criterion::{criterion_group, Criterion};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
@@ -11,8 +12,7 @@ use group::CurveProjective;
use pairing::bls12_381::*;
use pairing::{Engine, PairingCurveAffine};
#[bench]
fn bench_pairing_g1_preparation(b: &mut ::test::Bencher) {
fn bench_pairing_g1_preparation(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -23,15 +23,16 @@ fn bench_pairing_g1_preparation(b: &mut ::test::Bencher) {
let v: Vec<G1> = (0..SAMPLES).map(|_| G1::random(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let tmp = G1Affine::from(v[count]).prepare();
count = (count + 1) % SAMPLES;
tmp
c.bench_function("G1 preparation", |b| {
b.iter(|| {
let tmp = G1Affine::from(v[count]).prepare();
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_pairing_g2_preparation(b: &mut ::test::Bencher) {
fn bench_pairing_g2_preparation(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -42,15 +43,16 @@ fn bench_pairing_g2_preparation(b: &mut ::test::Bencher) {
let v: Vec<G2> = (0..SAMPLES).map(|_| G2::random(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let tmp = G2Affine::from(v[count]).prepare();
count = (count + 1) % SAMPLES;
tmp
c.bench_function("G2 preparation", |b| {
b.iter(|| {
let tmp = G2Affine::from(v[count]).prepare();
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_pairing_miller_loop(b: &mut ::test::Bencher) {
fn bench_pairing_miller_loop(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -68,15 +70,16 @@ fn bench_pairing_miller_loop(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let tmp = Bls12::miller_loop(&[(&v[count].0, &v[count].1)]);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Miller loop", |b| {
b.iter(|| {
let tmp = Bls12::miller_loop(&[(&v[count].0, &v[count].1)]);
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_pairing_final_exponentiation(b: &mut ::test::Bencher) {
fn bench_pairing_final_exponentiation(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -95,15 +98,16 @@ fn bench_pairing_final_exponentiation(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let tmp = Bls12::final_exponentiation(&v[count]);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Final exponentiation", |b| {
b.iter(|| {
let tmp = Bls12::final_exponentiation(&v[count]);
count = (count + 1) % SAMPLES;
tmp
})
});
}
#[bench]
fn bench_pairing_full(b: &mut ::test::Bencher) {
fn bench_pairing_full(c: &mut Criterion) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([
@@ -116,9 +120,20 @@ fn bench_pairing_full(b: &mut ::test::Bencher) {
.collect();
let mut count = 0;
b.iter(|| {
let tmp = Bls12::pairing(v[count].0, v[count].1);
count = (count + 1) % SAMPLES;
tmp
c.bench_function("Full pairing", |b| {
b.iter(|| {
let tmp = Bls12::pairing(v[count].0, v[count].1);
count = (count + 1) % SAMPLES;
tmp
})
});
}
criterion_group!(
benches,
bench_pairing_g1_preparation,
bench_pairing_g2_preparation,
bench_pairing_miller_loop,
bench_pairing_final_exponentiation,
bench_pairing_full,
);

View File

@@ -1,10 +1,12 @@
#![feature(test)]
extern crate ff;
extern crate group;
extern crate pairing;
extern crate rand_core;
extern crate rand_xorshift;
extern crate test;
use criterion::criterion_main;
mod bls12_381;
criterion_main!(
bls12_381::benches,
bls12_381::ec::g1::benches,
bls12_381::ec::g2::benches,
bls12_381::fq::benches,
bls12_381::fq12::benches,
bls12_381::fq2::benches,
bls12_381::fr::benches,
);

View File

@@ -54,10 +54,8 @@ macro_rules! curve_impl {
// 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 z1 = self.z.square();
let mut z2 = other.z.square();
let mut tmp1 = self.x;
tmp1.mul_assign(&z2);
@@ -88,7 +86,7 @@ macro_rules! curve_impl {
for i in bits {
res.double();
if i {
res.add_assign_mixed(self)
res.add_assign(self)
}
}
res
@@ -99,16 +97,14 @@ macro_rules! curve_impl {
///
/// 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> {
fn get_point_from_x(x: $basefield, greatest: bool) -> CtOption<$affine> {
// Compute x^3 + b
let mut x3b = x;
x3b.square();
let mut x3b = x.square();
x3b.mul_assign(&x);
x3b.add_assign(&$affine::get_coeff_b());
x3b.sqrt().map(|y| {
let mut negy = y;
negy.negate();
let negy = y.neg();
$affine {
x: x,
@@ -123,11 +119,9 @@ macro_rules! curve_impl {
true
} else {
// Check that the point is on the curve
let mut y2 = self.y;
y2.square();
let y2 = self.y.square();
let mut x3b = self.x;
x3b.square();
let mut x3b = self.x.square();
x3b.mul_assign(&self.x);
x3b.add_assign(&Self::get_coeff_b());
@@ -140,6 +134,19 @@ macro_rules! curve_impl {
}
}
impl ::std::ops::Neg for $affine {
type Output = Self;
#[inline]
fn neg(self) -> Self {
let mut ret = self;
if !ret.is_zero() {
ret.y = ret.y.neg();
}
ret
}
}
impl CurveAffine for $affine {
type Engine = Bls12;
type Scalar = $scalarfield;
@@ -169,12 +176,6 @@ macro_rules! curve_impl {
self.mul_bits(bits)
}
fn negate(&mut self) {
if !self.is_zero() {
self.y.negate();
}
}
fn into_projective(&self) -> $projective {
(*self).into()
}
@@ -194,6 +195,309 @@ macro_rules! curve_impl {
}
}
impl ::std::ops::Neg for $projective {
type Output = Self;
#[inline]
fn neg(self) -> Self {
let mut ret = self;
if !ret.is_zero() {
ret.y = ret.y.neg();
}
ret
}
}
impl<'r> ::std::ops::Add<&'r $projective> for $projective {
type Output = Self;
#[inline]
fn add(self, other: &Self) -> Self {
let mut ret = self;
ret.add_assign(other);
ret
}
}
impl ::std::ops::Add for $projective {
type Output = Self;
#[inline]
fn add(self, other: Self) -> Self {
self + &other
}
}
impl<'r> ::std::ops::AddAssign<&'r $projective> for $projective {
fn add_assign(&mut self, other: &Self) {
if self.is_zero() {
*self = *other;
return;
}
if other.is_zero() {
return;
}
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
// Z1Z1 = Z1^2
let z1z1 = self.z.square();
// Z2Z2 = Z2^2
let z2z2 = other.z.square();
// U1 = X1*Z2Z2
let mut u1 = self.x;
u1.mul_assign(&z2z2);
// U2 = X2*Z1Z1
let mut u2 = other.x;
u2.mul_assign(&z1z1);
// S1 = Y1*Z2*Z2Z2
let mut s1 = self.y;
s1.mul_assign(&other.z);
s1.mul_assign(&z2z2);
// S2 = Y2*Z1*Z1Z1
let mut s2 = other.y;
s2.mul_assign(&self.z);
s2.mul_assign(&z1z1);
if u1 == u2 && s1 == s2 {
// The two points are equal, so we double.
self.double();
} else {
// If we're adding -a and a together, self.z becomes zero as H becomes zero.
// H = U2-U1
let mut h = u2;
h.sub_assign(&u1);
// I = (2*H)^2
let i = h.double().square();
// J = H*I
let mut j = h;
j.mul_assign(&i);
// r = 2*(S2-S1)
let mut r = s2;
r.sub_assign(&s1);
r = r.double();
// V = U1*I
let mut v = u1;
v.mul_assign(&i);
// X3 = r^2 - J - 2*V
self.x = r.square();
self.x.sub_assign(&j);
self.x.sub_assign(&v);
self.x.sub_assign(&v);
// Y3 = r*(V - X3) - 2*S1*J
self.y = v;
self.y.sub_assign(&self.x);
self.y.mul_assign(&r);
s1.mul_assign(&j); // S1 = S1 * J * 2
s1 = s1.double();
self.y.sub_assign(&s1);
// Z3 = ((Z1+Z2)^2 - Z1Z1 - Z2Z2)*H
self.z.add_assign(&other.z);
self.z = self.z.square();
self.z.sub_assign(&z1z1);
self.z.sub_assign(&z2z2);
self.z.mul_assign(&h);
}
}
}
impl ::std::ops::AddAssign for $projective {
#[inline]
fn add_assign(&mut self, other: Self) {
self.add_assign(&other);
}
}
impl<'r> ::std::ops::Sub<&'r $projective> for $projective {
type Output = Self;
#[inline]
fn sub(self, other: &Self) -> Self {
let mut ret = self;
ret.sub_assign(other);
ret
}
}
impl ::std::ops::Sub for $projective {
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self {
self - &other
}
}
impl<'r> ::std::ops::SubAssign<&'r $projective> for $projective {
fn sub_assign(&mut self, other: &Self) {
self.add_assign(&other.neg());
}
}
impl ::std::ops::SubAssign for $projective {
#[inline]
fn sub_assign(&mut self, other: Self) {
self.sub_assign(&other);
}
}
impl<'r> ::std::ops::Add<&'r <$projective as CurveProjective>::Affine> for $projective {
type Output = Self;
#[inline]
fn add(self, other: &<$projective as CurveProjective>::Affine) -> Self {
let mut ret = self;
ret.add_assign(other);
ret
}
}
impl ::std::ops::Add<<$projective as CurveProjective>::Affine> for $projective {
type Output = Self;
#[inline]
fn add(self, other: <$projective as CurveProjective>::Affine) -> Self {
self + &other
}
}
impl<'r> ::std::ops::AddAssign<&'r <$projective as CurveProjective>::Affine>
for $projective
{
fn add_assign(&mut self, other: &<$projective as CurveProjective>::Affine) {
if other.is_zero() {
return;
}
if self.is_zero() {
self.x = other.x;
self.y = other.y;
self.z = $basefield::one();
return;
}
// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl
// Z1Z1 = Z1^2
let z1z1 = self.z.square();
// U2 = X2*Z1Z1
let mut u2 = other.x;
u2.mul_assign(&z1z1);
// S2 = Y2*Z1*Z1Z1
let mut s2 = other.y;
s2.mul_assign(&self.z);
s2.mul_assign(&z1z1);
if self.x == u2 && self.y == s2 {
// The two points are equal, so we double.
self.double();
} else {
// If we're adding -a and a together, self.z becomes zero as H becomes zero.
// H = U2-X1
let mut h = u2;
h.sub_assign(&self.x);
// HH = H^2
let hh = h.square();
// I = 4*HH
let i = hh.double().double();
// J = H*I
let mut j = h;
j.mul_assign(&i);
// r = 2*(S2-Y1)
let mut r = s2;
r.sub_assign(&self.y);
r = r.double();
// V = X1*I
let mut v = self.x;
v.mul_assign(&i);
// X3 = r^2 - J - 2*V
self.x = r.square();
self.x.sub_assign(&j);
self.x.sub_assign(&v);
self.x.sub_assign(&v);
// Y3 = r*(V-X3)-2*Y1*J
j.mul_assign(&self.y); // J = 2*Y1*J
j = j.double();
self.y = v;
self.y.sub_assign(&self.x);
self.y.mul_assign(&r);
self.y.sub_assign(&j);
// Z3 = (Z1+H)^2-Z1Z1-HH
self.z.add_assign(&h);
self.z = self.z.square();
self.z.sub_assign(&z1z1);
self.z.sub_assign(&hh);
}
}
}
impl ::std::ops::AddAssign<<$projective as CurveProjective>::Affine> for $projective {
#[inline]
fn add_assign(&mut self, other: <$projective as CurveProjective>::Affine) {
self.add_assign(&other);
}
}
impl<'r> ::std::ops::Sub<&'r <$projective as CurveProjective>::Affine> for $projective {
type Output = Self;
#[inline]
fn sub(self, other: &<$projective as CurveProjective>::Affine) -> Self {
let mut ret = self;
ret.sub_assign(other);
ret
}
}
impl ::std::ops::Sub<<$projective as CurveProjective>::Affine> for $projective {
type Output = Self;
#[inline]
fn sub(self, other: <$projective as CurveProjective>::Affine) -> Self {
self - &other
}
}
impl<'r> ::std::ops::SubAssign<&'r <$projective as CurveProjective>::Affine>
for $projective
{
fn sub_assign(&mut self, other: &<$projective as CurveProjective>::Affine) {
self.add_assign(&other.neg());
}
}
impl ::std::ops::SubAssign<<$projective as CurveProjective>::Affine> for $projective {
#[inline]
fn sub_assign(&mut self, other: <$projective as CurveProjective>::Affine) {
self.sub_assign(&other);
}
}
impl CurveProjective for $projective {
type Engine = Bls12;
type Scalar = $scalarfield;
@@ -205,8 +509,9 @@ macro_rules! curve_impl {
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();
let p = $affine::get_point_from_x(x, greatest);
if p.is_some().into() {
let p = p.unwrap().scale_by_cofactor();
if !p.is_zero() {
return p;
@@ -257,7 +562,7 @@ macro_rules! curve_impl {
}
// Invert `tmp`.
tmp = tmp.inverse().unwrap(); // Guaranteed to be nonzero.
tmp = tmp.invert().unwrap(); // Guaranteed to be nonzero.
// Second pass: iterate backwards to compute inverses
for (g, s) in v
@@ -284,8 +589,7 @@ macro_rules! curve_impl {
// 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
let mut z = g.z.square(); // 1/z^2
g.x.mul_assign(&z); // x/z^2
z.mul_assign(&g.z); // 1/z^3
g.y.mul_assign(&z); // y/z^3
@@ -306,37 +610,32 @@ macro_rules! curve_impl {
// 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();
let a = self.x.square();
// B = Y1^2
let mut b = self.y;
b.square();
let b = self.y.square();
// C = B^2
let mut c = b;
c.square();
let mut c = b.square();
// D = 2*((X1+B)2-A-C)
let mut d = self.x;
d.add_assign(&b);
d.square();
d = d.square();
d.sub_assign(&a);
d.sub_assign(&c);
d.double();
d = d.double();
// E = 3*A
let mut e = a;
e.double();
let mut e = a.double();
e.add_assign(&a);
// F = E^2
let mut f = e;
f.square();
let f = e.square();
// Z3 = 2*Y1*Z1
self.z.mul_assign(&self.y);
self.z.double();
self.z = self.z.double();
// X3 = F-2*D
self.x = f;
@@ -347,190 +646,10 @@ macro_rules! curve_impl {
self.y = d;
self.y.sub_assign(&self.x);
self.y.mul_assign(&e);
c.double();
c.double();
c.double();
c = c.double().double().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();
@@ -544,7 +663,7 @@ macro_rules! curve_impl {
}
if i {
res.add_assign(self);
res.add_assign(&*self);
}
}
@@ -595,9 +714,8 @@ macro_rules! curve_impl {
}
} 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();
let zinv = p.z.invert().unwrap();
let mut zinv_powered = zinv.square();
// X/Z^2
let mut x = p.x;
@@ -627,6 +745,8 @@ pub mod g1 {
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
use rand_core::RngCore;
use std::fmt;
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use subtle::CtOption;
curve_impl!(
"G1",
@@ -831,7 +951,12 @@ pub mod g1 {
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)
let ret = G1Affine::get_point_from_x(x, greatest);
if ret.is_some().into() {
Ok(ret.unwrap())
} else {
Err(GroupDecodingError::NotOnCurve)
}
}
}
fn from_affine(affine: G1Affine) -> Self {
@@ -848,8 +973,7 @@ pub mod g1 {
affine.x.into_repr().write_be(&mut writer).unwrap();
}
let mut negy = affine.y;
negy.negate();
let negy = affine.y.neg();
// Set the third most significant bit if the correct y-coordinate
// is lexicographically largest.
@@ -940,15 +1064,15 @@ pub mod g1 {
let mut i = 0;
loop {
// y^2 = x^3 + b
let mut rhs = x;
rhs.square();
let mut rhs = x.square();
rhs.mul_assign(&x);
rhs.add_assign(&G1Affine::get_coeff_b());
if let Some(y) = rhs.sqrt() {
let y = rhs.sqrt();
if y.is_some().into() {
let y = y.unwrap();
let yrepr = y.into_repr();
let mut negy = y;
negy.negate();
let negy = y.neg();
let negyrepr = negy.into_repr();
let p = G1Affine {
@@ -1276,7 +1400,7 @@ pub mod g1 {
assert_eq!(tmp1, c.into_projective());
let mut tmp2 = a.into_projective();
tmp2.add_assign_mixed(&b);
tmp2.add_assign(&b);
assert_eq!(tmp2.into_affine(), c);
assert_eq!(tmp2, c.into_projective());
}
@@ -1296,6 +1420,8 @@ pub mod g2 {
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
use rand_core::RngCore;
use std::fmt;
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use subtle::CtOption;
curve_impl!(
"G2",
@@ -1524,7 +1650,12 @@ pub mod g2 {
})?,
};
G2Affine::get_point_from_x(x, greatest).ok_or(GroupDecodingError::NotOnCurve)
let ret = G2Affine::get_point_from_x(x, greatest);
if ret.is_some().into() {
Ok(ret.unwrap())
} else {
Err(GroupDecodingError::NotOnCurve)
}
}
}
fn from_affine(affine: G2Affine) -> Self {
@@ -1542,8 +1673,7 @@ pub mod g2 {
affine.x.c0.into_repr().write_be(&mut writer).unwrap();
}
let mut negy = affine.y;
negy.negate();
let negy = affine.y.neg();
// Set the third most significant bit if the correct y-coordinate
// is lexicographically largest.
@@ -1646,14 +1776,14 @@ pub mod g2 {
let mut i = 0;
loop {
// y^2 = x^3 + b
let mut rhs = x;
rhs.square();
let mut rhs = x.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 y = rhs.sqrt();
if y.is_some().into() {
let y = y.unwrap();
let negy = y.neg();
let p = G2Affine {
x,

View File

@@ -1,5 +1,9 @@
use super::fq2::Fq2;
use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr};
use std::ops::{AddAssign, MulAssign, SubAssign};
#[cfg(test)]
use std::ops::Neg;
// B coefficient of BLS12-381 curve, 4.
pub const B_COEFF: Fq = Fq(FqRepr([
@@ -454,14 +458,14 @@ fn test_b_coeff() {
}
#[test]
#[allow(clippy::cognitive_complexity)]
fn test_frob_coeffs() {
let mut nqr = Fq::one();
nqr.negate();
let nqr = Fq::one().neg();
assert_eq!(FROBENIUS_COEFF_FQ2_C1[0], Fq::one());
assert_eq!(
FROBENIUS_COEFF_FQ2_C1[1],
nqr.pow([
nqr.pow_vartime([
0xdcff7fffffffd555,
0xf55ffff58a9ffff,
0xb39869507b587b12,
@@ -479,7 +483,7 @@ fn test_frob_coeffs() {
assert_eq!(FROBENIUS_COEFF_FQ6_C1[0], Fq2::one());
assert_eq!(
FROBENIUS_COEFF_FQ6_C1[1],
nqr.pow([
nqr.pow_vartime([
0x9354ffffffffe38e,
0xa395554e5c6aaaa,
0xcd104635a790520c,
@@ -490,7 +494,7 @@ fn test_frob_coeffs() {
);
assert_eq!(
FROBENIUS_COEFF_FQ6_C1[2],
nqr.pow([
nqr.pow_vartime([
0xb78e0000097b2f68,
0xd44f23b47cbd64e3,
0x5cb9668120b069a9,
@@ -507,7 +511,7 @@ fn test_frob_coeffs() {
);
assert_eq!(
FROBENIUS_COEFF_FQ6_C1[3],
nqr.pow([
nqr.pow_vartime([
0xdbc6fcd6f35b9e06,
0x997dead10becd6aa,
0x9dbbd24c17206460,
@@ -530,7 +534,7 @@ fn test_frob_coeffs() {
);
assert_eq!(
FROBENIUS_COEFF_FQ6_C1[4],
nqr.pow([
nqr.pow_vartime([
0x4649add3c71c6d90,
0x43caa6528972a865,
0xcda8445bbaaa0fbb,
@@ -559,7 +563,7 @@ fn test_frob_coeffs() {
);
assert_eq!(
FROBENIUS_COEFF_FQ6_C1[5],
nqr.pow([
nqr.pow_vartime([
0xf896f792732eb2be,
0x49c86a6d1dc593a1,
0xe5b31e94581f91c3,
@@ -596,7 +600,7 @@ fn test_frob_coeffs() {
assert_eq!(FROBENIUS_COEFF_FQ6_C2[0], Fq2::one());
assert_eq!(
FROBENIUS_COEFF_FQ6_C2[1],
nqr.pow([
nqr.pow_vartime([
0x26a9ffffffffc71c,
0x1472aaa9cb8d5555,
0x9a208c6b4f20a418,
@@ -607,7 +611,7 @@ fn test_frob_coeffs() {
);
assert_eq!(
FROBENIUS_COEFF_FQ6_C2[2],
nqr.pow([
nqr.pow_vartime([
0x6f1c000012f65ed0,
0xa89e4768f97ac9c7,
0xb972cd024160d353,
@@ -624,7 +628,7 @@ fn test_frob_coeffs() {
);
assert_eq!(
FROBENIUS_COEFF_FQ6_C2[3],
nqr.pow([
nqr.pow_vartime([
0xb78df9ade6b73c0c,
0x32fbd5a217d9ad55,
0x3b77a4982e40c8c1,
@@ -647,7 +651,7 @@ fn test_frob_coeffs() {
);
assert_eq!(
FROBENIUS_COEFF_FQ6_C2[4],
nqr.pow([
nqr.pow_vartime([
0x8c935ba78e38db20,
0x87954ca512e550ca,
0x9b5088b775541f76,
@@ -676,7 +680,7 @@ fn test_frob_coeffs() {
);
assert_eq!(
FROBENIUS_COEFF_FQ6_C2[5],
nqr.pow([
nqr.pow_vartime([
0xf12def24e65d657c,
0x9390d4da3b8b2743,
0xcb663d28b03f2386,
@@ -713,7 +717,7 @@ fn test_frob_coeffs() {
assert_eq!(FROBENIUS_COEFF_FQ12_C1[0], Fq2::one());
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[1],
nqr.pow([
nqr.pow_vartime([
0x49aa7ffffffff1c7,
0x51caaaa72e35555,
0xe688231ad3c82906,
@@ -724,7 +728,7 @@ fn test_frob_coeffs() {
);
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[2],
nqr.pow([
nqr.pow_vartime([
0xdbc7000004bd97b4,
0xea2791da3e5eb271,
0x2e5cb340905834d4,
@@ -741,7 +745,7 @@ fn test_frob_coeffs() {
);
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[3],
nqr.pow(vec![
nqr.pow_vartime(vec![
0x6de37e6b79adcf03,
0x4cbef56885f66b55,
0x4edde9260b903230,
@@ -764,7 +768,7 @@ fn test_frob_coeffs() {
);
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[4],
nqr.pow(vec![
nqr.pow_vartime(vec![
0xa324d6e9e38e36c8,
0xa1e5532944b95432,
0x66d4222ddd5507dd,
@@ -793,7 +797,7 @@ fn test_frob_coeffs() {
);
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[5],
nqr.pow(vec![
nqr.pow_vartime(vec![
0xfc4b7bc93997595f,
0xa4e435368ee2c9d0,
0xf2d98f4a2c0fc8e1,
@@ -828,7 +832,7 @@ fn test_frob_coeffs() {
);
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[6],
nqr.pow(vec![
nqr.pow_vartime(vec![
0x21219610a012ba3c,
0xa5c19ad35375325,
0x4e9df1e497674396,
@@ -869,7 +873,7 @@ fn test_frob_coeffs() {
);
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[7],
nqr.pow(vec![
nqr.pow_vartime(vec![
0x742754a1f22fdb,
0x2a1955c2dec3a702,
0x9747b28c796d134e,
@@ -916,7 +920,7 @@ fn test_frob_coeffs() {
);
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[8],
nqr.pow(vec![
nqr.pow_vartime(vec![
0x802f5720d0b25710,
0x6714f0a258b85c7c,
0x31394c90afdf16e,
@@ -969,7 +973,7 @@ fn test_frob_coeffs() {
);
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[9],
nqr.pow(vec![
nqr.pow_vartime(vec![
0x4af4accf7de0b977,
0x742485e21805b4ee,
0xee388fbc4ac36dec,
@@ -1028,7 +1032,7 @@ fn test_frob_coeffs() {
);
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[10],
nqr.pow(vec![
nqr.pow_vartime(vec![
0xe5953a4f96cdda44,
0x336b2d734cbc32bb,
0x3f79bfe3cd7410e,
@@ -1093,7 +1097,7 @@ fn test_frob_coeffs() {
);
assert_eq!(
FROBENIUS_COEFF_FQ12_C1[11],
nqr.pow(vec![
nqr.pow_vartime(vec![
0x107db680942de533,
0x6262b24d2052393b,
0x6136df824159ebc,
@@ -1166,8 +1170,7 @@ fn test_frob_coeffs() {
#[test]
fn test_neg_one() {
let mut o = Fq::one();
o.negate();
let o = Fq::one().neg();
assert_eq!(NEGATIVE_ONE, o);
}
@@ -1928,7 +1931,7 @@ fn test_fq_mul_assign() {
#[test]
fn test_fq_squaring() {
let mut a = Fq(FqRepr([
let a = Fq(FqRepr([
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
@@ -1937,9 +1940,8 @@ fn test_fq_squaring() {
0x19ffffffffffffff,
]));
assert!(a.is_valid());
a.square();
assert_eq!(
a,
a.square(),
Fq::from_repr(FqRepr([
0x1cfb28fe7dfbbb86,
0x24cbe1731577a59,
@@ -1959,20 +1961,13 @@ fn test_fq_squaring() {
for _ in 0..1000000 {
// Ensure that (a * a) = a^2
let a = Fq::random(&mut rng);
let mut tmp = a;
tmp.square();
let mut tmp2 = a;
tmp2.mul_assign(&a);
assert_eq!(tmp, tmp2);
assert_eq!(a.square(), a * a);
}
}
#[test]
fn test_fq_inverse() {
assert!(Fq::zero().inverse().is_none());
fn test_fq_invert() {
assert!(bool::from(Fq::zero().invert().is_none()));
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
@@ -1984,7 +1979,7 @@ fn test_fq_inverse() {
for _ in 0..1000 {
// Ensure that a * a^-1 = 1
let mut a = Fq::random(&mut rng);
let ainv = a.inverse().unwrap();
let ainv = a.invert().unwrap();
a.mul_assign(&ainv);
assert_eq!(a, one);
}
@@ -1999,19 +1994,15 @@ fn test_fq_double() {
for _ in 0..1000 {
// Ensure doubling a is equivalent to adding a to itself.
let mut a = Fq::random(&mut rng);
let mut b = a;
b.add_assign(&a);
a.double();
assert_eq!(a, b);
let a = Fq::random(&mut rng);
assert_eq!(a.double(), a + a);
}
}
#[test]
fn test_fq_negate() {
fn test_fq_neg() {
{
let mut a = Fq::zero();
a.negate();
let a = Fq::zero().neg();
assert!(a.is_zero());
}
@@ -2024,8 +2015,7 @@ fn test_fq_negate() {
for _ in 0..1000 {
// Ensure (a - (-a)) = 0.
let mut a = Fq::random(&mut rng);
let mut b = a;
b.negate();
let b = a.neg();
a.add_assign(&b);
assert!(a.is_zero());
@@ -2043,7 +2033,7 @@ fn test_fq_pow() {
// Exponentiate by various small numbers and ensure it consists with repeated
// multiplication.
let a = Fq::random(&mut rng);
let target = a.pow(&[i]);
let target = a.pow_vartime(&[i]);
let mut c = Fq::one();
for _ in 0..i {
c.mul_assign(&a);
@@ -2055,7 +2045,7 @@ fn test_fq_pow() {
// Exponentiating by the modulus should have no effect in a prime field.
let a = Fq::random(&mut rng);
assert_eq!(a, a.pow(Fq::char()));
assert_eq!(a, a.pow_vartime(Fq::char()));
}
}
@@ -2073,10 +2063,8 @@ fn test_fq_sqrt() {
for _ in 0..1000 {
// Ensure sqrt(a^2) = a or -a
let a = Fq::random(&mut rng);
let mut nega = a;
nega.negate();
let mut b = a;
b.square();
let nega = a.neg();
let b = a.square();
let b = b.sqrt().unwrap();
@@ -2087,10 +2075,9 @@ fn test_fq_sqrt() {
// Ensure sqrt(a)^2 = a for random a
let a = Fq::random(&mut rng);
if let Some(mut tmp) = a.sqrt() {
tmp.square();
assert_eq!(a, tmp);
let tmp = a.sqrt();
if tmp.is_some().into() {
assert_eq!(a, tmp.unwrap().square());
}
}
}
@@ -2209,7 +2196,7 @@ fn test_fq_root_of_unity() {
Fq::from_repr(FqRepr::from(2)).unwrap()
);
assert_eq!(
Fq::multiplicative_generator().pow([
Fq::multiplicative_generator().pow_vartime([
0xdcff7fffffffd555,
0xf55ffff58a9ffff,
0xb39869507b587b12,
@@ -2219,8 +2206,8 @@ fn test_fq_root_of_unity() {
]),
Fq::root_of_unity()
);
assert_eq!(Fq::root_of_unity().pow([1 << Fq::S]), Fq::one());
assert!(Fq::multiplicative_generator().sqrt().is_none());
assert_eq!(Fq::root_of_unity().pow_vartime([1 << Fq::S]), Fq::one());
assert!(bool::from(Fq::multiplicative_generator().sqrt().is_none()));
}
#[test]
@@ -2246,40 +2233,3 @@ fn test_fq_ordering() {
fn fq_repr_tests() {
crate::tests::repr::random_repr_tests::<Fq>();
}
#[test]
fn test_fq_legendre() {
use ff::LegendreSymbol::*;
use ff::SqrtField;
assert_eq!(QuadraticResidue, Fq::one().legendre());
assert_eq!(Zero, Fq::zero().legendre());
assert_eq!(
QuadraticNonResidue,
Fq::from_repr(FqRepr::from(2)).unwrap().legendre()
);
assert_eq!(
QuadraticResidue,
Fq::from_repr(FqRepr::from(4)).unwrap().legendre()
);
let e = FqRepr([
0x52a112f249778642,
0xd0bedb989b7991f,
0xdad3b6681aa63c05,
0xf2efc0bb4721b283,
0x6057a98f18c24733,
0x1022c2fd122889e4,
]);
assert_eq!(QuadraticNonResidue, Fq::from_repr(e).unwrap().legendre());
let e = FqRepr([
0x6dae594e53a96c74,
0x19b16ca9ba64b37b,
0x5c764661a59bfc68,
0xaa346e9b31c60a,
0x346059f9d87a9fa9,
0x1d61ac6bfd5c88b,
]);
assert_eq!(QuadraticResidue, Fq::from_repr(e).unwrap().legendre());
}

View File

@@ -3,9 +3,11 @@ use super::fq2::Fq2;
use super::fq6::Fq6;
use ff::Field;
use rand_core::RngCore;
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use subtle::{Choice, ConditionallySelectable, CtOption};
/// An element of Fq12, represented by c0 + c1 * w.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct Fq12 {
pub c0: Fq6,
pub c1: Fq6,
@@ -19,7 +21,7 @@ impl ::std::fmt::Display for Fq12 {
impl Fq12 {
pub fn conjugate(&mut self) {
self.c1.negate();
self.c1 = self.c1.neg();
}
pub fn mul_by_014(&mut self, c0: &Fq2, c1: &Fq2, c4: &Fq2) {
@@ -39,6 +41,132 @@ impl Fq12 {
}
}
impl ConditionallySelectable for Fq12 {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Fq12 {
c0: Fq6::conditional_select(&a.c0, &b.c0, choice),
c1: Fq6::conditional_select(&a.c1, &b.c1, choice),
}
}
}
impl Neg for Fq12 {
type Output = Self;
fn neg(self) -> Self {
Fq12 {
c0: self.c0.neg(),
c1: self.c1.neg(),
}
}
}
impl<'r> Add<&'r Fq12> for Fq12 {
type Output = Self;
fn add(self, other: &Self) -> Self {
Fq12 {
c0: self.c0 + other.c0,
c1: self.c1 + other.c1,
}
}
}
impl Add for Fq12 {
type Output = Self;
fn add(self, other: Self) -> Self {
self.add(&other)
}
}
impl<'r> AddAssign<&'r Fq12> for Fq12 {
fn add_assign(&mut self, other: &'r Self) {
self.c0.add_assign(&other.c0);
self.c1.add_assign(&other.c1);
}
}
impl AddAssign for Fq12 {
fn add_assign(&mut self, other: Self) {
self.add_assign(&other);
}
}
impl<'r> Sub<&'r Fq12> for Fq12 {
type Output = Self;
fn sub(self, other: &Self) -> Self {
Fq12 {
c0: self.c0 - other.c0,
c1: self.c1 - other.c1,
}
}
}
impl Sub for Fq12 {
type Output = Self;
fn sub(self, other: Self) -> Self {
self.sub(&other)
}
}
impl<'r> SubAssign<&'r Fq12> for Fq12 {
fn sub_assign(&mut self, other: &'r Self) {
self.c0.sub_assign(&other.c0);
self.c1.sub_assign(&other.c1);
}
}
impl SubAssign for Fq12 {
fn sub_assign(&mut self, other: Self) {
self.sub_assign(&other);
}
}
impl<'r> Mul<&'r Fq12> for Fq12 {
type Output = Self;
fn mul(self, other: &Self) -> Self {
let mut ret = self;
ret.mul_assign(other);
ret
}
}
impl Mul for Fq12 {
type Output = Self;
fn mul(self, other: Self) -> Self {
self.mul(&other)
}
}
impl<'r> MulAssign<&'r Fq12> for Fq12 {
fn mul_assign(&mut self, other: &Self) {
let mut aa = self.c0;
aa.mul_assign(&other.c0);
let mut bb = self.c1;
bb.mul_assign(&other.c1);
let mut o = other.c0;
o.add_assign(&other.c1);
self.c1.add_assign(&self.c0);
self.c1.mul_assign(&o);
self.c1.sub_assign(&aa);
self.c1.sub_assign(&bb);
self.c0 = bb;
self.c0.mul_by_nonresidue();
self.c0.add_assign(&aa);
}
}
impl MulAssign for Fq12 {
fn mul_assign(&mut self, other: Self) {
self.mul_assign(&other);
}
}
impl Field for Fq12 {
fn random<R: RngCore + ?std::marker::Sized>(rng: &mut R) -> Self {
Fq12 {
@@ -65,24 +193,11 @@ impl Field for Fq12 {
self.c0.is_zero() && self.c1.is_zero()
}
fn double(&mut self) {
self.c0.double();
self.c1.double();
}
fn negate(&mut self) {
self.c0.negate();
self.c1.negate();
}
fn add_assign(&mut self, other: &Self) {
self.c0.add_assign(&other.c0);
self.c1.add_assign(&other.c1);
}
fn sub_assign(&mut self, other: &Self) {
self.c0.sub_assign(&other.c0);
self.c1.sub_assign(&other.c1);
fn double(&self) -> Self {
Fq12 {
c0: self.c0.double(),
c1: self.c1.double(),
}
}
fn frobenius_map(&mut self, power: usize) {
@@ -94,7 +209,7 @@ impl Field for Fq12 {
self.c1.c2.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]);
}
fn square(&mut self) {
fn square(&self) -> Self {
let mut ab = self.c0;
ab.mul_assign(&self.c1);
let mut c0c1 = self.c0;
@@ -104,44 +219,22 @@ impl Field for Fq12 {
c0.add_assign(&self.c0);
c0.mul_assign(&c0c1);
c0.sub_assign(&ab);
self.c1 = ab;
self.c1.add_assign(&ab);
let mut c1 = ab;
c1.add_assign(&ab);
ab.mul_by_nonresidue();
c0.sub_assign(&ab);
self.c0 = c0;
Fq12 { c0, c1 }
}
fn mul_assign(&mut self, other: &Self) {
let mut aa = self.c0;
aa.mul_assign(&other.c0);
let mut bb = self.c1;
bb.mul_assign(&other.c1);
let mut o = other.c0;
o.add_assign(&other.c1);
self.c1.add_assign(&self.c0);
self.c1.mul_assign(&o);
self.c1.sub_assign(&aa);
self.c1.sub_assign(&bb);
self.c0 = bb;
self.c0.mul_by_nonresidue();
self.c0.add_assign(&aa);
}
fn inverse(&self) -> Option<Self> {
let mut c0s = self.c0;
c0s.square();
let mut c1s = self.c1;
c1s.square();
fn invert(&self) -> CtOption<Self> {
let mut c0s = self.c0.square();
let mut c1s = self.c1.square();
c1s.mul_by_nonresidue();
c0s.sub_assign(&c1s);
c0s.inverse().map(|t| {
let mut tmp = Fq12 { c0: t, c1: t };
tmp.c0.mul_assign(&self.c0);
tmp.c1.mul_assign(&self.c1);
tmp.c1.negate();
tmp
c0s.invert().map(|t| Fq12 {
c0: t.mul(&self.c0),
c1: t.mul(&self.c1).neg(),
})
}
}

View File

@@ -1,11 +1,12 @@
use super::fq::{Fq, FROBENIUS_COEFF_FQ2_C1, NEGATIVE_ONE};
use ff::{Field, SqrtField};
use rand_core::RngCore;
use std::cmp::Ordering;
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use subtle::{Choice, ConditionallySelectable, CtOption};
/// An element of Fq2, represented by c0 + c1 * u.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct Fq2 {
pub c0: Fq,
pub c1: Fq,
@@ -46,16 +47,139 @@ impl Fq2 {
/// Norm of Fq2 as extension field in i over Fq
pub fn norm(&self) -> Fq {
let mut t0 = self.c0;
let mut t1 = self.c1;
t0.square();
t1.square();
let t0 = self.c0.square();
let mut t1 = self.c1.square();
t1.add_assign(&t0);
t1
}
}
impl ConditionallySelectable for Fq2 {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Fq2 {
c0: Fq::conditional_select(&a.c0, &b.c0, choice),
c1: Fq::conditional_select(&a.c1, &b.c1, choice),
}
}
}
impl Neg for Fq2 {
type Output = Self;
fn neg(self) -> Self {
Fq2 {
c0: self.c0.neg(),
c1: self.c1.neg(),
}
}
}
impl<'r> Add<&'r Fq2> for Fq2 {
type Output = Self;
fn add(self, other: &Self) -> Self {
Fq2 {
c0: self.c0 + other.c0,
c1: self.c1 + other.c1,
}
}
}
impl Add for Fq2 {
type Output = Self;
fn add(self, other: Self) -> Self {
self.add(&other)
}
}
impl<'r> AddAssign<&'r Fq2> for Fq2 {
fn add_assign(&mut self, other: &'r Self) {
self.c0.add_assign(&other.c0);
self.c1.add_assign(&other.c1);
}
}
impl AddAssign for Fq2 {
fn add_assign(&mut self, other: Self) {
self.add_assign(&other);
}
}
impl<'r> Sub<&'r Fq2> for Fq2 {
type Output = Self;
fn sub(self, other: &Self) -> Self {
Fq2 {
c0: self.c0 - other.c0,
c1: self.c1 - other.c1,
}
}
}
impl Sub for Fq2 {
type Output = Self;
fn sub(self, other: Self) -> Self {
self.sub(&other)
}
}
impl<'r> SubAssign<&'r Fq2> for Fq2 {
fn sub_assign(&mut self, other: &'r Self) {
self.c0.sub_assign(&other.c0);
self.c1.sub_assign(&other.c1);
}
}
impl SubAssign for Fq2 {
fn sub_assign(&mut self, other: Self) {
self.sub_assign(&other);
}
}
impl<'r> Mul<&'r Fq2> for Fq2 {
type Output = Self;
fn mul(self, other: &Self) -> Self {
let mut ret = self;
ret.mul_assign(other);
ret
}
}
impl Mul for Fq2 {
type Output = Self;
fn mul(self, other: Self) -> Self {
self.mul(&other)
}
}
impl<'r> MulAssign<&'r Fq2> for Fq2 {
fn mul_assign(&mut self, other: &Self) {
let mut aa = self.c0;
aa.mul_assign(&other.c0);
let mut bb = self.c1;
bb.mul_assign(&other.c1);
let mut o = other.c0;
o.add_assign(&other.c1);
self.c1.add_assign(&self.c0);
self.c1.mul_assign(&o);
self.c1.sub_assign(&aa);
self.c1.sub_assign(&bb);
self.c0 = aa;
self.c0.sub_assign(&bb);
}
}
impl MulAssign for Fq2 {
fn mul_assign(&mut self, other: Self) {
self.mul_assign(&other);
}
}
impl Field for Fq2 {
fn random<R: RngCore + ?std::marker::Sized>(rng: &mut R) -> Self {
Fq2 {
@@ -82,73 +206,35 @@ impl Field for Fq2 {
self.c0.is_zero() && self.c1.is_zero()
}
fn square(&mut self) {
fn square(&self) -> Self {
let mut ab = self.c0;
ab.mul_assign(&self.c1);
let mut c0c1 = self.c0;
c0c1.add_assign(&self.c1);
let mut c0 = self.c1;
c0.negate();
let mut c0 = self.c1.neg();
c0.add_assign(&self.c0);
c0.mul_assign(&c0c1);
c0.sub_assign(&ab);
self.c1 = ab;
self.c1.add_assign(&ab);
let mut c1 = ab;
c1.add_assign(&ab);
c0.add_assign(&ab);
self.c0 = c0;
Fq2 { c0, c1 }
}
fn double(&mut self) {
self.c0.double();
self.c1.double();
fn double(&self) -> Self {
Fq2 {
c0: self.c0.double(),
c1: self.c1.double(),
}
}
fn negate(&mut self) {
self.c0.negate();
self.c1.negate();
}
fn add_assign(&mut self, other: &Self) {
self.c0.add_assign(&other.c0);
self.c1.add_assign(&other.c1);
}
fn sub_assign(&mut self, other: &Self) {
self.c0.sub_assign(&other.c0);
self.c1.sub_assign(&other.c1);
}
fn mul_assign(&mut self, other: &Self) {
let mut aa = self.c0;
aa.mul_assign(&other.c0);
let mut bb = self.c1;
bb.mul_assign(&other.c1);
let mut o = other.c0;
o.add_assign(&other.c1);
self.c1.add_assign(&self.c0);
self.c1.mul_assign(&o);
self.c1.sub_assign(&aa);
self.c1.sub_assign(&bb);
self.c0 = aa;
self.c0.sub_assign(&bb);
}
fn inverse(&self) -> Option<Self> {
let mut t1 = self.c1;
t1.square();
let mut t0 = self.c0;
t0.square();
fn invert(&self) -> CtOption<Self> {
let t1 = self.c1.square();
let mut t0 = self.c0.square();
t0.add_assign(&t1);
t0.inverse().map(|t| {
let mut tmp = Fq2 {
c0: self.c0,
c1: self.c1,
};
tmp.c0.mul_assign(&t);
tmp.c1.mul_assign(&t);
tmp.c1.negate();
tmp
t0.invert().map(|t| Fq2 {
c0: self.c0.mul(&t),
c1: self.c1.mul(&t).neg(),
})
}
@@ -158,18 +244,16 @@ impl Field for Fq2 {
}
impl SqrtField for Fq2 {
fn legendre(&self) -> ::ff::LegendreSymbol {
self.norm().legendre()
}
fn sqrt(&self) -> Option<Self> {
/// WARNING: THIS IS NOT ACTUALLY CONSTANT TIME YET!
/// THIS WILL BE REPLACED BY THE bls12_381 CRATE, WHICH IS CONSTANT TIME!
fn sqrt(&self) -> CtOption<Self> {
// Algorithm 9, https://eprint.iacr.org/2012/685.pdf
if self.is_zero() {
Some(Self::zero())
CtOption::new(Self::zero(), Choice::from(1))
} else {
// a1 = self^((q - 3) / 4)
let mut a1 = self.pow([
let mut a1 = self.pow_vartime([
0xee7fbfffffffeaaa,
0x7aaffffac54ffff,
0xd9cc34a83dac3d89,
@@ -177,8 +261,7 @@ impl SqrtField for Fq2 {
0x92c6e9ed90d2eb35,
0x680447a8e5ff9a6,
]);
let mut alpha = a1;
alpha.square();
let mut alpha = a1.square();
alpha.mul_assign(self);
let mut a0 = alpha;
a0.frobenius_map(1);
@@ -190,7 +273,7 @@ impl SqrtField for Fq2 {
};
if a0 == neg1 {
None
CtOption::new(Self::zero(), Choice::from(0))
} else {
a1.mul_assign(self);
@@ -202,7 +285,7 @@ impl SqrtField for Fq2 {
} else {
alpha.add_assign(&Fq2::one());
// alpha = alpha^((q - 1) / 2)
alpha = alpha.pow([
alpha = alpha.pow_vartime([
0xdcff7fffffffd555,
0xf55ffff58a9ffff,
0xb39869507b587b12,
@@ -213,7 +296,7 @@ impl SqrtField for Fq2 {
a1.mul_assign(&alpha);
}
Some(a1)
CtOption::new(a1, Choice::from(1))
}
}
}
@@ -226,7 +309,7 @@ fn test_fq2_ordering() {
c1: Fq::zero(),
};
let mut b = a.clone();
let mut b = a;
assert!(a.cmp(&b) == Ordering::Equal);
b.c0.add_assign(&Fq::one());
@@ -273,34 +356,30 @@ fn test_fq2_squaring() {
use super::fq::FqRepr;
use ff::PrimeField;
let mut a = Fq2 {
let a = Fq2 {
c0: Fq::one(),
c1: Fq::one(),
}; // u + 1
a.square();
assert_eq!(
a,
a.square(),
Fq2 {
c0: Fq::zero(),
c1: Fq::from_repr(FqRepr::from(2)).unwrap(),
}
); // 2u
let mut a = Fq2 {
let a = Fq2 {
c0: Fq::zero(),
c1: Fq::one(),
}; // u
a.square();
assert_eq!(a, {
let mut neg1 = Fq::one();
neg1.negate();
assert_eq!(a.square(), {
Fq2 {
c0: neg1,
c0: Fq::one().neg(),
c1: Fq::zero(),
}
}); // -1
let mut a = Fq2 {
let a = Fq2 {
c0: Fq::from_repr(FqRepr([
0x9c2c6309bbf8b598,
0x4eef5c946536f602,
@@ -320,9 +399,8 @@ fn test_fq2_squaring() {
]))
.unwrap(),
};
a.square();
assert_eq!(
a,
a.square(),
Fq2 {
c0: Fq::from_repr(FqRepr([
0xf262c28c538bcf68,
@@ -417,11 +495,11 @@ fn test_fq2_mul() {
}
#[test]
fn test_fq2_inverse() {
fn test_fq2_invert() {
use super::fq::FqRepr;
use ff::PrimeField;
assert!(Fq2::zero().inverse().is_none());
assert!(bool::from(Fq2::zero().invert().is_none()));
let a = Fq2 {
c0: Fq::from_repr(FqRepr([
@@ -443,7 +521,7 @@ fn test_fq2_inverse() {
]))
.unwrap(),
};
let a = a.inverse().unwrap();
let a = a.invert().unwrap();
assert_eq!(
a,
Fq2 {
@@ -614,7 +692,7 @@ fn test_fq2_negation() {
use super::fq::FqRepr;
use ff::PrimeField;
let mut a = Fq2 {
let a = Fq2 {
c0: Fq::from_repr(FqRepr([
0x2d0078036923ffc7,
0x11e59ea221a3b6d2,
@@ -633,8 +711,8 @@ fn test_fq2_negation() {
0x12d1137b8a6a837,
]))
.unwrap(),
};
a.negate();
}
.neg();
assert_eq!(
a,
Fq2 {
@@ -665,7 +743,7 @@ fn test_fq2_doubling() {
use super::fq::FqRepr;
use ff::PrimeField;
let mut a = Fq2 {
let a = Fq2 {
c0: Fq::from_repr(FqRepr([
0x2d0078036923ffc7,
0x11e59ea221a3b6d2,
@@ -685,9 +763,8 @@ fn test_fq2_doubling() {
]))
.unwrap(),
};
a.double();
assert_eq!(
a,
a.double(),
Fq2 {
c0: Fq::from_repr(FqRepr([
0x5a00f006d247ff8e,
@@ -914,19 +991,6 @@ fn test_fq2_sqrt() {
);
}
#[test]
fn test_fq2_legendre() {
use ff::LegendreSymbol::*;
assert_eq!(Zero, Fq2::zero().legendre());
// i^2 = -1
let mut m1 = Fq2::one();
m1.negate();
assert_eq!(QuadraticResidue, m1.legendre());
m1.mul_by_nonresidue();
assert_eq!(QuadraticNonResidue, m1.legendre());
}
#[cfg(test)]
use rand_core::SeedableRng;
#[cfg(test)]

View File

@@ -2,9 +2,11 @@ use super::fq::{FROBENIUS_COEFF_FQ6_C1, FROBENIUS_COEFF_FQ6_C2};
use super::fq2::Fq2;
use ff::Field;
use rand_core::RngCore;
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use subtle::{Choice, ConditionallySelectable, CtOption};
/// An element of Fq6, represented by c0 + c1 * v + c2 * v^(2).
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct Fq6 {
pub c0: Fq2,
pub c1: Fq2,
@@ -99,101 +101,115 @@ impl Fq6 {
}
}
impl Field for Fq6 {
fn random<R: RngCore + ?std::marker::Sized>(rng: &mut R) -> Self {
impl ConditionallySelectable for Fq6 {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
Fq6 {
c0: Fq2::random(rng),
c1: Fq2::random(rng),
c2: Fq2::random(rng),
c0: Fq2::conditional_select(&a.c0, &b.c0, choice),
c1: Fq2::conditional_select(&a.c1, &b.c1, choice),
c2: Fq2::conditional_select(&a.c2, &b.c2, choice),
}
}
}
fn zero() -> Self {
impl Neg for Fq6 {
type Output = Self;
fn neg(self) -> Self {
Fq6 {
c0: Fq2::zero(),
c1: Fq2::zero(),
c2: Fq2::zero(),
c0: self.c0.neg(),
c1: self.c1.neg(),
c2: self.c2.neg(),
}
}
}
fn one() -> Self {
impl<'r> Add<&'r Fq6> for Fq6 {
type Output = Self;
fn add(self, other: &Self) -> Self {
Fq6 {
c0: Fq2::one(),
c1: Fq2::zero(),
c2: Fq2::zero(),
c0: self.c0 + other.c0,
c1: self.c1 + other.c1,
c2: self.c2 + other.c2,
}
}
}
fn is_zero(&self) -> bool {
self.c0.is_zero() && self.c1.is_zero() && self.c2.is_zero()
impl Add for Fq6 {
type Output = Self;
fn add(self, other: Self) -> Self {
self.add(&other)
}
}
fn double(&mut self) {
self.c0.double();
self.c1.double();
self.c2.double();
}
fn negate(&mut self) {
self.c0.negate();
self.c1.negate();
self.c2.negate();
}
fn add_assign(&mut self, other: &Self) {
impl<'r> AddAssign<&'r Fq6> for Fq6 {
fn add_assign(&mut self, other: &'r Self) {
self.c0.add_assign(&other.c0);
self.c1.add_assign(&other.c1);
self.c2.add_assign(&other.c2);
}
}
fn sub_assign(&mut self, other: &Self) {
impl AddAssign for Fq6 {
fn add_assign(&mut self, other: Self) {
self.add_assign(&other);
}
}
impl<'r> Sub<&'r Fq6> for Fq6 {
type Output = Self;
fn sub(self, other: &Self) -> Self {
Fq6 {
c0: self.c0 - other.c0,
c1: self.c1 - other.c1,
c2: self.c2 - other.c2,
}
}
}
impl Sub for Fq6 {
type Output = Self;
fn sub(self, other: Self) -> Self {
self.sub(&other)
}
}
impl<'r> SubAssign<&'r Fq6> for Fq6 {
fn sub_assign(&mut self, other: &'r Self) {
self.c0.sub_assign(&other.c0);
self.c1.sub_assign(&other.c1);
self.c2.sub_assign(&other.c2);
}
}
fn frobenius_map(&mut self, power: usize) {
self.c0.frobenius_map(power);
self.c1.frobenius_map(power);
self.c2.frobenius_map(power);
self.c1.mul_assign(&FROBENIUS_COEFF_FQ6_C1[power % 6]);
self.c2.mul_assign(&FROBENIUS_COEFF_FQ6_C2[power % 6]);
impl SubAssign for Fq6 {
fn sub_assign(&mut self, other: Self) {
self.sub_assign(&other);
}
}
fn square(&mut self) {
let mut s0 = self.c0;
s0.square();
let mut ab = self.c0;
ab.mul_assign(&self.c1);
let mut s1 = ab;
s1.double();
let mut s2 = self.c0;
s2.sub_assign(&self.c1);
s2.add_assign(&self.c2);
s2.square();
let mut bc = self.c1;
bc.mul_assign(&self.c2);
let mut s3 = bc;
s3.double();
let mut s4 = self.c2;
s4.square();
impl<'r> Mul<&'r Fq6> for Fq6 {
type Output = Self;
self.c0 = s3;
self.c0.mul_by_nonresidue();
self.c0.add_assign(&s0);
self.c1 = s4;
self.c1.mul_by_nonresidue();
self.c1.add_assign(&s1);
self.c2 = s1;
self.c2.add_assign(&s2);
self.c2.add_assign(&s3);
self.c2.sub_assign(&s0);
self.c2.sub_assign(&s4);
fn mul(self, other: &Self) -> Self {
let mut ret = self;
ret.mul_assign(other);
ret
}
}
impl Mul for Fq6 {
type Output = Self;
fn mul(self, other: Self) -> Self {
self.mul(&other)
}
}
impl<'r> MulAssign<&'r Fq6> for Fq6 {
fn mul_assign(&mut self, other: &Self) {
let mut a_a = self.c0;
let mut b_b = self.c1;
@@ -244,27 +260,108 @@ impl Field for Fq6 {
self.c1 = t2;
self.c2 = t3;
}
}
fn inverse(&self) -> Option<Self> {
impl MulAssign for Fq6 {
fn mul_assign(&mut self, other: Self) {
self.mul_assign(&other);
}
}
impl Field for Fq6 {
fn random<R: RngCore + ?std::marker::Sized>(rng: &mut R) -> Self {
Fq6 {
c0: Fq2::random(rng),
c1: Fq2::random(rng),
c2: Fq2::random(rng),
}
}
fn zero() -> Self {
Fq6 {
c0: Fq2::zero(),
c1: Fq2::zero(),
c2: Fq2::zero(),
}
}
fn one() -> Self {
Fq6 {
c0: Fq2::one(),
c1: Fq2::zero(),
c2: Fq2::zero(),
}
}
fn is_zero(&self) -> bool {
self.c0.is_zero() && self.c1.is_zero() && self.c2.is_zero()
}
fn double(&self) -> Self {
Fq6 {
c0: self.c0.double(),
c1: self.c1.double(),
c2: self.c2.double(),
}
}
fn frobenius_map(&mut self, power: usize) {
self.c0.frobenius_map(power);
self.c1.frobenius_map(power);
self.c2.frobenius_map(power);
self.c1.mul_assign(&FROBENIUS_COEFF_FQ6_C1[power % 6]);
self.c2.mul_assign(&FROBENIUS_COEFF_FQ6_C2[power % 6]);
}
fn square(&self) -> Self {
let s0 = self.c0.square();
let mut ab = self.c0;
ab.mul_assign(&self.c1);
let s1 = ab.double();
let mut s2 = self.c0;
s2.sub_assign(&self.c1);
s2.add_assign(&self.c2);
s2 = s2.square();
let mut bc = self.c1;
bc.mul_assign(&self.c2);
let s3 = bc.double();
let s4 = self.c2.square();
let mut c0 = s3;
c0.mul_by_nonresidue();
c0.add_assign(&s0);
let mut c1 = s4;
c1.mul_by_nonresidue();
c1.add_assign(&s1);
let mut c2 = s1;
c2.add_assign(&s2);
c2.add_assign(&s3);
c2.sub_assign(&s0);
c2.sub_assign(&s4);
Fq6 { c0, c1, c2 }
}
fn invert(&self) -> CtOption<Self> {
let mut c0 = self.c2;
c0.mul_by_nonresidue();
c0.mul_assign(&self.c1);
c0.negate();
c0 = c0.neg();
{
let mut c0s = self.c0;
c0s.square();
let c0s = self.c0.square();
c0.add_assign(&c0s);
}
let mut c1 = self.c2;
c1.square();
let mut c1 = self.c2.square();
c1.mul_by_nonresidue();
{
let mut c01 = self.c0;
c01.mul_assign(&self.c1);
c1.sub_assign(&c01);
}
let mut c2 = self.c1;
c2.square();
let mut c2 = self.c1.square();
{
let mut c02 = self.c0;
c02.mul_assign(&self.c2);
@@ -281,21 +378,18 @@ impl Field for Fq6 {
tmp2.mul_assign(&c0);
tmp1.add_assign(&tmp2);
match tmp1.inverse() {
Some(t) => {
let mut tmp = Fq6 {
c0: t,
c1: t,
c2: t,
};
tmp.c0.mul_assign(&c0);
tmp.c1.mul_assign(&c1);
tmp.c2.mul_assign(&c2);
tmp1.invert().map(|t| {
let mut tmp = Fq6 {
c0: t,
c1: t,
c2: t,
};
tmp.c0.mul_assign(&c0);
tmp.c1.mul_assign(&c1);
tmp.c2.mul_assign(&c2);
Some(tmp)
}
None => None,
}
tmp
})
}
}

View File

@@ -1,4 +1,5 @@
use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr};
use std::ops::{AddAssign, MulAssign, SubAssign};
#[derive(PrimeField)]
#[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"]
@@ -9,6 +10,8 @@ pub struct Fr(FrRepr);
use rand_core::SeedableRng;
#[cfg(test)]
use rand_xorshift::XorShiftRng;
#[cfg(test)]
use std::ops::Neg;
#[test]
fn test_fr_repr_ordering() {
@@ -275,30 +278,6 @@ fn test_fr_repr_sub_noborrow() {
);
}
#[test]
fn test_fr_legendre() {
use ff::LegendreSymbol::*;
use ff::SqrtField;
assert_eq!(QuadraticResidue, Fr::one().legendre());
assert_eq!(Zero, Fr::zero().legendre());
let e = FrRepr([
0x0dbc5349cd5664da,
0x8ac5b6296e3ae29d,
0x127cb819feceaa3b,
0x3a6b21fb03867191,
]);
assert_eq!(QuadraticResidue, Fr::from_repr(e).unwrap().legendre());
let e = FrRepr([
0x96341aefd047c045,
0x9b5f4254500a4d65,
0x1ee08223b68ac240,
0x31d9cd545c0ec7c6,
]);
assert_eq!(QuadraticNonResidue, Fr::from_repr(e).unwrap().legendre());
}
#[test]
fn test_fr_repr_add_nocarry() {
let mut rng = XorShiftRng::from_seed([
@@ -690,16 +669,15 @@ fn test_fr_mul_assign() {
#[test]
fn test_fr_squaring() {
let mut a = Fr(FrRepr([
let a = Fr(FrRepr([
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
0x73eda753299d7d47,
]));
assert!(a.is_valid());
a.square();
assert_eq!(
a,
a.square(),
Fr::from_repr(FrRepr([
0xc0d698e7bde077b8,
0xb79a310579e76ec2,
@@ -717,20 +695,13 @@ fn test_fr_squaring() {
for _ in 0..1000000 {
// Ensure that (a * a) = a^2
let a = Fr::random(&mut rng);
let mut tmp = a;
tmp.square();
let mut tmp2 = a;
tmp2.mul_assign(&a);
assert_eq!(tmp, tmp2);
assert_eq!(a.square(), a * a);
}
}
#[test]
fn test_fr_inverse() {
assert!(Fr::zero().inverse().is_none());
fn test_fr_invert() {
assert!(bool::from(Fr::zero().invert().is_none()));
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
@@ -742,7 +713,7 @@ fn test_fr_inverse() {
for _ in 0..1000 {
// Ensure that a * a^-1 = 1
let mut a = Fr::random(&mut rng);
let ainv = a.inverse().unwrap();
let ainv = a.invert().unwrap();
a.mul_assign(&ainv);
assert_eq!(a, one);
}
@@ -757,19 +728,15 @@ fn test_fr_double() {
for _ in 0..1000 {
// Ensure doubling a is equivalent to adding a to itself.
let mut a = Fr::random(&mut rng);
let mut b = a;
b.add_assign(&a);
a.double();
assert_eq!(a, b);
let a = Fr::random(&mut rng);
assert_eq!(a.double(), a + a);
}
}
#[test]
fn test_fr_negate() {
fn test_fr_neg() {
{
let mut a = Fr::zero();
a.negate();
let a = Fr::zero().neg();
assert!(a.is_zero());
}
@@ -782,8 +749,7 @@ fn test_fr_negate() {
for _ in 0..1000 {
// Ensure (a - (-a)) = 0.
let mut a = Fr::random(&mut rng);
let mut b = a;
b.negate();
let b = a.neg();
a.add_assign(&b);
assert!(a.is_zero());
@@ -801,7 +767,7 @@ fn test_fr_pow() {
// Exponentiate by various small numbers and ensure it consists with repeated
// multiplication.
let a = Fr::random(&mut rng);
let target = a.pow(&[i]);
let target = a.pow_vartime(&[i]);
let mut c = Fr::one();
for _ in 0..i {
c.mul_assign(&a);
@@ -813,7 +779,7 @@ fn test_fr_pow() {
// Exponentiating by the modulus should have no effect in a prime field.
let a = Fr::random(&mut rng);
assert_eq!(a, a.pow(Fr::char()));
assert_eq!(a, a.pow_vartime(Fr::char()));
}
}
@@ -831,10 +797,8 @@ fn test_fr_sqrt() {
for _ in 0..1000 {
// Ensure sqrt(a^2) = a or -a
let a = Fr::random(&mut rng);
let mut nega = a;
nega.negate();
let mut b = a;
b.square();
let nega = a.neg();
let b = a.square();
let b = b.sqrt().unwrap();
@@ -845,10 +809,9 @@ fn test_fr_sqrt() {
// Ensure sqrt(a)^2 = a for random a
let a = Fr::random(&mut rng);
if let Some(mut tmp) = a.sqrt() {
tmp.square();
assert_eq!(a, tmp);
let tmp = a.sqrt();
if tmp.is_some().into() {
assert_eq!(a, tmp.unwrap().square());
}
}
}
@@ -1001,7 +964,7 @@ fn test_fr_root_of_unity() {
Fr::from_repr(FrRepr::from(7)).unwrap()
);
assert_eq!(
Fr::multiplicative_generator().pow([
Fr::multiplicative_generator().pow_vartime([
0xfffe5bfeffffffff,
0x9a1d80553bda402,
0x299d7d483339d808,
@@ -1009,8 +972,8 @@ fn test_fr_root_of_unity() {
]),
Fr::root_of_unity()
);
assert_eq!(Fr::root_of_unity().pow([1 << Fr::S]), Fr::one());
assert!(Fr::multiplicative_generator().sqrt().is_none());
assert_eq!(Fr::root_of_unity().pow_vartime([1 << Fr::S]), Fr::one());
assert!(bool::from(Fr::multiplicative_generator().sqrt().is_none()));
}
#[test]

View File

@@ -25,6 +25,8 @@ use super::{Engine, PairingCurveAffine};
use ff::{BitIterator, Field, ScalarEngine};
use group::CurveAffine;
use std::ops::{AddAssign, MulAssign, Neg, SubAssign};
use subtle::CtOption;
// The BLS parameter x for BLS12-381 is -0xd201000000010000
const BLS_X: u64 = 0xd201000000010000;
@@ -96,7 +98,7 @@ impl Engine for Bls12 {
}
}
f.square();
f = f.square();
}
for &mut (p, ref mut coeffs) in &mut pairs {
@@ -110,62 +112,58 @@ impl Engine for Bls12 {
f
}
fn final_exponentiation(r: &Fq12) -> Option<Fq12> {
fn final_exponentiation(r: &Fq12) -> CtOption<Fq12> {
let mut f1 = *r;
f1.conjugate();
match r.inverse() {
Some(mut f2) => {
let mut r = f1;
r.mul_assign(&f2);
f2 = r;
r.frobenius_map(2);
r.mul_assign(&f2);
r.invert().map(|mut f2| {
let mut r = f1;
r.mul_assign(&f2);
f2 = r;
r.frobenius_map(2);
r.mul_assign(&f2);
fn exp_by_x(f: &mut Fq12, x: u64) {
*f = f.pow(&[x]);
if BLS_X_IS_NEGATIVE {
f.conjugate();
}
fn exp_by_x(f: &mut Fq12, x: u64) {
*f = f.pow_vartime(&[x]);
if BLS_X_IS_NEGATIVE {
f.conjugate();
}
let mut x = BLS_X;
let mut y0 = r;
y0.square();
let mut y1 = y0;
exp_by_x(&mut y1, x);
x >>= 1;
let mut y2 = y1;
exp_by_x(&mut y2, x);
x <<= 1;
let mut y3 = r;
y3.conjugate();
y1.mul_assign(&y3);
y1.conjugate();
y1.mul_assign(&y2);
y2 = y1;
exp_by_x(&mut y2, x);
y3 = y2;
exp_by_x(&mut y3, x);
y1.conjugate();
y3.mul_assign(&y1);
y1.conjugate();
y1.frobenius_map(3);
y2.frobenius_map(2);
y1.mul_assign(&y2);
y2 = y3;
exp_by_x(&mut y2, x);
y2.mul_assign(&y0);
y2.mul_assign(&r);
y1.mul_assign(&y2);
y2 = y3;
y2.frobenius_map(1);
y1.mul_assign(&y2);
Some(y1)
}
None => None,
}
let mut x = BLS_X;
let y0 = r.square();
let mut y1 = y0;
exp_by_x(&mut y1, x);
x >>= 1;
let mut y2 = y1;
exp_by_x(&mut y2, x);
x <<= 1;
let mut y3 = r;
y3.conjugate();
y1.mul_assign(&y3);
y1.conjugate();
y1.mul_assign(&y2);
y2 = y1;
exp_by_x(&mut y2, x);
y3 = y2;
exp_by_x(&mut y3, x);
y1.conjugate();
y3.mul_assign(&y1);
y1.conjugate();
y1.frobenius_map(3);
y2.frobenius_map(2);
y1.mul_assign(&y2);
y2 = y3;
exp_by_x(&mut y2, x);
y2.mul_assign(&y0);
y2.mul_assign(&r);
y1.mul_assign(&y2);
y2 = y3;
y2.frobenius_map(1);
y1.mul_assign(&y2);
y1
})
}
}
@@ -184,41 +182,35 @@ impl G2Prepared {
fn doubling_step(r: &mut G2) -> (Fq2, Fq2, Fq2) {
// Adaptation of Algorithm 26, https://eprint.iacr.org/2010/354.pdf
let mut tmp0 = r.x;
tmp0.square();
let mut tmp0 = r.x.square();
let mut tmp1 = r.y;
tmp1.square();
let mut tmp1 = r.y.square();
let mut tmp2 = tmp1;
tmp2.square();
let mut tmp2 = tmp1.square();
let mut tmp3 = tmp1;
tmp3.add_assign(&r.x);
tmp3.square();
tmp3 = tmp3.square();
tmp3.sub_assign(&tmp0);
tmp3.sub_assign(&tmp2);
tmp3.double();
tmp3 = tmp3.double();
let mut tmp4 = tmp0;
tmp4.double();
let mut tmp4 = tmp0.double();
tmp4.add_assign(&tmp0);
let mut tmp6 = r.x;
tmp6.add_assign(&tmp4);
let mut tmp5 = tmp4;
tmp5.square();
let tmp5 = tmp4.square();
let mut zsquared = r.z;
zsquared.square();
let zsquared = r.z.square();
r.x = tmp5;
r.x.sub_assign(&tmp3);
r.x.sub_assign(&tmp3);
r.z.add_assign(&r.y);
r.z.square();
r.z = r.z.square();
r.z.sub_assign(&tmp1);
r.z.sub_assign(&zsquared);
@@ -226,47 +218,41 @@ impl G2Prepared {
r.y.sub_assign(&r.x);
r.y.mul_assign(&tmp4);
tmp2.double();
tmp2.double();
tmp2.double();
tmp2 = tmp2.double().double().double();
r.y.sub_assign(&tmp2);
tmp3 = tmp4;
tmp3.mul_assign(&zsquared);
tmp3.double();
tmp3.negate();
tmp3 = tmp3.double().neg();
tmp6.square();
tmp6 = tmp6.square();
tmp6.sub_assign(&tmp0);
tmp6.sub_assign(&tmp5);
tmp1.double();
tmp1.double();
tmp1 = tmp1.double().double();
tmp6.sub_assign(&tmp1);
tmp0 = r.z;
tmp0.mul_assign(&zsquared);
tmp0.double();
tmp0 = tmp0.double();
(tmp0, tmp3, tmp6)
}
fn addition_step(r: &mut G2, q: &G2Affine) -> (Fq2, Fq2, Fq2) {
// Adaptation of Algorithm 27, https://eprint.iacr.org/2010/354.pdf
let mut zsquared = r.z;
zsquared.square();
let zsquared = r.z.square();
let mut ysquared = q.y;
ysquared.square();
let ysquared = q.y.square();
let mut t0 = zsquared;
t0.mul_assign(&q.x);
let mut t1 = q.y;
t1.add_assign(&r.z);
t1.square();
t1 = t1.square();
t1.sub_assign(&ysquared);
t1.sub_assign(&zsquared);
t1.mul_assign(&zsquared);
@@ -274,12 +260,9 @@ impl G2Prepared {
let mut t2 = t0;
t2.sub_assign(&r.x);
let mut t3 = t2;
t3.square();
let t3 = t2.square();
let mut t4 = t3;
t4.double();
t4.double();
let t4 = t3.double().double();
let mut t5 = t4;
t5.mul_assign(&t2);
@@ -294,14 +277,13 @@ impl G2Prepared {
let mut t7 = t4;
t7.mul_assign(&r.x);
r.x = t6;
r.x.square();
r.x = t6.square();
r.x.sub_assign(&t5);
r.x.sub_assign(&t7);
r.x.sub_assign(&t7);
r.z.add_assign(&t2);
r.z.square();
r.z = r.z.square();
r.z.sub_assign(&zsquared);
r.z.sub_assign(&t3);
@@ -314,29 +296,26 @@ impl G2Prepared {
t0 = r.y;
t0.mul_assign(&t5);
t0.double();
t0 = t0.double();
r.y = t8;
r.y.sub_assign(&t0);
t10.square();
t10 = t10.square();
t10.sub_assign(&ysquared);
let mut ztsquared = r.z;
ztsquared.square();
let ztsquared = r.z.square();
t10.sub_assign(&ztsquared);
t9.double();
t9 = t9.double();
t9.sub_assign(&t10);
t10 = r.z;
t10.double();
t10 = r.z.double();
t6.negate();
t6 = t6.neg();
t1 = t6;
t1.double();
t1 = t6.double();
(t10, t1, t9)
}

View File

@@ -189,12 +189,14 @@ fn test_g1_uncompressed_invalid_vectors() {
let mut x = Fq::one();
loop {
let mut x3b = x;
x3b.square();
let mut x3b = x.square();
x3b.mul_assign(&x);
x3b.add_assign(&Fq::from_repr(FqRepr::from(4)).unwrap()); // TODO: perhaps expose coeff_b through API?
if let Some(y) = x3b.sqrt() {
let y = x3b.sqrt();
if y.is_some().into() {
let y = y.unwrap();
// We know this is on the curve, but it's likely not going to be in the correct subgroup.
x.into_repr().write_be(&mut o.as_mut()[0..]).unwrap();
y.into_repr().write_be(&mut o.as_mut()[48..]).unwrap();
@@ -326,15 +328,17 @@ fn test_g2_uncompressed_invalid_vectors() {
let mut x = Fq2::one();
loop {
let mut x3b = x;
x3b.square();
let mut x3b = x.square();
x3b.mul_assign(&x);
x3b.add_assign(&Fq2 {
c0: Fq::from_repr(FqRepr::from(4)).unwrap(),
c1: Fq::from_repr(FqRepr::from(4)).unwrap(),
}); // TODO: perhaps expose coeff_b through API?
if let Some(y) = x3b.sqrt() {
let y = x3b.sqrt();
if y.is_some().into() {
let y = y.unwrap();
// We know this is on the curve, but it's likely not going to be in the correct subgroup.
x.c1.into_repr().write_be(&mut o.as_mut()[0..]).unwrap();
x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap();
@@ -422,12 +426,11 @@ fn test_g1_compressed_invalid_vectors() {
let mut x = Fq::one();
loop {
let mut x3b = x;
x3b.square();
let mut x3b = x.square();
x3b.mul_assign(&x);
x3b.add_assign(&Fq::from_repr(FqRepr::from(4)).unwrap()); // TODO: perhaps expose coeff_b through API?
if let Some(_) = x3b.sqrt() {
if x3b.sqrt().is_some().into() {
x.add_assign(&Fq::one());
} else {
x.into_repr().write_be(&mut o.as_mut()[0..]).unwrap();
@@ -447,12 +450,11 @@ fn test_g1_compressed_invalid_vectors() {
let mut x = Fq::one();
loop {
let mut x3b = x;
x3b.square();
let mut x3b = x.square();
x3b.mul_assign(&x);
x3b.add_assign(&Fq::from_repr(FqRepr::from(4)).unwrap()); // TODO: perhaps expose coeff_b through API?
if let Some(_) = x3b.sqrt() {
if x3b.sqrt().is_some().into() {
// We know this is on the curve, but it's likely not going to be in the correct subgroup.
x.into_repr().write_be(&mut o.as_mut()[0..]).unwrap();
o.as_mut()[0] |= 0b1000_0000;
@@ -553,15 +555,14 @@ fn test_g2_compressed_invalid_vectors() {
};
loop {
let mut x3b = x;
x3b.square();
let mut x3b = x.square();
x3b.mul_assign(&x);
x3b.add_assign(&Fq2 {
c0: Fq::from_repr(FqRepr::from(4)).unwrap(),
c1: Fq::from_repr(FqRepr::from(4)).unwrap(),
}); // TODO: perhaps expose coeff_b through API?
if let Some(_) = x3b.sqrt() {
if x3b.sqrt().is_some().into() {
x.add_assign(&Fq2::one());
} else {
x.c1.into_repr().write_be(&mut o.as_mut()[0..]).unwrap();
@@ -585,15 +586,14 @@ fn test_g2_compressed_invalid_vectors() {
};
loop {
let mut x3b = x;
x3b.square();
let mut x3b = x.square();
x3b.mul_assign(&x);
x3b.add_assign(&Fq2 {
c0: Fq::from_repr(FqRepr::from(4)).unwrap(),
c1: Fq::from_repr(FqRepr::from(4)).unwrap(),
}); // TODO: perhaps expose coeff_b through API?
if let Some(_) = x3b.sqrt() {
if x3b.sqrt().is_some().into() {
// We know this is on the curve, but it's likely not going to be in the correct subgroup.
x.c1.into_repr().write_be(&mut o.as_mut()[0..]).unwrap();
x.c0.into_repr().write_be(&mut o.as_mut()[48..]).unwrap();

View File

@@ -21,19 +21,18 @@ pub mod tests;
pub mod bls12_381;
use ff::{Field, PrimeField, ScalarEngine, SqrtField};
use group::{CurveAffine, CurveProjective};
use group::{CurveAffine, CurveOps, CurveOpsOwned, CurveProjective};
use subtle::CtOption;
/// An "engine" is a collection of types (fields, elliptic curve groups, etc.)
/// with well-defined relationships. In particular, the G1/G2 curve groups are
/// of prime order `r`, and are equipped with a bilinear pairing function.
pub trait Engine: ScalarEngine {
/// The projective representation of an element in G1.
type G1: CurveProjective<
Engine = Self,
Base = Self::Fq,
Scalar = Self::Fr,
Affine = Self::G1Affine,
> + From<Self::G1Affine>;
type G1: CurveProjective<Engine = Self, Base = Self::Fq, Scalar = Self::Fr, Affine = Self::G1Affine>
+ From<Self::G1Affine>
+ CurveOps<Self::G1Affine>
+ CurveOpsOwned<Self::G1Affine>;
/// The affine representation of an element in G1.
type G1Affine: PairingCurveAffine<
@@ -46,12 +45,10 @@ pub trait Engine: ScalarEngine {
> + From<Self::G1>;
/// The projective representation of an element in G2.
type G2: CurveProjective<
Engine = Self,
Base = Self::Fqe,
Scalar = Self::Fr,
Affine = Self::G2Affine,
> + From<Self::G2Affine>;
type G2: CurveProjective<Engine = Self, Base = Self::Fqe, Scalar = Self::Fr, Affine = Self::G2Affine>
+ From<Self::G2Affine>
+ CurveOps<Self::G2Affine>
+ CurveOpsOwned<Self::G2Affine>;
/// The affine representation of an element in G2.
type G2Affine: PairingCurveAffine<
@@ -83,7 +80,7 @@ pub trait Engine: ScalarEngine {
>;
/// Perform final exponentiation of the result of a miller loop.
fn final_exponentiation(_: &Self::Fqk) -> Option<Self::Fqk>;
fn final_exponentiation(_: &Self::Fqk) -> CtOption<Self::Fqk>;
/// Performs a complete pairing operation `(p, q)`.
fn pairing<G1, G2>(p: G1, q: G2) -> Self::Fqk

View File

@@ -1,6 +1,7 @@
use group::{CurveAffine, CurveProjective};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use std::ops::MulAssign;
use crate::{Engine, Field, PairingCurveAffine, PrimeField};
@@ -129,7 +130,7 @@ fn random_bilinearity_tests<E: Engine>() {
let mut cd = c;
cd.mul_assign(&d);
let abcd = E::pairing(a, b).pow(cd.into_repr());
let abcd = E::pairing(a, b).pow_vartime(cd.into_repr());
assert_eq!(acbd, adbc);
assert_eq!(acbd, abcd);

View File

@@ -1,4 +1,4 @@
use ff::{Field, LegendreSymbol, PrimeField, SqrtField};
use ff::{Field, PrimeField, SqrtField};
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
@@ -9,12 +9,12 @@ pub fn random_frobenius_tests<F: Field, C: AsRef<[u64]>>(characteristic: C, maxp
]);
for _ in 0..100 {
for i in 0..(maxpower + 1) {
for i in 0..=maxpower {
let mut a = F::random(&mut rng);
let mut b = a;
for _ in 0..i {
a = a.pow(&characteristic);
a = a.pow_vartime(&characteristic);
}
b.frobenius_map(i);
@@ -31,27 +31,22 @@ pub fn random_sqrt_tests<F: SqrtField>() {
for _ in 0..10000 {
let a = F::random(&mut rng);
let mut b = a;
b.square();
assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue);
let b = a.square();
let b = b.sqrt().unwrap();
let mut negb = b;
negb.negate();
let negb = b.neg();
assert!(a == b || a == negb);
}
let mut c = F::one();
for _ in 0..10000 {
let mut b = c;
b.square();
assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue);
let mut b = c.square();
b = b.sqrt().unwrap();
if b != c {
b.negate();
b = b.neg();
}
assert_eq!(b, c);
@@ -77,12 +72,11 @@ pub fn random_field_tests<F: Field>() {
assert!(F::zero().is_zero());
{
let mut z = F::zero();
z.negate();
let z = F::zero().neg();
assert!(z.is_zero());
}
assert!(F::zero().inverse().is_none());
assert!(bool::from(F::zero().invert().is_none()));
// Multiplication by zero
{
@@ -204,8 +198,7 @@ fn random_subtraction_tests<F: Field, R: RngCore>(rng: &mut R) {
fn random_negation_tests<F: Field, R: RngCore>(rng: &mut R) {
for _ in 0..10000 {
let a = F::random(rng);
let mut b = a;
b.negate();
let mut b = a.neg();
b.add_assign(&a);
assert!(b.is_zero());
@@ -214,32 +207,24 @@ fn random_negation_tests<F: Field, R: RngCore>(rng: &mut R) {
fn random_doubling_tests<F: Field, R: RngCore>(rng: &mut R) {
for _ in 0..10000 {
let mut a = F::random(rng);
let mut b = a;
a.add_assign(&b);
b.double();
assert_eq!(a, b);
let a = F::random(rng);
assert_eq!(a + a, a.double());
}
}
fn random_squaring_tests<F: Field, R: RngCore>(rng: &mut R) {
for _ in 0..10000 {
let mut a = F::random(rng);
let mut b = a;
a.mul_assign(&b);
b.square();
assert_eq!(a, b);
let a = F::random(rng);
assert_eq!(a * a, a.square());
}
}
fn random_inversion_tests<F: Field, R: RngCore>(rng: &mut R) {
assert!(F::zero().inverse().is_none());
assert!(bool::from(F::zero().invert().is_none()));
for _ in 0..10000 {
let mut a = F::random(rng);
let b = a.inverse().unwrap(); // probablistically nonzero
let b = a.invert().unwrap(); // probablistically nonzero
a.mul_assign(&b);
assert_eq!(a, F::one());

View File

@@ -68,7 +68,7 @@ fn random_shl_tests<P: PrimeField>() {
for _ in 0..100 {
let r = P::random(&mut rng).into_repr();
for shift in 0..(r.num_bits() + 1) {
for shift in 0..=r.num_bits() {
let mut r1 = r;
let mut r2 = r;
@@ -92,7 +92,7 @@ fn random_shr_tests<P: PrimeField>() {
for _ in 0..100 {
let r = P::random(&mut rng).into_repr();
for shift in 0..(r.num_bits() + 1) {
for shift in 0..=r.num_bits() {
let mut r1 = r;
let mut r2 = r;