BN256 commit
This commit is contained in:
parent
183a64b08e
commit
1363d02170
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
target/
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
.vscode
|
@ -2,17 +2,18 @@
|
||||
name = "pairing"
|
||||
|
||||
# Remember to change version string in README.md.
|
||||
version = "0.14.2"
|
||||
version = "0.15.0"
|
||||
authors = [
|
||||
"Sean Bowe <ewillbefull@gmail.com>",
|
||||
"Jack Grigg <jack@z.cash>",
|
||||
"Alex Vlasov <alex.m.vlasov@gmail.com>"
|
||||
]
|
||||
license = "MIT/Apache-2.0"
|
||||
|
||||
description = "Pairing-friendly elliptic curve library"
|
||||
documentation = "https://docs.rs/pairing/"
|
||||
homepage = "https://github.com/ebfull/pairing"
|
||||
repository = "https://github.com/ebfull/pairing"
|
||||
homepage = "https://github.com/matterinc/pairing"
|
||||
repository = "https://github.com/matterinc/pairing"
|
||||
|
||||
[dependencies]
|
||||
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/)
|
||||
|
||||
|
127
benches/bn256/ec.rs
Normal file
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
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
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
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
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
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;
|
||||
|
||||
mod bls12_381;
|
||||
mod bn256;
|
||||
|
@ -1262,6 +1262,7 @@ pub mod g1 {
|
||||
#[test]
|
||||
fn g1_curve_tests() {
|
||||
::tests::curve::curve_tests::<G1>();
|
||||
::tests::curve::random_transformation_tests_with_cofactor::<G1>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2015,6 +2016,7 @@ pub mod g2 {
|
||||
#[test]
|
||||
fn g2_curve_tests() {
|
||||
::tests::curve::curve_tests::<G2>();
|
||||
::tests::curve::random_transformation_tests_with_cofactor::<G2>();
|
||||
}
|
||||
}
|
||||
|
||||
|
14
src/bn256/README.md
Normal file
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
1598
src/bn256/ec.rs
Normal file
File diff suppressed because it is too large
Load Diff
579
src/bn256/fq.rs
Normal file
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
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
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
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
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
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>();
|
||||
}
|
14
src/lib.rs
14
src/lib.rs
@ -2,17 +2,16 @@
|
||||
// common mistakes or strange code patterns. If the `cargo-clippy` feature
|
||||
// is provided, all compiler warnings are prohibited.
|
||||
#![cfg_attr(feature = "cargo-clippy", deny(warnings))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(inline_always))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]
|
||||
#![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(write_literal))]
|
||||
// #![cfg_attr(feature = "cargo-clippy", allow(inline_always))]
|
||||
// #![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
|
||||
// #![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]
|
||||
// #![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(write_literal))]
|
||||
// Force public structures to implement Debug
|
||||
#![deny(missing_debug_implementations)]
|
||||
|
||||
extern crate byteorder;
|
||||
#[macro_use]
|
||||
extern crate ff;
|
||||
extern crate rand;
|
||||
|
||||
@ -20,6 +19,7 @@ extern crate rand;
|
||||
pub mod tests;
|
||||
|
||||
pub mod bls12_381;
|
||||
pub mod bn256;
|
||||
|
||||
mod wnaf;
|
||||
pub use self::wnaf::Wnaf;
|
||||
|
@ -61,7 +61,6 @@ pub fn curve_tests<G: CurveProjective>() {
|
||||
random_multiplication_tests::<G>();
|
||||
random_doubling_tests::<G>();
|
||||
random_negation_tests::<G>();
|
||||
random_transformation_tests::<G>();
|
||||
random_wnaf_tests::<G>();
|
||||
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]);
|
||||
|
||||
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<_>>();
|
||||
|
||||
for i in &v {
|
||||
|
||||
assert!(!i.is_normalized());
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user