Starting fresh...
This commit is contained in:
parent
e282bc095a
commit
bf03be0b9d
12
Cargo.toml
12
Cargo.toml
@ -9,11 +9,11 @@ repository = "https://github.com/ebfull/bellman"
|
||||
version = "0.0.3"
|
||||
|
||||
[dependencies]
|
||||
rand = "0.3.*"
|
||||
byteorder = "1.*"
|
||||
serde = "1.0"
|
||||
crossbeam = "0.2"
|
||||
num_cpus = "1.0"
|
||||
#rand = "0.3.*"
|
||||
#byteorder = "1.*"
|
||||
#serde = "1.0"
|
||||
#crossbeam = "0.2"
|
||||
#num_cpus = "1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
bincode = "0.8.0"
|
||||
#bincode = "0.8.0"
|
||||
|
235
benches/curve.rs
235
benches/curve.rs
@ -1,235 +0,0 @@
|
||||
#![feature(test)]
|
||||
#![allow(unused_mut)]
|
||||
|
||||
extern crate rand;
|
||||
extern crate bellman;
|
||||
extern crate test;
|
||||
|
||||
use bellman::curves::*;
|
||||
use bellman::curves::bls381::*;
|
||||
|
||||
const SAMPLES: usize = 30;
|
||||
|
||||
macro_rules! benchmark(
|
||||
($name:ident, $engine:ident, $input:ident($rng:ident) = $pre:expr; $post:expr) => (
|
||||
#[bench]
|
||||
fn $name(b: &mut test::Bencher) {
|
||||
let $rng = &mut rand::thread_rng();
|
||||
let $engine = &Bls381::new();
|
||||
let $input: Vec<_> = (0..SAMPLES).map(|_| $pre).collect();
|
||||
|
||||
let mut c = 0;
|
||||
|
||||
b.iter(|| {
|
||||
c += 1;
|
||||
|
||||
let mut $input = $input[c % SAMPLES].clone();
|
||||
|
||||
$post
|
||||
})
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
benchmark!(g1_multiexp, e,
|
||||
input(rng) = {
|
||||
let mut g = G1::random(e, rng);
|
||||
let mut a = G1::random(e, rng);
|
||||
(
|
||||
(0..1000).map(|_| {
|
||||
g.add_assign(e, &a);
|
||||
a.double(e);
|
||||
g.to_affine(e)
|
||||
}).collect::<Vec<_>>(),
|
||||
(0..1000).map(|_| Fr::random(e, rng)).collect::<Vec<_>>(),
|
||||
)
|
||||
};
|
||||
|
||||
e.multiexp::<G1>(&input.0, &input.1)
|
||||
);
|
||||
|
||||
benchmark!(g2_multiexp, e,
|
||||
input(rng) = {
|
||||
let mut g = G2::random(e, rng);
|
||||
let mut a = G2::random(e, rng);
|
||||
(
|
||||
(0..1000).map(|_| {
|
||||
g.add_assign(e, &a);
|
||||
a.double(e);
|
||||
g.to_affine(e)
|
||||
}).collect::<Vec<_>>(),
|
||||
(0..1000).map(|_| Fr::random(e, rng)).collect::<Vec<_>>(),
|
||||
)
|
||||
};
|
||||
|
||||
e.multiexp::<G2>(&input.0, &input.1)
|
||||
);
|
||||
|
||||
benchmark!(full_pairing, e,
|
||||
input(rng) = (G1::random(e, rng), G2::random(e, rng));
|
||||
|
||||
e.pairing(&input.0, &input.1)
|
||||
);
|
||||
|
||||
benchmark!(g1_pairing_preparation, e,
|
||||
input(rng) = G1::random(e, rng);
|
||||
|
||||
input.prepare(e)
|
||||
);
|
||||
|
||||
benchmark!(g2_pairing_preparation, e,
|
||||
input(rng) = G2::random(e, rng);
|
||||
|
||||
input.prepare(e)
|
||||
);
|
||||
|
||||
benchmark!(miller_loop, e,
|
||||
input(rng) = (G1::random(e, rng).prepare(e), G2::random(e, rng).prepare(e));
|
||||
|
||||
e.miller_loop([(&input.0, &input.1)].into_iter())
|
||||
);
|
||||
|
||||
benchmark!(double_miller_loop, e,
|
||||
input(rng) = (G1::random(e, rng).prepare(e), G2::random(e, rng).prepare(e), G1::random(e, rng).prepare(e), G2::random(e, rng).prepare(e));
|
||||
|
||||
e.miller_loop([
|
||||
(&input.0, &input.1),
|
||||
(&input.2, &input.3),
|
||||
].into_iter())
|
||||
);
|
||||
|
||||
benchmark!(final_exponentiation, e,
|
||||
input(rng) = e.miller_loop([
|
||||
(&G1::random(e, rng).prepare(e), &G2::random(e, rng).prepare(e)),
|
||||
].into_iter());
|
||||
|
||||
e.final_exponentiation(&input)
|
||||
);
|
||||
|
||||
macro_rules! group_tests(
|
||||
(
|
||||
$name:ident,
|
||||
$mul:ident,
|
||||
$mul_mixed:ident,
|
||||
$add:ident
|
||||
) => {
|
||||
benchmark!($mul, e,
|
||||
input(rng) = ($name::random(e, rng), Fr::random(e, rng));
|
||||
|
||||
{input.0.mul_assign(e, &input.1); input.0}
|
||||
);
|
||||
|
||||
benchmark!($mul_mixed, e,
|
||||
input(rng) = ($name::random(e, rng).to_affine(e), Fr::random(e, rng));
|
||||
|
||||
{input.0.mul(e, &input.1)}
|
||||
);
|
||||
|
||||
benchmark!($add, e,
|
||||
input(rng) = ($name::random(e, rng), $name::random(e, rng));
|
||||
|
||||
{input.0.add_assign(e, &input.1); input.0}
|
||||
);
|
||||
};
|
||||
);
|
||||
|
||||
macro_rules! field_tests(
|
||||
(
|
||||
@nosqrt,
|
||||
$name:ident,
|
||||
$mul:ident,
|
||||
$square:ident,
|
||||
$add:ident,
|
||||
$inverse:ident
|
||||
) => {
|
||||
benchmark!($mul, e,
|
||||
input(rng) = ($name::random(e, rng), $name::random(e, rng));
|
||||
|
||||
{input.0.mul_assign(e, &input.1); input.0}
|
||||
);
|
||||
|
||||
benchmark!($square, e,
|
||||
input(rng) = $name::random(e, rng);
|
||||
|
||||
{input.square(e); input}
|
||||
);
|
||||
|
||||
benchmark!($add, e,
|
||||
input(rng) = ($name::random(e, rng), $name::random(e, rng));
|
||||
|
||||
{input.0.add_assign(e, &input.1); input.0}
|
||||
);
|
||||
|
||||
benchmark!($inverse, e,
|
||||
input(rng) = $name::random(e, rng);
|
||||
|
||||
{input.inverse(e)}
|
||||
);
|
||||
};
|
||||
(
|
||||
$name:ident,
|
||||
$mul:ident,
|
||||
$square:ident,
|
||||
$add:ident,
|
||||
$inverse:ident,
|
||||
$sqrt:ident
|
||||
) => {
|
||||
field_tests!(@nosqrt, $name, $mul, $square, $add, $inverse);
|
||||
|
||||
benchmark!($sqrt, e,
|
||||
input(rng) = {let mut tmp = $name::random(e, rng); tmp.square(e); tmp};
|
||||
|
||||
{input.sqrt(e)}
|
||||
);
|
||||
};
|
||||
);
|
||||
|
||||
field_tests!(
|
||||
Fr,
|
||||
fr_multiplication,
|
||||
fr_squaring,
|
||||
fr_addition,
|
||||
fr_inverse,
|
||||
fr_sqrt
|
||||
);
|
||||
|
||||
field_tests!(
|
||||
Fq,
|
||||
fq_multiplication,
|
||||
fq_squaring,
|
||||
fq_addition,
|
||||
fq_inverse,
|
||||
fq_sqrt
|
||||
);
|
||||
|
||||
field_tests!(
|
||||
Fq2,
|
||||
fq2_multiplication,
|
||||
fq2_squaring,
|
||||
fq2_addition,
|
||||
fq2_inverse,
|
||||
fq2_sqrt
|
||||
);
|
||||
|
||||
field_tests!(
|
||||
@nosqrt,
|
||||
Fq12,
|
||||
fq12_multiplication,
|
||||
fq12_squaring,
|
||||
fq12_addition,
|
||||
fq12_inverse
|
||||
);
|
||||
|
||||
group_tests!(
|
||||
G1,
|
||||
g1_multiplication,
|
||||
g1_multiplication_mixed,
|
||||
g1_addition
|
||||
);
|
||||
|
||||
group_tests!(
|
||||
G2,
|
||||
g2_multiplication,
|
||||
g2_multiplication_mixed,
|
||||
g2_addition
|
||||
);
|
@ -1,456 +0,0 @@
|
||||
macro_rules! curve_impl {
|
||||
(
|
||||
$engine:ident,
|
||||
$name:ident,
|
||||
$name_affine:ident,
|
||||
$name_prepared:ident,
|
||||
$name_uncompressed:ident,
|
||||
$params_name:ident,
|
||||
$params_field:ident,
|
||||
$basefield:ident,
|
||||
$scalarfield:ident
|
||||
) => {
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct $name_affine {
|
||||
x: $basefield,
|
||||
y: $basefield,
|
||||
infinity: bool
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct $name {
|
||||
x: $basefield,
|
||||
y: $basefield,
|
||||
z: $basefield
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct $params_name {
|
||||
zero: $name,
|
||||
one: $name,
|
||||
coeff_b: $basefield,
|
||||
windows: Vec<usize>,
|
||||
batch_windows: (usize, Vec<usize>)
|
||||
}
|
||||
|
||||
impl Convert<$name_affine, $engine> for $name {
|
||||
type Target = $name_affine;
|
||||
|
||||
fn convert(&self, engine: &$engine) -> Cow<$name_affine> {
|
||||
Cow::Owned(self.to_affine(engine))
|
||||
}
|
||||
}
|
||||
|
||||
impl Group<$engine> for $name {
|
||||
fn group_zero(e: &$engine) -> $name {
|
||||
$name::zero(e)
|
||||
}
|
||||
fn group_mul_assign(&mut self, e: &$engine, scalar: &$scalarfield) {
|
||||
self.mul_assign(e, scalar);
|
||||
}
|
||||
fn group_add_assign(&mut self, e: &$engine, other: &Self) {
|
||||
self.add_assign(e, other);
|
||||
}
|
||||
fn group_sub_assign(&mut self, e: &$engine, other: &Self) {
|
||||
self.sub_assign(e, other);
|
||||
}
|
||||
}
|
||||
|
||||
impl CurveAffine<$engine> for $name_affine {
|
||||
type Jacobian = $name;
|
||||
type Uncompressed = $name_uncompressed;
|
||||
|
||||
fn is_valid(&self, e: &$engine) -> bool {
|
||||
if self.is_zero() {
|
||||
true
|
||||
} else {
|
||||
// Check that the point is on the curve
|
||||
let mut y2 = self.y;
|
||||
y2.square(e);
|
||||
|
||||
let mut x3b = self.x;
|
||||
x3b.square(e);
|
||||
x3b.mul_assign(e, &self.x);
|
||||
x3b.add_assign(e, &e.$params_field.coeff_b);
|
||||
|
||||
if y2 == x3b {
|
||||
// Check that the point is in the correct subgroup
|
||||
if self.mul(e, &$scalarfield::char(e)).is_zero() {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn to_uncompressed(&self, engine: &$engine) -> Self::Uncompressed {
|
||||
$name_uncompressed::from_affine(self, engine)
|
||||
}
|
||||
|
||||
fn to_jacobian(&self, engine: &$engine) -> $name {
|
||||
if self.infinity {
|
||||
$name::zero(engine)
|
||||
} else {
|
||||
$name {
|
||||
x: self.x,
|
||||
y: self.y,
|
||||
z: $basefield::one(engine)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare(self, e: &$engine) -> $name_prepared {
|
||||
$name_prepared::from_engine(e, self)
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.infinity
|
||||
}
|
||||
|
||||
fn mul<S: Convert<<$scalarfield as PrimeField<$engine>>::Repr, $engine>>(&self, e: &$engine, other: &S) -> $name {
|
||||
let mut res = $name::zero(e);
|
||||
|
||||
for i in BitIterator::new((*other.convert(e)).borrow())
|
||||
{
|
||||
res.double(e);
|
||||
|
||||
if i {
|
||||
res.add_assign_mixed(e, self);
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
fn negate(&mut self, e: &$engine) {
|
||||
if !self.is_zero() {
|
||||
self.y.negate(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl multiexp::Projective<$engine> for $name {
|
||||
type WindowTable = wnaf::WindowTable<$engine, $name>;
|
||||
|
||||
fn identity(e: &$engine) -> Self {
|
||||
Self::zero(e)
|
||||
}
|
||||
|
||||
fn add_to_projective(&self, e: &$engine, projective: &mut Self) {
|
||||
projective.add_assign(e, self);
|
||||
}
|
||||
|
||||
fn exponentiate(&mut self,
|
||||
e: &$engine,
|
||||
scalar: <$scalarfield as PrimeField<$engine>>::Repr,
|
||||
table: &mut Self::WindowTable,
|
||||
scratch: &mut wnaf::WNAFTable
|
||||
)
|
||||
{
|
||||
*self = self.optimal_exp(e, scalar, table, scratch);
|
||||
}
|
||||
|
||||
fn new_window_table(e: &$engine) -> Self::WindowTable {
|
||||
wnaf::WindowTable::<$engine, $name>::new(e, $name::zero(e), 2)
|
||||
}
|
||||
}
|
||||
|
||||
impl Curve<$engine> for $name {
|
||||
type Affine = $name_affine;
|
||||
type Prepared = $name_prepared;
|
||||
|
||||
fn optimal_window(engine: &$engine, scalar_bits: usize) -> Option<usize> {
|
||||
for (i, bits) in engine.$params_field.windows.iter().enumerate().rev() {
|
||||
if &scalar_bits >= bits {
|
||||
return Some(i + 2);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn optimal_window_batch(&self, engine: &$engine, scalars: usize) -> wnaf::WindowTable<$engine, $name> {
|
||||
let mut window = engine.$params_field.batch_windows.0;
|
||||
|
||||
for i in &engine.$params_field.batch_windows.1 {
|
||||
if scalars >= *i {
|
||||
window += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wnaf::WindowTable::new(engine, *self, window)
|
||||
}
|
||||
|
||||
fn zero(engine: &$engine) -> Self {
|
||||
engine.$params_field.zero
|
||||
}
|
||||
|
||||
fn one(engine: &$engine) -> Self {
|
||||
engine.$params_field.one
|
||||
}
|
||||
|
||||
fn random<R: rand::Rng>(engine: &$engine, rng: &mut R) -> Self {
|
||||
let mut tmp = Self::one(engine);
|
||||
tmp.mul_assign(engine, &$scalarfield::random(engine, rng));
|
||||
|
||||
tmp
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.z.is_zero()
|
||||
}
|
||||
|
||||
fn is_equal(&self, engine: &$engine, other: &Self) -> bool {
|
||||
if self.is_zero() {
|
||||
return other.is_zero();
|
||||
}
|
||||
|
||||
if other.is_zero() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut z1 = self.z;
|
||||
z1.square(engine);
|
||||
let mut z2 = other.z;
|
||||
z2.square(engine);
|
||||
|
||||
let mut tmp1 = self.x;
|
||||
tmp1.mul_assign(engine, &z2);
|
||||
|
||||
let mut tmp2 = other.x;
|
||||
tmp2.mul_assign(engine, &z1);
|
||||
|
||||
if tmp1 != tmp2 {
|
||||
return false;
|
||||
}
|
||||
|
||||
z1.mul_assign(engine, &self.z);
|
||||
z2.mul_assign(engine, &other.z);
|
||||
z2.mul_assign(engine, &self.y);
|
||||
z1.mul_assign(engine, &other.y);
|
||||
|
||||
if z1 != z2 {
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn to_affine(&self, engine: &$engine) -> Self::Affine {
|
||||
if self.is_zero() {
|
||||
$name_affine {
|
||||
x: $basefield::zero(),
|
||||
y: $basefield::one(engine),
|
||||
infinity: true
|
||||
}
|
||||
} else {
|
||||
let zinv = self.z.inverse(engine).unwrap();
|
||||
let mut zinv_powered = zinv;
|
||||
zinv_powered.square(engine);
|
||||
|
||||
let mut x = self.x;
|
||||
x.mul_assign(engine, &zinv_powered);
|
||||
|
||||
let mut y = self.y;
|
||||
zinv_powered.mul_assign(engine, &zinv);
|
||||
y.mul_assign(engine, &zinv_powered);
|
||||
|
||||
$name_affine {
|
||||
x: x,
|
||||
y: y,
|
||||
infinity: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare(&self, e: &$engine) -> $name_prepared {
|
||||
self.to_affine(e).prepare(e)
|
||||
}
|
||||
|
||||
fn double(&mut self, engine: &$engine) {
|
||||
if self.is_zero() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut a = self.x;
|
||||
a.square(engine);
|
||||
let mut c = self.y;
|
||||
c.square(engine);
|
||||
let mut d = c;
|
||||
c.square(engine);
|
||||
d.add_assign(engine, &self.x);
|
||||
d.square(engine);
|
||||
d.sub_assign(engine, &a);
|
||||
d.sub_assign(engine, &c);
|
||||
d.double(engine);
|
||||
let mut e = a;
|
||||
e.add_assign(engine, &a);
|
||||
e.add_assign(engine, &a);
|
||||
self.x = e;
|
||||
self.x.square(engine);
|
||||
self.x.sub_assign(engine, &d);
|
||||
self.x.sub_assign(engine, &d);
|
||||
c.double(engine);
|
||||
c.double(engine);
|
||||
c.double(engine);
|
||||
self.z.mul_assign(engine, &self.y);
|
||||
self.z.double(engine);
|
||||
self.y = d;
|
||||
self.y.sub_assign(engine, &self.x);
|
||||
self.y.mul_assign(engine, &e);
|
||||
self.y.sub_assign(engine, &c);
|
||||
}
|
||||
|
||||
fn negate(&mut self, engine: &$engine) {
|
||||
if !self.is_zero() {
|
||||
self.y.negate(engine)
|
||||
}
|
||||
}
|
||||
|
||||
fn mul_assign<S: Convert<<$scalarfield as PrimeField<$engine>>::Repr, $engine>>(&mut self, engine: &$engine, other: &S) {
|
||||
let mut res = Self::zero(engine);
|
||||
|
||||
for i in BitIterator::new((*other.convert(engine)).borrow())
|
||||
{
|
||||
res.double(engine);
|
||||
|
||||
if i {
|
||||
res.add_assign(engine, self);
|
||||
}
|
||||
}
|
||||
|
||||
*self = res;
|
||||
}
|
||||
|
||||
fn sub_assign(&mut self, engine: &$engine, other: &Self) {
|
||||
let mut tmp = *other;
|
||||
tmp.negate(engine);
|
||||
self.add_assign(engine, &tmp);
|
||||
}
|
||||
|
||||
fn add_assign_mixed(&mut self, e: &$engine, other: &$name_affine) {
|
||||
if other.is_zero() {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.is_zero() {
|
||||
self.x = other.x;
|
||||
self.y = other.y;
|
||||
self.z = $basefield::one(e);
|
||||
return;
|
||||
}
|
||||
|
||||
let mut z1z1 = self.z;
|
||||
z1z1.square(e);
|
||||
let mut u2 = other.x;
|
||||
u2.mul_assign(e, &z1z1);
|
||||
let mut z1cubed = self.z;
|
||||
z1cubed.mul_assign(e, &z1z1);
|
||||
let mut s2 = other.y;
|
||||
s2.mul_assign(e, &z1cubed);
|
||||
|
||||
if self.x == u2 && self.y == s2 {
|
||||
self.double(e);
|
||||
return;
|
||||
}
|
||||
|
||||
let mut h = u2;
|
||||
h.sub_assign(e, &self.x);
|
||||
let mut hh = h;
|
||||
hh.square(e);
|
||||
let mut i = hh;
|
||||
i.double(e);
|
||||
i.double(e);
|
||||
let mut j = h;
|
||||
j.mul_assign(e, &i);
|
||||
let mut r = s2;
|
||||
r.sub_assign(e, &self.y);
|
||||
r.double(e);
|
||||
let mut v = self.x;
|
||||
v.mul_assign(e, &i);
|
||||
|
||||
self.x = r;
|
||||
self.x.square(e);
|
||||
self.x.sub_assign(e, &j);
|
||||
self.x.sub_assign(e, &v);
|
||||
self.x.sub_assign(e, &v);
|
||||
|
||||
self.y.mul_assign(e, &j);
|
||||
let mut tmp = v;
|
||||
tmp.sub_assign(e, &self.x);
|
||||
tmp.mul_assign(e, &r);
|
||||
tmp.sub_assign(e, &self.y);
|
||||
tmp.sub_assign(e, &self.y);
|
||||
self.y = tmp;
|
||||
|
||||
self.z.add_assign(e, &h);
|
||||
self.z.square(e);
|
||||
self.z.sub_assign(e, &z1z1);
|
||||
self.z.sub_assign(e, &hh);
|
||||
}
|
||||
|
||||
fn add_assign(&mut self, engine: &$engine, other: &Self) {
|
||||
if self.is_zero() {
|
||||
*self = *other;
|
||||
return;
|
||||
}
|
||||
|
||||
if other.is_zero() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut z1_squared = self.z;
|
||||
z1_squared.square(engine);
|
||||
let mut z2_squared = other.z;
|
||||
z2_squared.square(engine);
|
||||
let mut u1 = self.x;
|
||||
u1.mul_assign(engine, &z2_squared);
|
||||
let mut u2 = other.x;
|
||||
u2.mul_assign(engine, &z1_squared);
|
||||
let mut s1 = other.z;
|
||||
s1.mul_assign(engine, &z2_squared);
|
||||
s1.mul_assign(engine, &self.y);
|
||||
let mut s2 = self.z;
|
||||
s2.mul_assign(engine, &z1_squared);
|
||||
s2.mul_assign(engine, &other.y);
|
||||
|
||||
if u1 == u2 && s1 == s2 {
|
||||
self.double(engine);
|
||||
} else {
|
||||
u2.sub_assign(engine, &u1);
|
||||
s2.sub_assign(engine, &s1);
|
||||
s2.double(engine);
|
||||
let mut i = u2;
|
||||
i.double(engine);
|
||||
i.square(engine);
|
||||
let mut v = i;
|
||||
v.mul_assign(engine, &u1);
|
||||
i.mul_assign(engine, &u2);
|
||||
s1.mul_assign(engine, &i);
|
||||
s1.double(engine);
|
||||
self.x = s2;
|
||||
self.x.square(engine);
|
||||
self.x.sub_assign(engine, &i);
|
||||
self.x.sub_assign(engine, &v);
|
||||
self.x.sub_assign(engine, &v);
|
||||
self.y = v;
|
||||
self.y.sub_assign(engine, &self.x);
|
||||
self.y.mul_assign(engine, &s2);
|
||||
self.y.sub_assign(engine, &s1);
|
||||
self.z.add_assign(engine, &other.z);
|
||||
self.z.square(engine);
|
||||
self.z.sub_assign(engine, &z1_squared);
|
||||
self.z.sub_assign(engine, &z2_squared);
|
||||
self.z.mul_assign(engine, &u2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,771 +0,0 @@
|
||||
macro_rules! fp_params_impl {
|
||||
(
|
||||
$name:ident = (3 mod 4),
|
||||
engine = $engine:ident,
|
||||
params = $params_field:ident : $params_name:ident,
|
||||
limbs = $limbs:expr,
|
||||
modulus = $modulus:expr,
|
||||
r1 = $r1:expr,
|
||||
r2 = $r2:expr,
|
||||
modulus_minus_3_over_4 = $modulus_minus_3_over_4:expr,
|
||||
modulus_minus_1_over_2 = $modulus_minus_1_over_2:expr,
|
||||
inv = $inv:expr
|
||||
) => {
|
||||
#[derive(Clone)]
|
||||
struct $params_name {
|
||||
modulus: [u64; $limbs],
|
||||
r1: $name,
|
||||
r2: $name,
|
||||
inv: u64,
|
||||
one: $name,
|
||||
num_bits: usize,
|
||||
modulus_minus_3_over_4: [u64; $limbs],
|
||||
modulus_minus_1_over_2: [u64; $limbs],
|
||||
base10: [$name; 11]
|
||||
}
|
||||
|
||||
impl $params_name {
|
||||
fn partial_init() -> $params_name {
|
||||
let mut tmp = $params_name {
|
||||
modulus: $modulus,
|
||||
r1: $name($r1),
|
||||
r2: $name($r2),
|
||||
inv: $inv,
|
||||
one: $name::zero(),
|
||||
num_bits: 0,
|
||||
modulus_minus_3_over_4: $modulus_minus_3_over_4,
|
||||
modulus_minus_1_over_2: $modulus_minus_1_over_2,
|
||||
base10: [$name::zero(); 11]
|
||||
};
|
||||
|
||||
tmp.one.0[0] = 1;
|
||||
|
||||
tmp
|
||||
}
|
||||
}
|
||||
};
|
||||
(
|
||||
$name:ident = (1 mod 16),
|
||||
engine = $engine:ident,
|
||||
params = $params_field:ident : $params_name:ident,
|
||||
limbs = $limbs:expr,
|
||||
modulus = $modulus:expr,
|
||||
r1 = $r1:expr,
|
||||
r2 = $r2:expr,
|
||||
modulus_minus_1_over_2 = $modulus_minus_1_over_2:expr,
|
||||
s = $s:expr,
|
||||
t = $t:expr,
|
||||
t_plus_1_over_2 = $t_plus_1_over_2:expr,
|
||||
inv = $inv:expr
|
||||
) => {
|
||||
#[derive(Clone)]
|
||||
struct $params_name {
|
||||
modulus: [u64; $limbs],
|
||||
r1: $name,
|
||||
r2: $name,
|
||||
inv: u64,
|
||||
one: $name,
|
||||
num_bits: usize,
|
||||
modulus_minus_1_over_2: [u64; $limbs],
|
||||
s: u64,
|
||||
t: [u64; $limbs],
|
||||
t_plus_1_over_2: [u64; $limbs],
|
||||
root_of_unity: $name,
|
||||
multiplicative_generator: $name,
|
||||
base10: [$name; 11]
|
||||
}
|
||||
|
||||
impl $params_name {
|
||||
fn partial_init() -> $params_name {
|
||||
let mut tmp = $params_name {
|
||||
modulus: $modulus,
|
||||
r1: $name($r1),
|
||||
r2: $name($r2),
|
||||
inv: $inv,
|
||||
one: $name::zero(),
|
||||
num_bits: 0,
|
||||
modulus_minus_1_over_2: $modulus_minus_1_over_2,
|
||||
s: $s,
|
||||
t: $t,
|
||||
t_plus_1_over_2: $t_plus_1_over_2,
|
||||
root_of_unity: $name::zero(),
|
||||
multiplicative_generator: $name::zero(),
|
||||
base10: [$name::zero(); 11]
|
||||
};
|
||||
|
||||
tmp.one.0[0] = 1;
|
||||
|
||||
tmp
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! fp_sqrt_impl {
|
||||
(
|
||||
$name:ident = (3 mod 4),
|
||||
engine = $engine:ident,
|
||||
params = $params_field:ident : $params_name:ident
|
||||
) => {
|
||||
impl SqrtField<$engine> for $name {
|
||||
fn sqrt(&self, engine: &$engine) -> Option<Self> {
|
||||
let mut a1 = self.pow(engine, &engine.$params_field.modulus_minus_3_over_4);
|
||||
|
||||
let mut a0 = a1;
|
||||
a0.square(engine);
|
||||
a0.mul_assign(engine, self);
|
||||
|
||||
let mut neg1 = Self::one(engine);
|
||||
neg1.negate(engine);
|
||||
|
||||
if a0 == neg1 {
|
||||
None
|
||||
} else {
|
||||
a1.mul_assign(engine, self);
|
||||
Some(a1)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
(
|
||||
$name:ident = (1 mod 16),
|
||||
engine = $engine:ident,
|
||||
params = $params_field:ident : $params_name:ident
|
||||
) => {
|
||||
impl SqrtField<$engine> for $name {
|
||||
fn sqrt(&self, engine: &$engine) -> Option<Self> {
|
||||
if self.is_zero() {
|
||||
return Some(*self);
|
||||
}
|
||||
|
||||
if self.pow(engine, &engine.$params_field.modulus_minus_1_over_2) != $name::one(engine) {
|
||||
None
|
||||
} else {
|
||||
let mut c = engine.$params_field.root_of_unity;
|
||||
|
||||
let mut r = self.pow(engine, &engine.$params_field.t_plus_1_over_2);
|
||||
let mut t = self.pow(engine, &engine.$params_field.t);
|
||||
let mut m = engine.$params_field.s;
|
||||
|
||||
while t != Self::one(engine) {
|
||||
let mut i = 1;
|
||||
{
|
||||
let mut t2i = t;
|
||||
t2i.square(engine);
|
||||
loop {
|
||||
if t2i == Self::one(engine) {
|
||||
break;
|
||||
}
|
||||
t2i.square(engine);
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
for _ in 0..(m - i - 1) {
|
||||
c.square(engine);
|
||||
}
|
||||
r.mul_assign(engine, &c);
|
||||
c.square(engine);
|
||||
t.mul_assign(engine, &c);
|
||||
m = i;
|
||||
}
|
||||
|
||||
Some(r)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! fp_impl {
|
||||
(
|
||||
$name:ident = ($($congruency:tt)*),
|
||||
engine = $engine:ident,
|
||||
params = $params_field:ident : $params_name:ident,
|
||||
arith = $arith_mod:ident,
|
||||
repr = $repr:ident,
|
||||
limbs = $limbs:expr,
|
||||
$($params:tt)*
|
||||
) => {
|
||||
fp_params_impl!(
|
||||
$name = ($($congruency)*),
|
||||
engine = $engine,
|
||||
params = $params_field : $params_name,
|
||||
limbs = $limbs,
|
||||
$($params)*
|
||||
);
|
||||
|
||||
impl $params_name {
|
||||
fn base10(e: &$engine) -> [$name; 11] {
|
||||
let mut ret = [$name::zero(); 11];
|
||||
|
||||
let mut acc = $name::zero();
|
||||
for i in 0..11 {
|
||||
ret[i] = acc;
|
||||
acc.add_assign(e, &$name::one(e));
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
fp_sqrt_impl!(
|
||||
$name = ($($congruency)*),
|
||||
engine = $engine,
|
||||
params = $params_field : $params_name
|
||||
);
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
pub struct $name([u64; $limbs]);
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
pub struct $repr([u64; $limbs]);
|
||||
|
||||
impl PrimeFieldRepr for $repr {
|
||||
fn from_u64(a: u64) -> Self {
|
||||
let mut tmp: [u64; $limbs] = Default::default();
|
||||
tmp[0] = a;
|
||||
$repr(tmp)
|
||||
}
|
||||
|
||||
fn sub_noborrow(&mut self, other: &Self) {
|
||||
$arith_mod::sub_noborrow(&mut self.0, &other.0);
|
||||
}
|
||||
|
||||
fn add_nocarry(&mut self, other: &Self) {
|
||||
$arith_mod::add_nocarry(&mut self.0, &other.0);
|
||||
}
|
||||
|
||||
fn num_bits(&self) -> usize {
|
||||
$arith_mod::num_bits(&self.0)
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.0.iter().all(|&e| e==0)
|
||||
}
|
||||
|
||||
fn is_odd(&self) -> bool {
|
||||
$arith_mod::odd(&self.0)
|
||||
}
|
||||
|
||||
fn div2(&mut self) {
|
||||
$arith_mod::div2(&mut self.0);
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u64]> for $repr {
|
||||
fn as_ref(&self) -> &[u64] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for $repr {
|
||||
fn cmp(&self, other: &$repr) -> Ordering {
|
||||
if $arith_mod::lt(&self.0, &other.0) {
|
||||
Ordering::Less
|
||||
} else if self.0 == other.0 {
|
||||
Ordering::Equal
|
||||
} else {
|
||||
Ordering::Greater
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for $repr {
|
||||
fn partial_cmp(&self, other: &$repr) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for $name
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
ENGINE.with(|e| {
|
||||
try!(write!(f, "Fp(0x"));
|
||||
for i in self.into_repr(&e).0.iter().rev() {
|
||||
try!(write!(f, "{:016x}", *i));
|
||||
}
|
||||
write!(f, ")")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl $name
|
||||
{
|
||||
#[inline]
|
||||
fn mont_reduce(&mut self, engine: &$engine, res: &mut [u64; $limbs*2]) {
|
||||
// The Montgomery reduction here is based on Algorithm 14.32 in
|
||||
// Handbook of Applied Cryptography
|
||||
// <http://cacr.uwaterloo.ca/hac/about/chap14.pdf>.
|
||||
|
||||
for i in 0..$limbs {
|
||||
let k = res[i].wrapping_mul(engine.$params_field.inv);
|
||||
$arith_mod::mac_digit(&mut res[i..], &engine.$params_field.modulus, k);
|
||||
}
|
||||
|
||||
self.0.copy_from_slice(&res[$limbs..]);
|
||||
|
||||
self.reduce(engine);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reduce(&mut self, engine: &$engine) {
|
||||
if !$arith_mod::lt(&self.0, &engine.$params_field.modulus) {
|
||||
$arith_mod::sub_noborrow(&mut self.0, &engine.$params_field.modulus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Convert<$repr, $engine> for $name
|
||||
{
|
||||
type Target = $repr;
|
||||
|
||||
fn convert(&self, engine: &$engine) -> Cow<$repr> {
|
||||
Cow::Owned(self.into_repr(engine))
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimeField<$engine> for $name
|
||||
{
|
||||
type Repr = $repr;
|
||||
|
||||
fn from_repr(engine: &$engine, repr: Self::Repr) -> Result<Self, ()> {
|
||||
let mut tmp = $name(repr.0);
|
||||
if $arith_mod::lt(&tmp.0, &engine.$params_field.modulus) {
|
||||
tmp.mul_assign(engine, &engine.$params_field.r2);
|
||||
Ok(tmp)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
fn into_repr(&self, engine: &$engine) -> Self::Repr {
|
||||
let mut tmp = *self;
|
||||
tmp.mul_assign(engine, &engine.$params_field.one);
|
||||
$repr(tmp.0)
|
||||
}
|
||||
|
||||
fn from_u64(engine: &$engine, n: u64) -> Self {
|
||||
let mut r = [0; $limbs];
|
||||
r[0] = n;
|
||||
|
||||
Self::from_repr(engine, $repr(r)).unwrap()
|
||||
}
|
||||
|
||||
fn from_str(engine: &$engine, s: &str) -> Result<Self, ()> {
|
||||
let mut res = Self::zero();
|
||||
for c in s.chars() {
|
||||
match c.to_digit(10) {
|
||||
Some(d) => {
|
||||
res.mul_assign(engine, &engine.$params_field.base10[10]);
|
||||
res.add_assign(engine, &engine.$params_field.base10[d as usize]);
|
||||
},
|
||||
None => {
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn char(engine: &$engine) -> Self::Repr {
|
||||
$repr(engine.$params_field.modulus)
|
||||
}
|
||||
|
||||
fn num_bits(engine: &$engine) -> usize {
|
||||
engine.$params_field.num_bits
|
||||
}
|
||||
|
||||
fn capacity(engine: &$engine) -> usize {
|
||||
Self::num_bits(engine) - 1
|
||||
}
|
||||
}
|
||||
|
||||
impl Field<$engine> for $name
|
||||
{
|
||||
fn zero() -> Self {
|
||||
$name([0; $limbs])
|
||||
}
|
||||
|
||||
fn one(engine: &$engine) -> Self {
|
||||
engine.$params_field.r1
|
||||
}
|
||||
|
||||
fn random<R: rand::Rng>(engine: &$engine, rng: &mut R) -> Self {
|
||||
let mut tmp = [0; $limbs*2];
|
||||
for i in &mut tmp {
|
||||
*i = rng.gen();
|
||||
}
|
||||
|
||||
$name($arith_mod::divrem(&tmp, &engine.$params_field.modulus).1)
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.0.iter().all(|&e| e==0)
|
||||
}
|
||||
|
||||
fn double(&mut self, engine: &$engine) {
|
||||
$arith_mod::mul2(&mut self.0);
|
||||
|
||||
self.reduce(engine);
|
||||
}
|
||||
|
||||
fn frobenius_map(&mut self, _: &$engine, _: usize)
|
||||
{
|
||||
// This is the identity function for a prime field.
|
||||
}
|
||||
|
||||
fn negate(&mut self, engine: &$engine) {
|
||||
if !self.is_zero() {
|
||||
let mut tmp = engine.$params_field.modulus;
|
||||
$arith_mod::sub_noborrow(&mut tmp, &self.0);
|
||||
|
||||
self.0 = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
fn add_assign(&mut self, engine: &$engine, other: &Self) {
|
||||
$arith_mod::add_nocarry(&mut self.0, &other.0);
|
||||
|
||||
self.reduce(engine);
|
||||
}
|
||||
|
||||
fn sub_assign(&mut self, engine: &$engine, other: &Self) {
|
||||
if $arith_mod::lt(&self.0, &other.0) {
|
||||
$arith_mod::add_nocarry(&mut self.0, &engine.$params_field.modulus);
|
||||
}
|
||||
|
||||
$arith_mod::sub_noborrow(&mut self.0, &other.0);
|
||||
}
|
||||
|
||||
fn square(&mut self, engine: &$engine)
|
||||
{
|
||||
let mut res = [0; $limbs*2];
|
||||
$arith_mod::mac3(&mut res, &self.0, &self.0);
|
||||
|
||||
self.mont_reduce(engine, &mut res);
|
||||
}
|
||||
|
||||
fn mul_assign(&mut self, engine: &$engine, other: &Self) {
|
||||
let mut res = [0; $limbs*2];
|
||||
$arith_mod::mac3(&mut res, &self.0, &other.0);
|
||||
|
||||
self.mont_reduce(engine, &mut res);
|
||||
}
|
||||
|
||||
fn inverse(&self, engine: &$engine) -> Option<Self> {
|
||||
if self.is_zero() {
|
||||
None
|
||||
} else {
|
||||
// Guajardo Kumar Paar Pelzl
|
||||
// Efficient Software-Implementation of Finite Fields with Applications to Cryptography
|
||||
// Algorithm 16 (BEA for Inversion in Fp)
|
||||
|
||||
let mut u = self.0;
|
||||
let mut v = engine.$params_field.modulus;
|
||||
let mut b = engine.$params_field.r2; // Avoids unnecessary reduction step.
|
||||
let mut c = Self::zero();
|
||||
|
||||
while u != engine.$params_field.one.0 && v != engine.$params_field.one.0 {
|
||||
while $arith_mod::even(&u) {
|
||||
$arith_mod::div2(&mut u);
|
||||
|
||||
if $arith_mod::even(&b.0) {
|
||||
$arith_mod::div2(&mut b.0);
|
||||
} else {
|
||||
$arith_mod::add_nocarry(&mut b.0, &engine.$params_field.modulus);
|
||||
$arith_mod::div2(&mut b.0);
|
||||
}
|
||||
}
|
||||
|
||||
while $arith_mod::even(&v) {
|
||||
$arith_mod::div2(&mut v);
|
||||
|
||||
if $arith_mod::even(&c.0) {
|
||||
$arith_mod::div2(&mut c.0);
|
||||
} else {
|
||||
$arith_mod::add_nocarry(&mut c.0, &engine.$params_field.modulus);
|
||||
$arith_mod::div2(&mut c.0);
|
||||
}
|
||||
}
|
||||
|
||||
if $arith_mod::lt(&v, &u) {
|
||||
$arith_mod::sub_noborrow(&mut u, &v);
|
||||
b.sub_assign(engine, &c);
|
||||
} else {
|
||||
$arith_mod::sub_noborrow(&mut v, &u);
|
||||
c.sub_assign(engine, &b);
|
||||
}
|
||||
}
|
||||
|
||||
if u == engine.$params_field.one.0 {
|
||||
Some(b)
|
||||
} else {
|
||||
Some(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod $arith_mod {
|
||||
// Arithmetic
|
||||
#[allow(dead_code)]
|
||||
pub fn num_bits(v: &[u64; $limbs]) -> usize
|
||||
{
|
||||
let mut ret = 64 * $limbs;
|
||||
for i in v.iter().rev() {
|
||||
let leading = i.leading_zeros() as usize;
|
||||
ret -= leading;
|
||||
if leading != 64 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mac_digit(acc: &mut [u64], b: &[u64], c: u64)
|
||||
{
|
||||
#[inline]
|
||||
fn mac_with_carry(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 {
|
||||
let tmp = (a as u128) + (b as u128) * (c as u128) + (*carry as u128);
|
||||
|
||||
*carry = (tmp >> 64) as u64;
|
||||
|
||||
tmp as u64
|
||||
}
|
||||
|
||||
let mut b_iter = b.iter();
|
||||
let mut carry = 0;
|
||||
|
||||
for ai in acc.iter_mut() {
|
||||
if let Some(bi) = b_iter.next() {
|
||||
*ai = mac_with_carry(*ai, *bi, c, &mut carry);
|
||||
} else {
|
||||
*ai = mac_with_carry(*ai, 0, c, &mut carry);
|
||||
}
|
||||
}
|
||||
|
||||
debug_assert!(carry == 0);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mac3_long(acc: &mut [u64], b: &[u64], c: &[u64]) {
|
||||
for (i, xi) in b.iter().enumerate() {
|
||||
mac_digit(&mut acc[i..], c, *xi);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mac3(acc: &mut [u64; $limbs*2], b: &[u64; $limbs], c: &[u64; $limbs]) {
|
||||
if $limbs > 4 {
|
||||
let (x0, x1) = b.split_at($limbs / 2);
|
||||
let (y0, y1) = c.split_at($limbs / 2);
|
||||
|
||||
let mut p = [0; $limbs+1];
|
||||
mac3_long(&mut p, x1, y1);
|
||||
add_nocarry(&mut acc[$limbs/2..], &p);
|
||||
add_nocarry(&mut acc[$limbs..], &p);
|
||||
p = [0; $limbs+1];
|
||||
mac3_long(&mut p, x0, y0);
|
||||
add_nocarry(&mut acc[..], &p);
|
||||
add_nocarry(&mut acc[$limbs/2..], &p);
|
||||
|
||||
let mut sign;
|
||||
let mut j0 = [0; $limbs / 2];
|
||||
let mut j1 = [0; $limbs / 2];
|
||||
if lt(x1, x0) {
|
||||
sign = false;
|
||||
j0.copy_from_slice(x0);
|
||||
sub_noborrow(&mut j0, x1);
|
||||
} else {
|
||||
sign = true;
|
||||
j0.copy_from_slice(x1);
|
||||
sub_noborrow(&mut j0, x0);
|
||||
}
|
||||
if lt(&y1, &y0) {
|
||||
sign = sign == false;
|
||||
j1.copy_from_slice(y0);
|
||||
sub_noborrow(&mut j1, y1);
|
||||
} else {
|
||||
sign = sign == true;
|
||||
j1.copy_from_slice(y1);
|
||||
sub_noborrow(&mut j1, y0);
|
||||
}
|
||||
|
||||
if sign {
|
||||
p = [0; $limbs+1];
|
||||
mac3_long(&mut p, &j0, &j1);
|
||||
sub_noborrow(&mut acc[$limbs/2..], &p);
|
||||
} else {
|
||||
mac3_long(&mut acc[$limbs/2..], &j0, &j1);
|
||||
}
|
||||
} else {
|
||||
mac3_long(acc, b, c);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn adc(a: u64, b: u64, carry: &mut u64) -> u64 {
|
||||
let tmp = (a as u128) + (b as u128) + (*carry as u128);
|
||||
|
||||
*carry = (tmp >> 64) as u64;
|
||||
|
||||
tmp as u64
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(dead_code)]
|
||||
pub fn add_carry(a: &mut [u64], b: &[u64]) {
|
||||
use std::iter;
|
||||
|
||||
let mut carry = 0;
|
||||
|
||||
for (a, b) in a.into_iter().zip(b.iter().chain(iter::repeat(&0))) {
|
||||
*a = adc(*a, *b, &mut carry);
|
||||
}
|
||||
|
||||
debug_assert!(0 == carry);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn add_nocarry(a: &mut [u64], b: &[u64]) {
|
||||
let mut carry = 0;
|
||||
|
||||
for (a, b) in a.into_iter().zip(b.iter()) {
|
||||
*a = adc(*a, *b, &mut carry);
|
||||
}
|
||||
|
||||
debug_assert!(0 == carry);
|
||||
}
|
||||
|
||||
/// Returns true if a < b.
|
||||
#[inline]
|
||||
pub fn lt(a: &[u64], b: &[u64]) -> bool {
|
||||
for (a, b) in a.iter().zip(b.iter()).rev() {
|
||||
if *a > *b {
|
||||
return false;
|
||||
} else if *a < *b {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn sub_noborrow(a: &mut [u64], b: &[u64]) {
|
||||
#[inline]
|
||||
fn sbb(a: u64, b: u64, borrow: &mut u64) -> u64 {
|
||||
let tmp = (1u128 << 64) + (a as u128) - (b as u128) - (*borrow as u128);
|
||||
|
||||
*borrow = if tmp >> 64 == 0 { 1 } else { 0 };
|
||||
|
||||
tmp as u64
|
||||
}
|
||||
|
||||
let mut borrow = 0;
|
||||
|
||||
for (a, b) in a.into_iter().zip(b.iter()) {
|
||||
*a = sbb(*a, *b, &mut borrow);
|
||||
}
|
||||
|
||||
debug_assert!(0 == borrow);
|
||||
}
|
||||
|
||||
/// Returns if number is even.
|
||||
#[inline(always)]
|
||||
#[allow(dead_code)]
|
||||
pub fn even(a: &[u64; $limbs]) -> bool {
|
||||
a[0] & 1 == 0
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[allow(dead_code)]
|
||||
pub fn odd(a: &[u64; $limbs]) -> bool {
|
||||
a[0] & 1 == 1
|
||||
}
|
||||
|
||||
/// Divide by two
|
||||
#[inline]
|
||||
pub fn div2(a: &mut [u64; $limbs]) {
|
||||
let mut t = 0;
|
||||
for i in a.iter_mut().rev() {
|
||||
let t2 = *i << 63;
|
||||
*i >>= 1;
|
||||
*i |= t;
|
||||
t = t2;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mul2(a: &mut [u64; $limbs]) {
|
||||
let mut last = 0;
|
||||
for i in a {
|
||||
let tmp = *i >> 63;
|
||||
*i <<= 1;
|
||||
*i |= last;
|
||||
last = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
fn get_bit(this: &[u64; $limbs*2], n: usize) -> bool {
|
||||
let part = n / 64;
|
||||
let bit = n - (64 * part);
|
||||
|
||||
this[part] & (1 << bit) > 0
|
||||
}
|
||||
|
||||
fn set_bit(this: &mut [u64; $limbs], n: usize, to: bool) -> bool
|
||||
{
|
||||
let part = n / 64;
|
||||
let bit = n - (64 * part);
|
||||
|
||||
match this.get_mut(part) {
|
||||
Some(e) => {
|
||||
if to {
|
||||
*e |= 1 << bit;
|
||||
} else {
|
||||
*e &= !(1 << bit);
|
||||
}
|
||||
|
||||
true
|
||||
},
|
||||
None => false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn divrem(
|
||||
this: &[u64; $limbs*2],
|
||||
modulo: &[u64; $limbs]
|
||||
) -> (Option<[u64; $limbs]>, [u64; $limbs])
|
||||
{
|
||||
let mut q = Some([0; $limbs]);
|
||||
let mut r = [0; $limbs];
|
||||
|
||||
for i in (0..($limbs*2*64)).rev() {
|
||||
// NB: modulo's first bit is unset so this will never
|
||||
// destroy information
|
||||
mul2(&mut r);
|
||||
assert!(set_bit(&mut r, 0, get_bit(this, i)));
|
||||
if !lt(&r, modulo) {
|
||||
sub_noborrow(&mut r, modulo);
|
||||
if q.is_some() && !set_bit(q.as_mut().unwrap(), i, true) {
|
||||
q = None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if q.is_some() && !lt(q.as_ref().unwrap(), modulo) {
|
||||
(None, r)
|
||||
} else {
|
||||
(q, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,151 +0,0 @@
|
||||
use super::{Bls381, Fq2, Fq6};
|
||||
use rand;
|
||||
use super::Field;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct Fq12 {
|
||||
pub c0: Fq6,
|
||||
pub c1: Fq6
|
||||
}
|
||||
|
||||
impl Fq12 {
|
||||
pub fn unitary_inverse(&mut self, e: &Bls381)
|
||||
{
|
||||
self.c1.negate(e);
|
||||
}
|
||||
|
||||
pub fn mul_by_015(
|
||||
&mut self,
|
||||
e: &Bls381,
|
||||
a: &Fq2,
|
||||
b: &Fq2,
|
||||
c: &Fq2
|
||||
)
|
||||
{
|
||||
let mut aa = self.c0;
|
||||
aa.mul_by_01(e, a, b);
|
||||
let mut bb = self.c1;
|
||||
bb.mul_by_1(e, c);
|
||||
let mut o = *b;
|
||||
o.add_assign(e, &c);
|
||||
self.c1.add_assign(e, &self.c0);
|
||||
self.c1.mul_by_01(e, a, &o);
|
||||
self.c1.sub_assign(e, &aa);
|
||||
self.c1.sub_assign(e, &bb);
|
||||
self.c0 = bb;
|
||||
self.c0.mul_by_nonresidue(e);
|
||||
self.c0.add_assign(e, &aa);
|
||||
}
|
||||
}
|
||||
|
||||
impl Field<Bls381> for Fq12
|
||||
{
|
||||
fn zero() -> Self {
|
||||
Fq12 {
|
||||
c0: Fq6::zero(),
|
||||
c1: Fq6::zero()
|
||||
}
|
||||
}
|
||||
|
||||
fn one(engine: &Bls381) -> Self {
|
||||
Fq12 {
|
||||
c0: Fq6::one(engine),
|
||||
c1: Fq6::zero()
|
||||
}
|
||||
}
|
||||
|
||||
fn random<R: rand::Rng>(engine: &Bls381, rng: &mut R) -> Self {
|
||||
Fq12 {
|
||||
c0: Fq6::random(engine, rng),
|
||||
c1: Fq6::random(engine, rng)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.c0.is_zero() && self.c1.is_zero()
|
||||
}
|
||||
|
||||
fn double(&mut self, engine: &Bls381) {
|
||||
self.c0.double(engine);
|
||||
self.c1.double(engine);
|
||||
}
|
||||
|
||||
fn negate(&mut self, engine: &Bls381) {
|
||||
self.c0.negate(engine);
|
||||
self.c1.negate(engine);
|
||||
}
|
||||
|
||||
fn add_assign(&mut self, engine: &Bls381, other: &Self) {
|
||||
self.c0.add_assign(engine, &other.c0);
|
||||
self.c1.add_assign(engine, &other.c1);
|
||||
}
|
||||
|
||||
fn sub_assign(&mut self, engine: &Bls381, other: &Self) {
|
||||
self.c0.sub_assign(engine, &other.c0);
|
||||
self.c1.sub_assign(engine, &other.c1);
|
||||
}
|
||||
|
||||
fn frobenius_map(&mut self, e: &Bls381, power: usize)
|
||||
{
|
||||
self.c0.frobenius_map(e, power);
|
||||
self.c1.frobenius_map(e, power);
|
||||
|
||||
self.c1.c0.mul_assign(e, &e.frobenius_coeff_fq12[power % 12]);
|
||||
self.c1.c1.mul_assign(e, &e.frobenius_coeff_fq12[power % 12]);
|
||||
self.c1.c2.mul_assign(e, &e.frobenius_coeff_fq12[power % 12]);
|
||||
}
|
||||
|
||||
fn square(&mut self, e: &Bls381) {
|
||||
let mut ab = self.c0;
|
||||
ab.mul_assign(e, &self.c1);
|
||||
let mut c0c1 = self.c0;
|
||||
c0c1.add_assign(e, &self.c1);
|
||||
let mut c0 = self.c1;
|
||||
c0.mul_by_nonresidue(e);
|
||||
c0.add_assign(e, &self.c0);
|
||||
c0.mul_assign(e, &c0c1);
|
||||
c0.sub_assign(e, &ab);
|
||||
self.c1 = ab;
|
||||
self.c1.add_assign(e, &ab);
|
||||
ab.mul_by_nonresidue(e);
|
||||
c0.sub_assign(e, &ab);
|
||||
self.c0 = c0;
|
||||
}
|
||||
|
||||
fn mul_assign(&mut self, e: &Bls381, other: &Self) {
|
||||
let mut aa = self.c0;
|
||||
aa.mul_assign(e, &other.c0);
|
||||
let mut bb = self.c1;
|
||||
bb.mul_assign(e, &other.c1);
|
||||
let mut o = other.c0;
|
||||
o.add_assign(e, &other.c1);
|
||||
self.c1.add_assign(e, &self.c0);
|
||||
self.c1.mul_assign(e, &o);
|
||||
self.c1.sub_assign(e, &aa);
|
||||
self.c1.sub_assign(e, &bb);
|
||||
self.c0 = bb;
|
||||
self.c0.mul_by_nonresidue(e);
|
||||
self.c0.add_assign(e, &aa);
|
||||
}
|
||||
|
||||
fn inverse(&self, e: &Bls381) -> Option<Self> {
|
||||
let mut c0s = self.c0;
|
||||
c0s.square(e);
|
||||
let mut c1s = self.c1;
|
||||
c1s.square(e);
|
||||
c1s.mul_by_nonresidue(e);
|
||||
c0s.sub_assign(e, &c1s);
|
||||
|
||||
c0s.inverse(e).map(|t| {
|
||||
let mut tmp = Fq12 {
|
||||
c0: t,
|
||||
c1: t
|
||||
};
|
||||
tmp.c0.mul_assign(e, &self.c0);
|
||||
tmp.c1.mul_assign(e, &self.c1);
|
||||
tmp.c1.negate(e);
|
||||
|
||||
tmp
|
||||
})
|
||||
}
|
||||
}
|
@ -1,156 +0,0 @@
|
||||
use super::{Bls381, Fq};
|
||||
use rand;
|
||||
use super::{Field, SqrtField};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct Fq2 {
|
||||
pub c0: Fq,
|
||||
pub c1: Fq
|
||||
}
|
||||
|
||||
impl Fq2 {
|
||||
pub fn mul_by_nonresidue(&mut self, e: &Bls381) {
|
||||
let t0 = self.c0;
|
||||
self.c0.sub_assign(e, &self.c1);
|
||||
self.c1.add_assign(e, &t0);
|
||||
}
|
||||
}
|
||||
|
||||
impl SqrtField<Bls381> for Fq2 {
|
||||
fn sqrt(&self, engine: &Bls381) -> Option<Self> {
|
||||
// Algorithm 9, https://eprint.iacr.org/2012/685.pdf
|
||||
|
||||
if self.is_zero() {
|
||||
return Some(Self::zero());
|
||||
} else {
|
||||
let mut a1 = self.pow(engine, &engine.fqparams.modulus_minus_3_over_4);
|
||||
let mut alpha = a1;
|
||||
alpha.square(engine);
|
||||
alpha.mul_assign(engine, self);
|
||||
let mut a0 = alpha.pow(engine, &engine.fqparams.modulus);
|
||||
a0.mul_assign(engine, &alpha);
|
||||
|
||||
let mut neg1 = Self::one(engine);
|
||||
neg1.negate(engine);
|
||||
|
||||
if a0 == neg1 {
|
||||
None
|
||||
} else {
|
||||
a1.mul_assign(engine, self);
|
||||
|
||||
if alpha == neg1 {
|
||||
a1.mul_assign(engine, &Fq2{c0: Fq::zero(), c1: Fq::one(engine)});
|
||||
} else {
|
||||
alpha.add_assign(engine, &Fq2::one(engine));
|
||||
alpha = alpha.pow(engine, &engine.fqparams.modulus_minus_1_over_2);
|
||||
a1.mul_assign(engine, &alpha);
|
||||
}
|
||||
|
||||
Some(a1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Field<Bls381> for Fq2
|
||||
{
|
||||
fn zero() -> Self {
|
||||
Fq2 {
|
||||
c0: Fq::zero(),
|
||||
c1: Fq::zero()
|
||||
}
|
||||
}
|
||||
|
||||
fn one(engine: &Bls381) -> Self {
|
||||
Fq2 {
|
||||
c0: Fq::one(engine),
|
||||
c1: Fq::zero()
|
||||
}
|
||||
}
|
||||
|
||||
fn random<R: rand::Rng>(engine: &Bls381, rng: &mut R) -> Self {
|
||||
Fq2 {
|
||||
c0: Fq::random(engine, rng),
|
||||
c1: Fq::random(engine, rng)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.c0.is_zero() && self.c1.is_zero()
|
||||
}
|
||||
|
||||
fn double(&mut self, engine: &Bls381) {
|
||||
self.c0.double(engine);
|
||||
self.c1.double(engine);
|
||||
}
|
||||
|
||||
fn negate(&mut self, engine: &Bls381) {
|
||||
self.c0.negate(engine);
|
||||
self.c1.negate(engine);
|
||||
}
|
||||
|
||||
fn add_assign(&mut self, engine: &Bls381, other: &Self) {
|
||||
self.c0.add_assign(engine, &other.c0);
|
||||
self.c1.add_assign(engine, &other.c1);
|
||||
}
|
||||
|
||||
fn sub_assign(&mut self, engine: &Bls381, other: &Self) {
|
||||
self.c0.sub_assign(engine, &other.c0);
|
||||
self.c1.sub_assign(engine, &other.c1);
|
||||
}
|
||||
|
||||
fn frobenius_map(&mut self, e: &Bls381, power: usize)
|
||||
{
|
||||
self.c1.mul_assign(e, &e.frobenius_coeff_fq2[power % 2]);
|
||||
}
|
||||
|
||||
fn square(&mut self, engine: &Bls381) {
|
||||
let mut ab = self.c0;
|
||||
ab.mul_assign(engine, &self.c1);
|
||||
let mut c0c1 = self.c0;
|
||||
c0c1.add_assign(engine, &self.c1);
|
||||
let mut c0 = self.c1;
|
||||
c0.negate(engine);
|
||||
c0.add_assign(engine, &self.c0);
|
||||
c0.mul_assign(engine, &c0c1);
|
||||
c0.sub_assign(engine, &ab);
|
||||
self.c1 = ab;
|
||||
self.c1.add_assign(engine, &ab);
|
||||
c0.add_assign(engine, &ab);
|
||||
self.c0 = c0;
|
||||
}
|
||||
|
||||
fn mul_assign(&mut self, engine: &Bls381, other: &Self) {
|
||||
let mut aa = self.c0;
|
||||
aa.mul_assign(engine, &other.c0);
|
||||
let mut bb = self.c1;
|
||||
bb.mul_assign(engine, &other.c1);
|
||||
let mut o = other.c0;
|
||||
o.add_assign(engine, &other.c1);
|
||||
self.c1.add_assign(engine, &self.c0);
|
||||
self.c1.mul_assign(engine, &o);
|
||||
self.c1.sub_assign(engine, &aa);
|
||||
self.c1.sub_assign(engine, &bb);
|
||||
self.c0 = aa;
|
||||
self.c0.sub_assign(engine, &bb);
|
||||
}
|
||||
|
||||
fn inverse(&self, engine: &Bls381) -> Option<Self> {
|
||||
let mut t1 = self.c1;
|
||||
t1.square(engine);
|
||||
let mut t0 = self.c0;
|
||||
t0.square(engine);
|
||||
t0.add_assign(engine, &t1);
|
||||
t0.inverse(engine).map(|t| {
|
||||
let mut tmp = Fq2 {
|
||||
c0: self.c0,
|
||||
c1: self.c1
|
||||
};
|
||||
tmp.c0.mul_assign(engine, &t);
|
||||
tmp.c1.mul_assign(engine, &t);
|
||||
tmp.c1.negate(engine);
|
||||
|
||||
tmp
|
||||
})
|
||||
}
|
||||
}
|
@ -1,295 +0,0 @@
|
||||
use super::{Bls381, Fq2};
|
||||
use rand;
|
||||
use super::Field;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct Fq6 {
|
||||
pub c0: Fq2,
|
||||
pub c1: Fq2,
|
||||
pub c2: Fq2
|
||||
}
|
||||
|
||||
impl Fq6 {
|
||||
pub fn mul_by_nonresidue(&mut self, e: &Bls381) {
|
||||
use std::mem::swap;
|
||||
swap(&mut self.c0, &mut self.c1);
|
||||
swap(&mut self.c0, &mut self.c2);
|
||||
|
||||
self.c0.mul_by_nonresidue(e);
|
||||
}
|
||||
|
||||
pub fn mul_by_1(&mut self, e: &Bls381, c1: &Fq2)
|
||||
{
|
||||
let mut b_b = self.c1;
|
||||
b_b.mul_assign(e, c1);
|
||||
|
||||
let mut t1 = *c1;
|
||||
{
|
||||
let mut tmp = self.c1;
|
||||
tmp.add_assign(e, &self.c2);
|
||||
|
||||
t1.mul_assign(e, &tmp);
|
||||
t1.sub_assign(e, &b_b);
|
||||
t1.mul_by_nonresidue(e);
|
||||
}
|
||||
|
||||
let mut t2 = *c1;
|
||||
{
|
||||
let mut tmp = self.c0;
|
||||
tmp.add_assign(e, &self.c1);
|
||||
|
||||
t2.mul_assign(e, &tmp);
|
||||
t2.sub_assign(e, &b_b);
|
||||
}
|
||||
|
||||
self.c0 = t1;
|
||||
self.c1 = t2;
|
||||
self.c2 = b_b;
|
||||
}
|
||||
|
||||
pub fn mul_by_01(&mut self, e: &Bls381, c0: &Fq2, c1: &Fq2)
|
||||
{
|
||||
let mut a_a = self.c0;
|
||||
let mut b_b = self.c1;
|
||||
a_a.mul_assign(e, c0);
|
||||
b_b.mul_assign(e, c1);
|
||||
|
||||
let mut t1 = *c1;
|
||||
{
|
||||
let mut tmp = self.c1;
|
||||
tmp.add_assign(e, &self.c2);
|
||||
|
||||
t1.mul_assign(e, &tmp);
|
||||
t1.sub_assign(e, &b_b);
|
||||
t1.mul_by_nonresidue(e);
|
||||
t1.add_assign(e, &a_a);
|
||||
}
|
||||
|
||||
let mut t3 = *c0;
|
||||
{
|
||||
let mut tmp = self.c0;
|
||||
tmp.add_assign(e, &self.c2);
|
||||
|
||||
t3.mul_assign(e, &tmp);
|
||||
t3.sub_assign(e, &a_a);
|
||||
t3.add_assign(e, &b_b);
|
||||
}
|
||||
|
||||
let mut t2 = *c0;
|
||||
t2.add_assign(e, c1);
|
||||
{
|
||||
let mut tmp = self.c0;
|
||||
tmp.add_assign(e, &self.c1);
|
||||
|
||||
t2.mul_assign(e, &tmp);
|
||||
t2.sub_assign(e, &a_a);
|
||||
t2.sub_assign(e, &b_b);
|
||||
}
|
||||
|
||||
self.c0 = t1;
|
||||
self.c1 = t2;
|
||||
self.c2 = t3;
|
||||
}
|
||||
}
|
||||
|
||||
impl Field<Bls381> for Fq6
|
||||
{
|
||||
fn zero() -> Self {
|
||||
Fq6 {
|
||||
c0: Fq2::zero(),
|
||||
c1: Fq2::zero(),
|
||||
c2: Fq2::zero()
|
||||
}
|
||||
}
|
||||
|
||||
fn one(engine: &Bls381) -> Self {
|
||||
Fq6 {
|
||||
c0: Fq2::one(engine),
|
||||
c1: Fq2::zero(),
|
||||
c2: Fq2::zero()
|
||||
}
|
||||
}
|
||||
|
||||
fn random<R: rand::Rng>(engine: &Bls381, rng: &mut R) -> Self {
|
||||
Fq6 {
|
||||
c0: Fq2::random(engine, rng),
|
||||
c1: Fq2::random(engine, rng),
|
||||
c2: Fq2::random(engine, rng)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_zero(&self) -> bool {
|
||||
self.c0.is_zero() && self.c1.is_zero() && self.c2.is_zero()
|
||||
}
|
||||
|
||||
fn double(&mut self, engine: &Bls381) {
|
||||
self.c0.double(engine);
|
||||
self.c1.double(engine);
|
||||
self.c2.double(engine);
|
||||
}
|
||||
|
||||
fn negate(&mut self, engine: &Bls381) {
|
||||
self.c0.negate(engine);
|
||||
self.c1.negate(engine);
|
||||
self.c2.negate(engine);
|
||||
}
|
||||
|
||||
fn add_assign(&mut self, engine: &Bls381, other: &Self) {
|
||||
self.c0.add_assign(engine, &other.c0);
|
||||
self.c1.add_assign(engine, &other.c1);
|
||||
self.c2.add_assign(engine, &other.c2);
|
||||
}
|
||||
|
||||
fn sub_assign(&mut self, engine: &Bls381, other: &Self) {
|
||||
self.c0.sub_assign(engine, &other.c0);
|
||||
self.c1.sub_assign(engine, &other.c1);
|
||||
self.c2.sub_assign(engine, &other.c2);
|
||||
}
|
||||
|
||||
fn frobenius_map(&mut self, e: &Bls381, power: usize)
|
||||
{
|
||||
self.c0.frobenius_map(e, power);
|
||||
self.c1.frobenius_map(e, power);
|
||||
self.c2.frobenius_map(e, power);
|
||||
|
||||
self.c1.mul_assign(e, &e.frobenius_coeff_fq6_c1[power % 6]);
|
||||
self.c2.mul_assign(e, &e.frobenius_coeff_fq6_c2[power % 6]);
|
||||
}
|
||||
|
||||
fn square(&mut self, e: &Bls381) {
|
||||
let mut s0 = self.c0;
|
||||
s0.square(e);
|
||||
let mut ab = self.c0;
|
||||
ab.mul_assign(e, &self.c1);
|
||||
let mut s1 = ab;
|
||||
s1.double(e);
|
||||
let mut s2 = self.c0;
|
||||
s2.sub_assign(e, &self.c1);
|
||||
s2.add_assign(e, &self.c2);
|
||||
s2.square(e);
|
||||
let mut bc = self.c1;
|
||||
bc.mul_assign(e, &self.c2);
|
||||
let mut s3 = bc;
|
||||
s3.double(e);
|
||||
let mut s4 = self.c2;
|
||||
s4.square(e);
|
||||
|
||||
self.c0 = s3;
|
||||
self.c0.mul_by_nonresidue(e);
|
||||
self.c0.add_assign(e, &s0);
|
||||
|
||||
self.c1 = s4;
|
||||
self.c1.mul_by_nonresidue(e);
|
||||
self.c1.add_assign(e, &s1);
|
||||
|
||||
self.c2 = s1;
|
||||
self.c2.add_assign(e, &s2);
|
||||
self.c2.add_assign(e, &s3);
|
||||
self.c2.sub_assign(e, &s0);
|
||||
self.c2.sub_assign(e, &s4);
|
||||
}
|
||||
|
||||
fn mul_assign(&mut self, e: &Bls381, other: &Self) {
|
||||
let mut a_a = self.c0;
|
||||
let mut b_b = self.c1;
|
||||
let mut c_c = self.c2;
|
||||
a_a.mul_assign(e, &other.c0);
|
||||
b_b.mul_assign(e, &other.c1);
|
||||
c_c.mul_assign(e, &other.c2);
|
||||
|
||||
let mut t1 = other.c1;
|
||||
t1.add_assign(e, &other.c2);
|
||||
{
|
||||
let mut tmp = self.c1;
|
||||
tmp.add_assign(e, &self.c2);
|
||||
|
||||
t1.mul_assign(e, &tmp);
|
||||
t1.sub_assign(e, &b_b);
|
||||
t1.sub_assign(e, &c_c);
|
||||
t1.mul_by_nonresidue(e);
|
||||
t1.add_assign(e, &a_a);
|
||||
}
|
||||
|
||||
let mut t3 = other.c0;
|
||||
t3.add_assign(e, &other.c2);
|
||||
{
|
||||
let mut tmp = self.c0;
|
||||
tmp.add_assign(e, &self.c2);
|
||||
|
||||
t3.mul_assign(e, &tmp);
|
||||
t3.sub_assign(e, &a_a);
|
||||
t3.add_assign(e, &b_b);
|
||||
t3.sub_assign(e, &c_c);
|
||||
}
|
||||
|
||||
let mut t2 = other.c0;
|
||||
t2.add_assign(e, &other.c1);
|
||||
{
|
||||
let mut tmp = self.c0;
|
||||
tmp.add_assign(e, &self.c1);
|
||||
|
||||
t2.mul_assign(e, &tmp);
|
||||
t2.sub_assign(e, &a_a);
|
||||
t2.sub_assign(e, &b_b);
|
||||
c_c.mul_by_nonresidue(e);
|
||||
t2.add_assign(e, &c_c);
|
||||
}
|
||||
|
||||
self.c0 = t1;
|
||||
self.c1 = t2;
|
||||
self.c2 = t3;
|
||||
}
|
||||
|
||||
fn inverse(&self, e: &Bls381) -> Option<Self> {
|
||||
let mut c0 = self.c2;
|
||||
c0.mul_by_nonresidue(e);
|
||||
c0.mul_assign(e, &self.c1);
|
||||
c0.negate(e);
|
||||
{
|
||||
let mut c0s = self.c0;
|
||||
c0s.square(e);
|
||||
c0.add_assign(e, &c0s);
|
||||
}
|
||||
let mut c1 = self.c2;
|
||||
c1.square(e);
|
||||
c1.mul_by_nonresidue(e);
|
||||
{
|
||||
let mut c01 = self.c0;
|
||||
c01.mul_assign(e, &self.c1);
|
||||
c1.sub_assign(e, &c01);
|
||||
}
|
||||
let mut c2 = self.c1;
|
||||
c2.square(e);
|
||||
{
|
||||
let mut c02 = self.c0;
|
||||
c02.mul_assign(e, &self.c2);
|
||||
c2.sub_assign(e, &c02);
|
||||
}
|
||||
|
||||
let mut tmp1 = self.c2;
|
||||
tmp1.mul_assign(e, &c1);
|
||||
let mut tmp2 = self.c1;
|
||||
tmp2.mul_assign(e, &c2);
|
||||
tmp1.add_assign(e, &tmp2);
|
||||
tmp1.mul_by_nonresidue(e);
|
||||
tmp2 = self.c0;
|
||||
tmp2.mul_assign(e, &c0);
|
||||
tmp1.add_assign(e, &tmp2);
|
||||
|
||||
match tmp1.inverse(e) {
|
||||
Some(t) => {
|
||||
let mut tmp = Fq6 {
|
||||
c0: t,
|
||||
c1: t,
|
||||
c2: t
|
||||
};
|
||||
tmp.c0.mul_assign(e, &c0);
|
||||
tmp.c1.mul_assign(e, &c1);
|
||||
tmp.c2.mul_assign(e, &c2);
|
||||
|
||||
Some(tmp)
|
||||
},
|
||||
None => None
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
@ -1,41 +0,0 @@
|
||||
extern crate bincode;
|
||||
|
||||
use curves::*;
|
||||
use super::*;
|
||||
|
||||
fn test_vectors<E: Engine, G: Curve<E>>(e: &E, expected: &[u8]) {
|
||||
let mut bytes = vec![];
|
||||
let mut acc = G::zero(e);
|
||||
let mut expected_reader = expected;
|
||||
|
||||
for _ in 0..10000 {
|
||||
{
|
||||
let acc = acc.to_affine(e);
|
||||
let exp: <G::Affine as CurveAffine<E>>::Uncompressed =
|
||||
bincode::deserialize_from(&mut expected_reader, bincode::Infinite).unwrap();
|
||||
|
||||
assert!(acc == exp.to_affine(e).unwrap());
|
||||
|
||||
let acc = acc.to_uncompressed(e);
|
||||
bincode::serialize_into(&mut bytes, &acc, bincode::Infinite).unwrap();
|
||||
}
|
||||
acc.double(e);
|
||||
acc.add_assign(e, &G::one(e));
|
||||
}
|
||||
|
||||
assert_eq!(&bytes[..], expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn g1_serialization_test_vectors() {
|
||||
let engine = Bls381::new();
|
||||
|
||||
test_vectors::<Bls381, G1>(&engine, include_bytes!("g1_serialized.bin"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn g2_serialization_test_vectors() {
|
||||
let engine = Bls381::new();
|
||||
|
||||
test_vectors::<Bls381, G2>(&engine, include_bytes!("g2_serialized.bin"));
|
||||
}
|
@ -1,374 +0,0 @@
|
||||
use super::{Engine, Field, SnarkField, PrimeField, Group};
|
||||
use crossbeam;
|
||||
use num_cpus;
|
||||
|
||||
pub struct EvaluationDomain<E: Engine> {
|
||||
pub m: u64,
|
||||
exp: u64,
|
||||
omega: E::Fr,
|
||||
omegainv: E::Fr,
|
||||
geninv: E::Fr,
|
||||
minv: E::Fr
|
||||
}
|
||||
|
||||
impl<E: Engine> EvaluationDomain<E> {
|
||||
pub fn new(e: &E, needed: u64) -> Self {
|
||||
if needed > 268435456 {
|
||||
panic!("circuit depths larger than 2^28 are not supported");
|
||||
}
|
||||
|
||||
let mut m = 1;
|
||||
let mut exp = 0;
|
||||
while m < needed {
|
||||
m *= 2;
|
||||
exp += 1;
|
||||
|
||||
assert!(exp < E::Fr::s(e));
|
||||
}
|
||||
|
||||
let mut omega = E::Fr::root_of_unity(e);
|
||||
for _ in exp..E::Fr::s(e) {
|
||||
omega.square(e);
|
||||
}
|
||||
|
||||
EvaluationDomain {
|
||||
m: m,
|
||||
exp: exp,
|
||||
omega: omega,
|
||||
omegainv: omega.inverse(e).unwrap(),
|
||||
geninv: E::Fr::multiplicative_generator(e).inverse(e).unwrap(),
|
||||
minv: E::Fr::from_u64(e, m).inverse(e).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn z(&self, e: &E, tau: &E::Fr) -> E::Fr {
|
||||
let mut tmp = tau.pow(e, &[self.m]);
|
||||
tmp.sub_assign(e, &E::Fr::one(e));
|
||||
|
||||
tmp
|
||||
}
|
||||
|
||||
pub fn ifft<T: Group<E>>(&self, e: &E, v: &mut [T])
|
||||
{
|
||||
assert!(v.len() == self.m as usize);
|
||||
best_fft(e, v, &self.omegainv, self.exp);
|
||||
|
||||
let chunk = (v.len() / num_cpus::get()) + 1;
|
||||
|
||||
crossbeam::scope(|scope| {
|
||||
for v in v.chunks_mut(chunk) {
|
||||
scope.spawn(move || {
|
||||
for v in v {
|
||||
v.group_mul_assign(e, &self.minv);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn mul_coset(&self, e: &E, v: &mut [E::Fr], g: &E::Fr)
|
||||
{
|
||||
let chunk = (v.len() / num_cpus::get()) + 1;
|
||||
|
||||
crossbeam::scope(|scope| {
|
||||
for (i, v) in v.chunks_mut(chunk).enumerate() {
|
||||
scope.spawn(move || {
|
||||
let mut u = g.pow(e, &[(i * chunk) as u64]);
|
||||
for v in v.iter_mut() {
|
||||
v.mul_assign(e, &u);
|
||||
u.mul_assign(e, g);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn coset_fft(&self, e: &E, v: &mut [E::Fr])
|
||||
{
|
||||
self.mul_coset(e, v, &E::Fr::multiplicative_generator(e));
|
||||
self.fft(e, v);
|
||||
}
|
||||
|
||||
pub fn icoset_fft(&self, e: &E, v: &mut [E::Fr])
|
||||
{
|
||||
self.ifft(e, v);
|
||||
self.mul_coset(e, v, &self.geninv);
|
||||
}
|
||||
|
||||
pub fn divide_by_z_on_coset(&self, e: &E, v: &mut [E::Fr])
|
||||
{
|
||||
let i = self.z(e, &E::Fr::multiplicative_generator(e)).inverse(e).unwrap();
|
||||
|
||||
let chunk = (v.len() / num_cpus::get()) + 1;
|
||||
|
||||
crossbeam::scope(|scope| {
|
||||
for v in v.chunks_mut(chunk) {
|
||||
scope.spawn(move || {
|
||||
for v in v {
|
||||
v.mul_assign(e, &i);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn mul_assign(&self, e: &E, a: &mut [E::Fr], b: Vec<E::Fr>) {
|
||||
assert_eq!(a.len(), b.len());
|
||||
|
||||
let chunk = (a.len() / num_cpus::get()) + 1;
|
||||
|
||||
crossbeam::scope(|scope| {
|
||||
for (a, b) in a.chunks_mut(chunk).zip(b.chunks(chunk)) {
|
||||
scope.spawn(move || {
|
||||
for (a, b) in a.iter_mut().zip(b.iter()) {
|
||||
a.mul_assign(e, b);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn sub_assign(&self, e: &E, a: &mut [E::Fr], b: Vec<E::Fr>) {
|
||||
assert_eq!(a.len(), b.len());
|
||||
|
||||
let chunk = (a.len() / num_cpus::get()) + 1;
|
||||
|
||||
crossbeam::scope(|scope| {
|
||||
for (a, b) in a.chunks_mut(chunk).zip(b.chunks(chunk)) {
|
||||
scope.spawn(move || {
|
||||
for (a, b) in a.iter_mut().zip(b.iter()) {
|
||||
a.sub_assign(e, b);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn fft<T: Group<E>>(&self, e: &E, a: &mut [T])
|
||||
{
|
||||
best_fft(e, a, &self.omega, self.exp);
|
||||
}
|
||||
}
|
||||
|
||||
fn best_fft<E: Engine, T: Group<E>>(e: &E, a: &mut [T], omega: &E::Fr, log_n: u64)
|
||||
{
|
||||
let log_cpus = get_log_cpus();
|
||||
|
||||
if log_n < log_cpus {
|
||||
serial_fft(e, a, omega, log_n);
|
||||
} else {
|
||||
parallel_fft(e, a, omega, log_n, log_cpus);
|
||||
}
|
||||
}
|
||||
|
||||
fn parallel_fft<E: Engine, T: Group<E>>(e: &E, a: &mut [T], omega: &E::Fr, log_n: u64, log_cpus: u64)
|
||||
{
|
||||
assert!(log_n >= log_cpus);
|
||||
|
||||
let num_cpus = 1 << log_cpus;
|
||||
let log_new_n = log_n - log_cpus;
|
||||
let mut tmp = vec![vec![T::group_zero(e); 1 << log_new_n]; num_cpus];
|
||||
let omega_num_cpus = omega.pow(e, &[num_cpus as u64]);
|
||||
|
||||
crossbeam::scope(|scope| {
|
||||
let a = &*a;
|
||||
|
||||
for (j, tmp) in tmp.iter_mut().enumerate() {
|
||||
scope.spawn(move || {
|
||||
let omega_j = omega.pow(e, &[j as u64]);
|
||||
let omega_step = omega.pow(e, &[(j as u64) << log_new_n]);
|
||||
|
||||
let mut elt = E::Fr::one(e);
|
||||
for i in 0..(1 << log_new_n) {
|
||||
for s in 0..num_cpus {
|
||||
let idx = (i + (s << log_new_n)) % (1 << log_n);
|
||||
let mut t = a[idx];
|
||||
t.group_mul_assign(e, &elt);
|
||||
tmp[i].group_add_assign(e, &t);
|
||||
elt.mul_assign(e, &omega_step);
|
||||
}
|
||||
elt.mul_assign(e, &omega_j);
|
||||
}
|
||||
|
||||
serial_fft(e, tmp, &omega_num_cpus, log_new_n);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let chunk = (a.len() / num_cpus) + 1;
|
||||
|
||||
crossbeam::scope(|scope| {
|
||||
let tmp = &tmp;
|
||||
|
||||
for (idx, a) in a.chunks_mut(chunk).enumerate() {
|
||||
scope.spawn(move || {
|
||||
let mut idx = idx * chunk;
|
||||
let mask = (1 << log_cpus) - 1;
|
||||
for a in a {
|
||||
*a = tmp[idx & mask][idx >> log_cpus];
|
||||
idx += 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn serial_fft<E: Engine, T: Group<E>>(e: &E, a: &mut [T], omega: &E::Fr, log_n: u64)
|
||||
{
|
||||
fn bitreverse(mut n: usize, l: u64) -> usize {
|
||||
let mut r = 0;
|
||||
for _ in 0..l {
|
||||
r = (r << 1) | (n & 1);
|
||||
n >>= 1;
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
let n = a.len();
|
||||
assert_eq!(n, 1 << log_n);
|
||||
|
||||
for k in 0..n {
|
||||
let rk = bitreverse(k, log_n);
|
||||
if k < rk {
|
||||
let tmp1 = a[rk];
|
||||
let tmp2 = a[k];
|
||||
a[rk] = tmp2;
|
||||
a[k] = tmp1;
|
||||
}
|
||||
}
|
||||
|
||||
let mut m = 1;
|
||||
for _ in 0..log_n {
|
||||
let w_m = omega.pow(e, &[(n / (2*m)) as u64]);
|
||||
|
||||
let mut k = 0;
|
||||
while k < n {
|
||||
let mut w = E::Fr::one(e);
|
||||
for j in 0..m {
|
||||
let mut t = a[(k+j+m) as usize];
|
||||
t.group_mul_assign(e, &w);
|
||||
let mut tmp = a[(k+j) as usize];
|
||||
tmp.group_sub_assign(e, &t);
|
||||
a[(k+j+m) as usize] = tmp;
|
||||
a[(k+j) as usize].group_add_assign(e, &t);
|
||||
w.mul_assign(e, &w_m);
|
||||
}
|
||||
|
||||
k += 2*m;
|
||||
}
|
||||
|
||||
m *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Test multiplying various (low degree) polynomials together and
|
||||
// comparing with naive evaluations.
|
||||
#[test]
|
||||
fn polynomial_arith() {
|
||||
use curves::*;
|
||||
use curves::bls381::Bls381;
|
||||
use rand;
|
||||
|
||||
fn test_mul<E: Engine, R: rand::Rng>(e: &E, rng: &mut R)
|
||||
{
|
||||
for coeffs_a in 1..70 {
|
||||
for coeffs_b in 1..70 {
|
||||
let final_degree = coeffs_a + coeffs_b - 1;
|
||||
|
||||
let domain = EvaluationDomain::new(e, final_degree as u64);
|
||||
let mut a: Vec<_> = (0..coeffs_a).map(|_| E::Fr::random(e, rng)).collect();
|
||||
let mut b: Vec<_> = (0..coeffs_b).map(|_| E::Fr::random(e, rng)).collect();
|
||||
|
||||
// naive evaluation
|
||||
let mut naive = vec![E::Fr::zero(); domain.m as usize];
|
||||
for (i1, a) in a.iter().enumerate() {
|
||||
for (i2, b) in b.iter().enumerate() {
|
||||
let mut prod = *a;
|
||||
prod.mul_assign(e, b);
|
||||
naive[i1 + i2].add_assign(e, &prod);
|
||||
}
|
||||
}
|
||||
|
||||
a.resize(domain.m as usize, E::Fr::zero());
|
||||
b.resize(domain.m as usize, E::Fr::zero());
|
||||
let mut c = vec![];
|
||||
c.resize(domain.m as usize, E::Fr::zero());
|
||||
|
||||
domain.fft(e, &mut a);
|
||||
domain.fft(e, &mut b);
|
||||
|
||||
for ((a, b), c) in a.iter().zip(b.iter()).zip(c.iter_mut()) {
|
||||
*c = *a;
|
||||
c.mul_assign(e, b);
|
||||
}
|
||||
|
||||
domain.ifft(e, &mut c);
|
||||
|
||||
for (naive, fft) in naive.iter().zip(c.iter()) {
|
||||
assert_eq!(naive, fft);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let e = &Bls381::new();
|
||||
let rng = &mut rand::thread_rng();
|
||||
|
||||
test_mul(e, rng);
|
||||
}
|
||||
|
||||
fn get_log_cpus() -> u64 {
|
||||
let num = num_cpus::get();
|
||||
log2_floor(num)
|
||||
}
|
||||
|
||||
fn log2_floor(num: usize) -> u64 {
|
||||
assert!(num > 0);
|
||||
|
||||
let mut pow = 0;
|
||||
|
||||
while (1 << (pow+1)) <= num {
|
||||
pow += 1;
|
||||
}
|
||||
|
||||
pow
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_log2_floor() {
|
||||
assert_eq!(log2_floor(1), 0);
|
||||
assert_eq!(log2_floor(2), 1);
|
||||
assert_eq!(log2_floor(3), 1);
|
||||
assert_eq!(log2_floor(4), 2);
|
||||
assert_eq!(log2_floor(5), 2);
|
||||
assert_eq!(log2_floor(6), 2);
|
||||
assert_eq!(log2_floor(7), 2);
|
||||
assert_eq!(log2_floor(8), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parallel_fft_consistency() {
|
||||
use curves::*;
|
||||
use curves::bls381::{Bls381, Fr};
|
||||
use std::cmp::min;
|
||||
use rand;
|
||||
|
||||
let e = &Bls381::new();
|
||||
let rng = &mut rand::thread_rng();
|
||||
|
||||
for log_d in 0..10 {
|
||||
let d = 1 << log_d;
|
||||
let domain = EvaluationDomain::new(e, d);
|
||||
assert_eq!(domain.m, d);
|
||||
|
||||
for log_cpus in 0..min(log_d, 3) {
|
||||
let mut v1 = (0..d).map(|_| Fr::random(e, rng)).collect::<Vec<_>>();
|
||||
let mut v2 = v1.clone();
|
||||
|
||||
parallel_fft(e, &mut v1, &domain.omega, log_d, log_cpus);
|
||||
serial_fft(e, &mut v2, &domain.omega, log_d);
|
||||
|
||||
assert_eq!(v1, v2);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,258 +0,0 @@
|
||||
use rand;
|
||||
use std::fmt;
|
||||
|
||||
use std::borrow::Borrow;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use super::BitIterator;
|
||||
|
||||
use super::{Cow, Convert};
|
||||
|
||||
pub mod bls381;
|
||||
pub mod multiexp;
|
||||
pub mod wnaf;
|
||||
pub mod domain;
|
||||
|
||||
pub trait Engine: Sized + Clone + Send + Sync
|
||||
{
|
||||
type Fq: PrimeField<Self> + Convert<<Self::Fq as PrimeField<Self>>::Repr, Self>;
|
||||
type Fr: SnarkField<Self> + Convert<<Self::Fr as PrimeField<Self>>::Repr, Self>;
|
||||
type Fqe: SqrtField<Self>;
|
||||
type Fqk: Field<Self>;
|
||||
type G1: Curve<Self> + Convert<<Self::G1 as Curve<Self>>::Affine, Self>;
|
||||
type G2: Curve<Self> + Convert<<Self::G2 as Curve<Self>>::Affine, Self>;
|
||||
|
||||
fn new() -> Self;
|
||||
|
||||
/// Operate over the thread-local engine instance
|
||||
fn with<R, F: for<'a> FnOnce(&'a Self) -> R>(F) -> R;
|
||||
|
||||
fn pairing<G1, G2>(&self, p: &G1, q: &G2) -> Self::Fqk
|
||||
where G1: Convert<<Self::G1 as Curve<Self>>::Affine, Self>,
|
||||
G2: Convert<<Self::G2 as Curve<Self>>::Affine, Self>
|
||||
{
|
||||
self.final_exponentiation(&self.miller_loop(
|
||||
[(
|
||||
&(*p.convert(self)).borrow().prepare(self),
|
||||
&(*q.convert(self)).borrow().prepare(self)
|
||||
)].into_iter()
|
||||
))
|
||||
}
|
||||
fn miller_loop<'a, I>(&self, I) -> Self::Fqk
|
||||
where I: IntoIterator<Item=&'a (
|
||||
&'a <Self::G1 as Curve<Self>>::Prepared,
|
||||
&'a <Self::G2 as Curve<Self>>::Prepared
|
||||
)>;
|
||||
fn final_exponentiation(&self, &Self::Fqk) -> Self::Fqk;
|
||||
|
||||
/// Perform multi-exponentiation. g and s must have the same length.
|
||||
fn multiexp<G: Curve<Self>>(&self, g: &[G::Affine], s: &[Self::Fr]) -> Result<G, ()>;
|
||||
fn batch_baseexp<G: Curve<Self>, S: AsRef<[Self::Fr]>>(&self, table: &wnaf::WindowTable<Self, G>, scalars: S) -> Vec<G::Affine>;
|
||||
|
||||
fn batchexp<G: Curve<Self>, S: AsRef<[Self::Fr]>>(&self, g: &mut [G::Affine], scalars: S, coeff: Option<&Self::Fr>);
|
||||
}
|
||||
|
||||
pub trait Group<E: Engine>: Copy + Send + Sync + Sized
|
||||
{
|
||||
fn group_zero(&E) -> Self;
|
||||
fn group_mul_assign(&mut self, &E, scalar: &E::Fr);
|
||||
fn group_add_assign(&mut self, &E, other: &Self);
|
||||
fn group_sub_assign(&mut self, &E, other: &Self);
|
||||
}
|
||||
|
||||
pub trait Curve<E: Engine>: Sized +
|
||||
Copy +
|
||||
Clone +
|
||||
Send +
|
||||
Sync +
|
||||
fmt::Debug +
|
||||
'static +
|
||||
Group<E> +
|
||||
self::multiexp::Projective<E>
|
||||
{
|
||||
type Affine: CurveAffine<E, Jacobian=Self>;
|
||||
type Prepared: Clone + Send + Sync + 'static;
|
||||
|
||||
fn zero(&E) -> Self;
|
||||
fn one(&E) -> Self;
|
||||
fn random<R: rand::Rng>(&E, &mut R) -> Self;
|
||||
|
||||
fn is_zero(&self) -> bool;
|
||||
fn is_equal(&self, &E, other: &Self) -> bool;
|
||||
|
||||
fn to_affine(&self, &E) -> Self::Affine;
|
||||
fn prepare(&self, &E) -> Self::Prepared;
|
||||
|
||||
fn double(&mut self, &E);
|
||||
fn negate(&mut self, engine: &E);
|
||||
fn add_assign(&mut self, &E, other: &Self);
|
||||
fn sub_assign(&mut self, &E, other: &Self);
|
||||
fn add_assign_mixed(&mut self, &E, other: &Self::Affine);
|
||||
fn mul_assign<S: Convert<<E::Fr as PrimeField<E>>::Repr, E>>(&mut self, &E, other: &S);
|
||||
|
||||
fn optimal_window(&E, scalar_bits: usize) -> Option<usize>;
|
||||
fn optimal_window_batch(&self, &E, scalars: usize) -> wnaf::WindowTable<E, Self>;
|
||||
|
||||
/// Performs optimal exponentiation of this curve element given the scalar, using
|
||||
/// wNAF when necessary.
|
||||
fn optimal_exp(
|
||||
&self,
|
||||
e: &E,
|
||||
scalar: <E::Fr as PrimeField<E>>::Repr,
|
||||
table: &mut wnaf::WindowTable<E, Self>,
|
||||
scratch: &mut wnaf::WNAFTable
|
||||
) -> Self {
|
||||
let bits = scalar.num_bits();
|
||||
match Self::optimal_window(e, bits) {
|
||||
Some(window) => {
|
||||
table.set_base(e, *self, window);
|
||||
scratch.set_scalar(table, scalar);
|
||||
table.exp(e, scratch)
|
||||
},
|
||||
None => {
|
||||
let mut tmp = *self;
|
||||
tmp.mul_assign(e, &scalar);
|
||||
tmp
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CurveAffine<E: Engine>: Copy +
|
||||
Clone +
|
||||
Sized +
|
||||
Send +
|
||||
Sync +
|
||||
fmt::Debug +
|
||||
PartialEq +
|
||||
Eq +
|
||||
'static
|
||||
{
|
||||
type Jacobian: Curve<E, Affine=Self>;
|
||||
type Uncompressed: CurveRepresentation<E, Affine=Self>;
|
||||
|
||||
fn to_jacobian(&self, &E) -> Self::Jacobian;
|
||||
fn prepare(self, &E) -> <Self::Jacobian as Curve<E>>::Prepared;
|
||||
fn is_zero(&self) -> bool;
|
||||
fn mul<S: Convert<<E::Fr as PrimeField<E>>::Repr, E>>(&self, &E, other: &S) -> Self::Jacobian;
|
||||
fn negate(&mut self, &E);
|
||||
|
||||
/// Returns true iff the point is on the curve and in the correct
|
||||
/// subgroup. This is guaranteed to return true unless the user
|
||||
/// invokes `to_affine_unchecked`.
|
||||
fn is_valid(&self, &E) -> bool;
|
||||
|
||||
/// Produces an "uncompressed" representation of the curve point according
|
||||
/// to IEEE standards.
|
||||
fn to_uncompressed(&self, &E) -> Self::Uncompressed;
|
||||
}
|
||||
|
||||
pub trait CurveRepresentation<E: Engine>: Serialize + for<'a> Deserialize<'a>
|
||||
{
|
||||
type Affine: CurveAffine<E>;
|
||||
|
||||
/// If the point representation is valid (lies on the curve, correct
|
||||
/// subgroup) this function will return it.
|
||||
fn to_affine(&self, e: &E) -> Result<Self::Affine, ()> {
|
||||
let p = try!(self.to_affine_unchecked(e));
|
||||
|
||||
if p.is_valid(e) {
|
||||
Ok(p)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the point under the assumption that it is valid. Undefined
|
||||
/// behavior if `to_affine` would have rejected the point.
|
||||
fn to_affine_unchecked(&self, &E) -> Result<Self::Affine, ()>;
|
||||
}
|
||||
|
||||
pub trait Field<E: Engine>: Sized +
|
||||
Eq +
|
||||
PartialEq +
|
||||
Copy +
|
||||
Clone +
|
||||
Send +
|
||||
Sync +
|
||||
fmt::Debug +
|
||||
'static
|
||||
{
|
||||
fn zero() -> Self;
|
||||
fn one(&E) -> Self;
|
||||
fn random<R: rand::Rng>(&E, &mut R) -> Self;
|
||||
fn is_zero(&self) -> bool;
|
||||
fn square(&mut self, engine: &E);
|
||||
fn double(&mut self, engine: &E);
|
||||
fn negate(&mut self, &E);
|
||||
fn add_assign(&mut self, &E, other: &Self);
|
||||
fn sub_assign(&mut self, &E, other: &Self);
|
||||
fn mul_assign(&mut self, &E, other: &Self);
|
||||
fn inverse(&self, &E) -> Option<Self>;
|
||||
fn frobenius_map(&mut self, &E, power: usize);
|
||||
fn pow<S: AsRef<[u64]>>(&self, engine: &E, exp: S) -> Self
|
||||
{
|
||||
let mut res = Self::one(engine);
|
||||
|
||||
for i in BitIterator::new(exp) {
|
||||
res.square(engine);
|
||||
if i {
|
||||
res.mul_assign(engine, self);
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SqrtField<E: Engine>: Field<E>
|
||||
{
|
||||
/// Returns a square root of the field element, if it is
|
||||
/// quadratic residue.
|
||||
fn sqrt(&self, engine: &E) -> Option<Self>;
|
||||
}
|
||||
|
||||
pub trait PrimeFieldRepr: Clone + Eq + Ord + AsRef<[u64]> {
|
||||
fn from_u64(a: u64) -> Self;
|
||||
fn sub_noborrow(&mut self, other: &Self);
|
||||
fn add_nocarry(&mut self, other: &Self);
|
||||
fn num_bits(&self) -> usize;
|
||||
fn is_zero(&self) -> bool;
|
||||
fn is_odd(&self) -> bool;
|
||||
fn div2(&mut self);
|
||||
}
|
||||
|
||||
pub trait PrimeField<E: Engine>: SqrtField<E>
|
||||
{
|
||||
type Repr: PrimeFieldRepr;
|
||||
|
||||
fn from_u64(&E, u64) -> Self;
|
||||
fn from_str(&E, s: &str) -> Result<Self, ()>;
|
||||
fn from_repr(&E, Self::Repr) -> Result<Self, ()>;
|
||||
fn into_repr(&self, &E) -> Self::Repr;
|
||||
|
||||
/// Returns the field characteristic; the modulus.
|
||||
fn char(&E) -> Self::Repr;
|
||||
|
||||
/// Returns how many bits are needed to represent an element of this
|
||||
/// field.
|
||||
fn num_bits(&E) -> usize;
|
||||
|
||||
/// Returns how many bits of information can be reliably stored in the
|
||||
/// field element.
|
||||
fn capacity(&E) -> usize;
|
||||
}
|
||||
|
||||
pub trait SnarkField<E: Engine>: PrimeField<E> + Group<E>
|
||||
{
|
||||
fn s(&E) -> u64;
|
||||
fn multiplicative_generator(&E) -> Self;
|
||||
fn root_of_unity(&E) -> Self;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[test]
|
||||
fn bls381_test_suite() {
|
||||
tests::test_engine::<bls381::Bls381>();
|
||||
}
|
@ -1,232 +0,0 @@
|
||||
//! This module provides an abstract implementation of the Bos-Coster multi-exponentiation algorithm.
|
||||
|
||||
use super::{Engine, Curve, CurveAffine, Field, PrimeField, PrimeFieldRepr};
|
||||
use super::wnaf;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::BinaryHeap;
|
||||
|
||||
pub trait Projective<E: Engine>: Sized + Copy + Clone + Send {
|
||||
type WindowTable;
|
||||
|
||||
/// Constructs an identity element.
|
||||
fn identity(e: &E) -> Self;
|
||||
|
||||
/// Adds this projective element to another projective element.
|
||||
fn add_to_projective(&self, e: &E, projective: &mut Self);
|
||||
|
||||
/// Exponentiates by a scalar.
|
||||
fn exponentiate(
|
||||
&mut self,
|
||||
e: &E,
|
||||
scalar: <E::Fr as PrimeField<E>>::Repr,
|
||||
table: &mut Self::WindowTable,
|
||||
scratch: &mut wnaf::WNAFTable
|
||||
);
|
||||
|
||||
/// Construct a blank window table
|
||||
fn new_window_table(e: &E) -> Self::WindowTable;
|
||||
}
|
||||
|
||||
pub trait Chunk<E: Engine>: Send {
|
||||
type Projective: Projective<E>;
|
||||
|
||||
/// Skips the next element from the source.
|
||||
fn skip(&mut self, e: &E) -> Result<(), ()>;
|
||||
|
||||
/// Adds the next element from the source to a projective element
|
||||
fn add_to_projective(&mut self, e: &E, acc: &mut Self::Projective) -> Result<(), ()>;
|
||||
|
||||
/// Turns the next element of the source into a projective element.
|
||||
fn into_projective(&mut self, e: &E) -> Result<Self::Projective, ()>;
|
||||
}
|
||||
|
||||
/// An `ElementSource` is something that contains a sequence of group elements or
|
||||
/// group element tuples.
|
||||
pub trait ElementSource<E: Engine> {
|
||||
type Chunk: Chunk<E>;
|
||||
|
||||
/// Gets the number of elements from the source.
|
||||
fn num_elements(&self) -> usize;
|
||||
|
||||
/// Returns a chunk size and a vector of chunks.
|
||||
fn chunks(&mut self, chunks: usize) -> (usize, Vec<Self::Chunk>);
|
||||
}
|
||||
|
||||
impl<'a, E: Engine, G: CurveAffine<E>> ElementSource<E> for &'a [G] {
|
||||
type Chunk = &'a [G];
|
||||
|
||||
fn num_elements(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
|
||||
fn chunks(&mut self, chunks: usize) -> (usize, Vec<Self::Chunk>) {
|
||||
let chunk_size = (self.len() / chunks) + 1;
|
||||
|
||||
(chunk_size, (*self).chunks(chunk_size).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: Engine, G: CurveAffine<E>> Chunk<E> for &'a [G]
|
||||
{
|
||||
type Projective = G::Jacobian;
|
||||
|
||||
fn skip(&mut self, _: &E) -> Result<(), ()> {
|
||||
if self.len() == 0 {
|
||||
Err(())
|
||||
} else {
|
||||
*self = &self[1..];
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds the next element from the source to a projective element
|
||||
fn add_to_projective(&mut self, e: &E, acc: &mut Self::Projective) -> Result<(), ()> {
|
||||
if self.len() == 0 {
|
||||
Err(())
|
||||
} else {
|
||||
acc.add_assign_mixed(e, &self[0]);
|
||||
*self = &self[1..];
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Turns the next element of the accumulator into a projective element.
|
||||
fn into_projective(&mut self, e: &E) -> Result<Self::Projective, ()> {
|
||||
if self.len() == 0 {
|
||||
Err(())
|
||||
} else {
|
||||
let ret = Ok(self[0].to_jacobian(e));
|
||||
*self = &self[1..];
|
||||
ret
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn justexp<E: Engine>(
|
||||
largest: &<E::Fr as PrimeField<E>>::Repr,
|
||||
smallest: &<E::Fr as PrimeField<E>>::Repr
|
||||
) -> bool
|
||||
{
|
||||
use std::cmp::min;
|
||||
|
||||
let abits = largest.num_bits();
|
||||
let bbits = smallest.num_bits();
|
||||
let limit = min(abits-bbits, 20);
|
||||
|
||||
if bbits < (1<<limit) {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn perform_multiexp<E: Engine, Source: ElementSource<E>>(
|
||||
e: &E,
|
||||
mut bases: Source,
|
||||
scalars: &[E::Fr]
|
||||
) -> Result<<Source::Chunk as Chunk<E>>::Projective, ()>
|
||||
{
|
||||
if bases.num_elements() != scalars.len() {
|
||||
return Err(())
|
||||
}
|
||||
|
||||
use crossbeam;
|
||||
use num_cpus;
|
||||
|
||||
let (chunk_len, bases) = bases.chunks(num_cpus::get());
|
||||
|
||||
return crossbeam::scope(|scope| {
|
||||
let mut threads = vec![];
|
||||
|
||||
for (mut chunk, scalars) in bases.into_iter().zip(scalars.chunks(chunk_len)) {
|
||||
threads.push(scope.spawn(move || {
|
||||
let mut heap: BinaryHeap<Exp<E>> = BinaryHeap::with_capacity(scalars.len());
|
||||
let mut elements = Vec::with_capacity(scalars.len());
|
||||
|
||||
let mut acc = Projective::<E>::identity(e);
|
||||
let one = E::Fr::one(e);
|
||||
|
||||
for scalar in scalars {
|
||||
if scalar.is_zero() {
|
||||
// Skip processing bases when we're multiplying by a zero anyway.
|
||||
chunk.skip(e)?;
|
||||
} else if *scalar == one {
|
||||
// Just perform mixed addition when we're multiplying by one.
|
||||
chunk.add_to_projective(e, &mut acc)?;
|
||||
} else {
|
||||
elements.push(chunk.into_projective(e)?);
|
||||
heap.push(Exp {
|
||||
scalar: scalar.into_repr(e),
|
||||
index: elements.len() - 1
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let mut window = <<Source::Chunk as Chunk<E>>::Projective as Projective<E>>::new_window_table(e);
|
||||
let mut scratch = wnaf::WNAFTable::new();
|
||||
|
||||
// Now that the heap is populated...
|
||||
while let Some(mut greatest) = heap.pop() {
|
||||
{
|
||||
let second_greatest = heap.peek();
|
||||
if second_greatest.is_none() || justexp::<E>(&greatest.scalar, &second_greatest.unwrap().scalar) {
|
||||
// Either this is the last value or multiplying is considered more efficient than
|
||||
// rewriting and reinsertion into the heap.
|
||||
//opt_exp(engine, &mut elements[greatest.index], greatest.scalar, &mut table);
|
||||
elements[greatest.index].exponentiate(e, greatest.scalar, &mut window, &mut scratch);
|
||||
elements[greatest.index].add_to_projective(e, &mut acc);
|
||||
continue;
|
||||
} else {
|
||||
// Rewrite
|
||||
let second_greatest = second_greatest.unwrap();
|
||||
|
||||
greatest.scalar.sub_noborrow(&second_greatest.scalar);
|
||||
let mut tmp = elements[second_greatest.index];
|
||||
elements[greatest.index].add_to_projective(e, &mut tmp);
|
||||
elements[second_greatest.index] = tmp;
|
||||
}
|
||||
}
|
||||
if !greatest.scalar.is_zero() {
|
||||
// Reinsert only nonzero scalars.
|
||||
heap.push(greatest);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(acc)
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
let mut acc = Projective::<E>::identity(e);
|
||||
for t in threads {
|
||||
t.join()?.add_to_projective(e, &mut acc);
|
||||
}
|
||||
|
||||
Ok(acc)
|
||||
})
|
||||
}
|
||||
|
||||
struct Exp<E: Engine> {
|
||||
scalar: <E::Fr as PrimeField<E>>::Repr,
|
||||
index: usize
|
||||
}
|
||||
|
||||
impl<E: Engine> Ord for Exp<E> {
|
||||
fn cmp(&self, other: &Exp<E>) -> Ordering {
|
||||
self.scalar.cmp(&other.scalar)
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> PartialOrd for Exp<E> {
|
||||
fn partial_cmp(&self, other: &Exp<E>) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> PartialEq for Exp<E> {
|
||||
fn eq(&self, other: &Exp<E>) -> bool {
|
||||
self.scalar == other.scalar
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> Eq for Exp<E> { }
|
@ -1,277 +0,0 @@
|
||||
use rand;
|
||||
use super::super::{Engine, Field, PrimeField, Curve, CurveAffine};
|
||||
|
||||
fn random_test_mixed_addition<E: Engine, G: Curve<E>>(e: &E)
|
||||
{
|
||||
let rng = &mut rand::thread_rng();
|
||||
|
||||
// affine is zero
|
||||
{
|
||||
let a = G::zero(e).to_affine(e);
|
||||
let mut b = G::random(e, rng);
|
||||
let bcpy = b;
|
||||
|
||||
b.add_assign_mixed(e, &a);
|
||||
|
||||
assert!(bcpy.is_equal(e, &b));
|
||||
assert_eq!(bcpy.to_affine(e), b.to_affine(e));
|
||||
}
|
||||
|
||||
// self is zero
|
||||
{
|
||||
let a = G::random(e, rng).to_affine(e);
|
||||
let mut b = G::zero(e);
|
||||
let acpy = a.to_jacobian(e);
|
||||
|
||||
b.add_assign_mixed(e, &a);
|
||||
|
||||
assert!(acpy.is_equal(e, &b));
|
||||
assert_eq!(acpy.to_affine(e), b.to_affine(e));
|
||||
}
|
||||
|
||||
// both are zero
|
||||
{
|
||||
let a = G::zero(e).to_affine(e);
|
||||
let mut b = G::zero(e);
|
||||
let acpy = a.to_jacobian(e);
|
||||
|
||||
b.add_assign_mixed(e, &a);
|
||||
|
||||
assert!(acpy.is_equal(e, &b));
|
||||
assert_eq!(acpy.to_affine(e), b.to_affine(e));
|
||||
}
|
||||
|
||||
// one is negative of the other
|
||||
{
|
||||
let a = G::random(e, rng);
|
||||
let mut b = a;
|
||||
b.negate(e);
|
||||
let a = a.to_affine(e);
|
||||
|
||||
b.add_assign_mixed(e, &a);
|
||||
assert!(b.is_zero());
|
||||
assert_eq!(b.to_affine(e), G::zero(e).to_affine(e));
|
||||
}
|
||||
|
||||
// doubling case
|
||||
{
|
||||
let a = G::random(e, rng);
|
||||
let b = a.to_affine(e);
|
||||
let mut acpy = a;
|
||||
acpy.add_assign_mixed(e, &b);
|
||||
|
||||
let mut t = a;
|
||||
t.double(e);
|
||||
assert!(acpy.is_equal(e, &t));
|
||||
}
|
||||
|
||||
for _ in 0..100 {
|
||||
let mut x = G::random(e, rng);
|
||||
let mut y = x;
|
||||
let b = G::random(e, rng);
|
||||
let baffine = b.to_affine(e);
|
||||
|
||||
x.add_assign(e, &b);
|
||||
y.add_assign_mixed(e, &baffine);
|
||||
|
||||
assert!(x.is_equal(e, &y));
|
||||
}
|
||||
}
|
||||
|
||||
fn random_test_addition<E: Engine, G: Curve<E>>(e: &E) {
|
||||
let rng = &mut rand::thread_rng();
|
||||
|
||||
for _ in 0..50 {
|
||||
let r1 = G::random(e, rng);
|
||||
let r2 = G::random(e, rng);
|
||||
let r3 = G::random(e, rng);
|
||||
|
||||
{
|
||||
let mut tmp1 = r1;
|
||||
tmp1.add_assign(e, &r2);
|
||||
tmp1.add_assign(e, &r3);
|
||||
|
||||
let mut tmp2 = r2;
|
||||
tmp2.add_assign(e, &r3);
|
||||
tmp2.add_assign(e, &r1);
|
||||
|
||||
assert!(tmp1.is_equal(e, &tmp2));
|
||||
}
|
||||
|
||||
{
|
||||
let mut tmp = r1;
|
||||
tmp.add_assign(e, &r2);
|
||||
tmp.add_assign(e, &r3);
|
||||
tmp.sub_assign(e, &r1);
|
||||
tmp.sub_assign(e, &r2);
|
||||
tmp.sub_assign(e, &r3);
|
||||
|
||||
assert!(tmp.is_zero());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn random_test_doubling<E: Engine, G: Curve<E>>(e: &E) {
|
||||
let rng = &mut rand::thread_rng();
|
||||
|
||||
for _ in 0..50 {
|
||||
let r1 = G::random(e, rng);
|
||||
let r2 = G::random(e, rng);
|
||||
let ti = E::Fr::from_str(e, "2").unwrap().inverse(e).unwrap();
|
||||
|
||||
{
|
||||
let mut tmp_1 = r1;
|
||||
tmp_1.add_assign(e, &r2);
|
||||
tmp_1.add_assign(e, &r1);
|
||||
|
||||
let mut tmp_2 = r1;
|
||||
tmp_2.double(e);
|
||||
tmp_2.add_assign(e, &r2);
|
||||
|
||||
assert!(tmp_1.is_equal(e, &tmp_2));
|
||||
}
|
||||
|
||||
{
|
||||
let mut tmp = r1;
|
||||
tmp.double(e);
|
||||
tmp.mul_assign(e, &ti);
|
||||
|
||||
assert!(tmp.is_equal(e, &r1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn random_test_dh<E: Engine, G: Curve<E>>(e: &E) {
|
||||
let rng = &mut rand::thread_rng();
|
||||
|
||||
for _ in 0..50 {
|
||||
let alice_sk = E::Fr::random(e, rng);
|
||||
let bob_sk = E::Fr::random(e, rng);
|
||||
|
||||
let mut alice_pk = G::one(e);
|
||||
alice_pk.mul_assign(e, &alice_sk);
|
||||
let mut bob_pk = G::one(e);
|
||||
bob_pk.mul_assign(e, &bob_sk);
|
||||
|
||||
let mut alice_shared = bob_pk;
|
||||
alice_shared.mul_assign(e, &alice_sk);
|
||||
let mut bob_shared = alice_pk;
|
||||
bob_shared.mul_assign(e, &bob_sk);
|
||||
|
||||
assert!(alice_shared.is_equal(e, &bob_shared));
|
||||
}
|
||||
}
|
||||
|
||||
fn random_mixed_addition<E: Engine, G: Curve<E>>(e: &E) {
|
||||
let rng = &mut rand::thread_rng();
|
||||
|
||||
for _ in 0..50 {
|
||||
let a = G::random(e, rng);
|
||||
|
||||
let mut res = a;
|
||||
res.double(e);
|
||||
|
||||
let affine = a.to_affine(e);
|
||||
let mut jacobian = affine.to_jacobian(e);
|
||||
jacobian.double(e);
|
||||
|
||||
assert!(jacobian.is_equal(e, &res));
|
||||
}
|
||||
}
|
||||
|
||||
fn random_test_equality<E: Engine, G: Curve<E>>(e: &E) {
|
||||
let rng = &mut rand::thread_rng();
|
||||
|
||||
for _ in 0..50 {
|
||||
let begin = G::random(e, rng);
|
||||
|
||||
let mut acc = begin;
|
||||
|
||||
let a = E::Fr::random(e, rng);
|
||||
let b = G::random(e, rng);
|
||||
let c = E::Fr::random(e, rng);
|
||||
let d = G::random(e, rng);
|
||||
|
||||
for _ in 0..10 {
|
||||
acc.mul_assign(e, &a);
|
||||
acc.negate(e);
|
||||
acc.add_assign(e, &b);
|
||||
acc.mul_assign(e, &c);
|
||||
acc.negate(e);
|
||||
acc.sub_assign(e, &d);
|
||||
acc.double(e);
|
||||
}
|
||||
|
||||
assert!(!acc.is_equal(e, &begin));
|
||||
|
||||
let ai = a.inverse(e).unwrap();
|
||||
let ci = c.inverse(e).unwrap();
|
||||
let ti = E::Fr::from_str(e, "2").unwrap().inverse(e).unwrap();
|
||||
|
||||
for _ in 0..10 {
|
||||
acc.mul_assign(e, &ti);
|
||||
acc.add_assign(e, &d);
|
||||
acc.negate(e);
|
||||
acc.mul_assign(e, &ci);
|
||||
acc.sub_assign(e, &b);
|
||||
acc.negate(e);
|
||||
acc.mul_assign(e, &ai);
|
||||
}
|
||||
|
||||
assert!(acc.is_equal(e, &begin));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_curve<E: Engine, G: Curve<E>>(e: &E) {
|
||||
{
|
||||
let rng = &mut rand::thread_rng();
|
||||
let mut g = G::random(e, rng);
|
||||
let order = <E::Fr as PrimeField<E>>::char(e);
|
||||
g.mul_assign(e, &order);
|
||||
|
||||
assert!(g.is_zero());
|
||||
}
|
||||
{
|
||||
let rng = &mut rand::thread_rng();
|
||||
let mut neg1 = E::Fr::one(e);
|
||||
neg1.negate(e);
|
||||
for _ in 0..1000 {
|
||||
let orig = G::random(e, rng);
|
||||
let mut a = orig;
|
||||
a.mul_assign(e, &neg1);
|
||||
assert!(!a.is_zero());
|
||||
a.add_assign(e, &orig);
|
||||
assert!(a.is_zero());
|
||||
}
|
||||
}
|
||||
{
|
||||
let mut o = G::one(e);
|
||||
o.sub_assign(e, &G::one(e));
|
||||
assert!(o.is_zero());
|
||||
}
|
||||
{
|
||||
let mut o = G::one(e);
|
||||
o.add_assign(e, &G::one(e));
|
||||
let mut r = G::one(e);
|
||||
r.mul_assign(e, &E::Fr::from_str(e, "2").unwrap());
|
||||
assert!(o.is_equal(e, &r));
|
||||
}
|
||||
{
|
||||
let mut z = G::zero(e);
|
||||
assert!(z.is_zero());
|
||||
z.double(e);
|
||||
assert!(z.is_zero());
|
||||
|
||||
let zaffine = z.to_affine(e);
|
||||
let zjacobian = zaffine.to_jacobian(e);
|
||||
|
||||
assert!(zjacobian.is_zero());
|
||||
}
|
||||
|
||||
random_test_equality::<E, G>(e);
|
||||
random_test_dh::<E, G>(e);
|
||||
random_test_doubling::<E, G>(e);
|
||||
random_test_addition::<E, G>(e);
|
||||
random_mixed_addition::<E, G>(e);
|
||||
random_test_mixed_addition::<E, G>(e);
|
||||
}
|
@ -1,219 +0,0 @@
|
||||
use rand::{self, Rng};
|
||||
use super::super::{Engine, Field, SqrtField, PrimeField};
|
||||
|
||||
fn inversion_tests<E: Engine, F: Field<E>, R: Rng>(e: &E, rng: &mut R) {
|
||||
let mut a = F::one(e);
|
||||
for _ in 0..10000 {
|
||||
let mut b = a.inverse(e).unwrap();
|
||||
b.mul_assign(e, &a);
|
||||
assert_eq!(b, F::one(e));
|
||||
a.add_assign(e, &F::one(e));
|
||||
}
|
||||
a = F::one(e);
|
||||
a.negate(e);
|
||||
for _ in 0..10000 {
|
||||
let mut b = a.inverse(e).unwrap();
|
||||
b.mul_assign(e, &a);
|
||||
assert_eq!(b, F::one(e));
|
||||
a.sub_assign(e, &F::one(e));
|
||||
}
|
||||
a = F::zero();
|
||||
assert!(a.inverse(e).is_none());
|
||||
for _ in 0..10000 {
|
||||
let r = F::random(e, rng);
|
||||
assert!(!r.is_zero());
|
||||
let mut rinv = r.inverse(e).unwrap();
|
||||
rinv.mul_assign(e, &r);
|
||||
assert_eq!(rinv, F::one(e));
|
||||
}
|
||||
}
|
||||
|
||||
fn expansion_tests<E: Engine, F: Field<E>, R: Rng>(e: &E, rng: &mut R) {
|
||||
for _ in 0..100 {
|
||||
let a = F::random(e, rng);
|
||||
let b = F::random(e, rng);
|
||||
let c = F::random(e, rng);
|
||||
let d = F::random(e, rng);
|
||||
|
||||
let lhs;
|
||||
{
|
||||
let mut t0 = a;
|
||||
t0.add_assign(e, &b);
|
||||
let mut t1 = c;
|
||||
t1.add_assign(e, &d);
|
||||
t0.mul_assign(e, &t1);
|
||||
lhs = t0;
|
||||
}
|
||||
|
||||
let rhs;
|
||||
{
|
||||
let mut t0 = a;
|
||||
t0.mul_assign(e, &c);
|
||||
let mut t1 = b;
|
||||
t1.mul_assign(e, &c);
|
||||
let mut t2 = a;
|
||||
t2.mul_assign(e, &d);
|
||||
let mut t3 = b;
|
||||
t3.mul_assign(e, &d);
|
||||
t0.add_assign(e, &t1);
|
||||
t0.add_assign(e, &t2);
|
||||
t0.add_assign(e, &t3);
|
||||
rhs = t0;
|
||||
}
|
||||
|
||||
assert_eq!(lhs, rhs);
|
||||
}
|
||||
}
|
||||
|
||||
fn squaring_tests<E: Engine, F: Field<E>, R: Rng>(e: &E, rng: &mut R) {
|
||||
for _ in 0..100 {
|
||||
let mut a = F::random(e, rng);
|
||||
let mut b = a;
|
||||
b.mul_assign(e, &a);
|
||||
a.square(e);
|
||||
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
let mut cur = F::zero();
|
||||
for _ in 0..100 {
|
||||
let mut a = cur;
|
||||
a.square(e);
|
||||
let mut b = cur;
|
||||
b.mul_assign(e, &cur);
|
||||
|
||||
assert_eq!(a, b);
|
||||
|
||||
cur.add_assign(e, &F::one(e));
|
||||
}
|
||||
}
|
||||
|
||||
fn operation_tests<E: Engine, F: Field<E>, R: Rng>(e: &E, rng: &mut R) {
|
||||
{
|
||||
let mut acc = F::zero();
|
||||
for _ in 0..1000 {
|
||||
let mut a = acc;
|
||||
a.negate(e);
|
||||
a.add_assign(e, &acc);
|
||||
|
||||
assert_eq!(a, F::zero());
|
||||
acc.add_assign(e, &F::one(e));
|
||||
}
|
||||
}
|
||||
{
|
||||
for _ in 0..1000 {
|
||||
let mut a = F::random(e, rng);
|
||||
let mut at = a;
|
||||
let mut b = F::random(e, rng);
|
||||
|
||||
a.sub_assign(e, &b);
|
||||
b.negate(e);
|
||||
at.add_assign(e, &b);
|
||||
|
||||
assert_eq!(a, at);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_field<E: Engine, F: Field<E>>(e: &E) {
|
||||
let rng = &mut rand::thread_rng();
|
||||
|
||||
inversion_tests::<E, F, _>(e, rng);
|
||||
expansion_tests::<E, F, _>(e, rng);
|
||||
squaring_tests::<E, F, _>(e, rng);
|
||||
operation_tests::<E, F, _>(e, rng);
|
||||
}
|
||||
|
||||
pub fn test_sqrt_field<E: Engine, F: SqrtField<E>>(e: &E) {
|
||||
const SAMPLES: isize = 10000;
|
||||
|
||||
{
|
||||
let mut acc = F::one(e);
|
||||
|
||||
for _ in 0..SAMPLES {
|
||||
let mut b = acc;
|
||||
b.square(e);
|
||||
let mut c = b.sqrt(e).unwrap();
|
||||
if c != acc {
|
||||
c.negate(e);
|
||||
}
|
||||
|
||||
assert_eq!(acc, c);
|
||||
|
||||
acc.add_assign(e, &F::one(e));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut acc = F::one(e);
|
||||
|
||||
for _ in 0..SAMPLES {
|
||||
match acc.sqrt(e) {
|
||||
Some(mut a) => {
|
||||
a.square(e);
|
||||
|
||||
assert_eq!(a, acc);
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
|
||||
acc.add_assign(e, &F::one(e));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let rng = &mut rand::thread_rng();
|
||||
|
||||
for _ in 0..SAMPLES {
|
||||
let a = F::random(e, rng);
|
||||
let mut b = a;
|
||||
b.square(e);
|
||||
let mut c = b.sqrt(e).unwrap();
|
||||
if c != a {
|
||||
c.negate(e);
|
||||
}
|
||||
|
||||
assert_eq!(a, c);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let rng = &mut rand::thread_rng();
|
||||
|
||||
let mut qr: isize = 0;
|
||||
let mut nqr: isize = 0;
|
||||
for _ in 0..SAMPLES {
|
||||
let a = F::random(e, rng);
|
||||
match a.sqrt(e) {
|
||||
Some(mut b) => {
|
||||
qr += 1;
|
||||
b.square(e);
|
||||
assert_eq!(a, b);
|
||||
},
|
||||
None => {
|
||||
nqr += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert!((qr - nqr < (SAMPLES / 20)) || (qr - nqr > -(SAMPLES / 20)));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test_prime_field<E: Engine, F: PrimeField<E>>(e: &E) {
|
||||
let rng = &mut rand::thread_rng();
|
||||
|
||||
for _ in 0..100 {
|
||||
let a = F::random(e, rng);
|
||||
let b = F::random(e, rng);
|
||||
let mut c = a;
|
||||
c.mul_assign(e, &b);
|
||||
let a = a.into_repr(e);
|
||||
let b = b.into_repr(e);
|
||||
let expected_a = F::from_repr(e, a).unwrap();
|
||||
let expected_b = F::from_repr(e, b).unwrap();
|
||||
let mut expected_c = expected_a;
|
||||
expected_c.mul_assign(e, &expected_b);
|
||||
assert_eq!(c, expected_c);
|
||||
}
|
||||
}
|
@ -1,182 +0,0 @@
|
||||
use super::{Engine, Curve, CurveAffine, Field, PrimeField};
|
||||
use rand::{self, Rng};
|
||||
|
||||
mod fields;
|
||||
mod curves;
|
||||
|
||||
fn test_batchexp<E: Engine, G: Curve<E>>(e: &E) {
|
||||
let rng = &mut rand::thread_rng();
|
||||
|
||||
fn test_batchexp_case<E: Engine, G: Curve<E>, R: Rng>(e: &E, rng: &mut R, amount: usize, coeff: Option<&E::Fr>)
|
||||
{
|
||||
let mut g: Vec<G::Affine> = (0..amount).map(|_| G::random(e, rng).to_affine(e)).collect();
|
||||
let mut s: Vec<E::Fr> = (0..amount).map(|_| E::Fr::random(e, rng)).collect();
|
||||
|
||||
let mut g_batch = g.clone();
|
||||
|
||||
e.batchexp::<G, _>(&mut g_batch, &s, coeff);
|
||||
|
||||
for (g, s) in g.iter_mut().zip(s.iter_mut()) {
|
||||
match coeff {
|
||||
Some(coeff) => {
|
||||
s.mul_assign(e, &coeff);
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
*g = g.mul(e, s).to_affine(e);
|
||||
}
|
||||
|
||||
assert_eq!(g_batch, g);
|
||||
}
|
||||
|
||||
for amt in 10..100 {
|
||||
if amt % 2 == 0 {
|
||||
let coeff = &E::Fr::random(e, rng);
|
||||
test_batchexp_case::<E, G, _>(e, rng, amt, Some(coeff));
|
||||
} else {
|
||||
test_batchexp_case::<E, G, _>(e, rng, amt, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn test_multiexp<E: Engine, G: Curve<E>>(e: &E) {
|
||||
fn naiveexp<E: Engine, G: Curve<E>>(e: &E, g: &[G::Affine], s: &[E::Fr]) -> G
|
||||
{
|
||||
assert!(g.len() == s.len());
|
||||
|
||||
let mut expected = G::zero(e);
|
||||
for (g, s) in g.iter().zip(s.iter()) {
|
||||
expected.add_assign(e, &g.mul(e, s));
|
||||
}
|
||||
|
||||
expected
|
||||
}
|
||||
|
||||
{
|
||||
let rng = &mut rand::thread_rng();
|
||||
|
||||
let g: Vec<G::Affine> = (0..1000).map(|_| G::random(e, rng).to_affine(e)).collect();
|
||||
let s: Vec<E::Fr> = (0..1000).map(|_| E::Fr::random(e, rng)).collect();
|
||||
|
||||
let naive = naiveexp::<E, G>(e, &g, &s);
|
||||
let multi = e.multiexp::<G>(&g, &s).unwrap();
|
||||
|
||||
assert!(naive.is_equal(e, &multi));
|
||||
assert!(multi.is_equal(e, &naive));
|
||||
}
|
||||
|
||||
{
|
||||
let rng = &mut rand::thread_rng();
|
||||
let g: Vec<G::Affine> = (0..2).map(|_| G::random(e, rng).to_affine(e)).collect();
|
||||
let s = vec![E::Fr::from_str(e, "3435973836800000000000000000000000").unwrap(), E::Fr::from_str(e, "3435973836700000000000000000000000").unwrap()];
|
||||
|
||||
let naive = naiveexp::<E, G>(e, &g, &s);
|
||||
let multi = e.multiexp::<G>(&g, &s).unwrap();
|
||||
|
||||
assert!(naive.is_equal(e, &multi));
|
||||
assert!(multi.is_equal(e, &naive));
|
||||
}
|
||||
|
||||
{
|
||||
let rng = &mut rand::thread_rng();
|
||||
let s = vec![E::Fr::one(e); 100];
|
||||
let g = vec![G::random(e, rng).to_affine(e); 101];
|
||||
|
||||
assert!(e.multiexp::<G>(&g, &s).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
fn test_bilinearity<E: Engine>(e: &E) {
|
||||
let rng = &mut rand::thread_rng();
|
||||
|
||||
let a = E::G1::random(e, rng);
|
||||
let b = E::G2::random(e, rng);
|
||||
let s = E::Fr::random(e, rng);
|
||||
|
||||
let mut a_s = a;
|
||||
a_s.mul_assign(e, &s);
|
||||
|
||||
let mut b_s = b;
|
||||
b_s.mul_assign(e, &s);
|
||||
|
||||
let test1 = e.pairing(&a_s, &b);
|
||||
assert!(test1 != E::Fqk::one(e));
|
||||
let test2 = e.pairing(&a, &b_s);
|
||||
assert_eq!(test1, test2);
|
||||
|
||||
let mut test4 = e.pairing(&a, &b);
|
||||
assert!(test4 != test1);
|
||||
test4 = test4.pow(e, &s.into_repr(e));
|
||||
assert_eq!(test1, test4);
|
||||
}
|
||||
|
||||
fn test_multimiller<E: Engine>(e: &E) {
|
||||
let rng = &mut rand::thread_rng();
|
||||
|
||||
let a1 = E::G1::random(e, rng);
|
||||
let a2 = E::G2::random(e, rng);
|
||||
|
||||
let b1 = E::G1::random(e, rng);
|
||||
let b2 = E::G2::random(e, rng);
|
||||
|
||||
let mut p1 = e.pairing(&a1, &a2);
|
||||
let p2 = e.pairing(&b1, &b2);
|
||||
p1.mul_assign(e, &p2);
|
||||
|
||||
let mm = e.final_exponentiation(&e.miller_loop(
|
||||
[
|
||||
(&a1.prepare(e), &a2.prepare(e)),
|
||||
(&b1.prepare(e), &b2.prepare(e))
|
||||
].into_iter()
|
||||
));
|
||||
|
||||
assert_eq!(p1, mm);
|
||||
}
|
||||
|
||||
pub fn test_engine<E: Engine>() {
|
||||
let engine = E::new();
|
||||
|
||||
fields::test_prime_field::<E, E::Fq>(&engine);
|
||||
fields::test_prime_field::<E, E::Fr>(&engine);
|
||||
fields::test_sqrt_field::<E, E::Fq>(&engine);
|
||||
fields::test_sqrt_field::<E, E::Fr>(&engine);
|
||||
fields::test_sqrt_field::<E, E::Fqe>(&engine);
|
||||
|
||||
fields::test_field::<E, E::Fq>(&engine);
|
||||
fields::test_field::<E, E::Fr>(&engine);
|
||||
fields::test_field::<E, E::Fqe>(&engine);
|
||||
fields::test_field::<E, E::Fqk>(&engine);
|
||||
|
||||
curves::test_curve::<E, E::G1>(&engine);
|
||||
curves::test_curve::<E, E::G2>(&engine);
|
||||
|
||||
test_bilinearity(&engine);
|
||||
test_multimiller(&engine);
|
||||
test_frobenius(&engine);
|
||||
test_multiexp::<E, E::G1>(&engine);
|
||||
test_multiexp::<E, E::G2>(&engine);
|
||||
|
||||
test_batchexp::<E, E::G1>(&engine);
|
||||
test_batchexp::<E, E::G2>(&engine);
|
||||
}
|
||||
|
||||
fn test_frobenius<E: Engine>(e: &E) {
|
||||
let rng = &mut rand::thread_rng();
|
||||
let modulus = E::Fq::char(e);
|
||||
|
||||
let a = E::Fqk::random(e, rng);
|
||||
let mut acpy = a;
|
||||
acpy.frobenius_map(e, 0);
|
||||
assert_eq!(acpy, a);
|
||||
|
||||
let mut a_q = a.pow(e, &modulus);
|
||||
|
||||
for p in 1..12 {
|
||||
acpy = a;
|
||||
acpy.frobenius_map(e, p);
|
||||
|
||||
assert_eq!(acpy, a_q);
|
||||
|
||||
a_q = a_q.pow(e, &modulus);
|
||||
}
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
use std::marker::PhantomData;
|
||||
use super::{Engine, Curve, PrimeField, PrimeFieldRepr};
|
||||
|
||||
/// Represents the scratch space for a wNAF form scalar.
|
||||
pub struct WNAFTable {
|
||||
window: usize,
|
||||
wnaf: Vec<i64>
|
||||
}
|
||||
|
||||
impl WNAFTable {
|
||||
pub fn new() -> WNAFTable {
|
||||
WNAFTable {
|
||||
window: 0,
|
||||
wnaf: vec![]
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert the scalar into wNAF form.
|
||||
pub fn set_scalar<E: Engine, G: Curve<E>>(&mut self, table: &WindowTable<E, G>, mut c: <E::Fr as PrimeField<E>>::Repr) {
|
||||
self.window = table.window;
|
||||
self.wnaf.truncate(0);
|
||||
|
||||
while !c.is_zero() {
|
||||
let mut u;
|
||||
if c.is_odd() {
|
||||
u = (c.as_ref()[0] % (1 << (self.window+1))) as i64;
|
||||
|
||||
if u > (1 << self.window) {
|
||||
u -= 1 << (self.window+1);
|
||||
}
|
||||
|
||||
if u > 0 {
|
||||
c.sub_noborrow(&<<E::Fr as PrimeField<E>>::Repr as PrimeFieldRepr>::from_u64(u as u64));
|
||||
} else {
|
||||
c.add_nocarry(&<<E::Fr as PrimeField<E>>::Repr as PrimeFieldRepr>::from_u64((-u) as u64));
|
||||
}
|
||||
} else {
|
||||
u = 0;
|
||||
}
|
||||
|
||||
self.wnaf.push(u);
|
||||
|
||||
c.div2();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a window table for a base curve point.
|
||||
pub struct WindowTable<E: Engine, G: Curve<E>>{
|
||||
window: usize,
|
||||
table: Vec<G>,
|
||||
_marker: PhantomData<E>
|
||||
}
|
||||
|
||||
impl<E: Engine, G: Curve<E>> WindowTable<E, G> {
|
||||
/// Construct a new window table for a given base.
|
||||
pub fn new(e: &E, base: G, window: usize) -> Self {
|
||||
let mut tmp = WindowTable {
|
||||
window: 0,
|
||||
table: vec![],
|
||||
_marker: PhantomData
|
||||
};
|
||||
|
||||
tmp.set_base(e, base, window);
|
||||
|
||||
tmp
|
||||
}
|
||||
|
||||
/// Replace this window table with a new one generated by a different base.
|
||||
pub fn set_base(&mut self, e: &E, mut base: G, window: usize) {
|
||||
assert!(window < 23);
|
||||
assert!(window > 1);
|
||||
|
||||
self.window = window;
|
||||
self.table.truncate(0);
|
||||
self.table.reserve(1 << (window-1));
|
||||
|
||||
let mut dbl = base;
|
||||
dbl.double(e);
|
||||
|
||||
for _ in 0..(1 << (window-1)) {
|
||||
self.table.push(base);
|
||||
base.add_assign(e, &dbl);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exp(&self, e: &E, wnaf: &WNAFTable) -> G {
|
||||
assert_eq!(wnaf.window, self.window);
|
||||
|
||||
let mut result = G::zero(e);
|
||||
|
||||
for n in wnaf.wnaf.iter().rev() {
|
||||
result.double(e);
|
||||
|
||||
if *n != 0 {
|
||||
if *n > 0 {
|
||||
result.add_assign(e, &self.table[(n/2) as usize]);
|
||||
} else {
|
||||
result.sub_assign(e, &self.table[((-n)/2) as usize]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn current_window(&self) -> usize {
|
||||
self.window
|
||||
}
|
||||
}
|
@ -1,527 +0,0 @@
|
||||
use curves::*;
|
||||
use super::*;
|
||||
|
||||
pub struct ProvingKey<E: Engine> {
|
||||
a_inputs: Vec<<E::G1 as Curve<E>>::Affine>,
|
||||
b1_inputs: Vec<<E::G1 as Curve<E>>::Affine>,
|
||||
b2_inputs: Vec<<E::G2 as Curve<E>>::Affine>,
|
||||
a_aux: Vec<<E::G1 as Curve<E>>::Affine>,
|
||||
b1_aux: Vec<<E::G1 as Curve<E>>::Affine>,
|
||||
b2_aux: Vec<<E::G2 as Curve<E>>::Affine>,
|
||||
h: Vec<<E::G1 as Curve<E>>::Affine>,
|
||||
l: Vec<<E::G1 as Curve<E>>::Affine>,
|
||||
alpha_g1: <E::G1 as Curve<E>>::Affine,
|
||||
beta_g1: <E::G1 as Curve<E>>::Affine,
|
||||
beta_g2: <E::G2 as Curve<E>>::Affine,
|
||||
delta_g1: <E::G1 as Curve<E>>::Affine,
|
||||
delta_g2: <E::G2 as Curve<E>>::Affine
|
||||
}
|
||||
|
||||
pub struct VerifyingKey<E: Engine> {
|
||||
alpha_g1: <E::G1 as Curve<E>>::Affine,
|
||||
beta_g2: <E::G2 as Curve<E>>::Affine,
|
||||
gamma_g2: <E::G2 as Curve<E>>::Affine,
|
||||
delta_g2: <E::G2 as Curve<E>>::Affine,
|
||||
ic: Vec<<E::G1 as Curve<E>>::Affine>
|
||||
}
|
||||
|
||||
pub struct PreparedVerifyingKey<E: Engine> {
|
||||
alpha_g1_beta_g2: E::Fqk,
|
||||
neg_gamma_g2: <E::G2 as Curve<E>>::Prepared,
|
||||
neg_delta_g2: <E::G2 as Curve<E>>::Prepared,
|
||||
ic: Vec<<E::G1 as Curve<E>>::Affine>
|
||||
}
|
||||
|
||||
pub struct Proof<E: Engine> {
|
||||
a: E::G1,
|
||||
b: E::G2,
|
||||
c: E::G1
|
||||
}
|
||||
|
||||
pub fn keypair<E: Engine, C: Circuit<E>>(
|
||||
e: &E,
|
||||
circuit: C,
|
||||
tau: &E::Fr,
|
||||
alpha: &E::Fr,
|
||||
beta: &E::Fr,
|
||||
gamma: &E::Fr,
|
||||
delta: &E::Fr
|
||||
) -> (ProvingKey<E>, VerifyingKey<E>)
|
||||
{
|
||||
struct KeypairAssembly<E: Engine> {
|
||||
num_inputs: usize,
|
||||
num_aux: usize,
|
||||
num_constraints: usize,
|
||||
at_inputs: Vec<Vec<(E::Fr, usize)>>,
|
||||
bt_inputs: Vec<Vec<(E::Fr, usize)>>,
|
||||
ct_inputs: Vec<Vec<(E::Fr, usize)>>,
|
||||
at_aux: Vec<Vec<(E::Fr, usize)>>,
|
||||
bt_aux: Vec<Vec<(E::Fr, usize)>>,
|
||||
ct_aux: Vec<Vec<(E::Fr, usize)>>
|
||||
}
|
||||
|
||||
impl<E: Engine> PublicConstraintSystem<E> for KeypairAssembly<E> {
|
||||
fn alloc_input(&mut self, _: E::Fr) -> Variable {
|
||||
let index = self.num_inputs;
|
||||
self.num_inputs += 1;
|
||||
|
||||
self.at_inputs.push(vec![]);
|
||||
self.bt_inputs.push(vec![]);
|
||||
self.ct_inputs.push(vec![]);
|
||||
|
||||
Variable(Index::Input(index))
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> ConstraintSystem<E> for KeypairAssembly<E> {
|
||||
fn alloc(&mut self, _: E::Fr) -> Variable {
|
||||
let index = self.num_aux;
|
||||
self.num_aux += 1;
|
||||
|
||||
self.at_aux.push(vec![]);
|
||||
self.bt_aux.push(vec![]);
|
||||
self.ct_aux.push(vec![]);
|
||||
|
||||
Variable(Index::Aux(index))
|
||||
}
|
||||
|
||||
fn enforce(
|
||||
&mut self,
|
||||
a: LinearCombination<E>,
|
||||
b: LinearCombination<E>,
|
||||
c: LinearCombination<E>
|
||||
)
|
||||
{
|
||||
fn qap_eval<E: Engine>(
|
||||
l: LinearCombination<E>,
|
||||
inputs: &mut [Vec<(E::Fr, usize)>],
|
||||
aux: &mut [Vec<(E::Fr, usize)>],
|
||||
this_constraint: usize
|
||||
)
|
||||
{
|
||||
for (index, coeff) in l.0 {
|
||||
match index {
|
||||
Index::Input(id) => inputs[id].push((coeff, this_constraint)),
|
||||
Index::Aux(id) => aux[id].push((coeff, this_constraint))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qap_eval(a, &mut self.at_inputs, &mut self.at_aux, self.num_constraints);
|
||||
qap_eval(b, &mut self.bt_inputs, &mut self.bt_aux, self.num_constraints);
|
||||
qap_eval(c, &mut self.ct_inputs, &mut self.ct_aux, self.num_constraints);
|
||||
|
||||
self.num_constraints += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let mut assembly = KeypairAssembly {
|
||||
num_inputs: 0,
|
||||
num_aux: 0,
|
||||
num_constraints: 0,
|
||||
at_inputs: vec![],
|
||||
bt_inputs: vec![],
|
||||
ct_inputs: vec![],
|
||||
at_aux: vec![],
|
||||
bt_aux: vec![],
|
||||
ct_aux: vec![]
|
||||
};
|
||||
|
||||
assembly.alloc_input(E::Fr::one(e));
|
||||
|
||||
circuit.synthesize(e, &mut assembly).synthesize(e, &mut assembly);
|
||||
|
||||
// Input consistency constraints: x * 0 = 0
|
||||
for i in 0..assembly.num_inputs {
|
||||
assembly.enforce(LinearCombination::zero(e).add(E::Fr::one(e), Variable(Index::Input(i))),
|
||||
LinearCombination::zero(e),
|
||||
LinearCombination::zero(e));
|
||||
}
|
||||
|
||||
let domain = domain::EvaluationDomain::new(e, assembly.num_constraints as u64);
|
||||
|
||||
let mut u = Vec::with_capacity(domain.m as usize);
|
||||
{
|
||||
let mut acc = E::Fr::one(e);
|
||||
for _ in 0..domain.m {
|
||||
u.push(acc);
|
||||
acc.mul_assign(e, tau);
|
||||
}
|
||||
}
|
||||
|
||||
let gamma_inverse = gamma.inverse(e).unwrap();
|
||||
let delta_inverse = delta.inverse(e).unwrap();
|
||||
|
||||
let g1_table;
|
||||
let h;
|
||||
{
|
||||
let mut powers_of_tau = u.clone();
|
||||
powers_of_tau.truncate((domain.m - 1) as usize);
|
||||
|
||||
let mut coeff = delta_inverse;
|
||||
coeff.mul_assign(e, &domain.z(e, tau));
|
||||
for h in &mut powers_of_tau {
|
||||
h.mul_assign(e, &coeff);
|
||||
}
|
||||
|
||||
g1_table = E::G1::one(e).optimal_window_batch(e,
|
||||
(domain.m - 1) as usize + (assembly.num_inputs + assembly.num_aux) * 3
|
||||
);
|
||||
|
||||
h = e.batch_baseexp(&g1_table, powers_of_tau);
|
||||
}
|
||||
|
||||
domain.ifft(e, &mut u);
|
||||
|
||||
fn eval<E: Engine>(
|
||||
e: &E,
|
||||
u: &[E::Fr],
|
||||
alpha: &E::Fr,
|
||||
beta: &E::Fr,
|
||||
inv: &E::Fr,
|
||||
at_in: Vec<Vec<(E::Fr, usize)>>,
|
||||
bt_in: Vec<Vec<(E::Fr, usize)>>,
|
||||
ct_in: Vec<Vec<(E::Fr, usize)>>
|
||||
) -> (Vec<E::Fr>, Vec<E::Fr>, Vec<E::Fr>)
|
||||
{
|
||||
assert_eq!(at_in.len(), bt_in.len());
|
||||
assert_eq!(bt_in.len(), ct_in.len());
|
||||
|
||||
fn eval_at_tau<E: Engine>(
|
||||
e: &E,
|
||||
val: Vec<(E::Fr, usize)>,
|
||||
u: &[E::Fr]
|
||||
) -> E::Fr
|
||||
{
|
||||
let mut acc = E::Fr::zero();
|
||||
|
||||
for (coeff, index) in val {
|
||||
let mut n = u[index];
|
||||
n.mul_assign(e, &coeff);
|
||||
acc.add_assign(e, &n);
|
||||
}
|
||||
|
||||
acc
|
||||
}
|
||||
|
||||
let mut a_out = Vec::with_capacity(at_in.len());
|
||||
let mut b_out = Vec::with_capacity(at_in.len());
|
||||
let mut l_out = Vec::with_capacity(at_in.len());
|
||||
|
||||
for ((a, b), c) in at_in.into_iter().zip(bt_in.into_iter()).zip(ct_in.into_iter()) {
|
||||
let a = eval_at_tau(e, a, u);
|
||||
let b = eval_at_tau(e, b, u);
|
||||
|
||||
let mut t0 = a;
|
||||
t0.mul_assign(e, beta);
|
||||
|
||||
let mut t1 = b;
|
||||
t1.mul_assign(e, alpha);
|
||||
|
||||
t0.add_assign(e, &t1);
|
||||
t0.add_assign(e, &eval_at_tau(e, c, u));
|
||||
t0.mul_assign(e, inv);
|
||||
|
||||
a_out.push(a);
|
||||
b_out.push(b);
|
||||
l_out.push(t0);
|
||||
}
|
||||
|
||||
(a_out, b_out, l_out)
|
||||
}
|
||||
|
||||
let (a_inputs, b_inputs, ic_coeffs) = eval(e, &u, alpha, beta, &gamma_inverse, assembly.at_inputs, assembly.bt_inputs, assembly.ct_inputs);
|
||||
let a_inputs = e.batch_baseexp(&g1_table, a_inputs);
|
||||
let b1_inputs = e.batch_baseexp(&g1_table, &b_inputs);
|
||||
let ic_coeffs = e.batch_baseexp(&g1_table, ic_coeffs);
|
||||
let (a_aux, b_aux, l_coeffs) = eval(e, &u, alpha, beta, &delta_inverse, assembly.at_aux, assembly.bt_aux, assembly.ct_aux);
|
||||
let a_aux = e.batch_baseexp(&g1_table, a_aux);
|
||||
let b1_aux = e.batch_baseexp(&g1_table, &b_aux);
|
||||
let l_coeffs = e.batch_baseexp(&g1_table, l_coeffs);
|
||||
|
||||
drop(g1_table);
|
||||
|
||||
let g2_table = E::G2::one(e).optimal_window_batch(e,
|
||||
(assembly.num_inputs + assembly.num_aux)
|
||||
);
|
||||
|
||||
let b2_inputs = e.batch_baseexp(&g2_table, b_inputs);
|
||||
let b2_aux = e.batch_baseexp(&g2_table, b_aux);
|
||||
|
||||
let mut alpha_g1 = E::G1::one(e);
|
||||
alpha_g1.mul_assign(e, alpha);
|
||||
let mut beta_g1 = E::G1::one(e);
|
||||
beta_g1.mul_assign(e, beta);
|
||||
let mut beta_g2 = E::G2::one(e);
|
||||
beta_g2.mul_assign(e, beta);
|
||||
let mut gamma_g2 = E::G2::one(e);
|
||||
gamma_g2.mul_assign(e, gamma);
|
||||
let mut delta_g1 = E::G1::one(e);
|
||||
delta_g1.mul_assign(e, delta);
|
||||
let mut delta_g2 = E::G2::one(e);
|
||||
delta_g2.mul_assign(e, delta);
|
||||
|
||||
(
|
||||
ProvingKey {
|
||||
a_inputs: a_inputs,
|
||||
b1_inputs: b1_inputs,
|
||||
b2_inputs: b2_inputs,
|
||||
a_aux: a_aux,
|
||||
b1_aux: b1_aux,
|
||||
b2_aux: b2_aux,
|
||||
h: h,
|
||||
l: l_coeffs,
|
||||
delta_g1: delta_g1.to_affine(e),
|
||||
delta_g2: delta_g2.to_affine(e),
|
||||
alpha_g1: alpha_g1.to_affine(e),
|
||||
beta_g1: beta_g1.to_affine(e),
|
||||
beta_g2: beta_g2.to_affine(e)
|
||||
},
|
||||
VerifyingKey {
|
||||
alpha_g1: alpha_g1.to_affine(e),
|
||||
beta_g2: beta_g2.to_affine(e),
|
||||
gamma_g2: gamma_g2.to_affine(e),
|
||||
delta_g2: delta_g2.to_affine(e),
|
||||
ic: ic_coeffs
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
pub fn prepare_verifying_key<E: Engine>(
|
||||
e: &E,
|
||||
vk: &VerifyingKey<E>
|
||||
) -> PreparedVerifyingKey<E>
|
||||
{
|
||||
let mut gamma = vk.gamma_g2;
|
||||
gamma.negate(e);
|
||||
let mut delta = vk.delta_g2;
|
||||
delta.negate(e);
|
||||
|
||||
PreparedVerifyingKey {
|
||||
alpha_g1_beta_g2: e.pairing(&vk.alpha_g1, &vk.beta_g2),
|
||||
neg_gamma_g2: gamma.prepare(e),
|
||||
neg_delta_g2: delta.prepare(e),
|
||||
ic: vk.ic.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VerifierInput<'a, E: Engine + 'a> {
|
||||
e: &'a E,
|
||||
acc: E::G1,
|
||||
ic: &'a [<E::G1 as Curve<E>>::Affine],
|
||||
insufficient_inputs: bool,
|
||||
num_inputs: usize,
|
||||
num_aux: usize
|
||||
}
|
||||
|
||||
impl<'a, E: Engine> ConstraintSystem<E> for VerifierInput<'a, E> {
|
||||
fn alloc(&mut self, _: E::Fr) -> Variable {
|
||||
let index = self.num_aux;
|
||||
self.num_aux += 1;
|
||||
|
||||
Variable(Index::Aux(index))
|
||||
}
|
||||
|
||||
fn enforce(
|
||||
&mut self,
|
||||
_: LinearCombination<E>,
|
||||
_: LinearCombination<E>,
|
||||
_: LinearCombination<E>
|
||||
)
|
||||
{
|
||||
// Do nothing; we don't care about the constraint system
|
||||
// in this context.
|
||||
}
|
||||
}
|
||||
|
||||
pub fn verify<'a, E: Engine, C: Input<E>, F: FnOnce(&mut VerifierInput<'a, E>) -> C>(
|
||||
e: &'a E,
|
||||
circuit: F,
|
||||
proof: &Proof<E>,
|
||||
pvk: &'a PreparedVerifyingKey<E>
|
||||
) -> bool
|
||||
{
|
||||
struct InputAllocator<T>(T);
|
||||
|
||||
impl<'a, 'b, E: Engine> PublicConstraintSystem<E> for InputAllocator<&'b mut VerifierInput<'a, E>> {
|
||||
fn alloc_input(&mut self, value: E::Fr) -> Variable {
|
||||
if self.0.ic.len() == 0 {
|
||||
self.0.insufficient_inputs = true;
|
||||
} else {
|
||||
self.0.acc.add_assign(self.0.e, &self.0.ic[0].mul(self.0.e, &value));
|
||||
self.0.ic = &self.0.ic[1..];
|
||||
}
|
||||
|
||||
let index = self.0.num_inputs;
|
||||
self.0.num_inputs += 1;
|
||||
|
||||
Variable(Index::Input(index))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, E: Engine> ConstraintSystem<E> for InputAllocator<&'b mut VerifierInput<'a, E>> {
|
||||
fn alloc(&mut self, num: E::Fr) -> Variable {
|
||||
self.0.alloc(num)
|
||||
}
|
||||
|
||||
fn enforce(
|
||||
&mut self,
|
||||
a: LinearCombination<E>,
|
||||
b: LinearCombination<E>,
|
||||
c: LinearCombination<E>
|
||||
)
|
||||
{
|
||||
self.0.enforce(a, b, c);
|
||||
}
|
||||
}
|
||||
|
||||
let mut witness = VerifierInput {
|
||||
e: e,
|
||||
acc: pvk.ic[0].to_jacobian(e),
|
||||
ic: &pvk.ic[1..],
|
||||
insufficient_inputs: false,
|
||||
num_inputs: 1,
|
||||
num_aux: 0
|
||||
};
|
||||
|
||||
circuit(&mut witness).synthesize(e, &mut InputAllocator(&mut witness));
|
||||
|
||||
if witness.ic.len() != 0 || witness.insufficient_inputs {
|
||||
return false;
|
||||
}
|
||||
|
||||
e.final_exponentiation(
|
||||
&e.miller_loop([
|
||||
(&proof.a.prepare(e), &proof.b.prepare(e)),
|
||||
(&witness.acc.prepare(e), &pvk.neg_gamma_g2),
|
||||
(&proof.c.prepare(e), &pvk.neg_delta_g2)
|
||||
].into_iter())
|
||||
) == pvk.alpha_g1_beta_g2
|
||||
}
|
||||
|
||||
pub fn prove<E: Engine, C: Circuit<E>>(
|
||||
e: &E,
|
||||
circuit: C,
|
||||
r: &E::Fr,
|
||||
s: &E::Fr,
|
||||
pk: &ProvingKey<E>
|
||||
) -> Result<Proof<E>, ()>
|
||||
{
|
||||
struct ProvingAssignment<'a, E: Engine + 'a> {
|
||||
e: &'a E,
|
||||
// Evaluations of A, B, C polynomials
|
||||
a: Vec<E::Fr>,
|
||||
b: Vec<E::Fr>,
|
||||
c: Vec<E::Fr>,
|
||||
// Assignments of variables
|
||||
input_assignment: Vec<E::Fr>,
|
||||
aux_assignment: Vec<E::Fr>
|
||||
}
|
||||
|
||||
impl<'a, E: Engine> PublicConstraintSystem<E> for ProvingAssignment<'a, E> {
|
||||
fn alloc_input(&mut self, value: E::Fr) -> Variable {
|
||||
self.input_assignment.push(value);
|
||||
|
||||
Variable(Index::Input(self.input_assignment.len() - 1))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: Engine> ConstraintSystem<E> for ProvingAssignment<'a, E> {
|
||||
fn alloc(&mut self, value: E::Fr) -> Variable {
|
||||
self.aux_assignment.push(value);
|
||||
|
||||
Variable(Index::Aux(self.aux_assignment.len() - 1))
|
||||
}
|
||||
|
||||
fn enforce(
|
||||
&mut self,
|
||||
a: LinearCombination<E>,
|
||||
b: LinearCombination<E>,
|
||||
c: LinearCombination<E>
|
||||
)
|
||||
{
|
||||
self.a.push(a.evaluate(self.e, &self.input_assignment, &self.aux_assignment));
|
||||
self.b.push(b.evaluate(self.e, &self.input_assignment, &self.aux_assignment));
|
||||
self.c.push(c.evaluate(self.e, &self.input_assignment, &self.aux_assignment));
|
||||
}
|
||||
}
|
||||
|
||||
let mut prover = ProvingAssignment {
|
||||
e: e,
|
||||
a: vec![],
|
||||
b: vec![],
|
||||
c: vec![],
|
||||
input_assignment: vec![],
|
||||
aux_assignment: vec![]
|
||||
};
|
||||
|
||||
prover.alloc_input(E::Fr::one(e));
|
||||
|
||||
circuit.synthesize(e, &mut prover).synthesize(e, &mut prover);
|
||||
|
||||
// Input consistency constraints: x * 0 = 0
|
||||
for i in 0..prover.input_assignment.len() {
|
||||
prover.enforce(LinearCombination::zero(e).add(E::Fr::one(e), Variable(Index::Input(i))),
|
||||
LinearCombination::zero(e),
|
||||
LinearCombination::zero(e));
|
||||
}
|
||||
|
||||
// Perform FFTs
|
||||
let h = {
|
||||
let domain = domain::EvaluationDomain::new(e, prover.a.len() as u64);
|
||||
prover.a.resize(domain.m as usize, E::Fr::zero());
|
||||
prover.b.resize(domain.m as usize, E::Fr::zero());
|
||||
prover.c.resize(domain.m as usize, E::Fr::zero());
|
||||
domain.ifft(e, &mut prover.a);
|
||||
domain.coset_fft(e, &mut prover.a);
|
||||
domain.ifft(e, &mut prover.b);
|
||||
domain.coset_fft(e, &mut prover.b);
|
||||
domain.ifft(e, &mut prover.c);
|
||||
domain.coset_fft(e, &mut prover.c);
|
||||
|
||||
let mut h = prover.a;
|
||||
domain.mul_assign(e, &mut h, prover.b);
|
||||
domain.sub_assign(e, &mut h, prover.c);
|
||||
domain.divide_by_z_on_coset(e, &mut h);
|
||||
domain.icoset_fft(e, &mut h);
|
||||
|
||||
e.multiexp(&pk.h, &h[0..(domain.m-1) as usize])?
|
||||
};
|
||||
|
||||
// Construct proof
|
||||
let mut g_a = pk.delta_g1.mul(e, r);
|
||||
g_a.add_assign(e, &pk.alpha_g1.to_jacobian(e));
|
||||
let mut g_b = pk.delta_g2.mul(e, s);
|
||||
g_b.add_assign(e, &pk.beta_g2.to_jacobian(e));
|
||||
let mut g_c;
|
||||
{
|
||||
let mut rs = *r;
|
||||
rs.mul_assign(e, s);
|
||||
g_c = pk.delta_g1.mul(e, &rs);
|
||||
g_c.add_assign(e, &pk.alpha_g1.mul(e, s));
|
||||
g_c.add_assign(e, &pk.beta_g1.mul(e, r));
|
||||
}
|
||||
let mut a_answer: E::G1 = e.multiexp(&pk.a_inputs, &prover.input_assignment)?;
|
||||
a_answer.add_assign(e, &e.multiexp(&pk.a_aux, &prover.aux_assignment)?);
|
||||
g_a.add_assign(e, &a_answer);
|
||||
a_answer.mul_assign(e, s);
|
||||
g_c.add_assign(e, &a_answer);
|
||||
let mut b1_answer: E::G1 = e.multiexp(&pk.b1_inputs, &prover.input_assignment)?;
|
||||
b1_answer.add_assign(e, &e.multiexp(&pk.b1_aux, &prover.aux_assignment)?);
|
||||
let mut b2_answer: E::G2 = e.multiexp(&pk.b2_inputs, &prover.input_assignment)?;
|
||||
b2_answer.add_assign(e, &e.multiexp(&pk.b2_aux, &prover.aux_assignment)?);
|
||||
g_b.add_assign(e, &b2_answer);
|
||||
b1_answer.mul_assign(e, r);
|
||||
g_c.add_assign(e, &b1_answer);
|
||||
g_c.add_assign(e, &h);
|
||||
g_c.add_assign(e, &e.multiexp(&pk.l, &prover.aux_assignment)?);
|
||||
|
||||
Ok(Proof {
|
||||
a: g_a,
|
||||
b: g_b,
|
||||
c: g_c
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
@ -1,207 +0,0 @@
|
||||
use super::*;
|
||||
use rand::{Rng, thread_rng};
|
||||
|
||||
struct RootCircuit<E: Engine> {
|
||||
root: E::Fr
|
||||
}
|
||||
|
||||
impl<E: Engine> Circuit<E> for RootCircuit<E> {
|
||||
type InputMap = RootInput<E>;
|
||||
|
||||
fn synthesize<CS: ConstraintSystem<E>>(self,
|
||||
e: &E,
|
||||
cs: &mut CS)
|
||||
-> Self::InputMap
|
||||
{
|
||||
let root_var = cs.alloc(self.root);
|
||||
|
||||
let mut cur = root_var;
|
||||
let mut cur_val = self.root;
|
||||
|
||||
for _ in 0..99 {
|
||||
cur_val.mul_assign(e, &self.root);
|
||||
let new = cs.alloc(cur_val);
|
||||
|
||||
cs.enforce(
|
||||
LinearCombination::zero(e) + (E::Fr::from_str(e, "3").unwrap(), cur),
|
||||
LinearCombination::zero(e) + (E::Fr::from_str(e, "4").unwrap(), root_var),
|
||||
LinearCombination::zero(e) + (E::Fr::from_str(e, "12").unwrap(), new),
|
||||
);
|
||||
|
||||
cur = new;
|
||||
}
|
||||
|
||||
RootInput {
|
||||
num: cur_val,
|
||||
num_var: cur
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct RootInput<E: Engine> {
|
||||
num: E::Fr,
|
||||
num_var: Variable
|
||||
}
|
||||
|
||||
impl<E: Engine> Input<E> for RootInput<E> {
|
||||
fn synthesize<CS: PublicConstraintSystem<E>>(
|
||||
self,
|
||||
e: &E,
|
||||
cs: &mut CS
|
||||
)
|
||||
{
|
||||
let result_input = cs.alloc_input(self.num);
|
||||
cs.enforce(
|
||||
LinearCombination::zero(e) + result_input,
|
||||
LinearCombination::one(e),
|
||||
LinearCombination::zero(e) + self.num_var
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn test_snark_system<E: Engine, R: Rng>(
|
||||
e: &E,
|
||||
rng: &mut R
|
||||
)
|
||||
{
|
||||
let tau = E::Fr::random(e, rng);
|
||||
let alpha = E::Fr::random(e, rng);
|
||||
let beta = E::Fr::random(e, rng);
|
||||
let gamma = E::Fr::random(e, rng);
|
||||
let delta = E::Fr::random(e, rng);
|
||||
|
||||
// create keypair
|
||||
let (pk, vk) = {
|
||||
let c = RootCircuit {
|
||||
root: E::Fr::zero()
|
||||
};
|
||||
|
||||
keypair(e, c, &tau, &alpha, &beta, &gamma, &delta)
|
||||
};
|
||||
|
||||
// construct proof
|
||||
let proof = {
|
||||
let r = E::Fr::random(e, rng);
|
||||
let s = E::Fr::random(e, rng);
|
||||
|
||||
let c = RootCircuit {
|
||||
root: E::Fr::from_str(e, "2").unwrap()
|
||||
};
|
||||
|
||||
prove(e, c, &r, &s, &pk).unwrap()
|
||||
};
|
||||
|
||||
// prepare verifying key
|
||||
let pvk = prepare_verifying_key(e, &vk);
|
||||
|
||||
// verify proof
|
||||
assert!(verify(e, |cs| {
|
||||
RootInput {
|
||||
num: E::Fr::from_str(e, "1267650600228229401496703205376").unwrap(),
|
||||
num_var: cs.alloc(E::Fr::one(e))
|
||||
}
|
||||
}, &proof, &pvk));
|
||||
|
||||
// verify invalid proof
|
||||
assert!(!verify(e, |cs| {
|
||||
RootInput {
|
||||
num: E::Fr::from_str(e, "1267650600228229401496703205375").unwrap(),
|
||||
num_var: cs.alloc(E::Fr::one(e))
|
||||
}
|
||||
}, &proof, &pvk));
|
||||
|
||||
// simulate a groth proof with trapdoors
|
||||
// ----------------
|
||||
// 99: a1 * a0 = l*
|
||||
// 100: a0 * 0 = 0
|
||||
// 101: a1 * 0 = 0
|
||||
// ---
|
||||
// u_0(tau) = tau^100
|
||||
// u_1(tau) = tau^99 + tau^101
|
||||
// v_0(tau) = tau^99
|
||||
// v_1(tau) = 0
|
||||
// w_0(tau) = 0
|
||||
// w_1(tau) = 0
|
||||
// ---
|
||||
|
||||
let mut lagrange_coeffs: Vec<E::Fr> = (0..128).map(|i| tau.pow(e, &[i])).collect();
|
||||
|
||||
let d = domain::EvaluationDomain::new(e, 128);
|
||||
d.ifft(e, &mut lagrange_coeffs);
|
||||
|
||||
let a = E::Fr::random(e, rng);
|
||||
let b = E::Fr::random(e, rng);
|
||||
|
||||
let mut c = a;
|
||||
c.mul_assign(e, &b);
|
||||
|
||||
let mut alphabeta = alpha;
|
||||
alphabeta.mul_assign(e, &beta);
|
||||
c.sub_assign(e, &alphabeta);
|
||||
|
||||
let mut ic = E::Fr::zero();
|
||||
{
|
||||
let mut ic_i_beta = lagrange_coeffs[100];
|
||||
ic_i_beta.mul_assign(e, &beta);
|
||||
|
||||
let mut ic_i_alpha = lagrange_coeffs[99];
|
||||
ic_i_alpha.mul_assign(e, &alpha);
|
||||
|
||||
ic_i_beta.add_assign(e, &ic_i_alpha);
|
||||
|
||||
ic.add_assign(e, &ic_i_beta);
|
||||
}
|
||||
{
|
||||
let mut ic_i_beta = lagrange_coeffs[99];
|
||||
ic_i_beta.add_assign(e, &lagrange_coeffs[101]);
|
||||
ic_i_beta.mul_assign(e, &beta);
|
||||
|
||||
ic_i_beta.mul_assign(e, &E::Fr::from_str(e, "100").unwrap());
|
||||
|
||||
ic.add_assign(e, &ic_i_beta);
|
||||
}
|
||||
|
||||
c.sub_assign(e, &ic);
|
||||
c.mul_assign(e, &delta.inverse(e).unwrap());
|
||||
|
||||
let mut a_g = E::G1::one(e);
|
||||
a_g.mul_assign(e, &a);
|
||||
|
||||
let mut b_g = E::G2::one(e);
|
||||
b_g.mul_assign(e, &b);
|
||||
|
||||
let mut c_g = E::G1::one(e);
|
||||
c_g.mul_assign(e, &c);
|
||||
|
||||
let fake_proof = Proof {
|
||||
a: a_g,
|
||||
b: b_g,
|
||||
c: c_g
|
||||
};
|
||||
|
||||
// verify fake proof
|
||||
assert!(verify(e, |cs| {
|
||||
RootInput {
|
||||
num: E::Fr::from_str(e, "100").unwrap(),
|
||||
num_var: cs.alloc(E::Fr::one(e))
|
||||
}
|
||||
}, &fake_proof, &pvk));
|
||||
|
||||
// verify fake proof with wrong input
|
||||
assert!(!verify(e, |cs| {
|
||||
RootInput {
|
||||
num: E::Fr::from_str(e, "101").unwrap(),
|
||||
num_var: cs.alloc(E::Fr::one(e))
|
||||
}
|
||||
}, &fake_proof, &pvk));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn groth_with_bls381() {
|
||||
use curves::bls381::Bls381;
|
||||
|
||||
let e = &Bls381::new();
|
||||
let rng = &mut thread_rng();
|
||||
|
||||
test_snark_system(e, rng);
|
||||
}
|
215
src/lib.rs
215
src/lib.rs
@ -1,215 +0,0 @@
|
||||
#![feature(i128_type)]
|
||||
|
||||
extern crate rand;
|
||||
extern crate num_cpus;
|
||||
extern crate crossbeam;
|
||||
extern crate byteorder;
|
||||
extern crate serde;
|
||||
|
||||
pub mod curves;
|
||||
pub mod groth16;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::ops;
|
||||
use std::ops::Deref;
|
||||
use std::borrow::Borrow;
|
||||
|
||||
use curves::{Engine, Field};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Variable(Index);
|
||||
|
||||
impl Variable {
|
||||
pub fn one() -> Self {
|
||||
Variable(Index::Input(0))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
enum Index {
|
||||
Input(usize),
|
||||
Aux(usize)
|
||||
}
|
||||
|
||||
pub struct LinearCombination<'a, E: Engine + 'a>(HashMap<Index, E::Fr>, &'a E);
|
||||
|
||||
impl<'a, E: Engine + 'a> ops::Add<Variable> for LinearCombination<'a, E> {
|
||||
type Output = LinearCombination<'a, E>;
|
||||
|
||||
fn add(self, other: Variable) -> LinearCombination<'a, E> {
|
||||
let one = E::Fr::one(self.1);
|
||||
|
||||
self.add(one, other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: Engine + 'a> ops::Add<(E::Fr, Variable)> for LinearCombination<'a, E> {
|
||||
type Output = LinearCombination<'a, E>;
|
||||
|
||||
fn add(self, (coeff, var): (E::Fr, Variable)) -> LinearCombination<'a, E> {
|
||||
self.add(coeff, var)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: Engine + 'a> ops::Sub<Variable> for LinearCombination<'a, E> {
|
||||
type Output = LinearCombination<'a, E>;
|
||||
|
||||
fn sub(self, other: Variable) -> LinearCombination<'a, E> {
|
||||
let one = E::Fr::one(self.1);
|
||||
|
||||
self.sub(one, other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: Engine + 'a> ops::Sub<(E::Fr, Variable)> for LinearCombination<'a, E> {
|
||||
type Output = LinearCombination<'a, E>;
|
||||
|
||||
fn sub(self, (coeff, var): (E::Fr, Variable)) -> LinearCombination<'a, E> {
|
||||
self.sub(coeff, var)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: Engine> LinearCombination<'a, E> {
|
||||
pub fn zero(e: &'a E) -> LinearCombination<'a, E> {
|
||||
LinearCombination(HashMap::new(), e)
|
||||
}
|
||||
|
||||
pub fn one(e: &'a E) -> LinearCombination<'a, E> {
|
||||
LinearCombination::zero(e).add(E::Fr::one(e), Variable::one())
|
||||
}
|
||||
|
||||
pub fn add(mut self, coeff: E::Fr, var: Variable) -> Self
|
||||
{
|
||||
self.0.entry(var.0)
|
||||
.or_insert(E::Fr::zero())
|
||||
.add_assign(self.1, &coeff);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn sub(self, mut coeff: E::Fr, var: Variable) -> Self
|
||||
{
|
||||
coeff.negate(self.1);
|
||||
|
||||
self.add(coeff, var)
|
||||
}
|
||||
|
||||
fn evaluate(
|
||||
&self,
|
||||
e: &E,
|
||||
input_assignment: &[E::Fr],
|
||||
aux_assignment: &[E::Fr]
|
||||
) -> E::Fr
|
||||
{
|
||||
let mut acc = E::Fr::zero();
|
||||
for (index, coeff) in self.0.iter() {
|
||||
let mut n = *coeff;
|
||||
match index {
|
||||
&Index::Input(id) => {
|
||||
n.mul_assign(e, &input_assignment[id]);
|
||||
},
|
||||
&Index::Aux(id) => {
|
||||
n.mul_assign(e, &aux_assignment[id]);
|
||||
}
|
||||
}
|
||||
acc.add_assign(e, &n);
|
||||
}
|
||||
|
||||
acc
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Circuit<E: Engine> {
|
||||
type InputMap: Input<E>;
|
||||
|
||||
/// Synthesize the circuit into a rank-1 quadratic constraint system
|
||||
#[must_use]
|
||||
fn synthesize<CS: ConstraintSystem<E>>(self, engine: &E, cs: &mut CS) -> Self::InputMap;
|
||||
}
|
||||
|
||||
pub trait Input<E: Engine> {
|
||||
/// Synthesize the circuit, except with additional access to public input
|
||||
/// variables
|
||||
fn synthesize<CS: PublicConstraintSystem<E>>(self, engine: &E, cs: &mut CS);
|
||||
}
|
||||
|
||||
pub trait PublicConstraintSystem<E: Engine>: ConstraintSystem<E> {
|
||||
/// Allocate a public input that the verifier knows.
|
||||
fn alloc_input(&mut self, value: E::Fr) -> Variable;
|
||||
}
|
||||
|
||||
pub trait ConstraintSystem<E: Engine> {
|
||||
/// Allocate a private variable in the constraint system, setting it to
|
||||
/// the provided value.
|
||||
fn alloc(&mut self, value: E::Fr) -> Variable;
|
||||
|
||||
/// Enforce that `A` * `B` = `C`.
|
||||
fn enforce(
|
||||
&mut self,
|
||||
a: LinearCombination<E>,
|
||||
b: LinearCombination<E>,
|
||||
c: LinearCombination<E>
|
||||
);
|
||||
}
|
||||
|
||||
pub enum Cow<'a, T: 'a> {
|
||||
Owned(T),
|
||||
Borrowed(&'a T)
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> Deref for Cow<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
match *self {
|
||||
Cow::Owned(ref v) => v,
|
||||
Cow::Borrowed(v) => v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Convert<T: ?Sized, E> {
|
||||
type Target: Borrow<T>;
|
||||
|
||||
fn convert(&self, &E) -> Cow<Self::Target>;
|
||||
}
|
||||
|
||||
impl<T, E> Convert<T, E> for T {
|
||||
type Target = T;
|
||||
|
||||
fn convert(&self, _: &E) -> Cow<T> {
|
||||
Cow::Borrowed(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BitIterator<T> {
|
||||
t: T,
|
||||
n: usize
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u64]>> BitIterator<T> {
|
||||
fn new(t: T) -> Self {
|
||||
let bits = 64 * t.as_ref().len();
|
||||
|
||||
BitIterator {
|
||||
t: t,
|
||||
n: bits
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u64]>> Iterator for BitIterator<T> {
|
||||
type Item = bool;
|
||||
|
||||
fn next(&mut self) -> Option<bool> {
|
||||
if self.n == 0 {
|
||||
None
|
||||
} else {
|
||||
self.n -= 1;
|
||||
let part = self.n / 64;
|
||||
let bit = self.n - (64 * part);
|
||||
|
||||
Some(self.t.as_ref()[part] & (1 << bit) > 0)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user