BN256 commit

This commit is contained in:
Alex Vlasov 2018-12-08 05:36:39 +08:00
parent 183a64b08e
commit 1363d02170
21 changed files with 5422 additions and 14 deletions

1
.gitignore vendored

@ -1,3 +1,4 @@
target/ target/
**/*.rs.bk **/*.rs.bk
Cargo.lock Cargo.lock
.vscode

@ -2,17 +2,18 @@
name = "pairing" name = "pairing"
# Remember to change version string in README.md. # Remember to change version string in README.md.
version = "0.14.2" version = "0.15.0"
authors = [ authors = [
"Sean Bowe <ewillbefull@gmail.com>", "Sean Bowe <ewillbefull@gmail.com>",
"Jack Grigg <jack@z.cash>", "Jack Grigg <jack@z.cash>",
"Alex Vlasov <alex.m.vlasov@gmail.com>"
] ]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
description = "Pairing-friendly elliptic curve library" description = "Pairing-friendly elliptic curve library"
documentation = "https://docs.rs/pairing/" documentation = "https://docs.rs/pairing/"
homepage = "https://github.com/ebfull/pairing" homepage = "https://github.com/matterinc/pairing"
repository = "https://github.com/ebfull/pairing" repository = "https://github.com/matterinc/pairing"
[dependencies] [dependencies]
rand = "0.4" rand = "0.4"

@ -1,6 +1,8 @@
# pairing [![Crates.io](https://img.shields.io/crates/v/pairing.svg)](https://crates.io/crates/pairing) # # pairing "community edition"
This is a Rust crate for using pairing-friendly elliptic curves. Currently, only the [BLS12-381](https://z.cash/blog/new-snark-curve.html) construction is implemented. Originally developed by ZCash, with extensions from us to make it a little more pleasant.
This is a Rust crate for using pairing-friendly elliptic curves. Currently, only the [BLS12-381](https://z.cash/blog/new-snark-curve.html) and BN256 curves are implemented.
## [Documentation](https://docs.rs/pairing/) ## [Documentation](https://docs.rs/pairing/)

127
benches/bn256/ec.rs Normal file

@ -0,0 +1,127 @@
mod g1 {
use rand::{Rand, SeedableRng, XorShiftRng};
use pairing::bn256::*;
use pairing::CurveProjective;
#[bench]
fn bench_g1_mul_assign(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(G1, Fr)> = (0..SAMPLES)
.map(|_| (G1::rand(&mut rng), Fr::rand(&mut rng)))
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_g1_add_assign(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(G1, G1)> = (0..SAMPLES)
.map(|_| (G1::rand(&mut rng), G1::rand(&mut rng)))
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_g1_add_assign_mixed(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(G1, G1Affine)> = (0..SAMPLES)
.map(|_| (G1::rand(&mut rng), G1::rand(&mut rng).into()))
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign_mixed(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
}
mod g2 {
use rand::{Rand, SeedableRng, XorShiftRng};
use pairing::bls12_381::*;
use pairing::CurveProjective;
#[bench]
fn bench_g2_mul_assign(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(G2, Fr)> = (0..SAMPLES)
.map(|_| (G2::rand(&mut rng), Fr::rand(&mut rng)))
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_g2_add_assign(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(G2, G2)> = (0..SAMPLES)
.map(|_| (G2::rand(&mut rng), G2::rand(&mut rng)))
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_g2_add_assign_mixed(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(G2, G2Affine)> = (0..SAMPLES)
.map(|_| (G2::rand(&mut rng), G2::rand(&mut rng).into()))
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign_mixed(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
}

268
benches/bn256/fq.rs Normal file

@ -0,0 +1,268 @@
use rand::{Rand, SeedableRng, XorShiftRng};
use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField};
use pairing::bn256::*;
#[bench]
fn bench_fq_repr_add_nocarry(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(FqRepr, FqRepr)> = (0..SAMPLES)
.map(|_| {
let mut tmp1 = FqRepr::rand(&mut rng);
let mut tmp2 = FqRepr::rand(&mut rng);
// Shave a few bits off to avoid overflow.
for _ in 0..3 {
tmp1.div2();
tmp2.div2();
}
(tmp1, tmp2)
})
.collect();
let mut count = 0;
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) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(FqRepr, FqRepr)> = (0..SAMPLES)
.map(|_| {
let tmp1 = FqRepr::rand(&mut rng);
let mut tmp2 = tmp1;
// Ensure tmp2 is smaller than tmp1.
for _ in 0..10 {
tmp2.div2();
}
(tmp1, tmp2)
})
.collect();
let mut count = 0;
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) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<FqRepr> = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let tmp = v[count].num_bits();
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fq_repr_mul2(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<FqRepr> = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.mul2();
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fq_repr_div2(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<FqRepr> = (0..SAMPLES).map(|_| FqRepr::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.div2();
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fq_add_assign(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(Fq, Fq)> = (0..SAMPLES)
.map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng)))
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fq_sub_assign(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(Fq, Fq)> = (0..SAMPLES)
.map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng)))
.collect();
let mut count = 0;
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) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(Fq, Fq)> = (0..SAMPLES)
.map(|_| (Fq::rand(&mut rng), Fq::rand(&mut rng)))
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fq_square(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<Fq> = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.square();
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fq_inverse(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<Fq> = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].inverse()
});
}
#[bench]
fn bench_fq_negate(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<Fq> = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.negate();
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fq_sqrt(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<Fq> = (0..SAMPLES)
.map(|_| {
let mut tmp = Fq::rand(&mut rng);
tmp.square();
tmp
})
.collect();
let mut count = 0;
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].sqrt()
});
}
#[bench]
fn bench_fq_into_repr(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<Fq> = (0..SAMPLES).map(|_| Fq::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].into_repr()
});
}
#[bench]
fn bench_fq_from_repr(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<FqRepr> = (0..SAMPLES)
.map(|_| Fq::rand(&mut rng).into_repr())
.collect();
let mut count = 0;
b.iter(|| {
count = (count + 1) % SAMPLES;
Fq::from_repr(v[count])
});
}

94
benches/bn256/fq12.rs Normal file

@ -0,0 +1,94 @@
use rand::{Rand, SeedableRng, XorShiftRng};
use ff::Field;
use pairing::bn256::*;
#[bench]
fn bench_fq12_add_assign(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(Fq12, Fq12)> = (0..SAMPLES)
.map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng)))
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fq12_sub_assign(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(Fq12, Fq12)> = (0..SAMPLES)
.map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng)))
.collect();
let mut count = 0;
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) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(Fq12, Fq12)> = (0..SAMPLES)
.map(|_| (Fq12::rand(&mut rng), Fq12::rand(&mut rng)))
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fq12_squaring(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<Fq12> = (0..SAMPLES).map(|_| Fq12::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.square();
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fq12_inverse(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<Fq12> = (0..SAMPLES).map(|_| Fq12::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let tmp = v[count].inverse();
count = (count + 1) % SAMPLES;
tmp
});
}

110
benches/bn256/fq2.rs Normal file

@ -0,0 +1,110 @@
use rand::{Rand, SeedableRng, XorShiftRng};
use ff::{Field, SqrtField};
use pairing::bn256::*;
#[bench]
fn bench_fq2_add_assign(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(Fq2, Fq2)> = (0..SAMPLES)
.map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng)))
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fq2_sub_assign(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(Fq2, Fq2)> = (0..SAMPLES)
.map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng)))
.collect();
let mut count = 0;
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) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(Fq2, Fq2)> = (0..SAMPLES)
.map(|_| (Fq2::rand(&mut rng), Fq2::rand(&mut rng)))
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fq2_squaring(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<Fq2> = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.square();
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fq2_inverse(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<Fq2> = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let tmp = v[count].inverse();
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fq2_sqrt(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<Fq2> = (0..SAMPLES).map(|_| Fq2::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let tmp = v[count].sqrt();
count = (count + 1) % SAMPLES;
tmp
});
}

268
benches/bn256/fr.rs Normal file

@ -0,0 +1,268 @@
use rand::{Rand, SeedableRng, XorShiftRng};
use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField};
use pairing::bn256::*;
#[bench]
fn bench_fr_repr_add_nocarry(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(FrRepr, FrRepr)> = (0..SAMPLES)
.map(|_| {
let mut tmp1 = FrRepr::rand(&mut rng);
let mut tmp2 = FrRepr::rand(&mut rng);
// Shave a few bits off to avoid overflow.
for _ in 0..3 {
tmp1.div2();
tmp2.div2();
}
(tmp1, tmp2)
})
.collect();
let mut count = 0;
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) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(FrRepr, FrRepr)> = (0..SAMPLES)
.map(|_| {
let tmp1 = FrRepr::rand(&mut rng);
let mut tmp2 = tmp1;
// Ensure tmp2 is smaller than tmp1.
for _ in 0..10 {
tmp2.div2();
}
(tmp1, tmp2)
})
.collect();
let mut count = 0;
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) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<FrRepr> = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let tmp = v[count].num_bits();
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fr_repr_mul2(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<FrRepr> = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.mul2();
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fr_repr_div2(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<FrRepr> = (0..SAMPLES).map(|_| FrRepr::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.div2();
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fr_add_assign(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(Fr, Fr)> = (0..SAMPLES)
.map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng)))
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.add_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fr_sub_assign(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(Fr, Fr)> = (0..SAMPLES)
.map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng)))
.collect();
let mut count = 0;
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) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(Fr, Fr)> = (0..SAMPLES)
.map(|_| (Fr::rand(&mut rng), Fr::rand(&mut rng)))
.collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count].0;
tmp.mul_assign(&v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fr_square(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<Fr> = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.square();
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fr_inverse(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<Fr> = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].inverse()
});
}
#[bench]
fn bench_fr_negate(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<Fr> = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let mut tmp = v[count];
tmp.negate();
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_fr_sqrt(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<Fr> = (0..SAMPLES)
.map(|_| {
let mut tmp = Fr::rand(&mut rng);
tmp.square();
tmp
})
.collect();
let mut count = 0;
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].sqrt()
});
}
#[bench]
fn bench_fr_into_repr(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<Fr> = (0..SAMPLES).map(|_| Fr::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
count = (count + 1) % SAMPLES;
v[count].into_repr()
});
}
#[bench]
fn bench_fr_from_repr(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<FrRepr> = (0..SAMPLES)
.map(|_| Fr::rand(&mut rng).into_repr())
.collect();
let mut count = 0;
b.iter(|| {
count = (count + 1) % SAMPLES;
Fr::from_repr(v[count])
});
}

107
benches/bn256/mod.rs Normal file

@ -0,0 +1,107 @@
mod ec;
mod fq;
mod fq12;
mod fq2;
mod fr;
use rand::{Rand, SeedableRng, XorShiftRng};
use pairing::bn256::*;
use pairing::{CurveAffine, Engine};
#[bench]
fn bench_pairing_g1_preparation(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<G1> = (0..SAMPLES).map(|_| G1::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let tmp = G1Affine::from(v[count]).prepare();
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_pairing_g2_preparation(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<G2> = (0..SAMPLES).map(|_| G2::rand(&mut rng)).collect();
let mut count = 0;
b.iter(|| {
let tmp = G2Affine::from(v[count]).prepare();
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_pairing_miller_loop(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(G1Prepared, G2Prepared)> = (0..SAMPLES)
.map(|_| {
(
G1Affine::from(G1::rand(&mut rng)).prepare(),
G2Affine::from(G2::rand(&mut rng)).prepare(),
)
})
.collect();
let mut count = 0;
b.iter(|| {
let tmp = Bn256::miller_loop(&[(&v[count].0, &v[count].1)]);
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_pairing_final_exponentiation(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<Fq12> = (0..SAMPLES)
.map(|_| {
(
G1Affine::from(G1::rand(&mut rng)).prepare(),
G2Affine::from(G2::rand(&mut rng)).prepare(),
)
})
.map(|(ref p, ref q)| Bn256::miller_loop(&[(p, q)]))
.collect();
let mut count = 0;
b.iter(|| {
let tmp = Bn256::final_exponentiation(&v[count]);
count = (count + 1) % SAMPLES;
tmp
});
}
#[bench]
fn bench_pairing_full(b: &mut ::test::Bencher) {
const SAMPLES: usize = 1000;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let v: Vec<(G1, G2)> = (0..SAMPLES)
.map(|_| (G1::rand(&mut rng), G2::rand(&mut rng)))
.collect();
let mut count = 0;
b.iter(|| {
let tmp = Bn256::pairing(v[count].0, v[count].1);
count = (count + 1) % SAMPLES;
tmp
});
}

@ -6,3 +6,4 @@ extern crate rand;
extern crate test; extern crate test;
mod bls12_381; mod bls12_381;
mod bn256;

@ -1262,6 +1262,7 @@ pub mod g1 {
#[test] #[test]
fn g1_curve_tests() { fn g1_curve_tests() {
::tests::curve::curve_tests::<G1>(); ::tests::curve::curve_tests::<G1>();
::tests::curve::random_transformation_tests_with_cofactor::<G1>();
} }
} }
@ -2015,6 +2016,7 @@ pub mod g2 {
#[test] #[test]
fn g2_curve_tests() { fn g2_curve_tests() {
::tests::curve::curve_tests::<G2>(); ::tests::curve::curve_tests::<G2>();
::tests::curve::random_transformation_tests_with_cofactor::<G2>();
} }
} }

14
src/bn256/README.md Normal file

@ -0,0 +1,14 @@
# BN256
This is an implementation of the BN256 pairing-friendly elliptic curve construction.
## BN256 Parameterization
Follows go-ethereum parametrization.
## Notes
- I couldn't find an easy wat of getting random G2 for BN256 curve (also have no idea why just scaling by cofactor works for BLS12), so don't use it. Make random sccalar and multiply by generator.
- For this reason tests had to be copied and modified for some cases.

1598
src/bn256/ec.rs Normal file

File diff suppressed because it is too large Load Diff

579
src/bn256/fq.rs Normal file

@ -0,0 +1,579 @@
use super::fq2::Fq2;
use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr};
#[derive(PrimeField)]
#[PrimeFieldModulus = "21888242871839275222246405745257275088696311157297823662689037894645226208583"]
#[PrimeFieldGenerator = "2"]
pub struct Fq(FqRepr);
// B coefficient of BN256 curve, B = 3
// In Montgommery form with R = 2^256
pub const B_COEFF: Fq = Fq(FqRepr([
0x7a17caa950ad28d7,
0x1f6ac17ae15521b9,
0x334bea4e696bd284,
0x2a1f6744ce179d8e,
]));
pub const B_COEFF_FQ2: Fq2 = Fq2 {
c0: Fq(FqRepr([
0x3bf938e377b802a8,
0x020b1b273633535d,
0x26b7edf049755260,
0x2514c6324384a86d,
])),
c1: Fq(FqRepr([
0x38e7ecccd1dcff67,
0x65f0b37d93ce0d3e,
0xd749d0dd22ac00aa,
0x0141b9ce4a688d4d,
])),
};
// The generators of G1/G2
// Generator of G1
// x = 1
// y = 2
pub const G1_GENERATOR_X: Fq = Fq(FqRepr([
0xd35d438dc58f0d9d,
0x0a78eb28f5c70b3d,
0x666ea36f7879462c,
0x0e0a77c19a07df2f,
]));
pub const G1_GENERATOR_Y: Fq = Fq(FqRepr([
0xa6ba871b8b1e1b3a,
0x14f1d651eb8e167b,
0xccdd46def0f28c58,
0x1c14ef83340fbe5e,
]));
// Generator of G2
//
// x = 11559732032986387107991004021392285783925812861821192530917403151452391805634*u
// + 10857046999023057135944570762232829481370756359578518086990519993285655852781
//
// y = 4082367875863433681332203403145435568316851327593401208105741076214120093531*u
// + 8495653923123431417604973247489272438418190587263600148770280649306958101930
pub const G2_GENERATOR_X_C0: Fq = Fq(FqRepr([
0x8e83b5d102bc2026,
0xdceb1935497b0172,
0xfbb8264797811adf,
0x19573841af96503b,
]));
pub const G2_GENERATOR_X_C1: Fq = Fq(FqRepr([
0xafb4737da84c6140,
0x6043dd5a5802d8c4,
0x09e950fc52a02f86,
0x14fef0833aea7b6b,
]));
pub const G2_GENERATOR_Y_C0: Fq = Fq(FqRepr([
0x619dfa9d886be9f6,
0xfe7fd297f59e9b78,
0xff9e1a62231b7dfe,
0x28fd7eebae9e4206,
]));
pub const G2_GENERATOR_Y_C1: Fq = Fq(FqRepr([
0x64095b56c71856ee,
0xdc57f922327d3cbb,
0x55f935be33351076,
0x0da4a0e693fd6482,
]));
// Coefficients for the Frobenius automorphism.
pub const FROBENIUS_COEFF_FQ2_C1: [Fq; 2] = [
// Fq(-1)**(((q^0) - 1) / 2)
// it's 1 in Montgommery form
Fq(FqRepr([
0xd35d438dc58f0d9d,
0x0a78eb28f5c70b3d,
0x666ea36f7879462c,
0x0e0a77c19a07df2f,
])),
// Fq(-1)**(((q^1) - 1) / 2)
Fq(FqRepr([
0x68c3488912edefaa,
0x8d087f6872aabf4f,
0x51e1a24709081231,
0x2259d6b14729c0fa,
])),
];
// Fq2(u + 9)**(((q^1) - 1) / 2)
pub const XI_TO_Q_MINUS_1_OVER_2: Fq2 = Fq2 {
c0: Fq(FqRepr([
0xe4bbdd0c2936b629,
0xbb30f162e133bacb,
0x31a9d1b6f9645366,
0x253570bea500f8dd,
])),
c1: Fq(FqRepr([
0xa1d77ce45ffe77c7,
0x07affd117826d1db,
0x6d16bd27bb7edc6b,
0x2c87200285defecc,
])),
};
pub const FROBENIUS_COEFF_FQ6_C1: [Fq2; 6] = [
// Fq2(u + 9)**(((q^0) - 1) / 3)
Fq2 {
c0: Fq(FqRepr([
0xd35d438dc58f0d9d,
0x0a78eb28f5c70b3d,
0x666ea36f7879462c,
0x0e0a77c19a07df2f,
])),
c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0])),
},
// Fq2(u + 9)**(((q^1) - 1) / 3)
// taken from go-ethereum and also re-calculated manually
Fq2 {
c0: Fq(FqRepr([
0xb5773b104563ab30,
0x347f91c8a9aa6454,
0x7a007127242e0991,
0x1956bcd8118214ec,
])),
c1: Fq(FqRepr([
0x6e849f1ea0aa4757,
0xaa1c7b6d89f89141,
0xb6e713cdfae0ca3a,
0x26694fbb4e82ebc3,
])),
},
// Fq2(u + 9)**(((q^2) - 1) / 3)
// this one and other below are recalculated manually
Fq2 {
c0: Fq(FqRepr([
0x3350c88e13e80b9c,
0x7dce557cdb5e56b9,
0x6001b4b8b615564a,
0x2682e617020217e0,
])),
c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0])),
},
// Fq2(u + 9)**(((q^3) - 1) / 3)
Fq2 {
c0: Fq(FqRepr([
0xc9af22f716ad6bad,
0xb311782a4aa662b2,
0x19eeaf64e248c7f4,
0x20273e77e3439f82,
])),
c1: Fq(FqRepr([
0xacc02860f7ce93ac,
0x3933d5817ba76b4c,
0x69e6188b446c8467,
0x0a46036d4417cc55,
])),
},
// Fq2(u + 9)**(((q^4) - 1) / 3)
Fq2 {
c0: Fq(FqRepr([
0x71930c11d782e155,
0xa6bb947cffbe3323,
0xaa303344d4741444,
0x2c3b3f0d26594943,
])),
c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0,])),
},
// Fq2(u + 9)**(((q^5) - 1) / 3)
Fq2 {
c0: Fq(FqRepr([
0xf91aba2654e8e3b1,
0x4771cb2fdc92ce12,
0xdcb16ae0fc8bdf35,
0x274aa195cd9d8be4,
])),
c1: Fq(FqRepr([
0x5cfc50ae18811f8b,
0x4bb28433cb43988c,
0x4fd35f13c3b56219,
0x301949bd2fc8883a,
])),
},
];
pub const FROBENIUS_COEFF_FQ6_C2: [Fq2; 6] = [
// Fq2(u + 1)**(((2q^0) - 2) / 3)
Fq2 {
c0: Fq(FqRepr([
0xd35d438dc58f0d9d,
0x0a78eb28f5c70b3d,
0x666ea36f7879462c,
0x0e0a77c19a07df2f,
])),
c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0])),
},
// Fq2(u + 1)**(((2q^1) - 2) / 3)
Fq2 {
c0: Fq(FqRepr([
0x7361d77f843abe92,
0xa5bb2bd3273411fb,
0x9c941f314b3e2399,
0x15df9cddbb9fd3ec,
])),
c1: Fq(FqRepr([
0x5dddfd154bd8c949,
0x62cb29a5a4445b60,
0x37bc870a0c7dd2b9,
0x24830a9d3171f0fd,
])),
},
// Fq2(u + 1)**(((2q^2) - 2) / 3)
Fq2 {
c0: Fq(FqRepr([
0x71930c11d782e155,
0xa6bb947cffbe3323,
0xaa303344d4741444,
0x2c3b3f0d26594943,
])),
c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0,])),
},
// Fq2(u + 1)**(((2q^3) - 2) / 3)
Fq2 {
c0: Fq(FqRepr([
0x448a93a57b6762df,
0xbfd62df528fdeadf,
0xd858f5d00e9bd47a,
0x06b03d4d3476ec58,
])),
c1: Fq(FqRepr([
0x2b19daf4bcc936d1,
0xa1a54e7a56f4299f,
0xb533eee05adeaef1,
0x170c812b84dda0b2,
])),
},
// Fq2(u + 1)**(((2q^4) - 2) / 3)
Fq2 {
c0: Fq(FqRepr([
0x3350c88e13e80b9c,
0x7dce557cdb5e56b9,
0x6001b4b8b615564a,
0x2682e617020217e0,
])),
c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0,])),
},
// Fq2(u + 1)**(((2q^5) - 2) / 3)
Fq2 {
c0: Fq(FqRepr([
0x843420f1d8dadbd6,
0x31f010c9183fcdb2,
0x436330b527a76049,
0x13d47447f11adfe4,
])),
c1: Fq(FqRepr([
0xef494023a857fa74,
0x2a925d02d5ab101a,
0x83b015829ba62f10,
0x2539111d0c13aea3,
])),
},
];
// non_residue^((modulus^i-1)/6) for i=0,...,11
pub const FROBENIUS_COEFF_FQ12_C1: [Fq2; 12] = [
// Fq2(u + 1)**(((q^0) - 1) / 6)
Fq2 {
c0: Fq(FqRepr([
0xd35d438dc58f0d9d,
0x0a78eb28f5c70b3d,
0x666ea36f7879462c,
0x0e0a77c19a07df2f,
])),
c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0])),
},
// Fq2(u + 1)**(((q^1) - 1) / 6)
Fq2 {
c0: Fq(FqRepr([
0xaf9ba69633144907,
0xca6b1d7387afb78a,
0x11bded5ef08a2087,
0x02f34d751a1f3a7c,
])),
c1: Fq(FqRepr([
0xa222ae234c492d72,
0xd00f02a4565de15b,
0xdc2ff3a253dfc926,
0x10a75716b3899551,
])),
},
// Fq2(u + 1)**(((q^2) - 1) / 6)
Fq2 {
c0: Fq(FqRepr([
0xca8d800500fa1bf2,
0xf0c5d61468b39769,
0x0e201271ad0d4418,
0x04290f65bad856e6,
])),
c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0])),
},
// Fq2(u + 1)**(((q^3) - 1) / 6)
Fq2 {
c0: Fq(FqRepr([
0x365316184e46d97d,
0x0af7129ed4c96d9f,
0x659da72fca1009b5,
0x08116d8983a20d23,
])),
c1: Fq(FqRepr([
0xb1df4af7c39c1939,
0x3d9f02878a73bf7f,
0x9b2220928caf0ae0,
0x26684515eff054a6,
])),
},
// Fq2(u + 1)**(((q^4) - 1) / 6)
Fq2 {
c0: Fq(FqRepr([
0x3350c88e13e80b9c,
0x7dce557cdb5e56b9,
0x6001b4b8b615564a,
0x2682e617020217e0,
])),
c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0,])),
},
// Fq2(u + 1)**(((q^5) - 1) / 6)
Fq2 {
c0: Fq(FqRepr([
0x86b76f821b329076,
0x408bf52b4d19b614,
0x53dfb9d0d985e92d,
0x051e20146982d2a7,
])),
c1: Fq(FqRepr([
0x0fbc9cd47752ebc7,
0x6d8fffe33415de24,
0xbef22cf038cf41b9,
0x15c0edff3c66bf54,
])),
},
// Fq2(u + 1)**(((q^6) - 1) / 6)
Fq2 {
c0: Fq(FqRepr([
0x68c3488912edefaa,
0x8d087f6872aabf4f,
0x51e1a24709081231,
0x2259d6b14729c0fa,
])),
c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0,])),
},
// Fq2(u + 1)**(((q^7) - 1) / 6)
Fq2 {
c0: Fq(FqRepr([
0x8c84e580a568b440,
0xcd164d1de0c21302,
0xa692585790f737d5,
0x2d7100fdc71265ad,
])),
c1: Fq(FqRepr([
0x99fdddf38c33cfd5,
0xc77267ed1213e931,
0xdc2052142da18f36,
0x1fbcf75c2da80ad7,
])),
},
// Fq2(u + 1)**(((q^8) - 1) / 6)
Fq2 {
c0: Fq(FqRepr([
0x71930c11d782e155,
0xa6bb947cffbe3323,
0xaa303344d4741444,
0x2c3b3f0d26594943,
])),
c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0,])),
},
// Fq2(u + 1)**(((q^9) - 1) / 6)
Fq2 {
c0: Fq(FqRepr([
0x05cd75fe8a3623ca,
0x8c8a57f293a85cee,
0x52b29e86b7714ea8,
0x2852e0e95d8f9306,
])),
c1: Fq(FqRepr([
0x8a41411f14e0e40e,
0x59e26809ddfe0b0d,
0x1d2e2523f4d24d7d,
0x09fc095cf1414b83,
])),
},
// Fq2(u + 1)**(((q^10) - 1) / 6)
Fq2 {
c0: Fq(FqRepr([
0x08cfc388c494f1ab,
0x19b315148d1373d4,
0x584e90fdcb6c0213,
0x09e1685bdf2f8849,
])),
c1: Fq(FqRepr([0x0, 0x0, 0x0, 0x0,])),
},
// Fq2(u + 1)**(((q^11) - 1) / 6)
Fq2 {
c0: Fq(FqRepr([
0xb5691c94bd4a6cd1,
0x56f575661b581478,
0x64708be5a7fb6f30,
0x2b462e5e77aecd82,
])),
c1: Fq(FqRepr([
0x2c63ef42612a1180,
0x29f16aae345bec69,
0xf95e18c648b216a4,
0x1aa36073a4cae0d4,
])),
},
];
// -((2**256) mod q) mod q
pub const NEGATIVE_ONE: Fq = Fq(FqRepr([
0x974bc177a0000006,
0xf13771b2da58a367,
0x51e1a2470908122e,
0x2259d6b14729c0fa,
]));
#[cfg(test)]
use rand::{Rand, SeedableRng, XorShiftRng};
#[test]
fn test_fq_repr_from() {
assert_eq!(FqRepr::from(100), FqRepr([100, 0, 0, 0]));
assert_eq!(FqRepr::from(3), FqRepr([3, 0, 0, 0]));
}
#[test]
fn test_fq_repr_is_odd() {
assert!(!FqRepr::from(0).is_odd());
assert!(FqRepr::from(0).is_even());
assert!(FqRepr::from(1).is_odd());
assert!(!FqRepr::from(1).is_even());
assert!(!FqRepr::from(324834872).is_odd());
assert!(FqRepr::from(324834872).is_even());
assert!(FqRepr::from(324834873).is_odd());
assert!(!FqRepr::from(324834873).is_even());
}
#[test]
fn test_fq_repr_num_bits() {
let mut a = FqRepr::from(0);
assert_eq!(0, a.num_bits());
a = FqRepr::from(1);
for i in 1..257 {
assert_eq!(i, a.num_bits());
a.mul2();
}
assert_eq!(0, a.num_bits());
}
#[test]
fn test_fq_is_valid() {
print!("modulus = {}\n", MODULUS);
print!("R = {}\n", R);
let mut a = Fq(MODULUS);
assert!(!a.is_valid());
a.0.sub_noborrow(&FqRepr::from(1));
assert!(a.is_valid());
assert!(Fq(FqRepr::from(0)).is_valid());
assert!(
Fq(FqRepr([
0xdf4671abd14dab3e,
0xe2dc0c9f534fbd33,
0x31ca6c880cc444a6,
0x257a67e70ef33359
])).is_valid()
);
assert!(
!Fq(FqRepr([
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
])).is_valid()
);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let a = Fq::rand(&mut rng);
assert!(a.is_valid());
}
}
#[test]
fn test_fq_repr_display() {
assert_eq!(
format!("{}", Fq::into_repr(&Fq::one())),
"0x0000000000000000000000000000000000000000000000000000000000000001".to_string()
);
assert_eq!(
format!("{}", FqRepr([0, 0, 0, 0])),
"0x0000000000000000000000000000000000000000000000000000000000000000".to_string()
);
}
#[test]
fn test_fq_num_bits() {
assert_eq!(Fq::NUM_BITS, 254);
assert_eq!(Fq::CAPACITY, 253);
}
#[test]
fn test_fq_sqrt() {
use ff::SqrtField;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
assert_eq!(Fq::zero().sqrt().unwrap(), Fq::zero());
for _ in 0..1000 {
// Ensure sqrt(a^2) = a or -a
let a = Fq::rand(&mut rng);
let mut nega = a;
nega.negate();
let mut b = a;
b.square();
let b = b.sqrt().unwrap();
assert!(a == b || nega == b);
}
for _ in 0..1000 {
// Ensure sqrt(a)^2 = a for random a
let a = Fq::rand(&mut rng);
if let Some(mut tmp) = a.sqrt() {
tmp.square();
assert_eq!(a, tmp);
}
}
}
#[test]
fn test_fq_sqrt_2() {
use ff::SqrtField;
let x = Fq::from_str("4").unwrap();
print!("x = {}\n", x);
if let Some(y) = x.sqrt() {
print!("y = {}\n", y);
let mut y_other = y;
y_other.negate();
print!("y' = {}\n", y_other);
}
}
#[test]
fn fq_field_tests() {
::tests::field::random_field_tests::<Fq>();
::tests::field::random_sqrt_tests::<Fq>();
::tests::field::random_frobenius_tests::<Fq, _>(Fq::char(), 13);
::tests::field::from_str_tests::<Fq>();
}

221
src/bn256/fq12.rs Normal file

@ -0,0 +1,221 @@
use super::fq::FROBENIUS_COEFF_FQ12_C1;
use super::fq2::Fq2;
use super::fq6::Fq6;
use ff::Field;
use rand::{Rand, Rng};
/// An element of Fq12, represented by c0 + c1 * w.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Fq12 {
pub c0: Fq6,
pub c1: Fq6,
}
impl ::std::fmt::Display for Fq12 {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "Fq12({} + {} * w)", self.c0, self.c1)
}
}
impl Rand for Fq12 {
fn rand<R: Rng>(rng: &mut R) -> Self {
Fq12 {
c0: rng.gen(),
c1: rng.gen(),
}
}
}
// BN256 and BLS12 implementations should be the same
// Defined over w^2 - v = 0
impl Fq12 {
pub fn conjugate(&mut self) {
self.c1.negate();
}
pub fn mul_by_014(&mut self, c0: &Fq2, c1: &Fq2, c4: &Fq2) {
let mut aa = self.c0;
aa.mul_by_01(c0, c1);
let mut bb = self.c1;
bb.mul_by_1(c4);
let mut o = *c1;
o.add_assign(c4);
self.c1.add_assign(&self.c0);
self.c1.mul_by_01(c0, &o);
self.c1.sub_assign(&aa);
self.c1.sub_assign(&bb);
self.c0 = bb;
self.c0.mul_by_nonresidue();
self.c0.add_assign(&aa);
}
// TODO make it hand optimized
// // multiply by (c0, c1, c2) + (c3, c4, c5)*w where only c0, c3 and c4 are non-zero
pub fn mul_by_034(&mut self, c0: &Fq2, c3: &Fq2, c4: &Fq2) {
self.mul_assign(&Fq12 {
c0: Fq6 {
c0: *c0,
c1: Fq2::zero(),
c2: Fq2::zero(),
},
c1: Fq6 {
c0: *c3,
c1: *c4,
c2: Fq2::zero(),
},
});
}
}
impl Field for Fq12 {
fn zero() -> Self {
Fq12 {
c0: Fq6::zero(),
c1: Fq6::zero(),
}
}
fn one() -> Self {
Fq12 {
c0: Fq6::one(),
c1: Fq6::zero(),
}
}
fn is_zero(&self) -> bool {
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 frobenius_map(&mut self, power: usize) {
self.c0.frobenius_map(power);
self.c1.frobenius_map(power);
self.c1.c0.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]);
self.c1.c1.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]);
self.c1.c2.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]);
}
fn square(&mut 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.mul_by_nonresidue();
c0.add_assign(&self.c0);
c0.mul_assign(&c0c1);
c0.sub_assign(&ab);
self.c1 = ab;
self.c1.add_assign(&ab);
ab.mul_by_nonresidue();
c0.sub_assign(&ab);
self.c0 = c0;
}
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();
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
})
}
}
#[cfg(test)]
use rand::{SeedableRng, XorShiftRng};
#[test]
fn test_fq12_mul_by_014() {
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let c0 = Fq2::rand(&mut rng);
let c1 = Fq2::rand(&mut rng);
let c5 = Fq2::rand(&mut rng);
let mut a = Fq12::rand(&mut rng);
let mut b = a;
a.mul_by_014(&c0, &c1, &c5);
b.mul_assign(&Fq12 {
c0: Fq6 {
c0: c0,
c1: c1,
c2: Fq2::zero(),
},
c1: Fq6 {
c0: Fq2::zero(),
c1: c5,
c2: Fq2::zero(),
},
});
assert_eq!(a, b);
}
}
#[test]
fn test_squaring() {
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let mut a = Fq12::rand(&mut rng);
let mut b = a;
b.mul_assign(&a);
a.square();
assert_eq!(a, b);
}
}
#[test]
fn fq12_field_tests() {
use ff::PrimeField;
::tests::field::random_field_tests::<Fq12>();
::tests::field::random_frobenius_tests::<Fq12, _>(super::fq::Fq::char(), 13);
}

966
src/bn256/fq2.rs Normal file

@ -0,0 +1,966 @@
use super::fq::{FROBENIUS_COEFF_FQ2_C1, Fq, NEGATIVE_ONE};
use ff::{Field, SqrtField};
use rand::{Rand, Rng};
use std::cmp::Ordering;
/// An element of Fq2, represented by c0 + c1 * u.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Fq2 {
pub c0: Fq,
pub c1: Fq,
}
impl ::std::fmt::Display for Fq2 {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "Fq2({} + {} * u)", self.c0, self.c1)
}
}
/// `Fq2` elements are ordered lexicographically.
impl Ord for Fq2 {
#[inline(always)]
fn cmp(&self, other: &Fq2) -> Ordering {
match self.c1.cmp(&other.c1) {
Ordering::Greater => Ordering::Greater,
Ordering::Less => Ordering::Less,
Ordering::Equal => self.c0.cmp(&other.c0),
}
}
}
impl PartialOrd for Fq2 {
#[inline(always)]
fn partial_cmp(&self, other: &Fq2) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Fq2 {
// This is very confusing part, cause depends not of Fq2 itself, but form Fq6 construction
/// Multiply this element by quadratic nonresidue 9 + u.
pub fn mul_by_nonresidue(&mut self) {
// (xi+y)(i+9) = (9x+y)i+(9y-x)
let t0 = self.c0;
let t1 = self.c1;
// 8*x*i + 8*y
self.double();
self.double();
self.double();
// 9*y
self.c0.add_assign(&t0);
// (9*y - x)
self.c0.sub_assign(&t1);
// (9*x)i
self.c1.add_assign(&t1);
// (9*x + y)
self.c1.add_assign(&t0);
}
// Multiply this element by ξ where ξ=i+9
pub fn mul_by_xi(&mut self) {
// (xi+y)(i+9) = (9x+y)i+(9y-x)
let t0 = self.c0;
let t1 = self.c1;
// 8*x*i + 8*y
self.double();
self.double();
self.double();
// 9*y
self.c0.add_assign(&t0);
// (9*y - x)
self.c0.sub_assign(&t1);
// (9*x)i
self.c1.add_assign(&t1);
// (9*x + y)
self.c1.add_assign(&t0);
}
/// 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();
t1.add_assign(&t0);
t1
}
// conjucate by negating c1
pub fn conjugate(&mut self) {
self.c1.negate();
}
}
impl Rand for Fq2 {
fn rand<R: Rng>(rng: &mut R) -> Self {
Fq2 {
c0: rng.gen(),
c1: rng.gen(),
}
}
}
impl Field for Fq2 {
fn zero() -> Self {
Fq2 {
c0: Fq::zero(),
c1: Fq::zero(),
}
}
fn one() -> Self {
Fq2 {
c0: Fq::one(),
c1: Fq::zero(),
}
}
fn is_zero(&self) -> bool {
self.c0.is_zero() && self.c1.is_zero()
}
fn square(&mut 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();
c0.add_assign(&self.c0);
c0.mul_assign(&c0c1);
c0.sub_assign(&ab);
self.c1 = ab;
self.c1.add_assign(&ab);
c0.add_assign(&ab);
self.c0 = c0;
}
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 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();
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
})
}
fn frobenius_map(&mut self, power: usize) {
self.c1.mul_assign(&FROBENIUS_COEFF_FQ2_C1[power % 2]);
}
}
impl SqrtField for Fq2 {
fn legendre(&self) -> ::ff::LegendreSymbol {
self.norm().legendre()
}
fn sqrt(&self) -> Option<Self> {
// Algorithm 9, https://eprint.iacr.org/2012/685.pdf
if self.is_zero() {
Some(Self::zero())
} else {
// a1 = self^((q - 3) / 4)
let mut a1 = self.pow([
0x4f082305b61f3f51,
0x65e05aa45a1c72a3,
0x6e14116da0605617,
0x0c19139cb84c680a,
]);
let mut alpha = a1;
alpha.square();
alpha.mul_assign(self);
let mut a0 = alpha;
a0.frobenius_map(1);
a0.mul_assign(&alpha);
let neg1 = Fq2 {
c0: NEGATIVE_ONE,
c1: Fq::zero(),
};
if a0 == neg1 {
None
} else {
a1.mul_assign(self);
if alpha == neg1 {
a1.mul_assign(&Fq2 {
c0: Fq::zero(),
c1: Fq::one(),
});
} else {
alpha.add_assign(&Fq2::one());
// alpha = alpha^((q - 1) / 2)
alpha = alpha.pow([
0x9e10460b6c3e7ea3,
0xcbc0b548b438e546,
0xdc2822db40c0ac2e,
0x183227397098d014,
]);
a1.mul_assign(&alpha);
}
Some(a1)
}
}
}
}
#[test]
fn test_fq2_get_b() {
use ff::Field;
let mut a = Fq2::one();
a.mul_by_nonresidue();
let mut b = a.inverse().unwrap();
let c = b;
b.double();
b.add_assign(&c);
print!("B coeff in Fq2 = {}\n", b);
}
#[test]
fn test_fq2_frobc1() {
use ff::Field;
let mut a = Fq2::one();
a.mul_by_nonresidue();
let res1 = a.pow([
0x69602eb24829a9c2,
0xdd2b2385cd7b4384,
0xe81ac1e7808072c9,
0x10216f7ba065e00d,
]);
print!("Frob1 = {}\n", res1);
let res2 = a.pow([
0x691c1d8b62747890,
0x8cab57b9adf8eb00,
0x18c55d8979dcee49,
0x56cd8a31d35b6b98,
0xb7a4a8c966ece684,
0xe5592c705cbd1cac,
0x1dde2529566d9b5e,
0x030c96e827699534,
]);
print!("Frob2 = {}\n", res2);
let res3 = a.pow([
0x3de6332b975d69b2,
0x587b5b2bd890e101,
0x16677d4bec77bbeb,
0x3fdfdba3309dd645,
0xdfd4137cd943954b,
0xcfb035047f38c226,
0x01b5daf7ac73104c,
0x4cce8699d63e4f06,
0x40c0b41264a4b9f4,
0x7806da9ba1f6d7fb,
0x110a40708107d53a,
0x00938e25ae57c88f,
]);
print!("Frob3 = {}\n", res3);
let res4 = a.pow([
0xabb30419f6bee420,
0x6ce183e5f2f8d3b9,
0x9db42a441998ac99,
0xf74b04aa96e3852f,
0x64de4542a9807c06,
0x41f83258fd90abd1,
0x5ecb5383626aeca3,
0xb60804ce8f24ca82,
0xd4b3aadc1344e8bb,
0x436b70833cb2615b,
0x1a87eeb627861611,
0x4e155ea3e5090666,
0xacfcff9291a10112,
0x1cba0005b295d5bc,
0x319c8e7f94b31729,
0x001be477ceef2455,
]);
print!("Frob4 = {}\n", res4);
let res5 = a.pow([
0x7501aa71de0e8ea2,
0x97516fd7ca83b8fe,
0x7da14ac0c03d4182,
0xaf5d35dc7f80498d,
0xb257f7f84fb899e0,
0x372cb1bd547dbe69,
0xb6696efbf52d5146,
0x03b6707d4a42574c,
0xeae6c62cf1670269,
0xfe70626cbbb760e9,
0xfa9d12d01fb42086,
0xc85218d5a7af23b7,
0x0a70a73464ed35fb,
0x878713d44d9a2aca,
0xc81d8fc5cdfe15ee,
0xa3ebe919611e544d,
0xfe46bd734126775c,
0x06f8a7579371f67f,
0xa94a371ceb68884c,
0x000545c441ba73d6,
]);
print!("Frob5 = {}\n", res5);
let res6 = a.pow([
0xfc4dae0d07a152b0,
0x3f383f79f9859a0a,
0x261f0da312f72ab2,
0x9cc6b2e6efb101d8,
0xf45a236f76e806da,
0x7158062cd79d6743,
0x8adabccc870f23db,
0x24428ff02b7988c1,
0x8f55fa0a7ecfa21d,
0xd5574a8dc73fdcc2,
0xb86f06772524e5ca,
0xb4b11653b762bd0f,
0xb84ec7291c154c58,
0x2a095f1259f99fb5,
0x6ccb38fbc9f54a74,
0x3a3f77faca5c2ea0,
0x21a469bdd36b9656,
0x0fa2e41314b53258,
0xf8ca5207cb9f028e,
0x489fbf415ec8104e,
0x711aafe44a1ab611,
0xfb508020969bab31,
0xb8b71e4e258cf968,
0x0000ff25aa9c2350,
]);
print!("Frob6 = {}\n", res6);
}
#[test]
fn test_fq2_frobc2() {
use ff::Field;
let mut a = Fq2::one();
a.mul_by_nonresidue();
let res1 = a.pow([
0xd2c05d6490535384,
0xba56470b9af68708,
0xd03583cf0100e593,
0x2042def740cbc01b,
]);
print!("Frob1 = {}\n", res1);
let res2 = a.pow([
0xd2383b16c4e8f120,
0x1956af735bf1d600,
0x318abb12f3b9dc93,
0xad9b1463a6b6d730,
0x6f495192cdd9cd08,
0xcab258e0b97a3959,
0x3bbc4a52acdb36bd,
0x06192dd04ed32a68,
]);
print!("Frob2 = {}\n", res2);
let res3 = a.pow([
0x7bcc66572ebad364,
0xb0f6b657b121c202,
0x2ccefa97d8ef77d6,
0x7fbfb746613bac8a,
0xbfa826f9b2872a96,
0x9f606a08fe71844d,
0x036bb5ef58e62099,
0x999d0d33ac7c9e0c,
0x81816824c94973e8,
0xf00db53743edaff6,
0x221480e1020faa74,
0x01271c4b5caf911e,
]);
print!("Frob3 = {}\n", res3);
let res4 = a.pow([
0x57660833ed7dc840,
0xd9c307cbe5f1a773,
0x3b68548833315932,
0xee9609552dc70a5f,
0xc9bc8a855300f80d,
0x83f064b1fb2157a2,
0xbd96a706c4d5d946,
0x6c10099d1e499504,
0xa96755b82689d177,
0x86d6e1067964c2b7,
0x350fdd6c4f0c2c22,
0x9c2abd47ca120ccc,
0x59f9ff2523420224,
0x3974000b652bab79,
0x63391cff29662e52,
0x0037c8ef9dde48aa,
]);
print!("Frob4 = {}\n", res4);
let res5 = a.pow([
0xea0354e3bc1d1d44,
0x2ea2dfaf950771fc,
0xfb429581807a8305,
0x5eba6bb8ff00931a,
0x64afeff09f7133c1,
0x6e59637aa8fb7cd3,
0x6cd2ddf7ea5aa28c,
0x076ce0fa9484ae99,
0xd5cd8c59e2ce04d2,
0xfce0c4d9776ec1d3,
0xf53a25a03f68410d,
0x90a431ab4f5e476f,
0x14e14e68c9da6bf7,
0x0f0e27a89b345594,
0x903b1f8b9bfc2bdd,
0x47d7d232c23ca89b,
0xfc8d7ae6824ceeb9,
0x0df14eaf26e3ecff,
0x52946e39d6d11098,
0x000a8b888374e7ad,
]);
print!("Frob5 = {}\n", res5);
let res6 = a.pow([
0xf89b5c1a0f42a560,
0x7e707ef3f30b3415,
0x4c3e1b4625ee5564,
0x398d65cddf6203b0,
0xe8b446deedd00db5,
0xe2b00c59af3ace87,
0x15b579990e1e47b6,
0x48851fe056f31183,
0x1eabf414fd9f443a,
0xaaae951b8e7fb985,
0x70de0cee4a49cb95,
0x69622ca76ec57a1f,
0x709d8e52382a98b1,
0x5412be24b3f33f6b,
0xd99671f793ea94e8,
0x747eeff594b85d40,
0x4348d37ba6d72cac,
0x1f45c826296a64b0,
0xf194a40f973e051c,
0x913f7e82bd90209d,
0xe2355fc894356c22,
0xf6a100412d375662,
0x716e3c9c4b19f2d1,
0x0001fe4b553846a1,
]);
print!("Frob6 = {}\n", res6);
}
#[test]
fn test_fq2_frob12() {
use ff::Field;
let mut a = Fq2::one();
a.mul_by_nonresidue();
let res1 = a.pow([
0x34b017592414d4e1,
0xee9591c2e6bda1c2,
0xf40d60f3c0403964,
0x0810b7bdd032f006,
]);
print!("Frob1 = {}\n", res1);
let res2 = a.pow([
0x348e0ec5b13a3c48,
0xc655abdcd6fc7580,
0x0c62aec4bcee7724,
0x2b66c518e9adb5cc,
0x5bd25464b3767342,
0x72ac96382e5e8e56,
0x0eef1294ab36cdaf,
0x01864b7413b4ca9a,
]);
print!("Frob2 = {}\n", res2);
let res3 = a.pow([
0x9ef31995cbaeb4d9,
0xac3dad95ec487080,
0x8b33bea5f63bddf5,
0x9fefedd1984eeb22,
0x6fea09be6ca1caa5,
0x67d81a823f9c6113,
0x00daed7bd6398826,
0x2667434ceb1f2783,
0xa0605a0932525cfa,
0x3c036d4dd0fb6bfd,
0x888520384083ea9d,
0x0049c712d72be447,
]);
print!("Frob3 = {}\n", res3);
let res4 = a.pow([
0xd5d9820cfb5f7210,
0xb670c1f2f97c69dc,
0xceda15220ccc564c,
0x7ba582554b71c297,
0xb26f22a154c03e03,
0xa0fc192c7ec855e8,
0x2f65a9c1b1357651,
0xdb04026747926541,
0xea59d56e09a2745d,
0xa1b5b8419e5930ad,
0x0d43f75b13c30b08,
0x270aaf51f2848333,
0x567e7fc948d08089,
0x8e5d0002d94aeade,
0x98ce473fca598b94,
0x000df23be777922a,
]);
print!("Frob4 = {}\n", res4);
let res5 = a.pow([
0x3a80d538ef074751,
0x4ba8b7ebe541dc7f,
0xbed0a560601ea0c1,
0x57ae9aee3fc024c6,
0xd92bfbfc27dc4cf0,
0x1b9658deaa3edf34,
0x5b34b77dfa96a8a3,
0x81db383ea5212ba6,
0xf573631678b38134,
0x7f3831365ddbb074,
0xfd4e89680fda1043,
0xe4290c6ad3d791db,
0x0538539a32769afd,
0x43c389ea26cd1565,
0xe40ec7e2e6ff0af7,
0x51f5f48cb08f2a26,
0xff235eb9a0933bae,
0x037c53abc9b8fb3f,
0x54a51b8e75b44426,
0x0002a2e220dd39eb,
]);
print!("Frob5 = {}\n", res5);
let res6 = a.pow([
0x7e26d70683d0a958,
0x1f9c1fbcfcc2cd05,
0x130f86d1897b9559,
0x4e63597377d880ec,
0xfa2d11b7bb74036d,
0xb8ac03166bceb3a1,
0xc56d5e66438791ed,
0x922147f815bcc460,
0x47aafd053f67d10e,
0x6aaba546e39fee61,
0xdc37833b929272e5,
0x5a588b29dbb15e87,
0xdc2763948e0aa62c,
0x1504af892cfccfda,
0x36659c7de4faa53a,
0x1d1fbbfd652e1750,
0x10d234dee9b5cb2b,
0x07d172098a5a992c,
0x7c652903e5cf8147,
0xa44fdfa0af640827,
0xb88d57f2250d5b08,
0x7da840104b4dd598,
0x5c5b8f2712c67cb4,
0x00007f92d54e11a8,
]);
print!("Frob6 = {}\n", res6);
let res7 = a.pow([
0x75e1bff130efc449,
0xfb4f505fb284ee15,
0x57b30efd96c492f5,
0xfdcb862e4e948b59,
0x3def467dae8887e2,
0xa47e3f76b755ca8c,
0xa63f6ea3debc563a,
0x115d1111a4fc4be2,
0xc3b2ece674d74549,
0xb2099a8141cb8830,
0x120dc0b8ac63867a,
0xae0245267985fe96,
0xed38ce9a40128f1d,
0xeba67d5d8ffa4939,
0xbff55f706b0de0f5,
0xb4f3f86e6f982aed,
0x062675f8a89bd61d,
0xa1098fb006a9726c,
0xe974fc0c7b0e5d9c,
0x0f10af0bdc56fe9e,
0x628ca855d5d4ac87,
0x7bd59e7101d9d82d,
0xed98625bf5dc71aa,
0x7ab9b78fdc8558f4,
0x489b4c8564d6f8d2,
0xd055177a2fbfcd94,
0x059f68dd1e0cb392,
0x0000181d8471f268,
]);
print!("Frob7 = {}\n", res7);
let res8 = a.pow([
0x742e7ca156ec6a20,
0x3fee59e5c3e8de2e,
0xfdef69cd295152ef,
0xe4ad8aece2ce3640,
0x05308778897ea5eb,
0x0a4fc046ae1c2e50,
0xb16faf17473bba4a,
0xd106751c900aadfa,
0x115301a6c43ba345,
0x19f012d49d8a716c,
0x6b9d91b1c2a56cc5,
0xb77230690204b675,
0xf6d68e7229980805,
0xf4263d3b11784a87,
0x24bb64e5adeaa33d,
0x684c4ff325fa1c4d,
0x79a8c6430472e684,
0x823af8186da5609c,
0x2087966741a30941,
0x1876205eaf407912,
0xa614d3f14990435e,
0xd405328435bcc8df,
0x5afac38bad541421,
0x0706fb9d17dec3d8,
0xecc747832c3f5f69,
0xe231b0ffd6651ed5,
0x45fa8e7ff2a80f15,
0xdce48166a2ee0170,
0x305fc72544895a12,
0x516ac4b20d800019,
0x826e9ab28689a4d3,
0x0000048efbc0eaac,
]);
print!("Frob8 = {}\n", res8);
let res9 = a.pow(&[
0x64984dce4c07e3c1,
0x2e2096f441339496,
0xd50c9bd49d279670,
0xd52ead3ce3a93422,
0x426dad5fc6a6779a,
0x3f9dd6b6f19bc638,
0x6be503d3981b0db5,
0x0b222e7512412d2c,
0x484bd275e77ff0bf,
0xb357542fb851205b,
0xd8c995246bf492ff,
0xc6b92fc3bf2887bc,
0xcd27cfd0d4499277,
0x967aa0012f40dcf9,
0x312baab0f5bc64e3,
0xe465b3c98a822e05,
0x3133d12c8828f7b8,
0x357a20a6a8a244ca,
0xd40b61719905e5b9,
0xcc4f1d5e2aed7a75,
0x7895032e16409563,
0x536db2a17eb54630,
0xdd66ae0d2d5ac57e,
0xe150b5a7f229f541,
0xd882dbabee789616,
0x1f380eb8775416ca,
0x73eca6c1c0abcd02,
0x8bd4f78c2fe1861e,
0xc53f421003b18ea2,
0xcae3f7b5d0591ecb,
0xbebe6ab21737113e,
0x838f0df2a5f7f26d,
0xbc2aa2593b06d88f,
0x0cb02b95a74a8a0a,
0x74bd9a7b50725838,
0x000000dc98741fbf,
][..]);
print!("Frob9 = {}\n", res9);
let res10 = a.pow(&[
0xed4127472fd6bc68,
0x72748872e11c4b47,
0x9c84e64776edc3f8,
0x008119b96d78b386,
0xfb0fbff1c5556968,
0x5009c51f998020be,
0xd6e688613527a368,
0xbe4f27942823152c,
0xd0f09d15c45fe09e,
0x7eb531158d2bbea5,
0x51bbe8e71be2cfd1,
0xbab37561b8c0c7c4,
0xd9173b5ab551b267,
0x05fafd9be4c78781,
0x61883bc8a78540ee,
0x7fe7aee3dcb694fb,
0x0e4e85b12b4ac8a8,
0x9a0aa13a9ab47a86,
0xd5a3bd591ae12d4b,
0x5865cbfabbe53b4d,
0xf98188a9b0cd490f,
0x3985ef4af715da43,
0x573661cd006ced38,
0x95853a6aaa77d5c1,
0x165d538f0628b55e,
0x583e75f890f32cac,
0x5becf43a08a490b9,
0x63ed4071c1a8087a,
0x151d41c7701faa25,
0x1c661c8e4900b051,
0x581aa0f552590875,
0x31bf39ff43375aca,
0xe27c0f3d11310329,
0x04071459ef3a42c2,
0x59a2b029be2d6a1f,
0x30ef71f271cdbf61,
0xf3774b177f326e78,
0x976d79b23e8501c5,
0x9ed0e138633123c9,
0x00000029b304ecc1,
][..]);
print!("Frob10 = {}\n", res10);
let res11 = a.pow(&[
0xf4e8c249a335ddb9,
0x965085c9440aef70,
0xc16d84a741174aef,
0xbe1a366b81fe0680,
0x1c65508409269d2f,
0x185861e9cd07fb21,
0x26b682d951220b7a,
0x09f189f5a7b75876,
0x0f7133ab3ecff7f0,
0xbf7d1ada5df0b2fd,
0x4b0df5207414a4b6,
0xbf6a6941b58966d3,
0x6a15cc7b6bb0483a,
0xc338843b8a236597,
0xc8d724986bc0856f,
0x1dcb8b084e928e52,
0x3645ba97c4af9161,
0x7d257d1abed180d3,
0x0a66e85068416bdb,
0x8b745a2aeb2bd27e,
0xe34f87ec4949ec06,
0x6ba47fa06f902fd6,
0x225cd33864121ed2,
0xea5d91e41a3b068b,
0x35d2fbc8b7a05f5c,
0xe5b1e22f3dcbc837,
0xa9f7bdbee44d8301,
0xbb7a57512450e143,
0x2e2ca4188fd4eb5b,
0x9d512b5d1e158636,
0xdd18753b03f38ee8,
0xbbe44db3214b380e,
0x4534f7b060cca3d2,
0xcbb0309736f9df06,
0xfcb01aba828f0678,
0xe2e4d5dac5cc7917,
0x6631e85c4224e136,
0xb6c334bbd109d480,
0x2608e9c50edc2cdf,
0x959dba8288258d16,
0x00d895fc73e207c8,
0x6b5ce08dc4a7bf13,
0xb02a4f252d6a301f,
0x00000007e1e7a192,
][..]);
print!("Frob11 = {}\n", res11);
}
#[test]
fn test_calculate_frob_1() {
let mut a = Fq2::one();
a.mul_by_nonresidue();
// Fq2(u + 9)**(((q^1) - 1) / 3)
print!("(i + 9) = {}\n", a);
}
#[test]
fn test_fq2_ordering() {
let mut a = Fq2 {
c0: Fq::zero(),
c1: Fq::zero(),
};
let mut b = a.clone();
assert!(a.cmp(&b) == Ordering::Equal);
b.c0.add_assign(&Fq::one());
assert!(a.cmp(&b) == Ordering::Less);
a.c0.add_assign(&Fq::one());
assert!(a.cmp(&b) == Ordering::Equal);
b.c1.add_assign(&Fq::one());
assert!(a.cmp(&b) == Ordering::Less);
a.c0.add_assign(&Fq::one());
assert!(a.cmp(&b) == Ordering::Less);
a.c1.add_assign(&Fq::one());
assert!(a.cmp(&b) == Ordering::Greater);
b.c0.add_assign(&Fq::one());
assert!(a.cmp(&b) == Ordering::Equal);
}
#[test]
fn test_fq2_basics() {
assert_eq!(
Fq2 {
c0: Fq::zero(),
c1: Fq::zero(),
},
Fq2::zero()
);
assert_eq!(
Fq2 {
c0: Fq::one(),
c1: Fq::zero(),
},
Fq2::one()
);
assert!(Fq2::zero().is_zero());
assert!(!Fq2::one().is_zero());
assert!(
!Fq2 {
c0: Fq::zero(),
c1: Fq::one(),
}.is_zero()
);
}
#[test]
fn test_fq2_squaring() {
use super::fq::FqRepr;
use ff::PrimeField;
let mut a = Fq2 {
c0: Fq::one(),
c1: Fq::one(),
}; // u + 1
a.square();
assert_eq!(
a,
Fq2 {
c0: Fq::zero(),
c1: Fq::from_repr(FqRepr::from(2)).unwrap(),
}
); // 2u
let mut a = Fq2 {
c0: Fq::zero(),
c1: Fq::one(),
}; // u
a.square();
assert_eq!(a, {
let mut neg1 = Fq::one();
neg1.negate();
Fq2 {
c0: neg1,
c1: Fq::zero(),
}
}); // -1
}
#[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::{SeedableRng, XorShiftRng};
#[test]
fn test_fq2_mul_nonresidue() {
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let mut nine = Fq::one();
nine.double();
nine.double();
nine.double();
nine.add_assign(&Fq::one());
let nqr = Fq2 {
c0: nine,
c1: Fq::one(),
};
for _ in 0..1000 {
let mut a = Fq2::rand(&mut rng);
let mut b = a;
a.mul_by_nonresidue();
b.mul_assign(&nqr);
assert_eq!(a, b);
}
}
#[test]
fn fq2_field_tests() {
use ff::PrimeField;
::tests::field::random_field_tests::<Fq2>();
::tests::field::random_sqrt_tests::<Fq2>();
::tests::field::random_frobenius_tests::<Fq2, _>(super::fq::Fq::char(), 13);
}

400
src/bn256/fq6.rs Normal file

@ -0,0 +1,400 @@
use super::fq::{FROBENIUS_COEFF_FQ6_C1, FROBENIUS_COEFF_FQ6_C2};
use super::fq2::Fq2;
use ff::Field;
use rand::{Rand, Rng};
/// An element of Fq6, represented by c0 + c1 * v + c2 * v^(2).
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Fq6 {
pub c0: Fq2,
pub c1: Fq2,
pub c2: Fq2,
}
impl ::std::fmt::Display for Fq6 {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "Fq6({} + {} * v, {} * v^2)", self.c0, self.c1, self.c2)
}
}
impl Rand for Fq6 {
fn rand<R: Rng>(rng: &mut R) -> Self {
Fq6 {
c0: rng.gen(),
c1: rng.gen(),
c2: rng.gen(),
}
}
}
// Here it's getting tough, because extension tower diverges with BLS12
// BLS12 (v^3 - ξ) where ξ = u + 1
// BN256 (v^3 - ξ) where ξ = u + 9
impl Fq6 {
/// Multiply by cubic nonresidue v.
pub fn mul_by_nonresidue(&mut self) {
use std::mem::swap;
swap(&mut self.c0, &mut self.c1);
swap(&mut self.c0, &mut self.c2);
// c0, c1, c2 -> c2, c0, c1
self.c0.mul_by_nonresidue();
}
/// Multiply by cubic nonresidue v.
pub fn mul_by_v(&mut self) {
use std::mem::swap;
swap(&mut self.c0, &mut self.c1);
swap(&mut self.c0, &mut self.c2);
self.c0.mul_by_xi();
}
pub fn mul_by_1(&mut self, c1: &Fq2) {
let mut b_b = self.c1;
b_b.mul_assign(c1);
let mut t1 = *c1;
{
let mut tmp = self.c1;
tmp.add_assign(&self.c2);
t1.mul_assign(&tmp);
t1.sub_assign(&b_b);
t1.mul_by_nonresidue();
}
let mut t2 = *c1;
{
let mut tmp = self.c0;
tmp.add_assign(&self.c1);
t2.mul_assign(&tmp);
t2.sub_assign(&b_b);
}
self.c0 = t1;
self.c1 = t2;
self.c2 = b_b;
}
pub fn mul_by_01(&mut self, c0: &Fq2, c1: &Fq2) {
let mut a_a = self.c0;
let mut b_b = self.c1;
a_a.mul_assign(c0);
b_b.mul_assign(c1);
let mut t1 = *c1;
{
let mut tmp = self.c1;
tmp.add_assign(&self.c2);
t1.mul_assign(&tmp);
t1.sub_assign(&b_b);
t1.mul_by_nonresidue();
t1.add_assign(&a_a);
}
let mut t3 = *c0;
{
let mut tmp = self.c0;
tmp.add_assign(&self.c2);
t3.mul_assign(&tmp);
t3.sub_assign(&a_a);
t3.add_assign(&b_b);
}
let mut t2 = *c0;
t2.add_assign(c1);
{
let mut tmp = self.c0;
tmp.add_assign(&self.c1);
t2.mul_assign(&tmp);
t2.sub_assign(&a_a);
t2.sub_assign(&b_b);
}
self.c0 = t1;
self.c1 = t2;
self.c2 = t3;
}
}
impl Field for Fq6 {
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(&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) {
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) {
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]);
}
fn square(&mut self) {
// s0 = a^2
let mut s0 = self.c0;
s0.square();
// s1 = 2ab
let mut ab = self.c0;
ab.mul_assign(&self.c1);
let mut s1 = ab;
s1.double();
// s2 = (a - b + c)^2
let mut s2 = self.c0;
s2.sub_assign(&self.c1);
s2.add_assign(&self.c2);
s2.square();
// bc
let mut bc = self.c1;
bc.mul_assign(&self.c2);
// s3 = 2bc
let mut s3 = bc;
s3.double();
// s4 = c^2
let mut s4 = self.c2;
s4.square();
// new c0 = 2bc.mul_by_xi + a^2
self.c0 = s3;
self.c0.mul_by_nonresidue();
// self.c0.mul_by_xi();
self.c0.add_assign(&s0);
// new c1 = (c^2).mul_by_xi + 2ab
self.c1 = s4;
self.c1.mul_by_nonresidue();
// self.c1.mul_by_xi();
self.c1.add_assign(&s1);
// new c2 = 2ab + (a - b + c)^2 + 2bc - a^2 - c^2 = b^2 + 2ac
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_assign(&mut self, other: &Self) {
let mut a_a = self.c0;
let mut b_b = self.c1;
let mut c_c = self.c2;
a_a.mul_assign(&other.c0);
b_b.mul_assign(&other.c1);
c_c.mul_assign(&other.c2);
let mut t1 = other.c1;
t1.add_assign(&other.c2);
{
let mut tmp = self.c1;
tmp.add_assign(&self.c2);
t1.mul_assign(&tmp);
t1.sub_assign(&b_b);
t1.sub_assign(&c_c);
t1.mul_by_nonresidue();
t1.add_assign(&a_a);
}
let mut t3 = other.c0;
t3.add_assign(&other.c2);
{
let mut tmp = self.c0;
tmp.add_assign(&self.c2);
t3.mul_assign(&tmp);
t3.sub_assign(&a_a);
t3.add_assign(&b_b);
t3.sub_assign(&c_c);
}
let mut t2 = other.c0;
t2.add_assign(&other.c1);
{
let mut tmp = self.c0;
tmp.add_assign(&self.c1);
t2.mul_assign(&tmp);
t2.sub_assign(&a_a);
t2.sub_assign(&b_b);
c_c.mul_by_nonresidue();
t2.add_assign(&c_c);
}
self.c0 = t1;
self.c1 = t2;
self.c2 = t3;
}
fn inverse(&self) -> Option<Self> {
let mut c0 = self.c2;
c0.mul_by_nonresidue();
c0.mul_assign(&self.c1);
c0.negate();
{
let mut c0s = self.c0;
c0s.square();
c0.add_assign(&c0s);
}
let mut c1 = self.c2;
c1.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 c02 = self.c0;
c02.mul_assign(&self.c2);
c2.sub_assign(&c02);
}
let mut tmp1 = self.c2;
tmp1.mul_assign(&c1);
let mut tmp2 = self.c1;
tmp2.mul_assign(&c2);
tmp1.add_assign(&tmp2);
tmp1.mul_by_nonresidue();
tmp2 = self.c0;
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);
Some(tmp)
}
None => None,
}
}
}
#[cfg(test)]
use rand::{SeedableRng, XorShiftRng};
#[test]
fn test_fq6_mul_nonresidue() {
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let nqr = Fq6 {
c0: Fq2::zero(),
c1: Fq2::one(),
c2: Fq2::zero(),
};
for _ in 0..1000 {
let mut a = Fq6::rand(&mut rng);
let mut b = a;
a.mul_by_nonresidue();
b.mul_assign(&nqr);
assert_eq!(a, b);
}
}
#[test]
fn test_fq6_mul_by_1() {
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let c1 = Fq2::rand(&mut rng);
let mut a = Fq6::rand(&mut rng);
let mut b = a;
a.mul_by_1(&c1);
b.mul_assign(&Fq6 {
c0: Fq2::zero(),
c1: c1,
c2: Fq2::zero(),
});
assert_eq!(a, b);
}
}
#[test]
fn test_fq6_mul_by_01() {
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let c0 = Fq2::rand(&mut rng);
let c1 = Fq2::rand(&mut rng);
let mut a = Fq6::rand(&mut rng);
let mut b = a;
a.mul_by_01(&c0, &c1);
b.mul_assign(&Fq6 {
c0: c0,
c1: c1,
c2: Fq2::zero(),
});
assert_eq!(a, b);
}
}
#[test]
fn fq6_field_tests() {
use ff::PrimeField;
::tests::field::random_field_tests::<Fq6>();
::tests::field::random_frobenius_tests::<Fq6, _>(super::fq::Fq::char(), 13);
}

11
src/bn256/fr.rs Normal file

@ -0,0 +1,11 @@
use ff::{Field, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr};
#[derive(PrimeField)]
#[PrimeFieldModulus = "21888242871839275222246405745257275088548364400416034343698204186575808495617"]
#[PrimeFieldGenerator = "7"]
pub struct Fr(FrRepr);
#[test]
fn test_roots_of_unity() {
assert_eq!(Fr::S, 28);
}

599
src/bn256/mod.rs Normal file

@ -0,0 +1,599 @@
mod ec;
mod fq;
mod fq12;
mod fq2;
mod fq6;
mod fr;
// #[cfg(test)]
// mod tests;
pub use self::ec::{
G1, G1Affine, G1Compressed, G1Prepared, G1Uncompressed,
G2, G2Affine, G2Compressed, G2Prepared, G2Uncompressed,
};
pub use self::fq::{Fq, FqRepr, FROBENIUS_COEFF_FQ6_C1, XI_TO_Q_MINUS_1_OVER_2};
pub use self::fq12::Fq12;
pub use self::fq2::Fq2;
pub use self::fq6::Fq6;
pub use self::fr::{Fr, FrRepr};
use super::{CurveAffine, Engine};
use ff::{Field, ScalarEngine};
#[derive(Clone, Debug)]
pub struct Bn256;
// U value that originates this particular curve
pub const BN_U: u64 = 4965661367192848881;
// // 6U+2 for in NAF form
pub const SIX_U_PLUS_2_NAF : [i8; 65] = [0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0,
0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0, 0, 1, 1,
1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1,
1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, 1, 1];
impl ScalarEngine for Bn256 {
type Fr = Fr;
}
impl Engine for Bn256 {
type G1 = G1;
type G1Affine = G1Affine;
type G2 = G2;
type G2Affine = G2Affine;
type Fq = Fq;
type Fqe = Fq2;
type Fqk = Fq12;
fn miller_loop<'a, I>(i: I) -> Self::Fqk
where
I: IntoIterator<
Item = &'a (
&'a <Self::G1Affine as CurveAffine>::Prepared,
&'a <Self::G2Affine as CurveAffine>::Prepared,
),
>,
{
let mut pairs = vec![];
for &(p, q) in i {
if !p.is_zero() && !q.is_zero() {
pairs.push((p, q.coeffs.iter()));
}
}
// Final steps of the line function on prepared coefficients
fn ell(f: &mut Fq12, coeffs: &(Fq2, Fq2, Fq2), p: &G1Affine) {
let mut c0 = coeffs.0;
let mut c1 = coeffs.1;
c0.c0.mul_assign(&p.y);
c0.c1.mul_assign(&p.y);
c1.c0.mul_assign(&p.x);
c1.c1.mul_assign(&p.x);
// Sparse multiplication in Fq12
f.mul_by_034(&c0, &c1, &coeffs.2);
}
let mut f = Fq12::one();
for i in (1..SIX_U_PLUS_2_NAF.len()).rev() {
if i != SIX_U_PLUS_2_NAF.len() - 1 {
f.square();
}
for &mut (p, ref mut coeffs) in &mut pairs {
ell(&mut f, coeffs.next().unwrap(), &p.0);
}
let x = SIX_U_PLUS_2_NAF[i-1];
match x {
1 => {
for &mut (p, ref mut coeffs) in &mut pairs {
ell(&mut f, coeffs.next().unwrap(), &p.0);
}
}
-1 => {
for &mut (p, ref mut coeffs) in &mut pairs {
ell(&mut f, coeffs.next().unwrap(), &p.0);
}
}
_ => {
continue
}
}
}
// two additional steps: for q1 and minus q2
for &mut (p, ref mut coeffs) in &mut pairs {
ell(&mut f, coeffs.next().unwrap(), &p.0);
}
for &mut (p, ref mut coeffs) in &mut pairs {
ell(&mut f, coeffs.next().unwrap(), &p.0);
}
for &mut (_p, ref mut coeffs) in &mut pairs {
assert_eq!(coeffs.next(), None);
}
f
}
fn final_exponentiation(r: &Fq12) -> Option<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);
fn exp_by_x(f: &mut Fq12, x: u64) {
*f = f.pow(&[x]);
}
let x = BN_U;
let mut fp = r;
fp.frobenius_map(1);
let mut fp2 = r;
fp2.frobenius_map(2);
let mut fp3 = fp2;
fp3.frobenius_map(1);
let mut fu = r;
exp_by_x(&mut fu, x);
let mut fu2 = fu;
exp_by_x(&mut fu2, x);
let mut fu3 = fu2;
exp_by_x(&mut fu3, x);
let mut y3 = fu;
y3.frobenius_map(1);
let mut fu2p = fu2;
fu2p.frobenius_map(1);
let mut fu3p = fu3;
fu3p.frobenius_map(1);
let mut y2 = fu2;
y2.frobenius_map(2);
let mut y0 = fp;
y0.mul_assign(&fp2);
y0.mul_assign(&fp3);
let mut y1 = r;
y1.conjugate();
let mut y5 = fu2;
y5.conjugate();
y3.conjugate();
let mut y4 = fu;
y4.mul_assign(&fu2p);
y4.conjugate();
let mut y6 = fu3;
y6.mul_assign(&fu3p);
y6.conjugate();
y6.square();
y6.mul_assign(&y4);
y6.mul_assign(&y5);
let mut t1 = y3;
t1.mul_assign(&y5);
t1.mul_assign(&y6);
y6.mul_assign(&y2);
t1.square();
t1.mul_assign(&y6);
t1.square();
let mut t0 = t1;
t0.mul_assign(&y1);
t1.mul_assign(&y0);
t0.square();
t0.mul_assign(&t1);
Some(t0)
}
None => None,
}
}
}
impl G2Prepared {
pub fn is_zero(&self) -> bool {
self.infinity
}
pub fn from_affine(q: G2Affine) -> Self {
if q.is_zero() {
return G2Prepared {
coeffs: vec![],
infinity: true,
};
}
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 tmp1 = r.y;
tmp1.square();
let mut tmp2 = tmp1;
tmp2.square();
let mut tmp3 = tmp1;
tmp3.add_assign(&r.x);
tmp3.square();
tmp3.sub_assign(&tmp0);
tmp3.sub_assign(&tmp2);
tmp3.double();
let mut tmp4 = tmp0;
tmp4.double();
tmp4.add_assign(&tmp0);
let mut tmp6 = r.x;
tmp6.add_assign(&tmp4);
let mut tmp5 = tmp4;
tmp5.square();
let mut zsquared = r.z;
zsquared.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.sub_assign(&tmp1);
r.z.sub_assign(&zsquared);
r.y = tmp3;
r.y.sub_assign(&r.x);
r.y.mul_assign(&tmp4);
tmp2.double();
tmp2.double();
tmp2.double();
r.y.sub_assign(&tmp2);
// up to here everything was by algorith, line 11
// use R instead of new T
// tmp3 is the first part of line 12
tmp3 = tmp4;
tmp3.mul_assign(&zsquared);
tmp3.double();
tmp3.negate();
// tmp6 is from line 14
tmp6.square();
tmp6.sub_assign(&tmp0);
tmp6.sub_assign(&tmp5);
tmp1.double();
tmp1.double();
tmp6.sub_assign(&tmp1);
// tmp0 is the first part of line 16
tmp0 = r.z;
tmp0.mul_assign(&zsquared);
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 mut ysquared = q.y;
ysquared.square();
// t0 corresponds to line 1
let mut t0 = zsquared;
t0.mul_assign(&q.x);
// t1 corresponds to lines 2 and 3
let mut t1 = q.y;
t1.add_assign(&r.z);
t1.square();
t1.sub_assign(&ysquared);
t1.sub_assign(&zsquared);
t1.mul_assign(&zsquared);
// t2 corresponds to line 4
let mut t2 = t0;
t2.sub_assign(&r.x);
// t3 corresponds to line 5
let mut t3 = t2;
t3.square();
// t4 corresponds to line 6
let mut t4 = t3;
t4.double();
t4.double();
// t5 corresponds to line 7
let mut t5 = t4;
t5.mul_assign(&t2);
// t6 corresponds to line 8
let mut t6 = t1;
t6.sub_assign(&r.y);
t6.sub_assign(&r.y);
// t9 corresponds to line 9
let mut t9 = t6;
t9.mul_assign(&q.x);
// corresponds to line 10
let mut t7 = t4;
t7.mul_assign(&r.x);
// corresponds to line 11, but assigns to r.x instead of T.x
r.x = t6;
r.x.square();
r.x.sub_assign(&t5);
r.x.sub_assign(&t7);
r.x.sub_assign(&t7);
// corresponds to line 12, but assigns to r.z instead of T.z
r.z.add_assign(&t2);
r.z.square();
r.z.sub_assign(&zsquared);
r.z.sub_assign(&t3);
// corresponds to line 13
let mut t10 = q.y;
t10.add_assign(&r.z);
// corresponds to line 14
let mut t8 = t7;
t8.sub_assign(&r.x);
t8.mul_assign(&t6);
// corresponds to line 15
t0 = r.y;
t0.mul_assign(&t5);
t0.double();
// corresponds to line 12, but assigns to r.y instead of T.y
r.y = t8;
r.y.sub_assign(&t0);
// corresponds to line 17
t10.square();
t10.sub_assign(&ysquared);
let mut ztsquared = r.z;
ztsquared.square();
t10.sub_assign(&ztsquared);
// corresponds to line 18
t9.double();
t9.sub_assign(&t10);
// t10 = 2*Zt from Algo 27, line 19
t10 = r.z;
t10.double();
// t1 = first multiplicator of line 21
t6.negate();
t1 = t6;
t1.double();
// t9 corresponds to t9 from Algo 27
(t10, t1, t9)
}
let mut coeffs = vec![];
let mut r: G2 = q.into();
let mut negq = q;
negq.negate();
for i in (1..SIX_U_PLUS_2_NAF.len()).rev() {
coeffs.push(doubling_step(& mut r));
let x = SIX_U_PLUS_2_NAF[i-1];
match x {
1 => {
coeffs.push(addition_step(&mut r, &q));
}
-1 => {
coeffs.push(addition_step(&mut r, &negq));
}
_ => continue,
}
}
let mut q1 = q;
q1.x.c1.negate();
q1.x.mul_assign(&FROBENIUS_COEFF_FQ6_C1[1]);
q1.y.c1.negate();
q1.y.mul_assign(&XI_TO_Q_MINUS_1_OVER_2);
coeffs.push(addition_step(&mut r, &q1));
let mut minusq2 = q;
minusq2.x.mul_assign(&FROBENIUS_COEFF_FQ6_C1[2]);
coeffs.push(addition_step(&mut r, &minusq2));
G2Prepared {
coeffs,
infinity: false,
}
}
}
#[cfg(test)]
use rand::{Rand, SeedableRng, XorShiftRng};
#[test]
fn test_pairing() {
use {CurveProjective};
let mut g1 = G1::one();
let mut g2 = G2::one();
g2.double();
let pair12 = Bn256::pairing(g1, g2);
g1 = G1::one();
g1.double();
g2 = G2::one();
let pair21 = Bn256::pairing(g1, g2);
assert_eq!(pair12, pair21);
// print!("GT = {}\n", pair12);
g1 = G1::one();
g1.double();
g1.double();
let pair41 = Bn256::pairing(g1, g2);
g1 = G1::one();
g1.double();
g2.double();
let pair22 = Bn256::pairing(g1, g2);
assert_eq!(pair41, pair22);
g1 = G1::one();
g1.double();
g1.add_assign(&G1::one());
g2 = G2::one();
g2.double();
let pair32 = Bn256::pairing(g1, g2);
g2 = G2::one();
g2.double();
g2.add_assign(&G2::one());
g1 = G1::one();
g1.double();
let pair23 = Bn256::pairing(g1, g2);
assert_eq!(pair23, pair32);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let a = Fr::rand(&mut rng);
let b = Fr::rand(&mut rng);
let mut g1 = G1::one();
g1.mul_assign(a);
let mut g2 = G2::one();
g1.mul_assign(b);
let pair_ab = Bn256::pairing(g1, g2);
g1 = G1::one();
g1.mul_assign(b);
g2 = G2::one();
g1.mul_assign(a);
let pair_ba = Bn256::pairing(g1, g2);
assert_eq!(pair_ab, pair_ba);
}
}
#[test]
fn random_bilinearity_tests() {
use {CurveProjective};
use ff::PrimeField;
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let mut a = G1::one();
let ka = Fr::rand(&mut rng);
a.mul_assign(ka);
let mut b = G2::one();
let kb = Fr::rand(&mut rng);
b.mul_assign(kb);
let c = Fr::rand(&mut rng);
let d = Fr::rand(&mut rng);
let mut ac = a;
ac.mul_assign(c);
let mut ad = a;
ad.mul_assign(d);
let mut bc = b;
bc.mul_assign(c);
let mut bd = b;
bd.mul_assign(d);
let acbd = Bn256::pairing(ac, bd);
let adbc = Bn256::pairing(ad, bc);
let mut cd = c;
cd.mul_assign(&d);
let abcd = Bn256::pairing(a, b).pow(cd.into_repr());
assert_eq!(acbd, adbc);
assert_eq!(acbd, abcd);
}
}
#[test]
fn bn256_engine_tests() {
::tests::engine::engine_tests::<Bn256>();
}

@ -2,17 +2,16 @@
// common mistakes or strange code patterns. If the `cargo-clippy` feature // common mistakes or strange code patterns. If the `cargo-clippy` feature
// is provided, all compiler warnings are prohibited. // is provided, all compiler warnings are prohibited.
#![cfg_attr(feature = "cargo-clippy", deny(warnings))] #![cfg_attr(feature = "cargo-clippy", deny(warnings))]
#![cfg_attr(feature = "cargo-clippy", allow(inline_always))] // #![cfg_attr(feature = "cargo-clippy", allow(inline_always))]
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] // #![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))] // #![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]
#![cfg_attr(feature = "cargo-clippy", allow(many_single_char_names))] // #![cfg_attr(feature = "cargo-clippy", allow(many_single_char_names))]
#![cfg_attr(feature = "cargo-clippy", allow(new_without_default_derive))] // #![cfg_attr(feature = "cargo-clippy", allow(new_without_default_derive))]
#![cfg_attr(feature = "cargo-clippy", allow(write_literal))] // #![cfg_attr(feature = "cargo-clippy", allow(write_literal))]
// Force public structures to implement Debug // Force public structures to implement Debug
#![deny(missing_debug_implementations)] #![deny(missing_debug_implementations)]
extern crate byteorder; extern crate byteorder;
#[macro_use]
extern crate ff; extern crate ff;
extern crate rand; extern crate rand;
@ -20,6 +19,7 @@ extern crate rand;
pub mod tests; pub mod tests;
pub mod bls12_381; pub mod bls12_381;
pub mod bn256;
mod wnaf; mod wnaf;
pub use self::wnaf::Wnaf; pub use self::wnaf::Wnaf;

@ -61,7 +61,6 @@ pub fn curve_tests<G: CurveProjective>() {
random_multiplication_tests::<G>(); random_multiplication_tests::<G>();
random_doubling_tests::<G>(); random_doubling_tests::<G>();
random_negation_tests::<G>(); random_negation_tests::<G>();
random_transformation_tests::<G>();
random_wnaf_tests::<G>(); random_wnaf_tests::<G>();
random_encoding_tests::<G::Affine>(); random_encoding_tests::<G::Affine>();
} }
@ -345,7 +344,46 @@ fn random_addition_tests<G: CurveProjective>() {
} }
} }
fn random_transformation_tests<G: CurveProjective>() { pub fn random_transformation_tests<G: CurveProjective>() {
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let g = G::rand(&mut rng);
let g_affine = g.into_affine();
let g_projective = g_affine.into_projective();
assert_eq!(g, g_projective);
}
// Batch normalization
for _ in 0..10 {
let mut v = (0..1000).map(|_| G::rand(&mut rng)).collect::<Vec<_>>();
use rand::distributions::{IndependentSample, Range};
let between = Range::new(0, 1000);
// Sprinkle in some normalized points
for _ in 0..5 {
v[between.ind_sample(&mut rng)] = G::zero();
}
for _ in 0..5 {
let s = between.ind_sample(&mut rng);
v[s] = v[s].into_affine().into_projective();
}
let expected_v = v
.iter()
.map(|v| v.into_affine().into_projective())
.collect::<Vec<_>>();
G::batch_normalization(&mut v);
for i in &v {
assert!(i.is_normalized());
}
assert_eq!(v, expected_v);
}
}
pub fn random_transformation_tests_with_cofactor<G: CurveProjective>() {
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]); let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 { for _ in 0..1000 {
@ -360,6 +398,7 @@ fn random_transformation_tests<G: CurveProjective>() {
let mut v = (0..1000).map(|_| G::rand(&mut rng)).collect::<Vec<_>>(); let mut v = (0..1000).map(|_| G::rand(&mut rng)).collect::<Vec<_>>();
for i in &v { for i in &v {
assert!(!i.is_normalized()); assert!(!i.is_normalized());
} }