3 Commits

Author SHA1 Message Date
mdr0id
07c60e0ad2 Sanity check url syntax 2018-10-11 19:06:41 -07:00
mdr0id
f30e703971 Second sanity check of local fork flow 2018-10-11 13:28:38 -07:00
mdr0id
0e056403f8 Remove stubbed line for sanity check on CI in production 2018-10-10 16:58:15 -07:00
164 changed files with 8339 additions and 26267 deletions

View File

@@ -5,7 +5,6 @@
# Date: 9/10/2018
# Description: Used to setup runners/jobs for librustzcash
# Usage: Commit source and the pipeline will trigger the according jobs.
# For now the build and test are done in the same jobs.
#
# Known bugs/missing features:
#

View File

@@ -1,13 +0,0 @@
language: rust
rust:
- 1.36.0
cache: cargo
before_script:
- rustup component add rustfmt
script:
- cargo build --verbose --release --all
- cargo fmt --all -- --check
- cargo test --verbose --release --all

948
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +1,13 @@
[workspace]
members = [
"bellman",
"ff",
"group",
"librustzcash",
"pairing",
"zcash_client_backend",
"zcash_client_sqlite",
"sapling-crypto",
"zcash_primitives",
"zcash_proofs",
"zcash_wallet",
"zip32",
]
[profile.release]

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2017-2019 Electric Coin Company
Copyright (c) 2017 Zcash Company
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -9,30 +9,14 @@ repository = "https://github.com/ebfull/bellman"
version = "0.1.0"
[dependencies]
rand = "0.4"
bit-vec = "0.4.4"
blake2s_simd = "0.5"
ff = { path = "../ff" }
futures = "0.1"
futures-cpupool = { version = "0.1", optional = true }
group = { path = "../group" }
num_cpus = { version = "1", optional = true }
crossbeam = { version = "0.3", optional = true }
pairing = { path = "../pairing", optional = true }
rand_core = "0.5"
futures-cpupool = "0.1"
num_cpus = "1"
crossbeam = "0.3"
pairing = { path = "../pairing" }
byteorder = "1"
[dev-dependencies]
hex-literal = "0.1"
rand = "0.7"
rand_xorshift = "0.2"
sha2 = "0.8"
[features]
groth16 = ["pairing"]
multicore = ["futures-cpupool", "crossbeam", "num_cpus"]
default = ["groth16", "multicore"]
[[test]]
name = "mimc"
path = "tests/mimc.rs"
required-features = ["groth16"]
default = []

View File

@@ -10,23 +10,29 @@
//! This allows us to perform polynomial operations in O(n)
//! by performing an O(n log n) FFT over such a domain.
use ff::{Field, PrimeField, ScalarEngine};
use group::CurveProjective;
use pairing::{
Engine,
Field,
PrimeField,
CurveProjective
};
use super::SynthesisError;
use super::{
SynthesisError
};
use super::multicore::Worker;
pub struct EvaluationDomain<E: ScalarEngine, G: Group<E>> {
pub struct EvaluationDomain<E: Engine, G: Group<E>> {
coeffs: Vec<G>,
exp: u32,
omega: E::Fr,
omegainv: E::Fr,
geninv: E::Fr,
minv: E::Fr,
minv: E::Fr
}
impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
impl<E: Engine, G: Group<E>> EvaluationDomain<E, G> {
pub fn as_ref(&self) -> &[G] {
&self.coeffs
}
@@ -39,7 +45,8 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
self.coeffs
}
pub fn from_coeffs(mut coeffs: Vec<G>) -> Result<EvaluationDomain<E, G>, SynthesisError> {
pub fn from_coeffs(mut coeffs: Vec<G>) -> Result<EvaluationDomain<E, G>, SynthesisError>
{
// Compute the size of our evaluation domain
let mut m = 1;
let mut exp = 0;
@@ -50,7 +57,7 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
// The pairing-friendly curve may not be able to support
// large enough (radix2) evaluation domains.
if exp >= E::Fr::S {
return Err(SynthesisError::PolynomialDegreeTooLarge);
return Err(SynthesisError::PolynomialDegreeTooLarge)
}
}
@@ -69,18 +76,17 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
omega: omega,
omegainv: omega.inverse().unwrap(),
geninv: E::Fr::multiplicative_generator().inverse().unwrap(),
minv: E::Fr::from_str(&format!("{}", m))
.unwrap()
.inverse()
.unwrap(),
minv: E::Fr::from_str(&format!("{}", m)).unwrap().inverse().unwrap()
})
}
pub fn fft(&mut self, worker: &Worker) {
pub fn fft(&mut self, worker: &Worker)
{
best_fft(&mut self.coeffs, worker, &self.omega, self.exp);
}
pub fn ifft(&mut self, worker: &Worker) {
pub fn ifft(&mut self, worker: &Worker)
{
best_fft(&mut self.coeffs, worker, &self.omegainv, self.exp);
worker.scope(self.coeffs.len(), |scope, chunk| {
@@ -96,7 +102,8 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
});
}
pub fn distribute_powers(&mut self, worker: &Worker, g: E::Fr) {
pub fn distribute_powers(&mut self, worker: &Worker, g: E::Fr)
{
worker.scope(self.coeffs.len(), |scope, chunk| {
for (i, v) in self.coeffs.chunks_mut(chunk).enumerate() {
scope.spawn(move || {
@@ -110,12 +117,14 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
});
}
pub fn coset_fft(&mut self, worker: &Worker) {
pub fn coset_fft(&mut self, worker: &Worker)
{
self.distribute_powers(worker, E::Fr::multiplicative_generator());
self.fft(worker);
}
pub fn icoset_fft(&mut self, worker: &Worker) {
pub fn icoset_fft(&mut self, worker: &Worker)
{
let geninv = self.geninv;
self.ifft(worker);
@@ -134,11 +143,9 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
/// The target polynomial is the zero polynomial in our
/// evaluation domain, so we must perform division over
/// a coset.
pub fn divide_by_z_on_coset(&mut self, worker: &Worker) {
let i = self
.z(&E::Fr::multiplicative_generator())
.inverse()
.unwrap();
pub fn divide_by_z_on_coset(&mut self, worker: &Worker)
{
let i = self.z(&E::Fr::multiplicative_generator()).inverse().unwrap();
worker.scope(self.coeffs.len(), |scope, chunk| {
for v in self.coeffs.chunks_mut(chunk) {
@@ -156,11 +163,7 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
assert_eq!(self.coeffs.len(), other.coeffs.len());
worker.scope(self.coeffs.len(), |scope, chunk| {
for (a, b) in self
.coeffs
.chunks_mut(chunk)
.zip(other.coeffs.chunks(chunk))
{
for (a, b) in self.coeffs.chunks_mut(chunk).zip(other.coeffs.chunks(chunk)) {
scope.spawn(move || {
for (a, b) in a.iter_mut().zip(b.iter()) {
a.group_mul_assign(&b.0);
@@ -175,11 +178,7 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
assert_eq!(self.coeffs.len(), other.coeffs.len());
worker.scope(self.coeffs.len(), |scope, chunk| {
for (a, b) in self
.coeffs
.chunks_mut(chunk)
.zip(other.coeffs.chunks(chunk))
{
for (a, b) in self.coeffs.chunks_mut(chunk).zip(other.coeffs.chunks(chunk)) {
scope.spawn(move || {
for (a, b) in a.iter_mut().zip(b.iter()) {
a.group_sub_assign(&b);
@@ -190,7 +189,7 @@ impl<E: ScalarEngine, G: Group<E>> EvaluationDomain<E, G> {
}
}
pub trait Group<E: ScalarEngine>: Sized + Copy + Clone + Send + Sync {
pub trait Group<E: Engine>: Sized + Copy + Clone + Send + Sync {
fn group_zero() -> Self;
fn group_mul_assign(&mut self, by: &E::Fr);
fn group_add_assign(&mut self, other: &Self);
@@ -205,7 +204,7 @@ impl<G: CurveProjective> PartialEq for Point<G> {
}
}
impl<G: CurveProjective> Copy for Point<G> {}
impl<G: CurveProjective> Copy for Point<G> { }
impl<G: CurveProjective> Clone for Point<G> {
fn clone(&self) -> Point<G> {
@@ -228,23 +227,23 @@ impl<G: CurveProjective> Group<G::Engine> for Point<G> {
}
}
pub struct Scalar<E: ScalarEngine>(pub E::Fr);
pub struct Scalar<E: Engine>(pub E::Fr);
impl<E: ScalarEngine> PartialEq for Scalar<E> {
impl<E: Engine> PartialEq for Scalar<E> {
fn eq(&self, other: &Scalar<E>) -> bool {
self.0 == other.0
}
}
impl<E: ScalarEngine> Copy for Scalar<E> {}
impl<E: Engine> Copy for Scalar<E> { }
impl<E: ScalarEngine> Clone for Scalar<E> {
impl<E: Engine> Clone for Scalar<E> {
fn clone(&self) -> Scalar<E> {
*self
}
}
impl<E: ScalarEngine> Group<E> for Scalar<E> {
impl<E: Engine> Group<E> for Scalar<E> {
fn group_zero() -> Self {
Scalar(E::Fr::zero())
}
@@ -259,7 +258,8 @@ impl<E: ScalarEngine> Group<E> for Scalar<E> {
}
}
fn best_fft<E: ScalarEngine, T: Group<E>>(a: &mut [T], worker: &Worker, omega: &E::Fr, log_n: u32) {
fn best_fft<E: Engine, T: Group<E>>(a: &mut [T], worker: &Worker, omega: &E::Fr, log_n: u32)
{
let log_cpus = worker.log_num_cpus();
if log_n <= log_cpus {
@@ -269,7 +269,8 @@ fn best_fft<E: ScalarEngine, T: Group<E>>(a: &mut [T], worker: &Worker, omega: &
}
}
fn serial_fft<E: ScalarEngine, T: Group<E>>(a: &mut [T], omega: &E::Fr, log_n: u32) {
fn serial_fft<E: Engine, T: Group<E>>(a: &mut [T], omega: &E::Fr, log_n: u32)
{
fn bitreverse(mut n: u32, l: u32) -> u32 {
let mut r = 0;
for _ in 0..l {
@@ -291,35 +292,36 @@ fn serial_fft<E: ScalarEngine, T: Group<E>>(a: &mut [T], omega: &E::Fr, log_n: u
let mut m = 1;
for _ in 0..log_n {
let w_m = omega.pow(&[(n / (2 * m)) as u64]);
let w_m = omega.pow(&[(n / (2*m)) as u64]);
let mut k = 0;
while k < n {
let mut w = E::Fr::one();
for j in 0..m {
let mut t = a[(k + j + m) as usize];
let mut t = a[(k+j+m) as usize];
t.group_mul_assign(&w);
let mut tmp = a[(k + j) as usize];
let mut tmp = a[(k+j) as usize];
tmp.group_sub_assign(&t);
a[(k + j + m) as usize] = tmp;
a[(k + j) as usize].group_add_assign(&t);
a[(k+j+m) as usize] = tmp;
a[(k+j) as usize].group_add_assign(&t);
w.mul_assign(&w_m);
}
k += 2 * m;
k += 2*m;
}
m *= 2;
}
}
fn parallel_fft<E: ScalarEngine, T: Group<E>>(
fn parallel_fft<E: Engine, T: Group<E>>(
a: &mut [T],
worker: &Worker,
omega: &E::Fr,
log_n: u32,
log_cpus: u32,
) {
log_cpus: u32
)
{
assert!(log_n >= log_cpus);
let num_cpus = 1 << log_cpus;
@@ -373,23 +375,19 @@ fn parallel_fft<E: ScalarEngine, T: Group<E>>(
// Test multiplying various (low degree) polynomials together and
// comparing with naive evaluations.
#[cfg(feature = "pairing")]
#[test]
fn polynomial_arith() {
use pairing::bls12_381::Bls12;
use rand_core::RngCore;
use rand::{self, Rand};
fn test_mul<E: ScalarEngine, R: RngCore>(rng: &mut R) {
fn test_mul<E: Engine, R: rand::Rng>(rng: &mut R)
{
let worker = Worker::new();
for coeffs_a in 0..70 {
for coeffs_b in 0..70 {
let mut a: Vec<_> = (0..coeffs_a)
.map(|_| Scalar::<E>(E::Fr::random(rng)))
.collect();
let mut b: Vec<_> = (0..coeffs_b)
.map(|_| Scalar::<E>(E::Fr::random(rng)))
.collect();
let mut a: Vec<_> = (0..coeffs_a).map(|_| Scalar::<E>(E::Fr::rand(rng))).collect();
let mut b: Vec<_> = (0..coeffs_b).map(|_| Scalar::<E>(E::Fr::rand(rng))).collect();
// naive evaluation
let mut naive = vec![Scalar(E::Fr::zero()); coeffs_a + coeffs_b];
@@ -424,13 +422,13 @@ fn polynomial_arith() {
test_mul::<Bls12, _>(rng);
}
#[cfg(feature = "pairing")]
#[test]
fn fft_composition() {
use pairing::bls12_381::Bls12;
use rand_core::RngCore;
use rand;
fn test_comp<E: ScalarEngine, R: RngCore>(rng: &mut R) {
fn test_comp<E: Engine, R: rand::Rng>(rng: &mut R)
{
let worker = Worker::new();
for coeffs in 0..10 {
@@ -438,7 +436,7 @@ fn fft_composition() {
let mut v = vec![];
for _ in 0..coeffs {
v.push(Scalar::<E>(E::Fr::random(rng)));
v.push(Scalar::<E>(rng.gen()));
}
let mut domain = EvaluationDomain::from_coeffs(v.clone()).unwrap();
@@ -462,27 +460,25 @@ fn fft_composition() {
test_comp::<Bls12, _>(rng);
}
#[cfg(feature = "pairing")]
#[test]
fn parallel_fft_consistency() {
use pairing::bls12_381::Bls12;
use rand_core::RngCore;
use rand::{self, Rand};
use std::cmp::min;
fn test_consistency<E: ScalarEngine, R: RngCore>(rng: &mut R) {
fn test_consistency<E: Engine, R: rand::Rng>(rng: &mut R)
{
let worker = Worker::new();
for _ in 0..5 {
for log_d in 0..10 {
let d = 1 << log_d;
let v1 = (0..d)
.map(|_| Scalar::<E>(E::Fr::random(rng)))
.collect::<Vec<_>>();
let v1 = (0..d).map(|_| Scalar::<E>(E::Fr::rand(rng))).collect::<Vec<_>>();
let mut v1 = EvaluationDomain::from_coeffs(v1).unwrap();
let mut v2 = EvaluationDomain::from_coeffs(v1.coeffs.clone()).unwrap();
for log_cpus in log_d..min(log_d + 1, 3) {
for log_cpus in log_d..min(log_d+1, 3) {
parallel_fft(&mut v1.coeffs, &worker, &v1.omega, log_d, log_cpus);
serial_fft(&mut v2.coeffs, &v2.omega, log_d);

View File

@@ -1,110 +0,0 @@
use super::boolean::Boolean;
use super::num::Num;
use super::Assignment;
use crate::{ConstraintSystem, SynthesisError};
use ff::{Field, PrimeField};
use pairing::Engine;
/// Takes a sequence of booleans and exposes them as compact
/// public inputs
pub fn pack_into_inputs<E, CS>(mut cs: CS, bits: &[Boolean]) -> Result<(), SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
{
for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate() {
let mut num = Num::<E>::zero();
let mut coeff = E::Fr::one();
for bit in bits {
num = num.add_bool_with_coeff(CS::one(), bit, coeff);
coeff.double();
}
let input = cs.alloc_input(|| format!("input {}", i), || Ok(*num.get_value().get()?))?;
// num * 1 = input
cs.enforce(
|| format!("packing constraint {}", i),
|_| num.lc(E::Fr::one()),
|lc| lc + CS::one(),
|lc| lc + input,
);
}
Ok(())
}
pub fn bytes_to_bits(bytes: &[u8]) -> Vec<bool> {
bytes
.iter()
.flat_map(|&v| (0..8).rev().map(move |i| (v >> i) & 1 == 1))
.collect()
}
pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec<bool> {
bytes
.iter()
.flat_map(|&v| (0..8).map(move |i| (v >> i) & 1 == 1))
.collect()
}
pub fn compute_multipacking<E: Engine>(bits: &[bool]) -> Vec<E::Fr> {
let mut result = vec![];
for bits in bits.chunks(E::Fr::CAPACITY as usize) {
let mut cur = E::Fr::zero();
let mut coeff = E::Fr::one();
for bit in bits {
if *bit {
cur.add_assign(&coeff);
}
coeff.double();
}
result.push(cur);
}
result
}
#[test]
fn test_multipacking() {
use crate::ConstraintSystem;
use pairing::bls12_381::Bls12;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
use super::boolean::{AllocatedBit, Boolean};
use crate::gadgets::test::*;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
for num_bits in 0..1500 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let bits: Vec<bool> = (0..num_bits).map(|_| rng.next_u32() % 2 != 0).collect();
let circuit_bits = bits
.iter()
.enumerate()
.map(|(i, &b)| {
Boolean::from(
AllocatedBit::alloc(cs.namespace(|| format!("bit {}", i)), Some(b)).unwrap(),
)
})
.collect::<Vec<_>>();
let expected_inputs = compute_multipacking::<Bls12>(&bits);
pack_into_inputs(cs.namespace(|| "pack"), &circuit_bits).unwrap();
assert!(cs.is_satisfied());
assert!(cs.verify(&expected_inputs));
}
}

View File

@@ -1,39 +1,65 @@
use rand_core::RngCore;
use rand::Rng;
use std::sync::Arc;
use ff::{Field, PrimeField};
use group::{CurveAffine, CurveProjective, Wnaf};
use pairing::Engine;
use pairing::{
Engine,
PrimeField,
Field,
Wnaf,
CurveProjective,
CurveAffine
};
use super::{Parameters, VerifyingKey};
use super::{
Parameters,
VerifyingKey
};
use {Circuit, ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};
use ::{
SynthesisError,
Circuit,
ConstraintSystem,
LinearCombination,
Variable,
Index
};
use domain::{EvaluationDomain, Scalar};
use ::domain::{
EvaluationDomain,
Scalar
};
use multicore::Worker;
use ::multicore::{
Worker
};
/// Generates a random common reference string for
/// a circuit.
pub fn generate_random_parameters<E, C, R>(
circuit: C,
rng: &mut R,
rng: &mut R
) -> Result<Parameters<E>, SynthesisError>
where
E: Engine,
C: Circuit<E>,
R: RngCore,
where E: Engine, C: Circuit<E>, R: Rng
{
let g1 = E::G1::random(rng);
let g2 = E::G2::random(rng);
let alpha = E::Fr::random(rng);
let beta = E::Fr::random(rng);
let gamma = E::Fr::random(rng);
let delta = E::Fr::random(rng);
let tau = E::Fr::random(rng);
let g1 = rng.gen();
let g2 = rng.gen();
let alpha = rng.gen();
let beta = rng.gen();
let gamma = rng.gen();
let delta = rng.gen();
let tau = rng.gen();
generate_parameters::<E, C>(circuit, g1, g2, alpha, beta, gamma, delta, tau)
generate_parameters::<E, C>(
circuit,
g1,
g2,
alpha,
beta,
gamma,
delta,
tau
)
}
/// This is our assembly structure that we'll use to synthesize the
@@ -47,17 +73,18 @@ struct KeypairAssembly<E: Engine> {
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)>>,
ct_aux: Vec<Vec<(E::Fr, usize)>>
}
impl<E: Engine> ConstraintSystem<E> for KeypairAssembly<E> {
type Root = Self;
fn alloc<F, A, AR>(&mut self, _: A, _: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
fn alloc<F, A, AR>(
&mut self,
_: A,
_: F
) -> Result<Variable, SynthesisError>
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
{
// There is no assignment, so we don't even invoke the
// function for obtaining one.
@@ -72,11 +99,12 @@ impl<E: Engine> ConstraintSystem<E> for KeypairAssembly<E> {
Ok(Variable(Index::Aux(index)))
}
fn alloc_input<F, A, AR>(&mut self, _: A, _: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
fn alloc_input<F, A, AR>(
&mut self,
_: A,
_: F
) -> Result<Variable, SynthesisError>
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
{
// There is no assignment, so we don't even invoke the
// function for obtaining one.
@@ -91,59 +119,48 @@ impl<E: Engine> ConstraintSystem<E> for KeypairAssembly<E> {
Ok(Variable(Index::Input(index)))
}
fn enforce<A, AR, LA, LB, LC>(&mut self, _: A, a: LA, b: LB, c: LC)
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
fn enforce<A, AR, LA, LB, LC>(
&mut self,
_: A,
a: LA,
b: LB,
c: LC
)
where A: FnOnce() -> AR, AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>
{
fn eval<E: Engine>(
l: LinearCombination<E>,
inputs: &mut [Vec<(E::Fr, usize)>],
aux: &mut [Vec<(E::Fr, usize)>],
this_constraint: usize,
) {
this_constraint: usize
)
{
for (index, coeff) in l.0 {
match index {
Variable(Index::Input(id)) => inputs[id].push((coeff, this_constraint)),
Variable(Index::Aux(id)) => aux[id].push((coeff, this_constraint)),
Variable(Index::Aux(id)) => aux[id].push((coeff, this_constraint))
}
}
}
eval(
a(LinearCombination::zero()),
&mut self.at_inputs,
&mut self.at_aux,
self.num_constraints,
);
eval(
b(LinearCombination::zero()),
&mut self.bt_inputs,
&mut self.bt_aux,
self.num_constraints,
);
eval(
c(LinearCombination::zero()),
&mut self.ct_inputs,
&mut self.ct_aux,
self.num_constraints,
);
eval(a(LinearCombination::zero()), &mut self.at_inputs, &mut self.at_aux, self.num_constraints);
eval(b(LinearCombination::zero()), &mut self.bt_inputs, &mut self.bt_aux, self.num_constraints);
eval(c(LinearCombination::zero()), &mut self.ct_inputs, &mut self.ct_aux, self.num_constraints);
self.num_constraints += 1;
}
fn push_namespace<NR, N>(&mut self, _: N)
where
NR: Into<String>,
N: FnOnce() -> NR,
where NR: Into<String>, N: FnOnce() -> NR
{
// Do nothing; we don't care about namespaces in this context.
}
fn pop_namespace(&mut self) {
fn pop_namespace(&mut self)
{
// Do nothing; we don't care about namespaces in this context.
}
@@ -161,11 +178,9 @@ pub fn generate_parameters<E, C>(
beta: E::Fr,
gamma: E::Fr,
delta: E::Fr,
tau: E::Fr,
tau: E::Fr
) -> Result<Parameters<E>, SynthesisError>
where
E: Engine,
C: Circuit<E>,
where E: Engine, C: Circuit<E>
{
let mut assembly = KeypairAssembly {
num_inputs: 0,
@@ -176,7 +191,7 @@ where
ct_inputs: vec![],
at_aux: vec![],
bt_aux: vec![],
ct_aux: vec![],
ct_aux: vec![]
};
// Allocate the "one" input variable
@@ -188,7 +203,11 @@ where
// Input constraints to ensure full density of IC query
// x * 0 = 0
for i in 0..assembly.num_inputs {
assembly.enforce(|| "", |lc| lc + Variable(Index::Input(i)), |lc| lc, |lc| lc);
assembly.enforce(|| "",
|lc| lc + Variable(Index::Input(i)),
|lc| lc,
|lc| lc,
);
}
// Create bases for blind evaluation of polynomials at tau
@@ -226,9 +245,10 @@ where
{
let powers_of_tau = powers_of_tau.as_mut();
worker.scope(powers_of_tau.len(), |scope, chunk| {
for (i, powers_of_tau) in powers_of_tau.chunks_mut(chunk).enumerate() {
for (i, powers_of_tau) in powers_of_tau.chunks_mut(chunk).enumerate()
{
scope.spawn(move || {
let mut current_tau_power = tau.pow(&[(i * chunk) as u64]);
let mut current_tau_power = tau.pow(&[(i*chunk) as u64]);
for p in powers_of_tau {
p.0 = current_tau_power;
@@ -245,15 +265,14 @@ where
// Compute the H query with multiple threads
worker.scope(h.len(), |scope, chunk| {
for (h, p) in h
.chunks_mut(chunk)
.zip(powers_of_tau.as_ref().chunks(chunk))
for (h, p) in h.chunks_mut(chunk).zip(powers_of_tau.as_ref().chunks(chunk))
{
let mut g1_wnaf = g1_wnaf.shared();
scope.spawn(move || {
// Set values of the H query to g1^{(tau^i * t(tau)) / delta}
for (h, p) in h.iter_mut().zip(p.iter()) {
for (h, p) in h.iter_mut().zip(p.iter())
{
// Compute final exponent
let mut exp = p.0;
exp.mul_assign(&coeff);
@@ -306,8 +325,9 @@ where
beta: &E::Fr,
// Worker
worker: &Worker,
) {
worker: &Worker
)
{
// Sanity check
assert_eq!(a.len(), at.len());
assert_eq!(a.len(), bt.len());
@@ -318,32 +338,31 @@ where
// Evaluate polynomials in multiple threads
worker.scope(a.len(), |scope, chunk| {
for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a
.chunks_mut(chunk)
.zip(b_g1.chunks_mut(chunk))
.zip(b_g2.chunks_mut(chunk))
.zip(ext.chunks_mut(chunk))
.zip(at.chunks(chunk))
.zip(bt.chunks(chunk))
.zip(ct.chunks(chunk))
for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a.chunks_mut(chunk)
.zip(b_g1.chunks_mut(chunk))
.zip(b_g2.chunks_mut(chunk))
.zip(ext.chunks_mut(chunk))
.zip(at.chunks(chunk))
.zip(bt.chunks(chunk))
.zip(ct.chunks(chunk))
{
let mut g1_wnaf = g1_wnaf.shared();
let mut g2_wnaf = g2_wnaf.shared();
scope.spawn(move || {
for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a
.iter_mut()
.zip(b_g1.iter_mut())
.zip(b_g2.iter_mut())
.zip(ext.iter_mut())
.zip(at.iter())
.zip(bt.iter())
.zip(ct.iter())
for ((((((a, b_g1), b_g2), ext), at), bt), ct) in a.iter_mut()
.zip(b_g1.iter_mut())
.zip(b_g2.iter_mut())
.zip(ext.iter_mut())
.zip(at.iter())
.zip(bt.iter())
.zip(ct.iter())
{
fn eval_at_tau<E: Engine>(
powers_of_tau: &[Scalar<E>],
p: &[(E::Fr, usize)],
) -> E::Fr {
p: &[(E::Fr, usize)]
) -> E::Fr
{
let mut acc = E::Fr::zero();
for &(ref coeff, index) in p {
@@ -408,10 +427,10 @@ where
&gamma_inverse,
&alpha,
&beta,
&worker,
&worker
);
// Evaluate for auxiliary variables.
// Evaluate for auxillary variables.
eval(
&g1_wnaf,
&g2_wnaf,
@@ -426,7 +445,7 @@ where
&delta_inverse,
&alpha,
&beta,
&worker,
&worker
);
// Don't allow any elements be unconstrained, so that
@@ -447,7 +466,7 @@ where
gamma_g2: g2.mul(gamma).into_affine(),
delta_g1: g1.mul(delta).into_affine(),
delta_g2: g2.mul(delta).into_affine(),
ic: ic.into_iter().map(|e| e.into_affine()).collect(),
ic: ic.into_iter().map(|e| e.into_affine()).collect()
};
Ok(Parameters {
@@ -456,23 +475,8 @@ where
l: Arc::new(l.into_iter().map(|e| e.into_affine()).collect()),
// Filter points at infinity away from A/B queries
a: Arc::new(
a.into_iter()
.filter(|e| !e.is_zero())
.map(|e| e.into_affine())
.collect(),
),
b_g1: Arc::new(
b_g1.into_iter()
.filter(|e| !e.is_zero())
.map(|e| e.into_affine())
.collect(),
),
b_g2: Arc::new(
b_g2.into_iter()
.filter(|e| !e.is_zero())
.map(|e| e.into_affine())
.collect(),
),
a: Arc::new(a.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect()),
b_g1: Arc::new(b_g1.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect()),
b_g2: Arc::new(b_g2.into_iter().filter(|e| !e.is_zero()).map(|e| e.into_affine()).collect())
})
}

View File

@@ -1,12 +1,17 @@
use group::{CurveAffine, EncodedPoint};
use pairing::{Engine, PairingCurveAffine};
use pairing::{
Engine,
CurveAffine,
EncodedPoint
};
use SynthesisError;
use ::{
SynthesisError
};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use multiexp::SourceBuilder;
use std::io::{self, Read, Write};
use std::sync::Arc;
use byteorder::{BigEndian, WriteBytesExt, ReadBytesExt};
#[cfg(test)]
mod tests;
@@ -23,17 +28,23 @@ pub use self::verifier::*;
pub struct Proof<E: Engine> {
pub a: E::G1Affine,
pub b: E::G2Affine,
pub c: E::G1Affine,
pub c: E::G1Affine
}
impl<E: Engine> PartialEq for Proof<E> {
fn eq(&self, other: &Self) -> bool {
self.a == other.a && self.b == other.b && self.c == other.c
self.a == other.a &&
self.b == other.b &&
self.c == other.c
}
}
impl<E: Engine> Proof<E> {
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
pub fn write<W: Write>(
&self,
mut writer: W
) -> io::Result<()>
{
writer.write_all(self.a.into_compressed().as_ref())?;
writer.write_all(self.b.into_compressed().as_ref())?;
writer.write_all(self.c.into_compressed().as_ref())?;
@@ -41,56 +52,48 @@ impl<E: Engine> Proof<E> {
Ok(())
}
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
pub fn read<R: Read>(
mut reader: R
) -> io::Result<Self>
{
let mut g1_repr = <E::G1Affine as CurveAffine>::Compressed::empty();
let mut g2_repr = <E::G2Affine as CurveAffine>::Compressed::empty();
reader.read_exact(g1_repr.as_mut())?;
let a = g1_repr
.into_affine()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
.and_then(|e| {
if e.is_zero() {
Err(io::Error::new(
io::ErrorKind::InvalidData,
"point at infinity",
))
.into_affine()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
.and_then(|e| if e.is_zero() {
Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity"))
} else {
Ok(e)
}
})?;
})?;
reader.read_exact(g2_repr.as_mut())?;
let b = g2_repr
.into_affine()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
.and_then(|e| {
if e.is_zero() {
Err(io::Error::new(
io::ErrorKind::InvalidData,
"point at infinity",
))
.into_affine()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
.and_then(|e| if e.is_zero() {
Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity"))
} else {
Ok(e)
}
})?;
})?;
reader.read_exact(g1_repr.as_mut())?;
let c = g1_repr
.into_affine()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
.and_then(|e| {
if e.is_zero() {
Err(io::Error::new(
io::ErrorKind::InvalidData,
"point at infinity",
))
.into_affine()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
.and_then(|e| if e.is_zero() {
Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity"))
} else {
Ok(e)
}
})?;
})?;
Ok(Proof { a: a, b: b, c: c })
Ok(Proof {
a: a,
b: b,
c: c
})
}
}
@@ -119,23 +122,27 @@ pub struct VerifyingKey<E: Engine> {
// for all public inputs. Because all public inputs have a dummy constraint,
// this is the same size as the number of inputs, and never contains points
// at infinity.
pub ic: Vec<E::G1Affine>,
pub ic: Vec<E::G1Affine>
}
impl<E: Engine> PartialEq for VerifyingKey<E> {
fn eq(&self, other: &Self) -> bool {
self.alpha_g1 == other.alpha_g1
&& self.beta_g1 == other.beta_g1
&& self.beta_g2 == other.beta_g2
&& self.gamma_g2 == other.gamma_g2
&& self.delta_g1 == other.delta_g1
&& self.delta_g2 == other.delta_g2
&& self.ic == other.ic
self.alpha_g1 == other.alpha_g1 &&
self.beta_g1 == other.beta_g1 &&
self.beta_g2 == other.beta_g2 &&
self.gamma_g2 == other.gamma_g2 &&
self.delta_g1 == other.delta_g1 &&
self.delta_g2 == other.delta_g2 &&
self.ic == other.ic
}
}
impl<E: Engine> VerifyingKey<E> {
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
pub fn write<W: Write>(
&self,
mut writer: W
) -> io::Result<()>
{
writer.write_all(self.alpha_g1.into_uncompressed().as_ref())?;
writer.write_all(self.beta_g1.into_uncompressed().as_ref())?;
writer.write_all(self.beta_g2.into_uncompressed().as_ref())?;
@@ -150,39 +157,30 @@ impl<E: Engine> VerifyingKey<E> {
Ok(())
}
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
pub fn read<R: Read>(
mut reader: R
) -> io::Result<Self>
{
let mut g1_repr = <E::G1Affine as CurveAffine>::Uncompressed::empty();
let mut g2_repr = <E::G2Affine as CurveAffine>::Uncompressed::empty();
reader.read_exact(g1_repr.as_mut())?;
let alpha_g1 = g1_repr
.into_affine()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
let alpha_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
reader.read_exact(g1_repr.as_mut())?;
let beta_g1 = g1_repr
.into_affine()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
let beta_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
reader.read_exact(g2_repr.as_mut())?;
let beta_g2 = g2_repr
.into_affine()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
let beta_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
reader.read_exact(g2_repr.as_mut())?;
let gamma_g2 = g2_repr
.into_affine()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
let gamma_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
reader.read_exact(g1_repr.as_mut())?;
let delta_g1 = g1_repr
.into_affine()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
let delta_g1 = g1_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
reader.read_exact(g2_repr.as_mut())?;
let delta_g2 = g2_repr
.into_affine()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
let delta_g2 = g2_repr.into_affine().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
let ic_len = reader.read_u32::<BigEndian>()? as usize;
@@ -191,18 +189,13 @@ impl<E: Engine> VerifyingKey<E> {
for _ in 0..ic_len {
reader.read_exact(g1_repr.as_mut())?;
let g1 = g1_repr
.into_affine()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
.and_then(|e| {
if e.is_zero() {
Err(io::Error::new(
io::ErrorKind::InvalidData,
"point at infinity",
))
} else {
Ok(e)
}
})?;
.into_affine()
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
.and_then(|e| if e.is_zero() {
Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity"))
} else {
Ok(e)
})?;
ic.push(g1);
}
@@ -214,7 +207,7 @@ impl<E: Engine> VerifyingKey<E> {
gamma_g2: gamma_g2,
delta_g1: delta_g1,
delta_g2: delta_g2,
ic: ic,
ic: ic
})
}
}
@@ -223,12 +216,12 @@ impl<E: Engine> VerifyingKey<E> {
pub struct Parameters<E: Engine> {
pub vk: VerifyingKey<E>,
// Elements of the form ((tau^i * t(tau)) / delta) for i between 0 and
// Elements of the form ((tau^i * t(tau)) / delta) for i between 0 and
// m-2 inclusive. Never contains points at infinity.
pub h: Arc<Vec<E::G1Affine>>,
// Elements of the form (beta * u_i(tau) + alpha v_i(tau) + w_i(tau)) / delta
// for all auxiliary inputs. Variables can never be unconstrained, so this
// for all auxillary inputs. Variables can never be unconstrained, so this
// never contains points at infinity.
pub l: Arc<Vec<E::G1Affine>>,
@@ -241,22 +234,26 @@ pub struct Parameters<E: Engine> {
// G1 and G2 for C/B queries, respectively. Never contains points at
// infinity for the same reason as the "A" polynomials.
pub b_g1: Arc<Vec<E::G1Affine>>,
pub b_g2: Arc<Vec<E::G2Affine>>,
pub b_g2: Arc<Vec<E::G2Affine>>
}
impl<E: Engine> PartialEq for Parameters<E> {
fn eq(&self, other: &Self) -> bool {
self.vk == other.vk
&& self.h == other.h
&& self.l == other.l
&& self.a == other.a
&& self.b_g1 == other.b_g1
&& self.b_g2 == other.b_g2
self.vk == other.vk &&
self.h == other.h &&
self.l == other.l &&
self.a == other.a &&
self.b_g1 == other.b_g1 &&
self.b_g2 == other.b_g2
}
}
impl<E: Engine> Parameters<E> {
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
pub fn write<W: Write>(
&self,
mut writer: W
) -> io::Result<()>
{
self.vk.write(&mut writer)?;
writer.write_u32::<BigEndian>(self.h.len() as u32)?;
@@ -287,26 +284,27 @@ impl<E: Engine> Parameters<E> {
Ok(())
}
pub fn read<R: Read>(mut reader: R, checked: bool) -> io::Result<Self> {
pub fn read<R: Read>(
mut reader: R,
checked: bool
) -> io::Result<Self>
{
let read_g1 = |reader: &mut R| -> io::Result<E::G1Affine> {
let mut repr = <E::G1Affine as CurveAffine>::Uncompressed::empty();
reader.read_exact(repr.as_mut())?;
if checked {
repr.into_affine()
repr
.into_affine()
} else {
repr.into_affine_unchecked()
repr
.into_affine_unchecked()
}
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
.and_then(|e| {
if e.is_zero() {
Err(io::Error::new(
io::ErrorKind::InvalidData,
"point at infinity",
))
} else {
Ok(e)
}
.and_then(|e| if e.is_zero() {
Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity"))
} else {
Ok(e)
})
};
@@ -315,20 +313,17 @@ impl<E: Engine> Parameters<E> {
reader.read_exact(repr.as_mut())?;
if checked {
repr.into_affine()
repr
.into_affine()
} else {
repr.into_affine_unchecked()
repr
.into_affine_unchecked()
}
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
.and_then(|e| {
if e.is_zero() {
Err(io::Error::new(
io::ErrorKind::InvalidData,
"point at infinity",
))
} else {
Ok(e)
}
.and_then(|e| if e.is_zero() {
Err(io::Error::new(io::ErrorKind::InvalidData, "point at infinity"))
} else {
Ok(e)
})
};
@@ -381,7 +376,7 @@ impl<E: Engine> Parameters<E> {
l: Arc::new(l),
a: Arc::new(a),
b_g1: Arc::new(b_g1),
b_g2: Arc::new(b_g2),
b_g2: Arc::new(b_g2)
})
}
}
@@ -390,34 +385,43 @@ pub struct PreparedVerifyingKey<E: Engine> {
/// Pairing result of alpha*beta
alpha_g1_beta_g2: E::Fqk,
/// -gamma in G2
neg_gamma_g2: <E::G2Affine as PairingCurveAffine>::Prepared,
neg_gamma_g2: <E::G2Affine as CurveAffine>::Prepared,
/// -delta in G2
neg_delta_g2: <E::G2Affine as PairingCurveAffine>::Prepared,
neg_delta_g2: <E::G2Affine as CurveAffine>::Prepared,
/// Copy of IC from `VerifiyingKey`.
ic: Vec<E::G1Affine>,
ic: Vec<E::G1Affine>
}
pub trait ParameterSource<E: Engine> {
type G1Builder: SourceBuilder<E::G1Affine>;
type G2Builder: SourceBuilder<E::G2Affine>;
fn get_vk(&mut self, num_ic: usize) -> Result<VerifyingKey<E>, SynthesisError>;
fn get_h(&mut self, num_h: usize) -> Result<Self::G1Builder, SynthesisError>;
fn get_l(&mut self, num_l: usize) -> Result<Self::G1Builder, SynthesisError>;
fn get_vk(
&mut self,
num_ic: usize
) -> Result<VerifyingKey<E>, SynthesisError>;
fn get_h(
&mut self,
num_h: usize
) -> Result<Self::G1Builder, SynthesisError>;
fn get_l(
&mut self,
num_l: usize
) -> Result<Self::G1Builder, SynthesisError>;
fn get_a(
&mut self,
num_inputs: usize,
num_aux: usize,
num_aux: usize
) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>;
fn get_b_g1(
&mut self,
num_inputs: usize,
num_aux: usize,
num_aux: usize
) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>;
fn get_b_g2(
&mut self,
num_inputs: usize,
num_aux: usize,
num_aux: usize
) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError>;
}
@@ -425,39 +429,54 @@ impl<'a, E: Engine> ParameterSource<E> for &'a Parameters<E> {
type G1Builder = (Arc<Vec<E::G1Affine>>, usize);
type G2Builder = (Arc<Vec<E::G2Affine>>, usize);
fn get_vk(&mut self, _: usize) -> Result<VerifyingKey<E>, SynthesisError> {
fn get_vk(
&mut self,
_: usize
) -> Result<VerifyingKey<E>, SynthesisError>
{
Ok(self.vk.clone())
}
fn get_h(&mut self, _: usize) -> Result<Self::G1Builder, SynthesisError> {
fn get_h(
&mut self,
_: usize
) -> Result<Self::G1Builder, SynthesisError>
{
Ok((self.h.clone(), 0))
}
fn get_l(&mut self, _: usize) -> Result<Self::G1Builder, SynthesisError> {
fn get_l(
&mut self,
_: usize
) -> Result<Self::G1Builder, SynthesisError>
{
Ok((self.l.clone(), 0))
}
fn get_a(
&mut self,
num_inputs: usize,
_: usize,
) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> {
_: usize
) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>
{
Ok(((self.a.clone(), 0), (self.a.clone(), num_inputs)))
}
fn get_b_g1(
&mut self,
num_inputs: usize,
_: usize,
) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError> {
_: usize
) -> Result<(Self::G1Builder, Self::G1Builder), SynthesisError>
{
Ok(((self.b_g1.clone(), 0), (self.b_g1.clone(), num_inputs)))
}
fn get_b_g2(
&mut self,
num_inputs: usize,
_: usize,
) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError> {
_: usize
) -> Result<(Self::G2Builder, Self::G2Builder), SynthesisError>
{
Ok(((self.b_g2.clone(), 0), (self.b_g2.clone(), num_inputs)))
}
}
@@ -465,38 +484,41 @@ impl<'a, E: Engine> ParameterSource<E> for &'a Parameters<E> {
#[cfg(test)]
mod test_with_bls12_381 {
use super::*;
use {Circuit, ConstraintSystem, SynthesisError};
use {Circuit, SynthesisError, ConstraintSystem};
use ff::Field;
use rand::{Rand, thread_rng};
use pairing::{Field};
use pairing::bls12_381::{Bls12, Fr};
use rand::thread_rng;
#[test]
fn serialization() {
struct MySillyCircuit<E: Engine> {
a: Option<E::Fr>,
b: Option<E::Fr>,
b: Option<E::Fr>
}
impl<E: Engine> Circuit<E> for MySillyCircuit<E> {
fn synthesize<CS: ConstraintSystem<E>>(
self,
cs: &mut CS,
) -> Result<(), SynthesisError> {
cs: &mut CS
) -> Result<(), SynthesisError>
{
let a = cs.alloc(|| "a", || self.a.ok_or(SynthesisError::AssignmentMissing))?;
let b = cs.alloc(|| "b", || self.b.ok_or(SynthesisError::AssignmentMissing))?;
let c = cs.alloc_input(
|| "c",
|| {
let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?;
let b = self.b.ok_or(SynthesisError::AssignmentMissing)?;
let c = cs.alloc_input(|| "c", || {
let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?;
let b = self.b.ok_or(SynthesisError::AssignmentMissing)?;
a.mul_assign(&b);
Ok(a)
},
)?;
a.mul_assign(&b);
Ok(a)
})?;
cs.enforce(|| "a*b=c", |lc| lc + a, |lc| lc + b, |lc| lc + c);
cs.enforce(
|| "a*b=c",
|lc| lc + a,
|lc| lc + b,
|lc| lc + c
);
Ok(())
}
@@ -504,9 +526,10 @@ mod test_with_bls12_381 {
let rng = &mut thread_rng();
let params =
generate_random_parameters::<Bls12, _, _>(MySillyCircuit { a: None, b: None }, rng)
.unwrap();
let params = generate_random_parameters::<Bls12, _, _>(
MySillyCircuit { a: None, b: None },
rng
).unwrap();
{
let mut v = vec![];
@@ -524,20 +547,19 @@ mod test_with_bls12_381 {
let pvk = prepare_verifying_key::<Bls12>(&params.vk);
for _ in 0..100 {
let a = Fr::random(rng);
let b = Fr::random(rng);
let a = Fr::rand(rng);
let b = Fr::rand(rng);
let mut c = a;
c.mul_assign(&b);
let proof = create_random_proof(
MySillyCircuit {
a: Some(a),
b: Some(b),
b: Some(b)
},
&params,
rng,
)
.unwrap();
rng
).unwrap();
let mut v = vec![];
proof.write(&mut v).unwrap();

View File

@@ -1,30 +1,54 @@
use rand_core::RngCore;
use rand::Rng;
use std::sync::Arc;
use futures::Future;
use ff::{Field, PrimeField};
use group::{CurveAffine, CurveProjective};
use pairing::Engine;
use pairing::{
Engine,
PrimeField,
Field,
CurveProjective,
CurveAffine
};
use super::{ParameterSource, Proof};
use super::{
ParameterSource,
Proof
};
use {Circuit, ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};
use ::{
SynthesisError,
Circuit,
ConstraintSystem,
LinearCombination,
Variable,
Index
};
use domain::{EvaluationDomain, Scalar};
use ::domain::{
EvaluationDomain,
Scalar
};
use multiexp::{multiexp, DensityTracker, FullDensity};
use ::multiexp::{
DensityTracker,
FullDensity,
multiexp
};
use multicore::Worker;
use ::multicore::{
Worker
};
fn eval<E: Engine>(
lc: &LinearCombination<E>,
mut input_density: Option<&mut DensityTracker>,
mut aux_density: Option<&mut DensityTracker>,
input_assignment: &[E::Fr],
aux_assignment: &[E::Fr],
) -> E::Fr {
aux_assignment: &[E::Fr]
) -> E::Fr
{
let mut acc = E::Fr::zero();
for &(index, coeff) in lc.0.iter() {
@@ -36,7 +60,7 @@ fn eval<E: Engine>(
if let Some(ref mut v) = input_density {
v.inc(i);
}
}
},
Variable(Index::Aux(i)) => {
tmp = aux_assignment[i];
if let Some(ref mut v) = aux_density {
@@ -46,10 +70,10 @@ fn eval<E: Engine>(
}
if coeff == E::Fr::one() {
acc.add_assign(&tmp);
acc.add_assign(&tmp);
} else {
tmp.mul_assign(&coeff);
acc.add_assign(&tmp);
tmp.mul_assign(&coeff);
acc.add_assign(&tmp);
}
}
@@ -69,17 +93,18 @@ struct ProvingAssignment<E: Engine> {
// Assignments of variables
input_assignment: Vec<E::Fr>,
aux_assignment: Vec<E::Fr>,
aux_assignment: Vec<E::Fr>
}
impl<E: Engine> ConstraintSystem<E> for ProvingAssignment<E> {
type Root = Self;
fn alloc<F, A, AR>(&mut self, _: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
fn alloc<F, A, AR>(
&mut self,
_: A,
f: F
) -> Result<Variable, SynthesisError>
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
{
self.aux_assignment.push(f()?);
self.a_aux_density.add_element();
@@ -88,11 +113,12 @@ impl<E: Engine> ConstraintSystem<E> for ProvingAssignment<E> {
Ok(Variable(Index::Aux(self.aux_assignment.len() - 1)))
}
fn alloc_input<F, A, AR>(&mut self, _: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
fn alloc_input<F, A, AR>(
&mut self,
_: A,
f: F
) -> Result<Variable, SynthesisError>
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
{
self.input_assignment.push(f()?);
self.b_input_density.add_element();
@@ -100,13 +126,17 @@ impl<E: Engine> ConstraintSystem<E> for ProvingAssignment<E> {
Ok(Variable(Index::Input(self.input_assignment.len() - 1)))
}
fn enforce<A, AR, LA, LB, LC>(&mut self, _: A, a: LA, b: LB, c: LC)
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
fn enforce<A, AR, LA, LB, LC>(
&mut self,
_: A,
a: LA,
b: LB,
c: LC
)
where A: FnOnce() -> AR, AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>
{
let a = a(LinearCombination::zero());
let b = b(LinearCombination::zero());
@@ -120,14 +150,14 @@ impl<E: Engine> ConstraintSystem<E> for ProvingAssignment<E> {
None,
Some(&mut self.a_aux_density),
&self.input_assignment,
&self.aux_assignment,
&self.aux_assignment
)));
self.b.push(Scalar(eval(
&b,
Some(&mut self.b_input_density),
Some(&mut self.b_aux_density),
&self.input_assignment,
&self.aux_assignment,
&self.aux_assignment
)));
self.c.push(Scalar(eval(
&c,
@@ -138,19 +168,18 @@ impl<E: Engine> ConstraintSystem<E> for ProvingAssignment<E> {
None,
None,
&self.input_assignment,
&self.aux_assignment,
&self.aux_assignment
)));
}
fn push_namespace<NR, N>(&mut self, _: N)
where
NR: Into<String>,
N: FnOnce() -> NR,
where NR: Into<String>, N: FnOnce() -> NR
{
// Do nothing; we don't care about namespaces in this context.
}
fn pop_namespace(&mut self) {
fn pop_namespace(&mut self)
{
// Do nothing; we don't care about namespaces in this context.
}
@@ -162,15 +191,12 @@ impl<E: Engine> ConstraintSystem<E> for ProvingAssignment<E> {
pub fn create_random_proof<E, C, R, P: ParameterSource<E>>(
circuit: C,
params: P,
rng: &mut R,
rng: &mut R
) -> Result<Proof<E>, SynthesisError>
where
E: Engine,
C: Circuit<E>,
R: RngCore,
where E: Engine, C: Circuit<E>, R: Rng
{
let r = E::Fr::random(rng);
let s = E::Fr::random(rng);
let r = rng.gen();
let s = rng.gen();
create_proof::<E, C, P>(circuit, params, r, s)
}
@@ -179,11 +205,9 @@ pub fn create_proof<E, C, P: ParameterSource<E>>(
circuit: C,
mut params: P,
r: E::Fr,
s: E::Fr,
s: E::Fr
) -> Result<Proof<E>, SynthesisError>
where
E: Engine,
C: Circuit<E>,
where E: Engine, C: Circuit<E>
{
let mut prover = ProvingAssignment {
a_aux_density: DensityTracker::new(),
@@ -193,7 +217,7 @@ where
b: vec![],
c: vec![],
input_assignment: vec![],
aux_assignment: vec![],
aux_assignment: vec![]
};
prover.alloc_input(|| "", || Ok(E::Fr::one()))?;
@@ -201,7 +225,11 @@ where
circuit.synthesize(&mut prover)?;
for i in 0..prover.input_assignment.len() {
prover.enforce(|| "", |lc| lc + Variable(Index::Input(i)), |lc| lc, |lc| lc);
prover.enforce(|| "",
|lc| lc + Variable(Index::Input(i)),
|lc| lc,
|lc| lc,
);
}
let worker = Worker::new();
@@ -235,76 +263,31 @@ where
};
// TODO: parallelize if it's even helpful
let input_assignment = Arc::new(
prover
.input_assignment
.into_iter()
.map(|s| s.into_repr())
.collect::<Vec<_>>(),
);
let aux_assignment = Arc::new(
prover
.aux_assignment
.into_iter()
.map(|s| s.into_repr())
.collect::<Vec<_>>(),
);
let input_assignment = Arc::new(prover.input_assignment.into_iter().map(|s| s.into_repr()).collect::<Vec<_>>());
let aux_assignment = Arc::new(prover.aux_assignment.into_iter().map(|s| s.into_repr()).collect::<Vec<_>>());
let l = multiexp(
&worker,
params.get_l(aux_assignment.len())?,
FullDensity,
aux_assignment.clone(),
);
let l = multiexp(&worker, params.get_l(aux_assignment.len())?, FullDensity, aux_assignment.clone());
let a_aux_density_total = prover.a_aux_density.get_total_density();
let (a_inputs_source, a_aux_source) =
params.get_a(input_assignment.len(), a_aux_density_total)?;
let (a_inputs_source, a_aux_source) = params.get_a(input_assignment.len(), a_aux_density_total)?;
let a_inputs = multiexp(
&worker,
a_inputs_source,
FullDensity,
input_assignment.clone(),
);
let a_aux = multiexp(
&worker,
a_aux_source,
Arc::new(prover.a_aux_density),
aux_assignment.clone(),
);
let a_inputs = multiexp(&worker, a_inputs_source, FullDensity, input_assignment.clone());
let a_aux = multiexp(&worker, a_aux_source, Arc::new(prover.a_aux_density), aux_assignment.clone());
let b_input_density = Arc::new(prover.b_input_density);
let b_input_density_total = b_input_density.get_total_density();
let b_aux_density = Arc::new(prover.b_aux_density);
let b_aux_density_total = b_aux_density.get_total_density();
let (b_g1_inputs_source, b_g1_aux_source) =
params.get_b_g1(b_input_density_total, b_aux_density_total)?;
let (b_g1_inputs_source, b_g1_aux_source) = params.get_b_g1(b_input_density_total, b_aux_density_total)?;
let b_g1_inputs = multiexp(
&worker,
b_g1_inputs_source,
b_input_density.clone(),
input_assignment.clone(),
);
let b_g1_aux = multiexp(
&worker,
b_g1_aux_source,
b_aux_density.clone(),
aux_assignment.clone(),
);
let b_g1_inputs = multiexp(&worker, b_g1_inputs_source, b_input_density.clone(), input_assignment.clone());
let b_g1_aux = multiexp(&worker, b_g1_aux_source, b_aux_density.clone(), aux_assignment.clone());
let (b_g2_inputs_source, b_g2_aux_source) =
params.get_b_g2(b_input_density_total, b_aux_density_total)?;
let b_g2_inputs = multiexp(
&worker,
b_g2_inputs_source,
b_input_density,
input_assignment,
);
let (b_g2_inputs_source, b_g2_aux_source) = params.get_b_g2(b_input_density_total, b_aux_density_total)?;
let b_g2_inputs = multiexp(&worker, b_g2_inputs_source, b_input_density, input_assignment);
let b_g2_aux = multiexp(&worker, b_g2_aux_source, b_aux_density, aux_assignment);
if vk.delta_g1.is_zero() || vk.delta_g2.is_zero() {
@@ -346,6 +329,6 @@ where
Ok(Proof {
a: g_a.into_affine(),
b: g_b.into_affine(),
c: g_c.into_affine(),
c: g_c.into_affine()
})
}

View File

@@ -1,13 +1,20 @@
use ff::{
Field, LegendreSymbol, PrimeField, PrimeFieldDecodingError, PrimeFieldRepr, ScalarEngine,
use pairing::{
Engine,
PrimeField,
PrimeFieldRepr,
Field,
SqrtField,
LegendreSymbol,
CurveProjective,
CurveAffine,
PrimeFieldDecodingError,
GroupDecodingError,
EncodedPoint
};
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
use pairing::{Engine, PairingCurveAffine};
use rand_core::RngCore;
use std::cmp::Ordering;
use std::fmt;
use rand::{Rand, Rng};
use std::num::Wrapping;
const MODULUS_R: Wrapping<u32> = Wrapping(64513);
@@ -21,11 +28,13 @@ impl fmt::Display for Fr {
}
}
impl Field for Fr {
fn random<R: RngCore>(rng: &mut R) -> Self {
Fr(Wrapping(rng.next_u32()) % MODULUS_R)
impl Rand for Fr {
fn rand<R: Rng>(rng: &mut R) -> Self {
Fr(Wrapping(rng.gen()) % MODULUS_R)
}
}
impl Field for Fr {
fn zero() -> Self {
Fr(Wrapping(0))
}
@@ -81,13 +90,9 @@ impl SqrtField for Fr {
fn legendre(&self) -> LegendreSymbol {
// s = self^((r - 1) // 2)
let s = self.pow([32256]);
if s == <Fr as Field>::zero() {
LegendreSymbol::Zero
} else if s == <Fr as Field>::one() {
LegendreSymbol::QuadraticResidue
} else {
LegendreSymbol::QuadraticNonResidue
}
if s == <Fr as Field>::zero() { LegendreSymbol::Zero }
else if s == <Fr as Field>::one() { LegendreSymbol::QuadraticResidue }
else { LegendreSymbol::QuadraticNonResidue }
}
fn sqrt(&self) -> Option<Self> {
@@ -105,7 +110,7 @@ impl SqrtField for Fr {
let mut m = Fr::S;
while t != <Fr as Field>::one() {
let mut i = 1;
let mut i = 1;
{
let mut t2i = t;
t2i.square();
@@ -148,6 +153,12 @@ impl PartialOrd for FrRepr {
}
}
impl Rand for FrRepr {
fn rand<R: Rng>(rng: &mut R) -> Self {
FrRepr([rng.gen()])
}
}
impl fmt::Display for FrRepr {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}", (self.0)[0])
@@ -252,29 +263,23 @@ impl PrimeField for Fr {
#[derive(Clone)]
pub struct DummyEngine;
impl ScalarEngine for DummyEngine {
type Fr = Fr;
}
impl Engine for DummyEngine {
type Fr = Fr;
type G1 = Fr;
type G1Affine = Fr;
type G2 = Fr;
type G2Affine = Fr;
type Fq = Fr;
type Fqe = Fr;
// TODO: This should be F_645131 or something. Doesn't matter for now.
type Fqk = Fr;
fn miller_loop<'a, I>(i: I) -> Self::Fqk
where
I: IntoIterator<
Item = &'a (
&'a <Self::G1Affine as PairingCurveAffine>::Prepared,
&'a <Self::G2Affine as PairingCurveAffine>::Prepared,
),
>,
where I: IntoIterator<Item=&'a (
&'a <Self::G1Affine as CurveAffine>::Prepared,
&'a <Self::G2Affine as CurveAffine>::Prepared
)>
{
let mut acc = <Fr as Field>::zero();
@@ -288,7 +293,8 @@ impl Engine for DummyEngine {
}
/// Perform final exponentiation of the result of a miller loop.
fn final_exponentiation(this: &Self::Fqk) -> Option<Self::Fqk> {
fn final_exponentiation(this: &Self::Fqk) -> Option<Self::Fqk>
{
Some(*this)
}
}
@@ -299,10 +305,6 @@ impl CurveProjective for Fr {
type Scalar = Fr;
type Engine = DummyEngine;
fn random<R: RngCore>(rng: &mut R) -> Self {
<Fr as Field>::random(rng)
}
fn zero() -> Self {
<Fr as Field>::zero()
}
@@ -315,7 +317,9 @@ impl CurveProjective for Fr {
<Fr as Field>::is_zero(self)
}
fn batch_normalization(_: &mut [Self]) {}
fn batch_normalization(_: &mut [Self]) {
}
fn is_normalized(&self) -> bool {
true
@@ -337,7 +341,8 @@ impl CurveProjective for Fr {
<Fr as Field>::negate(self);
}
fn mul_assign<S: Into<<Self::Scalar as PrimeField>::Repr>>(&mut self, other: S) {
fn mul_assign<S: Into<<Self::Scalar as PrimeField>::Repr>>(&mut self, other: S)
{
let tmp = Fr::from_repr(other.into()).unwrap();
<Fr as Field>::mul_assign(self, &tmp);
@@ -396,8 +401,11 @@ impl EncodedPoint for FakePoint {
}
impl CurveAffine for Fr {
type Pair = Fr;
type PairingResult = Fr;
type Compressed = FakePoint;
type Uncompressed = FakePoint;
type Prepared = Fr;
type Projective = Fr;
type Base = Fr;
type Scalar = Fr;
@@ -419,7 +427,8 @@ impl CurveAffine for Fr {
<Fr as Field>::negate(self);
}
fn mul<S: Into<<Self::Scalar as PrimeField>::Repr>>(&self, other: S) -> Self::Projective {
fn mul<S: Into<<Self::Scalar as PrimeField>::Repr>>(&self, other: S) -> Self::Projective
{
let mut res = *self;
let tmp = Fr::from_repr(other.into()).unwrap();
@@ -428,16 +437,6 @@ impl CurveAffine for Fr {
res
}
fn into_projective(&self) -> Self::Projective {
*self
}
}
impl PairingCurveAffine for Fr {
type Prepared = Fr;
type Pair = Fr;
type PairingResult = Fr;
fn prepare(&self) -> Self::Prepared {
*self
}
@@ -445,4 +444,8 @@ impl PairingCurveAffine for Fr {
fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
self.mul(*other)
}
fn into_projective(&self) -> Self::Projective {
*self
}
}

View File

@@ -1,87 +1,94 @@
use ff::{Field, PrimeField};
use pairing::Engine;
use pairing::{
Engine,
Field,
PrimeField
};
mod dummy_engine;
use self::dummy_engine::*;
use std::marker::PhantomData;
use {Circuit, ConstraintSystem, SynthesisError};
use ::{
Circuit,
ConstraintSystem,
SynthesisError
};
use super::{create_proof, generate_parameters, prepare_verifying_key, verify_proof};
use super::{
generate_parameters,
prepare_verifying_key,
create_proof,
verify_proof
};
struct XORDemo<E: Engine> {
a: Option<bool>,
b: Option<bool>,
_marker: PhantomData<E>,
_marker: PhantomData<E>
}
impl<E: Engine> Circuit<E> for XORDemo<E> {
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
let a_var = cs.alloc(
|| "a",
|| {
if self.a.is_some() {
if self.a.unwrap() {
Ok(E::Fr::one())
} else {
Ok(E::Fr::zero())
}
fn synthesize<CS: ConstraintSystem<E>>(
self,
cs: &mut CS
) -> Result<(), SynthesisError>
{
let a_var = cs.alloc(|| "a", || {
if self.a.is_some() {
if self.a.unwrap() {
Ok(E::Fr::one())
} else {
Err(SynthesisError::AssignmentMissing)
Ok(E::Fr::zero())
}
},
)?;
} else {
Err(SynthesisError::AssignmentMissing)
}
})?;
cs.enforce(
|| "a_boolean_constraint",
|lc| lc + CS::one() - a_var,
|lc| lc + a_var,
|lc| lc,
|lc| lc
);
let b_var = cs.alloc(
|| "b",
|| {
if self.b.is_some() {
if self.b.unwrap() {
Ok(E::Fr::one())
} else {
Ok(E::Fr::zero())
}
let b_var = cs.alloc(|| "b", || {
if self.b.is_some() {
if self.b.unwrap() {
Ok(E::Fr::one())
} else {
Err(SynthesisError::AssignmentMissing)
Ok(E::Fr::zero())
}
},
)?;
} else {
Err(SynthesisError::AssignmentMissing)
}
})?;
cs.enforce(
|| "b_boolean_constraint",
|lc| lc + CS::one() - b_var,
|lc| lc + b_var,
|lc| lc,
|lc| lc
);
let c_var = cs.alloc_input(
|| "c",
|| {
if self.a.is_some() && self.b.is_some() {
if self.a.unwrap() ^ self.b.unwrap() {
Ok(E::Fr::one())
} else {
Ok(E::Fr::zero())
}
let c_var = cs.alloc_input(|| "c", || {
if self.a.is_some() && self.b.is_some() {
if self.a.unwrap() ^ self.b.unwrap() {
Ok(E::Fr::one())
} else {
Err(SynthesisError::AssignmentMissing)
Ok(E::Fr::zero())
}
},
)?;
} else {
Err(SynthesisError::AssignmentMissing)
}
})?;
cs.enforce(
|| "c_xor_constraint",
|lc| lc + a_var + a_var,
|lc| lc + b_var,
|lc| lc + a_var + b_var - c_var,
|lc| lc + a_var + b_var - c_var
);
Ok(())
@@ -102,10 +109,19 @@ fn test_xordemo() {
let c = XORDemo::<DummyEngine> {
a: None,
b: None,
_marker: PhantomData,
_marker: PhantomData
};
generate_parameters(c, g1, g2, alpha, beta, gamma, delta, tau).unwrap()
generate_parameters(
c,
g1,
g2,
alpha,
beta,
gamma,
delta,
tau
).unwrap()
};
// This will synthesize the constraint system:
@@ -213,35 +229,32 @@ fn test_xordemo() {
59158
*/
let u_i = [59158, 48317, 21767, 10402]
.iter()
.map(|e| Fr::from_str(&format!("{}", e)).unwrap())
.collect::<Vec<Fr>>();
let v_i = [0, 0, 60619, 30791]
.iter()
.map(|e| Fr::from_str(&format!("{}", e)).unwrap())
.collect::<Vec<Fr>>();
let w_i = [0, 23320, 41193, 41193]
.iter()
.map(|e| Fr::from_str(&format!("{}", e)).unwrap())
.collect::<Vec<Fr>>();
let u_i = [59158, 48317, 21767, 10402].iter().map(|e| {
Fr::from_str(&format!("{}", e)).unwrap()
}).collect::<Vec<Fr>>();
let v_i = [0, 0, 60619, 30791].iter().map(|e| {
Fr::from_str(&format!("{}", e)).unwrap()
}).collect::<Vec<Fr>>();
let w_i = [0, 23320, 41193, 41193].iter().map(|e| {
Fr::from_str(&format!("{}", e)).unwrap()
}).collect::<Vec<Fr>>();
for (u, a) in u_i.iter().zip(&params.a[..]) {
for (u, a) in u_i.iter()
.zip(&params.a[..])
{
assert_eq!(u, a);
}
for (v, b) in v_i
.iter()
.filter(|&&e| e != Fr::zero())
.zip(&params.b_g1[..])
for (v, b) in v_i.iter()
.filter(|&&e| e != Fr::zero())
.zip(&params.b_g1[..])
{
assert_eq!(v, b);
}
for (v, b) in v_i
.iter()
.filter(|&&e| e != Fr::zero())
.zip(&params.b_g2[..])
for (v, b) in v_i.iter()
.filter(|&&e| e != Fr::zero())
.zip(&params.b_g2[..])
{
assert_eq!(v, b);
}
@@ -286,10 +299,15 @@ fn test_xordemo() {
let c = XORDemo {
a: Some(true),
b: Some(false),
_marker: PhantomData,
_marker: PhantomData
};
create_proof(c, &params, r, s).unwrap()
create_proof(
c,
&params,
r,
s
).unwrap()
};
// A(x) =
@@ -305,7 +323,7 @@ fn test_xordemo() {
expected_a.add_assign(&u_i[0]); // a_0 = 1
expected_a.add_assign(&u_i[1]); // a_1 = 1
expected_a.add_assign(&u_i[2]); // a_2 = 1
// a_3 = 0
// a_3 = 0
assert_eq!(proof.a, expected_a);
}
@@ -322,7 +340,7 @@ fn test_xordemo() {
expected_b.add_assign(&v_i[0]); // a_0 = 1
expected_b.add_assign(&v_i[1]); // a_1 = 1
expected_b.add_assign(&v_i[2]); // a_2 = 1
// a_3 = 0
// a_3 = 0
assert_eq!(proof.b, expected_b);
}
@@ -363,10 +381,7 @@ fn test_xordemo() {
expected_c.add_assign(&params.l[0]);
// H query answer
for (i, coeff) in [5040, 11763, 10755, 63633, 128, 9747, 8739]
.iter()
.enumerate()
{
for (i, coeff) in [5040, 11763, 10755, 63633, 128, 9747, 8739].iter().enumerate() {
let coeff = Fr::from_str(&format!("{}", coeff)).unwrap();
let mut tmp = params.h[i];
@@ -377,5 +392,9 @@ fn test_xordemo() {
assert_eq!(expected_c, proof.c);
}
assert!(verify_proof(&pvk, &proof, &[Fr::one()]).unwrap());
assert!(verify_proof(
&pvk,
&proof,
&[Fr::one()]
).unwrap());
}

View File

@@ -1,12 +1,24 @@
use ff::PrimeField;
use group::{CurveAffine, CurveProjective};
use pairing::{Engine, PairingCurveAffine};
use pairing::{
Engine,
CurveProjective,
CurveAffine,
PrimeField
};
use super::{PreparedVerifyingKey, Proof, VerifyingKey};
use super::{
Proof,
VerifyingKey,
PreparedVerifyingKey
};
use SynthesisError;
use ::{
SynthesisError
};
pub fn prepare_verifying_key<E: Engine>(vk: &VerifyingKey<E>) -> PreparedVerifyingKey<E> {
pub fn prepare_verifying_key<E: Engine>(
vk: &VerifyingKey<E>
) -> PreparedVerifyingKey<E>
{
let mut gamma = vk.gamma_g2;
gamma.negate();
let mut delta = vk.delta_g2;
@@ -16,15 +28,16 @@ pub fn prepare_verifying_key<E: Engine>(vk: &VerifyingKey<E>) -> PreparedVerifyi
alpha_g1_beta_g2: E::pairing(vk.alpha_g1, vk.beta_g2),
neg_gamma_g2: gamma.prepare(),
neg_delta_g2: delta.prepare(),
ic: vk.ic.clone(),
ic: vk.ic.clone()
}
}
pub fn verify_proof<'a, E: Engine>(
pvk: &'a PreparedVerifyingKey<E>,
proof: &Proof<E>,
public_inputs: &[E::Fr],
) -> Result<bool, SynthesisError> {
public_inputs: &[E::Fr]
) -> Result<bool, SynthesisError>
{
if (public_inputs.len() + 1) != pvk.ic.len() {
return Err(SynthesisError::MalformedVerifyingKey);
}
@@ -43,14 +56,11 @@ pub fn verify_proof<'a, E: Engine>(
// A * B + inputs * (-gamma) + C * (-delta) = alpha * beta
// which allows us to do a single final exponentiation.
Ok(E::final_exponentiation(&E::miller_loop(
[
Ok(E::final_exponentiation(
&E::miller_loop([
(&proof.a.prepare(), &proof.b.prepare()),
(&acc.into_affine().prepare(), &pvk.neg_gamma_g2),
(&proof.c.prepare(), &pvk.neg_delta_g2),
]
.into_iter(),
))
.unwrap()
== pvk.alpha_g1_beta_g2)
(&proof.c.prepare(), &pvk.neg_delta_g2)
].into_iter())
).unwrap() == pvk.alpha_g1_beta_g2)
}

View File

@@ -1,56 +1,35 @@
extern crate ff;
extern crate group;
#[cfg(feature = "pairing")]
extern crate pairing;
extern crate rand_core;
extern crate bit_vec;
extern crate blake2s_simd;
extern crate byteorder;
extern crate futures;
#[cfg(feature = "multicore")]
extern crate crossbeam;
#[cfg(feature = "multicore")]
extern crate futures_cpupool;
#[cfg(feature = "multicore")]
extern crate num_cpus;
#[cfg(test)]
#[macro_use]
extern crate hex_literal;
#[cfg(test)]
extern crate rand;
extern crate num_cpus;
extern crate futures;
extern crate futures_cpupool;
extern crate bit_vec;
extern crate crossbeam;
extern crate byteorder;
#[cfg(test)]
extern crate rand_xorshift;
#[cfg(test)]
extern crate sha2;
pub mod domain;
pub mod gadgets;
#[cfg(feature = "groth16")]
pub mod groth16;
pub mod multicore;
mod multiexp;
pub mod domain;
pub mod groth16;
use ff::{Field, ScalarEngine};
use pairing::{Engine, Field};
use std::error::Error;
use std::ops::{Add, Sub};
use std::fmt;
use std::error::Error;
use std::io;
use std::marker::PhantomData;
use std::ops::{Add, Sub};
/// Computations are expressed in terms of arithmetic circuits, in particular
/// rank-1 quadratic constraint systems. The `Circuit` trait represents a
/// circuit that can be synthesized. The `synthesize` method is called during
/// CRS generation and during proving.
pub trait Circuit<E: ScalarEngine> {
pub trait Circuit<E: Engine> {
/// Synthesize the circuit into a rank-1 quadratic constraint system
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError>;
fn synthesize<CS: ConstraintSystem<E>>(
self,
cs: &mut CS
) -> Result<(), SynthesisError>;
}
/// Represents a variable in our constraint system.
@@ -72,31 +51,31 @@ impl Variable {
}
/// Represents the index of either an input variable or
/// auxiliary variable.
/// auxillary variable.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum Index {
Input(usize),
Aux(usize),
Aux(usize)
}
/// This represents a linear combination of some variables, with coefficients
/// in the scalar field of a pairing-friendly elliptic curve group.
#[derive(Clone)]
pub struct LinearCombination<E: ScalarEngine>(Vec<(Variable, E::Fr)>);
pub struct LinearCombination<E: Engine>(Vec<(Variable, E::Fr)>);
impl<E: ScalarEngine> AsRef<[(Variable, E::Fr)]> for LinearCombination<E> {
impl<E: Engine> AsRef<[(Variable, E::Fr)]> for LinearCombination<E> {
fn as_ref(&self) -> &[(Variable, E::Fr)] {
&self.0
}
}
impl<E: ScalarEngine> LinearCombination<E> {
impl<E: Engine> LinearCombination<E> {
pub fn zero() -> LinearCombination<E> {
LinearCombination(vec![])
}
}
impl<E: ScalarEngine> Add<(E::Fr, Variable)> for LinearCombination<E> {
impl<E: Engine> Add<(E::Fr, Variable)> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn add(mut self, (coeff, var): (E::Fr, Variable)) -> LinearCombination<E> {
@@ -106,7 +85,7 @@ impl<E: ScalarEngine> Add<(E::Fr, Variable)> for LinearCombination<E> {
}
}
impl<E: ScalarEngine> Sub<(E::Fr, Variable)> for LinearCombination<E> {
impl<E: Engine> Sub<(E::Fr, Variable)> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn sub(self, (mut coeff, var): (E::Fr, Variable)) -> LinearCombination<E> {
@@ -116,7 +95,7 @@ impl<E: ScalarEngine> Sub<(E::Fr, Variable)> for LinearCombination<E> {
}
}
impl<E: ScalarEngine> Add<Variable> for LinearCombination<E> {
impl<E: Engine> Add<Variable> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn add(self, other: Variable) -> LinearCombination<E> {
@@ -124,7 +103,7 @@ impl<E: ScalarEngine> Add<Variable> for LinearCombination<E> {
}
}
impl<E: ScalarEngine> Sub<Variable> for LinearCombination<E> {
impl<E: Engine> Sub<Variable> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn sub(self, other: Variable) -> LinearCombination<E> {
@@ -132,7 +111,7 @@ impl<E: ScalarEngine> Sub<Variable> for LinearCombination<E> {
}
}
impl<'a, E: ScalarEngine> Add<&'a LinearCombination<E>> for LinearCombination<E> {
impl<'a, E: Engine> Add<&'a LinearCombination<E>> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn add(mut self, other: &'a LinearCombination<E>) -> LinearCombination<E> {
@@ -144,7 +123,7 @@ impl<'a, E: ScalarEngine> Add<&'a LinearCombination<E>> for LinearCombination<E>
}
}
impl<'a, E: ScalarEngine> Sub<&'a LinearCombination<E>> for LinearCombination<E> {
impl<'a, E: Engine> Sub<&'a LinearCombination<E>> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn sub(mut self, other: &'a LinearCombination<E>) -> LinearCombination<E> {
@@ -156,7 +135,7 @@ impl<'a, E: ScalarEngine> Sub<&'a LinearCombination<E>> for LinearCombination<E>
}
}
impl<'a, E: ScalarEngine> Add<(E::Fr, &'a LinearCombination<E>)> for LinearCombination<E> {
impl<'a, E: Engine> Add<(E::Fr, &'a LinearCombination<E>)> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn add(mut self, (coeff, other): (E::Fr, &'a LinearCombination<E>)) -> LinearCombination<E> {
@@ -170,7 +149,7 @@ impl<'a, E: ScalarEngine> Add<(E::Fr, &'a LinearCombination<E>)> for LinearCombi
}
}
impl<'a, E: ScalarEngine> Sub<(E::Fr, &'a LinearCombination<E>)> for LinearCombination<E> {
impl<'a, E: Engine> Sub<(E::Fr, &'a LinearCombination<E>)> for LinearCombination<E> {
type Output = LinearCombination<E>;
fn sub(mut self, (coeff, other): (E::Fr, &'a LinearCombination<E>)) -> LinearCombination<E> {
@@ -202,8 +181,8 @@ pub enum SynthesisError {
IoError(io::Error),
/// During verification, our verifying key was malformed.
MalformedVerifyingKey,
/// During CRS generation, we observed an unconstrained auxiliary variable
UnconstrainedVariable,
/// During CRS generation, we observed an unconstrained auxillary variable
UnconstrainedVariable
}
impl From<io::Error> for SynthesisError {
@@ -215,16 +194,14 @@ impl From<io::Error> for SynthesisError {
impl Error for SynthesisError {
fn description(&self) -> &str {
match *self {
SynthesisError::AssignmentMissing => {
"an assignment for a variable could not be computed"
}
SynthesisError::AssignmentMissing => "an assignment for a variable could not be computed",
SynthesisError::DivisionByZero => "division by zero",
SynthesisError::Unsatisfiable => "unsatisfiable constraint system",
SynthesisError::PolynomialDegreeTooLarge => "polynomial degree is too large",
SynthesisError::UnexpectedIdentity => "encountered an identity element in the CRS",
SynthesisError::IoError(_) => "encountered an I/O error",
SynthesisError::MalformedVerifyingKey => "malformed verifying key",
SynthesisError::UnconstrainedVariable => "auxiliary variable was unconstrained",
SynthesisError::UnconstrainedVariable => "auxillary variable was unconstrained"
}
}
}
@@ -242,7 +219,7 @@ impl fmt::Display for SynthesisError {
/// Represents a constraint system which can have new variables
/// allocated and constrains between them formed.
pub trait ConstraintSystem<E: ScalarEngine>: Sized {
pub trait ConstraintSystem<E: Engine>: Sized {
/// Represents the type of the "root" of this constraint system
/// so that nested namespaces can minimize indirection.
type Root: ConstraintSystem<E>;
@@ -256,36 +233,40 @@ pub trait ConstraintSystem<E: ScalarEngine>: Sized {
/// determine the assignment of the variable. The given `annotation` function is invoked
/// in testing contexts in order to derive a unique name for this variable in the current
/// namespace.
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>;
fn alloc<F, A, AR>(
&mut self,
annotation: A,
f: F
) -> Result<Variable, SynthesisError>
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>;
/// Allocate a public variable in the constraint system. The provided function is used to
/// determine the assignment of the variable.
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>;
fn alloc_input<F, A, AR>(
&mut self,
annotation: A,
f: F
) -> Result<Variable, SynthesisError>
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>;
/// Enforce that `A` * `B` = `C`. The `annotation` function is invoked in testing contexts
/// in order to derive a unique name for the constraint in the current namespace.
fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: A, a: LA, b: LB, c: LC)
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>;
fn enforce<A, AR, LA, LB, LC>(
&mut self,
annotation: A,
a: LA,
b: LB,
c: LC
)
where A: FnOnce() -> AR, AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>;
/// Create a new (sub)namespace and enter into it. Not intended
/// for downstream use; use `namespace` instead.
fn push_namespace<NR, N>(&mut self, name_fn: N)
where
NR: Into<String>,
N: FnOnce() -> NR;
where NR: Into<String>, N: FnOnce() -> NR;
/// Exit out of the existing namespace. Not intended for
/// downstream use; use `namespace` instead.
@@ -296,10 +277,11 @@ pub trait ConstraintSystem<E: ScalarEngine>: Sized {
fn get_root(&mut self) -> &mut Self::Root;
/// Begin a namespace for this constraint system.
fn namespace<'a, NR, N>(&'a mut self, name_fn: N) -> Namespace<'a, E, Self::Root>
where
NR: Into<String>,
N: FnOnce() -> NR,
fn namespace<'a, NR, N>(
&'a mut self,
name_fn: N
) -> Namespace<'a, E, Self::Root>
where NR: Into<String>, N: FnOnce() -> NR
{
self.get_root().push_namespace(name_fn);
@@ -309,40 +291,46 @@ pub trait ConstraintSystem<E: ScalarEngine>: Sized {
/// This is a "namespaced" constraint system which borrows a constraint system (pushing
/// a namespace context) and, when dropped, pops out of the namespace context.
pub struct Namespace<'a, E: ScalarEngine, CS: ConstraintSystem<E> + 'a>(&'a mut CS, PhantomData<E>);
pub struct Namespace<'a, E: Engine, CS: ConstraintSystem<E> + 'a>(&'a mut CS, PhantomData<E>);
impl<'cs, E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for Namespace<'cs, E, CS> {
impl<'cs, E: Engine, CS: ConstraintSystem<E>> ConstraintSystem<E> for Namespace<'cs, E, CS> {
type Root = CS::Root;
fn one() -> Variable {
CS::one()
}
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
fn alloc<F, A, AR>(
&mut self,
annotation: A,
f: F
) -> Result<Variable, SynthesisError>
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
{
self.0.alloc(annotation, f)
}
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
fn alloc_input<F, A, AR>(
&mut self,
annotation: A,
f: F
) -> Result<Variable, SynthesisError>
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
{
self.0.alloc_input(annotation, f)
}
fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: A, a: LA, b: LB, c: LC)
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
fn enforce<A, AR, LA, LB, LC>(
&mut self,
annotation: A,
a: LA,
b: LB,
c: LC
)
where A: FnOnce() -> AR, AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>
{
self.0.enforce(annotation, a, b, c)
}
@@ -352,23 +340,23 @@ impl<'cs, E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for Name
// never a root constraint system.
fn push_namespace<NR, N>(&mut self, _: N)
where
NR: Into<String>,
N: FnOnce() -> NR,
where NR: Into<String>, N: FnOnce() -> NR
{
panic!("only the root's push_namespace should be called");
}
fn pop_namespace(&mut self) {
fn pop_namespace(&mut self)
{
panic!("only the root's pop_namespace should be called");
}
fn get_root(&mut self) -> &mut Self::Root {
fn get_root(&mut self) -> &mut Self::Root
{
self.0.get_root()
}
}
impl<'a, E: ScalarEngine, CS: ConstraintSystem<E>> Drop for Namespace<'a, E, CS> {
impl<'a, E: Engine, CS: ConstraintSystem<E>> Drop for Namespace<'a, E, CS> {
fn drop(&mut self) {
self.get_root().pop_namespace()
}
@@ -376,55 +364,61 @@ impl<'a, E: ScalarEngine, CS: ConstraintSystem<E>> Drop for Namespace<'a, E, CS>
/// Convenience implementation of ConstraintSystem<E> for mutable references to
/// constraint systems.
impl<'cs, E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for &'cs mut CS {
impl<'cs, E: Engine, CS: ConstraintSystem<E>> ConstraintSystem<E> for &'cs mut CS {
type Root = CS::Root;
fn one() -> Variable {
CS::one()
}
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
fn alloc<F, A, AR>(
&mut self,
annotation: A,
f: F
) -> Result<Variable, SynthesisError>
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
{
(**self).alloc(annotation, f)
}
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
fn alloc_input<F, A, AR>(
&mut self,
annotation: A,
f: F
) -> Result<Variable, SynthesisError>
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
{
(**self).alloc_input(annotation, f)
}
fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: A, a: LA, b: LB, c: LC)
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
fn enforce<A, AR, LA, LB, LC>(
&mut self,
annotation: A,
a: LA,
b: LB,
c: LC
)
where A: FnOnce() -> AR, AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>
{
(**self).enforce(annotation, a, b, c)
}
fn push_namespace<NR, N>(&mut self, name_fn: N)
where
NR: Into<String>,
N: FnOnce() -> NR,
where NR: Into<String>, N: FnOnce() -> NR
{
(**self).push_namespace(name_fn)
}
fn pop_namespace(&mut self) {
fn pop_namespace(&mut self)
{
(**self).pop_namespace()
}
fn get_root(&mut self) -> &mut Self::Root {
fn get_root(&mut self) -> &mut Self::Root
{
(**self).get_root()
}
}

View File

@@ -4,158 +4,103 @@
//! crossbeam but may be extended in the future to
//! allow for various parallelism strategies.
#[cfg(feature = "multicore")]
mod implementation {
use crossbeam::{self, Scope};
use futures::{Future, IntoFuture, Poll};
use futures_cpupool::{CpuFuture, CpuPool};
use num_cpus;
use num_cpus;
use futures::{Future, IntoFuture, Poll};
use futures_cpupool::{CpuPool, CpuFuture};
use crossbeam::{self, Scope};
#[derive(Clone)]
pub struct Worker {
cpus: usize,
pool: CpuPool,
}
#[derive(Clone)]
pub struct Worker {
cpus: usize,
pool: CpuPool
}
impl Worker {
// We don't expose this outside the library so that
// all `Worker` instances have the same number of
// CPUs configured.
pub(crate) fn new_with_cpus(cpus: usize) -> Worker {
Worker {
cpus: cpus,
pool: CpuPool::new(cpus),
}
}
pub fn new() -> Worker {
Self::new_with_cpus(num_cpus::get())
}
pub fn log_num_cpus(&self) -> u32 {
log2_floor(self.cpus)
}
pub fn compute<F, R>(&self, f: F) -> WorkerFuture<R::Item, R::Error>
where
F: FnOnce() -> R + Send + 'static,
R: IntoFuture + 'static,
R::Future: Send + 'static,
R::Item: Send + 'static,
R::Error: Send + 'static,
{
WorkerFuture {
future: self.pool.spawn_fn(f),
}
}
pub fn scope<'a, F, R>(&self, elements: usize, f: F) -> R
where
F: FnOnce(&Scope<'a>, usize) -> R,
{
let chunk_size = if elements < self.cpus {
1
} else {
elements / self.cpus
};
crossbeam::scope(|scope| f(scope, chunk_size))
impl Worker {
// We don't expose this outside the library so that
// all `Worker` instances have the same number of
// CPUs configured.
pub(crate) fn new_with_cpus(cpus: usize) -> Worker {
Worker {
cpus: cpus,
pool: CpuPool::new(cpus)
}
}
pub struct WorkerFuture<T, E> {
future: CpuFuture<T, E>,
pub fn new() -> Worker {
Self::new_with_cpus(num_cpus::get())
}
impl<T: Send + 'static, E: Send + 'static> Future for WorkerFuture<T, E> {
type Item = T;
type Error = E;
pub fn log_num_cpus(&self) -> u32 {
log2_floor(self.cpus)
}
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
self.future.poll()
pub fn compute<F, R>(
&self, f: F
) -> WorkerFuture<R::Item, R::Error>
where F: FnOnce() -> R + Send + 'static,
R: IntoFuture + 'static,
R::Future: Send + 'static,
R::Item: Send + 'static,
R::Error: Send + 'static
{
WorkerFuture {
future: self.pool.spawn_fn(f)
}
}
fn log2_floor(num: usize) -> u32 {
assert!(num > 0);
pub fn scope<'a, F, R>(
&self,
elements: usize,
f: F
) -> R
where F: FnOnce(&Scope<'a>, usize) -> R
{
let chunk_size = if elements < self.cpus {
1
} else {
elements / self.cpus
};
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);
crossbeam::scope(|scope| {
f(scope, chunk_size)
})
}
}
#[cfg(not(feature = "multicore"))]
mod implementation {
use futures::{future, Future, IntoFuture, Poll};
pub struct WorkerFuture<T, E> {
future: CpuFuture<T, E>
}
#[derive(Clone)]
pub struct Worker;
impl<T: Send + 'static, E: Send + 'static> Future for WorkerFuture<T, E> {
type Item = T;
type Error = E;
impl Worker {
pub fn new() -> Worker {
Worker
}
pub fn log_num_cpus(&self) -> u32 {
0
}
pub fn compute<F, R>(&self, f: F) -> R::Future
where
F: FnOnce() -> R + Send + 'static,
R: IntoFuture + 'static,
R::Future: Send + 'static,
R::Item: Send + 'static,
R::Error: Send + 'static,
{
f().into_future()
}
pub fn scope<F, R>(&self, elements: usize, f: F) -> R
where
F: FnOnce(&DummyScope, usize) -> R,
{
f(&DummyScope, elements)
}
}
pub struct WorkerFuture<T, E> {
future: future::FutureResult<T, E>,
}
impl<T: Send + 'static, E: Send + 'static> Future for WorkerFuture<T, E> {
type Item = T;
type Error = E;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
self.future.poll()
}
}
pub struct DummyScope;
impl DummyScope {
pub fn spawn<F: FnOnce()>(&self, f: F) {
f();
}
fn poll(&mut self) -> Poll<Self::Item, Self::Error>
{
self.future.poll()
}
}
pub use self::implementation::*;
fn log2_floor(num: usize) -> u32 {
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);
}

View File

@@ -1,11 +1,17 @@
use super::multicore::Worker;
use bit_vec::{self, BitVec};
use ff::{Field, PrimeField, PrimeFieldRepr, ScalarEngine};
use futures::Future;
use group::{CurveAffine, CurveProjective};
use std::io;
use std::iter;
use pairing::{
CurveAffine,
CurveProjective,
Engine,
PrimeField,
Field,
PrimeFieldRepr
};
use std::sync::Arc;
use std::io;
use bit_vec::{self, BitVec};
use std::iter;
use futures::{Future};
use super::multicore::Worker;
use super::SynthesisError;
@@ -19,10 +25,7 @@ pub trait SourceBuilder<G: CurveAffine>: Send + Sync + 'static + Clone {
/// A source of bases, like an iterator.
pub trait Source<G: CurveAffine> {
/// Parses the element from the source. Fails if the point is at infinity.
fn add_assign_mixed(
&mut self,
to: &mut <G as CurveAffine>::Projective,
) -> Result<(), SynthesisError>;
fn add_assign_mixed(&mut self, to: &mut <G as CurveAffine>::Projective) -> Result<(), SynthesisError>;
/// Skips `amt` elements from the source, avoiding deserialization.
fn skip(&mut self, amt: usize) -> Result<(), SynthesisError>;
@@ -37,20 +40,13 @@ impl<G: CurveAffine> SourceBuilder<G> for (Arc<Vec<G>>, usize) {
}
impl<G: CurveAffine> Source<G> for (Arc<Vec<G>>, usize) {
fn add_assign_mixed(
&mut self,
to: &mut <G as CurveAffine>::Projective,
) -> Result<(), SynthesisError> {
fn add_assign_mixed(&mut self, to: &mut <G as CurveAffine>::Projective) -> Result<(), SynthesisError> {
if self.0.len() <= self.1 {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"expected more bases from source",
)
.into());
return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases from source").into());
}
if self.0[self.1].is_zero() {
return Err(SynthesisError::UnexpectedIdentity);
return Err(SynthesisError::UnexpectedIdentity)
}
to.add_assign_mixed(&self.0[self.1]);
@@ -62,11 +58,7 @@ impl<G: CurveAffine> Source<G> for (Arc<Vec<G>>, usize) {
fn skip(&mut self, amt: usize) -> Result<(), SynthesisError> {
if self.0.len() <= self.1 {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"expected more bases from source",
)
.into());
return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "expected more bases from source").into());
}
self.1 += amt;
@@ -77,7 +69,7 @@ impl<G: CurveAffine> Source<G> for (Arc<Vec<G>>, usize) {
pub trait QueryDensity {
/// Returns whether the base exists.
type Iter: Iterator<Item = bool>;
type Iter: Iterator<Item=bool>;
fn iter(self) -> Self::Iter;
fn get_query_size(self) -> Option<usize>;
@@ -106,7 +98,7 @@ impl<'a> QueryDensity for &'a FullDensity {
pub struct DensityTracker {
bv: BitVec,
total_density: usize,
total_density: usize
}
impl<'a> QueryDensity for &'a DensityTracker {
@@ -125,7 +117,7 @@ impl DensityTracker {
pub fn new() -> DensityTracker {
DensityTracker {
bv: BitVec::new(),
total_density: 0,
total_density: 0
}
}
@@ -149,16 +141,15 @@ fn multiexp_inner<Q, D, G, S>(
pool: &Worker,
bases: S,
density_map: D,
exponents: Arc<Vec<<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr>>,
exponents: Arc<Vec<<<G::Engine as Engine>::Fr as PrimeField>::Repr>>,
mut skip: u32,
c: u32,
handle_trivial: bool,
) -> Box<Future<Item = <G as CurveAffine>::Projective, Error = SynthesisError>>
where
for<'a> &'a Q: QueryDensity,
D: Send + Sync + 'static + Clone + AsRef<Q>,
G: CurveAffine,
S: SourceBuilder<G>,
handle_trivial: bool
) -> Box<Future<Item=<G as CurveAffine>::Projective, Error=SynthesisError>>
where for<'a> &'a Q: QueryDensity,
D: Send + Sync + 'static + Clone + AsRef<Q>,
G: CurveAffine,
S: SourceBuilder<G>
{
// Perform this region of the multiexp
let this = {
@@ -176,8 +167,8 @@ where
// Create space for the buckets
let mut buckets = vec![<G as CurveAffine>::Projective::zero(); (1 << c) - 1];
let zero = <G::Engine as ScalarEngine>::Fr::zero().into_repr();
let one = <G::Engine as ScalarEngine>::Fr::one().into_repr();
let zero = <G::Engine as Engine>::Fr::zero().into_repr();
let one = <G::Engine as Engine>::Fr::one().into_repr();
// Sort the bases into buckets
for (&exp, density) in exponents.iter().zip(density_map.as_ref().iter()) {
@@ -220,31 +211,23 @@ where
skip += c;
if skip >= <G::Engine as ScalarEngine>::Fr::NUM_BITS {
if skip >= <G::Engine as Engine>::Fr::NUM_BITS {
// There isn't another region.
Box::new(this)
} else {
// There's another region more significant. Calculate and join it with
// this region recursively.
Box::new(
this.join(multiexp_inner(
pool,
bases,
density_map,
exponents,
skip,
c,
false,
))
.map(move |(this, mut higher)| {
for _ in 0..c {
higher.double();
}
this.join(multiexp_inner(pool, bases, density_map, exponents, skip, c, false))
.map(move |(this, mut higher)| {
for _ in 0..c {
higher.double();
}
higher.add_assign(&this);
higher.add_assign(&this);
higher
}),
higher
})
)
}
}
@@ -255,13 +238,12 @@ pub fn multiexp<Q, D, G, S>(
pool: &Worker,
bases: S,
density_map: D,
exponents: Arc<Vec<<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr>>,
) -> Box<Future<Item = <G as CurveAffine>::Projective, Error = SynthesisError>>
where
for<'a> &'a Q: QueryDensity,
D: Send + Sync + 'static + Clone + AsRef<Q>,
G: CurveAffine,
S: SourceBuilder<G>,
exponents: Arc<Vec<<<G::Engine as Engine>::Fr as PrimeField>::Repr>>
) -> Box<Future<Item=<G as CurveAffine>::Projective, Error=SynthesisError>>
where for<'a> &'a Q: QueryDensity,
D: Send + Sync + 'static + Clone + AsRef<Q>,
G: CurveAffine,
S: SourceBuilder<G>
{
let c = if exponents.len() < 32 {
3u32
@@ -279,13 +261,13 @@ where
multiexp_inner(pool, bases, density_map, exponents, 0, c, true)
}
#[cfg(feature = "pairing")]
#[test]
fn test_with_bls12() {
fn naive_multiexp<G: CurveAffine>(
bases: Arc<Vec<G>>,
exponents: Arc<Vec<<G::Scalar as PrimeField>::Repr>>,
) -> G::Projective {
exponents: Arc<Vec<<G::Scalar as PrimeField>::Repr>>
) -> G::Projective
{
assert_eq!(bases.len(), exponents.len());
let mut acc = G::Projective::zero();
@@ -297,28 +279,25 @@ fn test_with_bls12() {
acc
}
use pairing::{bls12_381::Bls12, Engine};
use rand;
use rand::{self, Rand};
use pairing::bls12_381::Bls12;
const SAMPLES: usize = 1 << 14;
let rng = &mut rand::thread_rng();
let v = Arc::new(
(0..SAMPLES)
.map(|_| <Bls12 as ScalarEngine>::Fr::random(rng).into_repr())
.collect::<Vec<_>>(),
);
let g = Arc::new(
(0..SAMPLES)
.map(|_| <Bls12 as Engine>::G1::random(rng).into_affine())
.collect::<Vec<_>>(),
);
let v = Arc::new((0..SAMPLES).map(|_| <Bls12 as Engine>::Fr::rand(rng).into_repr()).collect::<Vec<_>>());
let g = Arc::new((0..SAMPLES).map(|_| <Bls12 as Engine>::G1::rand(rng).into_affine()).collect::<Vec<_>>());
let naive = naive_multiexp(g.clone(), v.clone());
let pool = Worker::new();
let fast = multiexp(&pool, (g, 0), FullDensity, v).wait().unwrap();
let fast = multiexp(
&pool,
(g, 0),
FullDensity,
v
).wait().unwrap();
assert_eq!(naive, fast);
}

View File

@@ -1,34 +1,45 @@
extern crate bellman;
extern crate ff;
extern crate pairing;
extern crate rand;
// For randomness (during paramgen and proof generation)
use rand::thread_rng;
use rand::{thread_rng, Rng};
// For benchmarking
use std::time::{Duration, Instant};
// Bring in some tools for using pairing-friendly curves
use ff::{Field, ScalarEngine};
use pairing::Engine;
use pairing::{
Engine,
Field
};
// We're going to use the BLS12-381 pairing-friendly elliptic curve.
use pairing::bls12_381::Bls12;
use pairing::bls12_381::{
Bls12
};
// We'll use these interfaces to construct our circuit.
use bellman::{Circuit, ConstraintSystem, SynthesisError};
use bellman::{
Circuit,
ConstraintSystem,
SynthesisError
};
// We're going to use the Groth16 proving system.
use bellman::groth16::{
create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof, Proof,
Proof,
generate_random_parameters,
prepare_verifying_key,
create_random_proof,
verify_proof,
};
const MIMC_ROUNDS: usize = 322;
/// This is an implementation of MiMC, specifically a
/// variant named `LongsightF322p3` for BLS12-381.
/// See http://eprint.iacr.org/2016/492 for more
/// See http://eprint.iacr.org/2016/492 for more
/// information about this construction.
///
/// ```
@@ -39,7 +50,12 @@ const MIMC_ROUNDS: usize = 322;
/// return xL
/// }
/// ```
fn mimc<E: Engine>(mut xl: E::Fr, mut xr: E::Fr, constants: &[E::Fr]) -> E::Fr {
fn mimc<E: Engine>(
mut xl: E::Fr,
mut xr: E::Fr,
constants: &[E::Fr]
) -> E::Fr
{
assert_eq!(constants.len(), MIMC_ROUNDS);
for i in 0..MIMC_ROUNDS {
@@ -61,29 +77,31 @@ fn mimc<E: Engine>(mut xl: E::Fr, mut xr: E::Fr, constants: &[E::Fr]) -> E::Fr {
struct MiMCDemo<'a, E: Engine> {
xl: Option<E::Fr>,
xr: Option<E::Fr>,
constants: &'a [E::Fr],
constants: &'a [E::Fr]
}
/// Our demo circuit implements this `Circuit` trait which
/// is used during paramgen and proving in order to
/// synthesize the constraint system.
impl<'a, E: Engine> Circuit<E> for MiMCDemo<'a, E> {
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
fn synthesize<CS: ConstraintSystem<E>>(
self,
cs: &mut CS
) -> Result<(), SynthesisError>
{
assert_eq!(self.constants.len(), MIMC_ROUNDS);
// Allocate the first component of the preimage.
let mut xl_value = self.xl;
let mut xl = cs.alloc(
|| "preimage xl",
|| xl_value.ok_or(SynthesisError::AssignmentMissing),
)?;
let mut xl = cs.alloc(|| "preimage xl", || {
xl_value.ok_or(SynthesisError::AssignmentMissing)
})?;
// Allocate the second component of the preimage.
let mut xr_value = self.xr;
let mut xr = cs.alloc(
|| "preimage xr",
|| xr_value.ok_or(SynthesisError::AssignmentMissing),
)?;
let mut xr = cs.alloc(|| "preimage xr", || {
xr_value.ok_or(SynthesisError::AssignmentMissing)
})?;
for i in 0..MIMC_ROUNDS {
// xL, xR := xR + (xL + Ci)^3, xL
@@ -95,16 +113,15 @@ impl<'a, E: Engine> Circuit<E> for MiMCDemo<'a, E> {
e.square();
e
});
let mut tmp = cs.alloc(
|| "tmp",
|| tmp_value.ok_or(SynthesisError::AssignmentMissing),
)?;
let mut tmp = cs.alloc(|| "tmp", || {
tmp_value.ok_or(SynthesisError::AssignmentMissing)
})?;
cs.enforce(
|| "tmp = (xL + Ci)^2",
|lc| lc + xl + (self.constants[i], CS::one()),
|lc| lc + xl + (self.constants[i], CS::one()),
|lc| lc + tmp,
|lc| lc + tmp
);
// new_xL = xR + (xL + Ci)^3
@@ -117,25 +134,23 @@ impl<'a, E: Engine> Circuit<E> for MiMCDemo<'a, E> {
e
});
let mut new_xl = if i == (MIMC_ROUNDS - 1) {
let mut new_xl = if i == (MIMC_ROUNDS-1) {
// This is the last round, xL is our image and so
// we allocate a public input.
cs.alloc_input(
|| "image",
|| new_xl_value.ok_or(SynthesisError::AssignmentMissing),
)?
cs.alloc_input(|| "image", || {
new_xl_value.ok_or(SynthesisError::AssignmentMissing)
})?
} else {
cs.alloc(
|| "new_xl",
|| new_xl_value.ok_or(SynthesisError::AssignmentMissing),
)?
cs.alloc(|| "new_xl", || {
new_xl_value.ok_or(SynthesisError::AssignmentMissing)
})?
};
cs.enforce(
|| "new_xL = xR + (xL + Ci)^3",
|lc| lc + tmp,
|lc| lc + xl + (self.constants[i], CS::one()),
|lc| lc + new_xl - xr,
|lc| lc + new_xl - xr
);
// xR = xL
@@ -158,9 +173,7 @@ fn test_mimc() {
let rng = &mut thread_rng();
// Generate the MiMC round constants
let constants = (0..MIMC_ROUNDS)
.map(|_| <Bls12 as ScalarEngine>::Fr::random(rng))
.collect::<Vec<_>>();
let constants = (0..MIMC_ROUNDS).map(|_| rng.gen()).collect::<Vec<_>>();
println!("Creating parameters...");
@@ -169,7 +182,7 @@ fn test_mimc() {
let c = MiMCDemo::<Bls12> {
xl: None,
xr: None,
constants: &constants,
constants: &constants
};
generate_random_parameters(c, rng).unwrap()
@@ -191,8 +204,8 @@ fn test_mimc() {
for _ in 0..SAMPLES {
// Generate a random preimage and compute the image
let xl = <Bls12 as ScalarEngine>::Fr::random(rng);
let xr = <Bls12 as ScalarEngine>::Fr::random(rng);
let xl = rng.gen();
let xr = rng.gen();
let image = mimc::<Bls12>(xl, xr, &constants);
proof_vec.truncate(0);
@@ -204,7 +217,7 @@ fn test_mimc() {
let c = MiMCDemo {
xl: Some(xl),
xr: Some(xr),
constants: &constants,
constants: &constants
};
// Create a groth16 proof with our parameters.
@@ -218,16 +231,20 @@ fn test_mimc() {
let start = Instant::now();
let proof = Proof::read(&proof_vec[..]).unwrap();
// Check the proof
assert!(verify_proof(&pvk, &proof, &[image]).unwrap());
assert!(verify_proof(
&pvk,
&proof,
&[image]
).unwrap());
total_verifying += start.elapsed();
}
let proving_avg = total_proving / SAMPLES;
let proving_avg =
proving_avg.subsec_nanos() as f64 / 1_000_000_000f64 + (proving_avg.as_secs() as f64);
let proving_avg = proving_avg.subsec_nanos() as f64 / 1_000_000_000f64
+ (proving_avg.as_secs() as f64);
let verifying_avg = total_verifying / SAMPLES;
let verifying_avg =
verifying_avg.subsec_nanos() as f64 / 1_000_000_000f64 + (verifying_avg.as_secs() as f64);
let verifying_avg = verifying_avg.subsec_nanos() as f64 / 1_000_000_000f64
+ (verifying_avg.as_secs() as f64);
println!("Average proving time: {:?} seconds", proving_avg);
println!("Average verifying time: {:?} seconds", verifying_avg);

View File

@@ -1,18 +0,0 @@
[package]
name = "ff"
version = "0.4.0"
authors = ["Sean Bowe <ewillbefull@gmail.com>"]
description = "Library for building and interfacing with finite fields"
documentation = "https://docs.rs/ff/"
homepage = "https://github.com/ebfull/ff"
license = "MIT/Apache-2.0"
repository = "https://github.com/ebfull/ff"
[dependencies]
byteorder = "1"
ff_derive = { version = "0.3.0", path = "ff_derive", optional = true }
rand_core = "0.5"
[features]
default = []
derive = ["ff_derive"]

View File

@@ -1,60 +0,0 @@
# ff
`ff` is a finite field library written in pure Rust, with no `unsafe{}` code.
## Disclaimers
* This library does not provide constant-time guarantees.
## Usage
Add the `ff` crate to your `Cargo.toml`:
```toml
[dependencies]
ff = "0.4"
```
The `ff` crate contains `Field`, `PrimeField`, `PrimeFieldRepr` and `SqrtField` traits. See the **[documentation](https://docs.rs/ff/0.4.0/ff/)** for more.
### #![derive(PrimeField)]
If you need an implementation of a prime field, this library also provides a procedural macro that will expand into an efficient implementation of a prime field when supplied with the modulus. `PrimeFieldGenerator` must be an element of Fp of p-1 order, that is also quadratic nonresidue.
First, enable the `derive` crate feature:
```toml
[dependencies]
ff = { version = "0.4", features = ["derive"] }
```
And then use the macro like so:
```rust
extern crate rand;
#[macro_use]
extern crate ff;
#[derive(PrimeField)]
#[PrimeFieldModulus = "52435875175126190479447740508185965837690552500527637822603658699938581184513"]
#[PrimeFieldGenerator = "7"]
struct Fp(FpRepr);
```
And that's it! `Fp` now implements `Field` and `PrimeField`. `Fp` will also implement `SqrtField` if supported. The library implements `FpRepr` itself and derives `PrimeFieldRepr` for it.
## License
Licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in the work by you, as defined in the Apache-2.0
license, shall be dual licensed as above, without any additional terms or
conditions.

View File

@@ -1,20 +0,0 @@
[package]
name = "ff_derive"
version = "0.3.0"
authors = ["Sean Bowe <ewillbefull@gmail.com>"]
description = "Procedural macro library used to build custom prime field implementations"
documentation = "https://docs.rs/ff/"
homepage = "https://github.com/ebfull/ff"
license = "MIT/Apache-2.0"
repository = "https://github.com/ebfull/ff"
[lib]
proc-macro = true
[dependencies]
num-bigint = "0.2"
num-traits = "0.2"
num-integer = "0.1"
proc-macro2 = "0.4"
quote = "0.6"
syn = "0.14"

File diff suppressed because it is too large Load Diff

View File

@@ -1,396 +0,0 @@
#![allow(unused_imports)]
extern crate byteorder;
extern crate rand_core;
#[cfg(feature = "derive")]
#[macro_use]
extern crate ff_derive;
#[cfg(feature = "derive")]
pub use ff_derive::*;
use rand_core::RngCore;
use std::error::Error;
use std::fmt;
use std::io::{self, Read, Write};
/// This trait represents an element of a field.
pub trait Field:
Sized + Eq + Copy + Clone + Send + Sync + fmt::Debug + fmt::Display + 'static
{
/// Returns an element chosen uniformly at random using a user-provided RNG.
fn random<R: RngCore>(rng: &mut R) -> Self;
/// Returns the zero element of the field, the additive identity.
fn zero() -> Self;
/// Returns the one element of the field, the multiplicative identity.
fn one() -> Self;
/// Returns true iff this element is zero.
fn is_zero(&self) -> bool;
/// Squares this element.
fn square(&mut self);
/// Doubles this element.
fn double(&mut self);
/// Negates this element.
fn negate(&mut self);
/// Adds another element to this element.
fn add_assign(&mut self, other: &Self);
/// Subtracts another element from this element.
fn sub_assign(&mut self, other: &Self);
/// Multiplies another element by this element.
fn mul_assign(&mut self, other: &Self);
/// Computes the multiplicative inverse of this element, if nonzero.
fn inverse(&self) -> Option<Self>;
/// Exponentiates this element by a power of the base prime modulus via
/// the Frobenius automorphism.
fn frobenius_map(&mut self, power: usize);
/// Exponentiates this element by a number represented with `u64` limbs,
/// least significant digit first.
fn pow<S: AsRef<[u64]>>(&self, exp: S) -> Self {
let mut res = Self::one();
let mut found_one = false;
for i in BitIterator::new(exp) {
if found_one {
res.square();
} else {
found_one = i;
}
if i {
res.mul_assign(self);
}
}
res
}
}
/// This trait represents an element of a field that has a square root operation described for it.
pub trait SqrtField: Field {
/// Returns the Legendre symbol of the field element.
fn legendre(&self) -> LegendreSymbol;
/// Returns the square root of the field element, if it is
/// quadratic residue.
fn sqrt(&self) -> Option<Self>;
}
/// This trait represents a wrapper around a biginteger which can encode any element of a particular
/// prime field. It is a smart wrapper around a sequence of `u64` limbs, least-significant digit
/// first.
pub trait PrimeFieldRepr:
Sized
+ Copy
+ Clone
+ Eq
+ Ord
+ Send
+ Sync
+ Default
+ fmt::Debug
+ fmt::Display
+ 'static
+ AsRef<[u64]>
+ AsMut<[u64]>
+ From<u64>
{
/// Subtract another represetation from this one.
fn sub_noborrow(&mut self, other: &Self);
/// Add another representation to this one.
fn add_nocarry(&mut self, other: &Self);
/// Compute the number of bits needed to encode this number. Always a
/// multiple of 64.
fn num_bits(&self) -> u32;
/// Returns true iff this number is zero.
fn is_zero(&self) -> bool;
/// Returns true iff this number is odd.
fn is_odd(&self) -> bool;
/// Returns true iff this number is even.
fn is_even(&self) -> bool;
/// Performs a rightwise bitshift of this number, effectively dividing
/// it by 2.
fn div2(&mut self);
/// Performs a rightwise bitshift of this number by some amount.
fn shr(&mut self, amt: u32);
/// Performs a leftwise bitshift of this number, effectively multiplying
/// it by 2. Overflow is ignored.
fn mul2(&mut self);
/// Performs a leftwise bitshift of this number by some amount.
fn shl(&mut self, amt: u32);
/// Writes this `PrimeFieldRepr` as a big endian integer.
fn write_be<W: Write>(&self, mut writer: W) -> io::Result<()> {
use byteorder::{BigEndian, WriteBytesExt};
for digit in self.as_ref().iter().rev() {
writer.write_u64::<BigEndian>(*digit)?;
}
Ok(())
}
/// Reads a big endian integer into this representation.
fn read_be<R: Read>(&mut self, mut reader: R) -> io::Result<()> {
use byteorder::{BigEndian, ReadBytesExt};
for digit in self.as_mut().iter_mut().rev() {
*digit = reader.read_u64::<BigEndian>()?;
}
Ok(())
}
/// Writes this `PrimeFieldRepr` as a little endian integer.
fn write_le<W: Write>(&self, mut writer: W) -> io::Result<()> {
use byteorder::{LittleEndian, WriteBytesExt};
for digit in self.as_ref().iter() {
writer.write_u64::<LittleEndian>(*digit)?;
}
Ok(())
}
/// Reads a little endian integer into this representation.
fn read_le<R: Read>(&mut self, mut reader: R) -> io::Result<()> {
use byteorder::{LittleEndian, ReadBytesExt};
for digit in self.as_mut().iter_mut() {
*digit = reader.read_u64::<LittleEndian>()?;
}
Ok(())
}
}
#[derive(Debug, PartialEq)]
pub enum LegendreSymbol {
Zero = 0,
QuadraticResidue = 1,
QuadraticNonResidue = -1,
}
/// An error that may occur when trying to interpret a `PrimeFieldRepr` as a
/// `PrimeField` element.
#[derive(Debug)]
pub enum PrimeFieldDecodingError {
/// The encoded value is not in the field
NotInField(String),
}
impl Error for PrimeFieldDecodingError {
fn description(&self) -> &str {
match *self {
PrimeFieldDecodingError::NotInField(..) => "not an element of the field",
}
}
}
impl fmt::Display for PrimeFieldDecodingError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
PrimeFieldDecodingError::NotInField(ref repr) => {
write!(f, "{} is not an element of the field", repr)
}
}
}
}
/// This represents an element of a prime field.
pub trait PrimeField: Field {
/// The prime field can be converted back and forth into this biginteger
/// representation.
type Repr: PrimeFieldRepr + From<Self>;
/// Interpret a string of numbers as a (congruent) prime field element.
/// Does not accept unnecessary leading zeroes or a blank string.
fn from_str(s: &str) -> Option<Self> {
if s.is_empty() {
return None;
}
if s == "0" {
return Some(Self::zero());
}
let mut res = Self::zero();
let ten = Self::from_repr(Self::Repr::from(10)).unwrap();
let mut first_digit = true;
for c in s.chars() {
match c.to_digit(10) {
Some(c) => {
if first_digit {
if c == 0 {
return None;
}
first_digit = false;
}
res.mul_assign(&ten);
res.add_assign(&Self::from_repr(Self::Repr::from(u64::from(c))).unwrap());
}
None => {
return None;
}
}
}
Some(res)
}
/// Convert this prime field element into a biginteger representation.
fn from_repr(Self::Repr) -> Result<Self, PrimeFieldDecodingError>;
/// Convert a biginteger representation into a prime field element, if
/// the number is an element of the field.
fn into_repr(&self) -> Self::Repr;
/// Returns the field characteristic; the modulus.
fn char() -> Self::Repr;
/// How many bits are needed to represent an element of this field.
const NUM_BITS: u32;
/// How many bits of information can be reliably stored in the field element.
const CAPACITY: u32;
/// Returns the multiplicative generator of `char()` - 1 order. This element
/// must also be quadratic nonresidue.
fn multiplicative_generator() -> Self;
/// 2^s * t = `char()` - 1 with t odd.
const S: u32;
/// Returns the 2^s root of unity computed by exponentiating the `multiplicative_generator()`
/// by t.
fn root_of_unity() -> Self;
}
/// An "engine" is a collection of types (fields, elliptic curve groups, etc.)
/// with well-defined relationships. Specific relationships (for example, a
/// pairing-friendly curve) can be defined in a subtrait.
pub trait ScalarEngine: Sized + 'static + Clone {
/// This is the scalar field of the engine's groups.
type Fr: PrimeField + SqrtField;
}
#[derive(Debug)]
pub struct BitIterator<E> {
t: E,
n: usize,
}
impl<E: AsRef<[u64]>> BitIterator<E> {
pub fn new(t: E) -> Self {
let n = t.as_ref().len() * 64;
BitIterator { t, n }
}
}
impl<E: AsRef<[u64]>> Iterator for BitIterator<E> {
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)
}
}
}
#[test]
fn test_bit_iterator() {
let mut a = BitIterator::new([0xa953d79b83f6ab59, 0x6dea2059e200bd39]);
let expected = "01101101111010100010000001011001111000100000000010111101001110011010100101010011110101111001101110000011111101101010101101011001";
for e in expected.chars() {
assert!(a.next().unwrap() == (e == '1'));
}
assert!(a.next().is_none());
let expected = "1010010101111110101010000101101011101000011101110101001000011001100100100011011010001011011011010001011011101100110100111011010010110001000011110100110001100110011101101000101100011100100100100100001010011101010111110011101011000011101000111011011101011001";
let mut a = BitIterator::new([
0x429d5f3ac3a3b759,
0xb10f4c66768b1c92,
0x92368b6d16ecd3b4,
0xa57ea85ae8775219,
]);
for e in expected.chars() {
assert!(a.next().unwrap() == (e == '1'));
}
assert!(a.next().is_none());
}
pub use self::arith_impl::*;
mod arith_impl {
/// Calculate a - b - borrow, returning the result and modifying
/// the borrow value.
#[inline(always)]
pub fn sbb(a: u64, b: u64, borrow: &mut u64) -> u64 {
let tmp = (1u128 << 64) + u128::from(a) - u128::from(b) - u128::from(*borrow);
*borrow = if tmp >> 64 == 0 { 1 } else { 0 };
tmp as u64
}
/// Calculate a + b + carry, returning the sum and modifying the
/// carry value.
#[inline(always)]
pub fn adc(a: u64, b: u64, carry: &mut u64) -> u64 {
let tmp = u128::from(a) + u128::from(b) + u128::from(*carry);
*carry = (tmp >> 64) as u64;
tmp as u64
}
/// Calculate a + (b * c) + carry, returning the least significant digit
/// and setting carry to the most significant digit.
#[inline(always)]
pub fn mac_with_carry(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 {
let tmp = (u128::from(a)) + u128::from(b) * u128::from(c) + u128::from(*carry);
*carry = (tmp >> 64) as u64;
tmp as u64
}
}

View File

@@ -1,18 +0,0 @@
[package]
name = "group"
version = "0.1.0"
authors = [
"Sean Bowe <ewillbefull@gmail.com>",
"Jack Grigg <jack@z.cash>",
]
license = "MIT/Apache-2.0"
description = "Elliptic curve group traits and utilities"
documentation = "https://docs.rs/group/"
homepage = "https://github.com/ebfull/group"
repository = "https://github.com/ebfull/group"
[dependencies]
ff = { path = "../ff" }
rand = "0.7"
rand_xorshift = "0.2"

View File

@@ -1,191 +0,0 @@
extern crate ff;
extern crate rand;
extern crate rand_xorshift;
use ff::{PrimeField, PrimeFieldDecodingError, ScalarEngine, SqrtField};
use rand::RngCore;
use std::error::Error;
use std::fmt;
pub mod tests;
mod wnaf;
pub use self::wnaf::Wnaf;
/// Projective representation of an elliptic curve point guaranteed to be
/// in the correct prime order subgroup.
pub trait CurveProjective:
PartialEq + Eq + Sized + Copy + Clone + Send + Sync + fmt::Debug + fmt::Display + 'static
{
type Engine: ScalarEngine<Fr = Self::Scalar>;
type Scalar: PrimeField + SqrtField;
type Base: SqrtField;
type Affine: CurveAffine<Projective = Self, Scalar = Self::Scalar>;
/// Returns an element chosen uniformly at random using a user-provided RNG.
fn random<R: RngCore>(rng: &mut R) -> Self;
/// Returns the additive identity.
fn zero() -> Self;
/// Returns a fixed generator of unknown exponent.
fn one() -> Self;
/// Determines if this point is the point at infinity.
fn is_zero(&self) -> bool;
/// Normalizes a slice of projective elements so that
/// conversion to affine is cheap.
fn batch_normalization(v: &mut [Self]);
/// Checks if the point is already "normalized" so that
/// cheap affine conversion is possible.
fn is_normalized(&self) -> bool;
/// Doubles this element.
fn double(&mut self);
/// Adds another element to this element.
fn add_assign(&mut self, other: &Self);
/// Subtracts another element from this element.
fn sub_assign(&mut self, other: &Self) {
let mut tmp = *other;
tmp.negate();
self.add_assign(&tmp);
}
/// Adds an affine element to this element.
fn add_assign_mixed(&mut self, other: &Self::Affine);
/// Negates this element.
fn negate(&mut self);
/// Performs scalar multiplication of this element.
fn mul_assign<S: Into<<Self::Scalar as PrimeField>::Repr>>(&mut self, other: S);
/// Converts this element into its affine representation.
fn into_affine(&self) -> Self::Affine;
/// Recommends a wNAF window table size given a scalar. Always returns a number
/// between 2 and 22, inclusive.
fn recommended_wnaf_for_scalar(scalar: <Self::Scalar as PrimeField>::Repr) -> usize;
/// Recommends a wNAF window size given the number of scalars you intend to multiply
/// a base by. Always returns a number between 2 and 22, inclusive.
fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize;
}
/// Affine representation of an elliptic curve point guaranteed to be
/// in the correct prime order subgroup.
pub trait CurveAffine:
Copy + Clone + Sized + Send + Sync + fmt::Debug + fmt::Display + PartialEq + Eq + 'static
{
type Engine: ScalarEngine<Fr = Self::Scalar>;
type Scalar: PrimeField + SqrtField;
type Base: SqrtField;
type Projective: CurveProjective<Affine = Self, Scalar = Self::Scalar>;
type Uncompressed: EncodedPoint<Affine = Self>;
type Compressed: EncodedPoint<Affine = Self>;
/// Returns the additive identity.
fn zero() -> Self;
/// Returns a fixed generator of unknown exponent.
fn one() -> Self;
/// Determines if this point represents the point at infinity; the
/// additive identity.
fn is_zero(&self) -> bool;
/// Negates this element.
fn negate(&mut self);
/// Performs scalar multiplication of this element with mixed addition.
fn mul<S: Into<<Self::Scalar as PrimeField>::Repr>>(&self, other: S) -> Self::Projective;
/// Converts this element into its affine representation.
fn into_projective(&self) -> Self::Projective;
/// Converts this element into its compressed encoding, so long as it's not
/// the point at infinity.
fn into_compressed(&self) -> Self::Compressed {
<Self::Compressed as EncodedPoint>::from_affine(*self)
}
/// Converts this element into its uncompressed encoding, so long as it's not
/// the point at infinity.
fn into_uncompressed(&self) -> Self::Uncompressed {
<Self::Uncompressed as EncodedPoint>::from_affine(*self)
}
}
/// An encoded elliptic curve point, which should essentially wrap a `[u8; N]`.
pub trait EncodedPoint:
Sized + Send + Sync + AsRef<[u8]> + AsMut<[u8]> + Clone + Copy + 'static
{
type Affine: CurveAffine;
/// Creates an empty representation.
fn empty() -> Self;
/// Returns the number of bytes consumed by this representation.
fn size() -> usize;
/// Converts an `EncodedPoint` into a `CurveAffine` element,
/// if the encoding represents a valid element.
fn into_affine(&self) -> Result<Self::Affine, GroupDecodingError>;
/// Converts an `EncodedPoint` into a `CurveAffine` element,
/// without guaranteeing that the encoding represents a valid
/// element. This is useful when the caller knows the encoding is
/// valid already.
///
/// If the encoding is invalid, this can break API invariants,
/// so caution is strongly encouraged.
fn into_affine_unchecked(&self) -> Result<Self::Affine, GroupDecodingError>;
/// Creates an `EncodedPoint` from an affine point, as long as the
/// point is not the point at infinity.
fn from_affine(affine: Self::Affine) -> Self;
}
/// An error that may occur when trying to decode an `EncodedPoint`.
#[derive(Debug)]
pub enum GroupDecodingError {
/// The coordinate(s) do not lie on the curve.
NotOnCurve,
/// The element is not part of the r-order subgroup.
NotInSubgroup,
/// One of the coordinates could not be decoded
CoordinateDecodingError(&'static str, PrimeFieldDecodingError),
/// The compression mode of the encoded element was not as expected
UnexpectedCompressionMode,
/// The encoding contained bits that should not have been set
UnexpectedInformation,
}
impl Error for GroupDecodingError {
fn description(&self) -> &str {
match *self {
GroupDecodingError::NotOnCurve => "coordinate(s) do not lie on the curve",
GroupDecodingError::NotInSubgroup => "the element is not part of an r-order subgroup",
GroupDecodingError::CoordinateDecodingError(..) => "coordinate(s) could not be decoded",
GroupDecodingError::UnexpectedCompressionMode => {
"encoding has unexpected compression mode"
}
GroupDecodingError::UnexpectedInformation => "encoding has unexpected information",
}
}
}
impl fmt::Display for GroupDecodingError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
GroupDecodingError::CoordinateDecodingError(description, ref err) => {
write!(f, "{} decoding error: {}", description, err)
}
_ => write!(f, "{}", self.description()),
}
}
}

View File

@@ -15,14 +15,13 @@ crate-type = ["staticlib"]
[dependencies]
bellman = { path = "../bellman" }
blake2b_simd = "0.5"
blake2s_simd = "0.5"
ff = { path = "../ff" }
libc = "0.2"
pairing = { path = "../pairing" }
lazy_static = "1"
byteorder = "1"
rand_core = "0.5"
rand_os = "0.2"
zcash_primitives = { path = "../zcash_primitives" }
zcash_proofs = { path = "../zcash_proofs" }
rand = "0.4"
sapling-crypto = { path = "../sapling-crypto" }
[dependencies.blake2-rfc]
git = "https://github.com/gtank/blake2-rfc"
rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"

View File

@@ -4,12 +4,6 @@
#include <stdint.h>
extern "C" {
#ifdef WIN32
typedef uint16_t codeunit;
#else
typedef uint8_t codeunit;
#endif
void librustzcash_to_scalar(const unsigned char *input, unsigned char *result);
void librustzcash_ask_to_ak(const unsigned char *ask, unsigned char *result);
@@ -25,14 +19,11 @@ extern "C" {
/// Loads the zk-SNARK parameters into memory and saves
/// paths as necessary. Only called once.
void librustzcash_init_zksnark_params(
const codeunit* spend_path,
size_t spend_path_len,
const char* spend_path,
const char* spend_hash,
const codeunit* output_path,
size_t output_path_len,
const char* output_path,
const char* output_hash,
const codeunit* sprout_path,
size_t sprout_path_len,
const char* sprout_path,
const char* sprout_hash
);
@@ -279,35 +270,6 @@ extern "C" {
uint64_t vpub_old,
uint64_t vpub_new
);
/// Derive the master ExtendedSpendingKey from a seed.
void librustzcash_zip32_xsk_master(
const unsigned char *seed,
size_t seedlen,
unsigned char *xsk_master
);
/// Derive a child ExtendedSpendingKey from a parent.
void librustzcash_zip32_xsk_derive(
const unsigned char *xsk_parent,
uint32_t i,
unsigned char *xsk_i
);
/// Derive a child ExtendedFullViewingKey from a parent.
bool librustzcash_zip32_xfvk_derive(
const unsigned char *xfvk_parent,
uint32_t i,
unsigned char *xfvk_i
);
/// Derive a PaymentAddress from an ExtendedFullViewingKey.
bool librustzcash_zip32_xfvk_address(
const unsigned char *xfvk,
const unsigned char *j,
unsigned char *j_ret,
unsigned char *addr_ret
);
}
#endif // LIBRUSTZCASH_INCLUDE_H_

View File

@@ -1,4 +1,4 @@
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams, State as Blake2bState};
use blake2_rfc::blake2b::{Blake2b, Blake2bResult};
use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
use std::io::Cursor;
use std::mem::size_of;
@@ -33,7 +33,7 @@ impl Params {
}
impl Node {
fn new(p: &Params, state: &Blake2bState, i: u32) -> Self {
fn new(p: &Params, state: &Blake2b, i: u32) -> Self {
let hash = generate_hash(state, i / p.indices_per_hash_output());
let start = ((i % p.indices_per_hash_output()) * p.n / 8) as usize;
let end = start + (p.n as usize) / 8;
@@ -99,18 +99,15 @@ impl Node {
}
}
fn initialise_state(n: u32, k: u32, digest_len: u8) -> Blake2bState {
fn initialise_state(n: u32, k: u32, digest_len: u8) -> Blake2b {
let mut personalization: Vec<u8> = Vec::from("ZcashPoW");
personalization.write_u32::<LittleEndian>(n).unwrap();
personalization.write_u32::<LittleEndian>(k).unwrap();
Blake2bParams::new()
.hash_length(digest_len as usize)
.personal(&personalization)
.to_state()
Blake2b::with_params(digest_len as usize, &[], &[], &personalization)
}
fn generate_hash(base_state: &Blake2bState, i: u32) -> Blake2bHash {
fn generate_hash(base_state: &Blake2b, i: u32) -> Blake2bResult {
let mut lei = [0u8; 4];
(&mut lei[..]).write_u32::<LittleEndian>(i).unwrap();
@@ -152,7 +149,8 @@ fn expand_array(vin: &[u8], bit_len: usize, byte_pad: usize) -> Vec<u8> {
vout[j + x] = ((
// Big-endian
acc_value >> (acc_bits + (8 * (out_width - x - 1)))
) & (
)
& (
// Apply bit_len_mask across byte boundaries
(bit_len_mask >> (8 * (out_width - x - 1))) & 0xFF
)) as u8;
@@ -252,7 +250,7 @@ pub fn is_valid_solution_iterative(
return rows[0].is_zero(hash_len);
}
fn tree_validator(p: &Params, state: &Blake2bState, indices: &[u32]) -> Option<Node> {
fn tree_validator(p: &Params, state: &Blake2b, indices: &[u32]) -> Option<Node> {
if indices.len() > 1 {
let end = indices.len();
let mid = end / 2;

View File

@@ -1,10 +1,10 @@
use blake2b_simd::State;
use blake2_rfc::blake2b::Blake2b;
use std::io::{self, Read};
/// Abstraction over a reader which hashes the data being read.
pub struct HashReader<R: Read> {
reader: R,
hasher: State,
hasher: Blake2b,
}
impl<R: Read> HashReader<R> {
@@ -12,7 +12,7 @@ impl<R: Read> HashReader<R> {
pub fn new(reader: R) -> Self {
HashReader {
reader: reader,
hasher: State::new(),
hasher: Blake2b::new(64),
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,8 @@
use ff::{PrimeField, PrimeFieldRepr};
use pairing::bls12_381::Bls12;
use rand_core::RngCore;
use rand_os::OsRng;
use zcash_primitives::jubjub::{edwards, JubjubBls12};
use zcash_primitives::primitives::{Diversifier, ViewingKey};
use pairing::{PrimeField, PrimeFieldRepr};
use rand::{OsRng, Rng};
use sapling_crypto::jubjub::{edwards, JubjubBls12};
use sapling_crypto::primitives::{Diversifier, ViewingKey};
use {
librustzcash_sapling_generate_r, librustzcash_sapling_ka_agree,
@@ -13,7 +12,7 @@ use {
#[test]
fn test_key_agreement() {
let params = JubjubBls12::new();
let mut rng = OsRng;
let mut rng = OsRng::new().unwrap();
// Create random viewing key
let vk = ViewingKey::<Bls12> {
@@ -23,9 +22,7 @@ fn test_key_agreement() {
// Create a random address with the viewing key
let addr = loop {
let mut d = [0; 11];
rng.fill_bytes(&mut d);
match vk.into_payment_address(Diversifier(d), &params) {
match vk.into_payment_address(Diversifier(rng.gen()), &params) {
Some(a) => break a,
None => {}
}

View File

@@ -1,6 +1,5 @@
use ff::{PrimeField, PrimeFieldRepr};
use pairing::bls12_381::Bls12;
use zcash_primitives::{
use pairing::{bls12_381::Bls12, PrimeField, PrimeFieldRepr};
use sapling_crypto::{
jubjub::{fs::FsRepr, FixedGenerators, JubjubEngine, JubjubParams},
primitives::{Diversifier, ProofGenerationKey},
};
@@ -28,8 +27,6 @@ fn key_components() {
note_v: u64,
note_r: [u8; 32],
note_cm: [u8; 32],
note_pos: u64,
note_nf: [u8; 32],
};
// From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_key_components.py
@@ -89,12 +86,6 @@ fn key_components() {
0x18, 0x50, 0xc9, 0xfe, 0xd4, 0x4f, 0xce, 0x08, 0x06, 0x27, 0x8f, 0x08, 0x3e, 0xf2,
0xdd, 0x07, 0x64, 0x39,
],
note_pos: 0,
note_nf: [
0x44, 0xfa, 0xd6, 0x56, 0x4f, 0xfd, 0xec, 0x9f, 0xa1, 0x9c, 0x43, 0xa2, 0x8f, 0x86,
0x1d, 0x5e, 0xbf, 0x60, 0x23, 0x46, 0x00, 0x7d, 0xe7, 0x62, 0x67, 0xd9, 0x75, 0x27,
0x47, 0xab, 0x40, 0x63,
],
},
TestVector {
sk: [
@@ -151,12 +142,6 @@ fn key_components() {
0x89, 0xe1, 0x0e, 0x26, 0x6b, 0xcf, 0xa3, 0x1c, 0x31, 0xb2, 0x9a, 0x53, 0xae, 0x72,
0xca, 0xd4, 0x69, 0x50,
],
note_pos: 763714296,
note_nf: [
0x67, 0x9e, 0xb0, 0xc3, 0xa7, 0x57, 0xe2, 0xae, 0x83, 0xcd, 0xb4, 0x2a, 0x1a, 0xb2,
0x59, 0xd7, 0x83, 0x88, 0x31, 0x54, 0x19, 0xad, 0xc7, 0x1d, 0x2e, 0x37, 0x63, 0x17,
0x4c, 0x2e, 0x9d, 0x93,
],
},
TestVector {
sk: [
@@ -213,12 +198,6 @@ fn key_components() {
0xb7, 0x40, 0x82, 0x96, 0x66, 0x17, 0x70, 0xb1, 0x01, 0xb0, 0xaa, 0x87, 0x83, 0x9f,
0x4e, 0x55, 0xf1, 0x51,
],
note_pos: 1527428592,
note_nf: [
0xe9, 0x8f, 0x6a, 0x8f, 0x34, 0xff, 0x49, 0x80, 0x59, 0xb3, 0xc7, 0x31, 0xb9, 0x1f,
0x45, 0x11, 0x08, 0xc4, 0x95, 0x4d, 0x91, 0x94, 0x84, 0x36, 0x1c, 0xf9, 0xb4, 0x8f,
0x59, 0xae, 0x1d, 0x14,
],
},
TestVector {
sk: [
@@ -275,12 +254,6 @@ fn key_components() {
0xbd, 0x10, 0x5d, 0x88, 0x39, 0x21, 0x2e, 0x0d, 0x16, 0x44, 0xb9, 0xd5, 0x5c, 0xaa,
0x60, 0xd1, 0x9b, 0x6c,
],
note_pos: 2291142888,
note_nf: [
0x55, 0x47, 0xaa, 0x12, 0xff, 0x80, 0xa6, 0xb3, 0x30, 0x4e, 0x3b, 0x05, 0x86, 0x56,
0x47, 0x2a, 0xbd, 0x2c, 0x81, 0x83, 0xb5, 0x9d, 0x07, 0x37, 0xb9, 0x3c, 0xee, 0x75,
0x8b, 0xec, 0x47, 0xa1,
],
},
TestVector {
sk: [
@@ -337,12 +310,6 @@ fn key_components() {
0xcf, 0x1e, 0x67, 0x15, 0xbf, 0xe7, 0x0b, 0x63, 0x2d, 0x04, 0x4b, 0x26, 0xfb, 0x2b,
0xc7, 0x1b, 0x7f, 0x36,
],
note_pos: 3054857184,
note_nf: [
0x8a, 0x9a, 0xbd, 0xa3, 0xd4, 0xef, 0x85, 0xca, 0xf2, 0x2b, 0xfa, 0xf2, 0xc4, 0x8f,
0x62, 0x38, 0x2a, 0x73, 0xa1, 0x62, 0x4e, 0xb8, 0xeb, 0x2b, 0xd0, 0x0d, 0x27, 0x03,
0x01, 0xbf, 0x3d, 0x13,
],
},
TestVector {
sk: [
@@ -399,12 +366,6 @@ fn key_components() {
0x1d, 0x74, 0xc5, 0xbc, 0xf2, 0xe1, 0xef, 0x95, 0x66, 0x90, 0x44, 0x73, 0x01, 0x69,
0xde, 0x1a, 0x5b, 0x4c,
],
note_pos: 3818571480,
note_nf: [
0x33, 0x2a, 0xd9, 0x9e, 0xb9, 0xe9, 0x77, 0xeb, 0x62, 0x7a, 0x12, 0x2d, 0xbf, 0xb2,
0xf2, 0x5f, 0xe5, 0x88, 0xe5, 0x97, 0x75, 0x3e, 0xc5, 0x58, 0x0f, 0xf2, 0xbe, 0x20,
0xb6, 0xc9, 0xa7, 0xe1,
],
},
TestVector {
sk: [
@@ -461,12 +422,6 @@ fn key_components() {
0x90, 0xb6, 0xe0, 0xf2, 0xf4, 0xbf, 0x4e, 0xc4, 0xa0, 0xdb, 0x5b, 0xbc, 0xcb, 0x5b,
0x78, 0x3a, 0x1e, 0x55,
],
note_pos: 287318480,
note_nf: [
0xfc, 0x74, 0xcd, 0x0e, 0x4b, 0xe0, 0x49, 0x57, 0xb1, 0x96, 0xcf, 0x87, 0x34, 0xae,
0x99, 0x23, 0x96, 0xaf, 0x4c, 0xfa, 0x8f, 0xec, 0xbb, 0x86, 0xf9, 0x61, 0xe6, 0xb4,
0x07, 0xd5, 0x1e, 0x11,
],
},
TestVector {
sk: [
@@ -523,12 +478,6 @@ fn key_components() {
0x60, 0xa0, 0x06, 0xf8, 0x2b, 0xb7, 0xad, 0xcd, 0x75, 0x22, 0x3f, 0xa8, 0x59, 0x36,
0xf7, 0x8c, 0x2b, 0x23,
],
note_pos: 1051032776,
note_nf: [
0xd2, 0xe8, 0x87, 0xbd, 0x85, 0x4a, 0x80, 0x2b, 0xce, 0x85, 0x70, 0x53, 0x02, 0x0f,
0x5d, 0x3e, 0x7c, 0x8a, 0xe5, 0x26, 0x7c, 0x5b, 0x65, 0x83, 0xb3, 0xd2, 0x12, 0xcc,
0x8b, 0xb6, 0x98, 0x90,
],
},
TestVector {
sk: [
@@ -585,12 +534,6 @@ fn key_components() {
0x23, 0x36, 0xc2, 0xa0, 0x5a, 0x08, 0x03, 0x23, 0x9b, 0x5b, 0x88, 0xfd, 0x92, 0x07,
0x8f, 0xea, 0x4d, 0x04,
],
note_pos: 1814747072,
note_nf: [
0xa8, 0x2f, 0x17, 0x50, 0xcc, 0x5b, 0x2b, 0xee, 0x64, 0x9a, 0x36, 0x5c, 0x04, 0x20,
0xed, 0x87, 0x07, 0x5b, 0x88, 0x71, 0xfd, 0xa4, 0xa7, 0xf5, 0x84, 0x0d, 0x6b, 0xbe,
0xb1, 0x7c, 0xd6, 0x20,
],
},
TestVector {
sk: [
@@ -647,12 +590,6 @@ fn key_components() {
0x64, 0x41, 0x9b, 0x0e, 0x55, 0x0a, 0xbb, 0xcb, 0x8e, 0x2b, 0xcb, 0xda, 0x8b, 0x63,
0xe4, 0x1d, 0xeb, 0x37,
],
note_pos: 2578461368,
note_nf: [
0x65, 0x36, 0x74, 0x87, 0x3b, 0x3c, 0x67, 0x0c, 0x58, 0x85, 0x84, 0x73, 0xe7, 0xfe,
0x72, 0x19, 0x72, 0xfb, 0x96, 0xe2, 0x15, 0xb8, 0x73, 0x77, 0xa1, 0x7c, 0xa3, 0x71,
0x0d, 0x93, 0xc9, 0xe9,
],
},
];
@@ -725,7 +662,5 @@ fn key_components() {
note.cm(&JUBJUB).into_repr().write_le(&mut vec).unwrap();
assert_eq!(&vec, &tv.note_cm);
}
assert_eq!(note.nf(&fvk, tv.note_pos, &JUBJUB), tv.note_nf);
}
}

View File

@@ -1,4 +1,4 @@
use zcash_primitives::jubjub::{FixedGenerators, JubjubParams};
use sapling_crypto::jubjub::{FixedGenerators, JubjubParams};
use super::JUBJUB;

View File

@@ -1,7 +1,7 @@
use ff::{PrimeField, PrimeFieldRepr};
use pairing::bls12_381::Bls12;
use zcash_primitives::jubjub::{FixedGenerators, JubjubEngine};
use zcash_primitives::redjubjub::{PrivateKey, PublicKey, Signature};
use pairing::{bls12_381::Bls12, PrimeField, PrimeFieldRepr};
use sapling_crypto::{
jubjub::{FixedGenerators, JubjubEngine}, redjubjub::{PrivateKey, PublicKey, Signature},
};
use super::JUBJUB;

View File

@@ -3,10 +3,7 @@ name = "pairing"
# Remember to change version string in README.md.
version = "0.14.2"
authors = [
"Sean Bowe <ewillbefull@gmail.com>",
"Jack Grigg <jack@z.cash>",
]
authors = ["Sean Bowe <ewillbefull@gmail.com>"]
license = "MIT/Apache-2.0"
description = "Pairing-friendly elliptic curve library"
@@ -15,15 +12,12 @@ homepage = "https://github.com/ebfull/pairing"
repository = "https://github.com/ebfull/pairing"
[dependencies]
rand = "0.4"
byteorder = "1"
ff = { path = "../ff", features = ["derive"] }
group = { path = "../group" }
rand_core = "0.5"
[dev-dependencies]
rand_xorshift = "0.2"
clippy = { version = "0.0.200", optional = true }
[features]
unstable-features = ["expose-arith"]
expose-arith = []
u128-support = []
default = []

View File

@@ -6,6 +6,14 @@ This is a Rust crate for using pairing-friendly elliptic curves. Currently, only
Bring the `pairing` crate into your project just as you normally would.
If you're using a supported platform and the nightly Rust compiler, you can enable the `u128-support` feature for faster arithmetic.
```toml
[dependencies.pairing]
version = "0.14"
features = ["u128-support"]
```
## Security Warnings
This library does not make any guarantees about constant-time operations, memory access patterns, or resistance to side-channel attacks.

View File

@@ -1,8 +1,8 @@
mod g1 {
use rand::{Rand, SeedableRng, XorShiftRng};
use group::CurveProjective;
use pairing::bls12_381::*;
use pairing::CurveProjective;
#[bench]
fn bench_g1_mul_assign(b: &mut ::test::Bencher) {
@@ -65,8 +65,8 @@ mod g1 {
mod g2 {
use rand::{Rand, SeedableRng, XorShiftRng};
use group::CurveProjective;
use pairing::bls12_381::*;
use pairing::CurveProjective;
#[bench]
fn bench_g2_mul_assign(b: &mut ::test::Bencher) {

View File

@@ -1,7 +1,7 @@
use rand::{Rand, SeedableRng, XorShiftRng};
use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField};
use pairing::bls12_381::*;
use pairing::{Field, PrimeField, PrimeFieldRepr, SqrtField};
#[bench]
fn bench_fq_repr_add_nocarry(b: &mut ::test::Bencher) {

View File

@@ -1,7 +1,7 @@
use rand::{Rand, SeedableRng, XorShiftRng};
use ff::Field;
use pairing::bls12_381::*;
use pairing::Field;
#[bench]
fn bench_fq12_add_assign(b: &mut ::test::Bencher) {

View File

@@ -1,7 +1,7 @@
use rand::{Rand, SeedableRng, XorShiftRng};
use ff::{Field, SqrtField};
use pairing::bls12_381::*;
use pairing::{Field, SqrtField};
#[bench]
fn bench_fq2_add_assign(b: &mut ::test::Bencher) {

View File

@@ -1,7 +1,7 @@
use rand::{Rand, SeedableRng, XorShiftRng};
use ff::{Field, PrimeField, PrimeFieldRepr, SqrtField};
use pairing::bls12_381::*;
use pairing::{Field, PrimeField, PrimeFieldRepr, SqrtField};
#[bench]
fn bench_fr_repr_add_nocarry(b: &mut ::test::Bencher) {

View File

@@ -7,7 +7,7 @@ mod fr;
use rand::{Rand, SeedableRng, XorShiftRng};
use pairing::bls12_381::*;
use pairing::{Engine, PairingCurveAffine};
use pairing::{CurveAffine, Engine};
#[bench]
fn bench_pairing_g1_preparation(b: &mut ::test::Bencher) {

View File

@@ -1,7 +1,5 @@
#![feature(test)]
extern crate ff;
extern crate group;
extern crate pairing;
extern crate rand;
extern crate test;

View File

@@ -14,10 +14,11 @@ macro_rules! curve_impl {
pub struct $affine {
pub(crate) x: $basefield,
pub(crate) y: $basefield,
pub(crate) infinity: bool,
pub(crate) infinity: bool
}
impl ::std::fmt::Display for $affine {
impl ::std::fmt::Display for $affine
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
if self.infinity {
write!(f, "{}(Infinity)", $name)
@@ -29,12 +30,13 @@ macro_rules! curve_impl {
#[derive(Copy, Clone, Debug, Eq)]
pub struct $projective {
pub(crate) x: $basefield,
pub(crate) y: $basefield,
pub(crate) z: $basefield,
pub(crate) x: $basefield,
pub(crate) y: $basefield,
pub(crate) z: $basefield
}
impl ::std::fmt::Display for $projective {
impl ::std::fmt::Display for $projective
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "{}", self.into_affine())
}
@@ -87,9 +89,7 @@ macro_rules! curve_impl {
let mut res = $projective::zero();
for i in bits {
res.double();
if i {
res.add_assign_mixed(self)
}
if i { res.add_assign_mixed(self) }
}
res
}
@@ -112,8 +112,12 @@ macro_rules! curve_impl {
$affine {
x: x,
y: if (y < negy) ^ greatest { y } else { negy },
infinity: false,
y: if (y < negy) ^ greatest {
y
} else {
negy
},
infinity: false
}
})
}
@@ -144,15 +148,18 @@ macro_rules! curve_impl {
type Engine = Bls12;
type Scalar = $scalarfield;
type Base = $basefield;
type Prepared = $prepared;
type Projective = $projective;
type Uncompressed = $uncompressed;
type Compressed = $compressed;
type Pair = $pairing;
type PairingResult = Fq12;
fn zero() -> Self {
$affine {
x: $basefield::zero(),
y: $basefield::one(),
infinity: true,
infinity: true
}
}
@@ -175,16 +182,6 @@ macro_rules! curve_impl {
}
}
fn into_projective(&self) -> $projective {
(*self).into()
}
}
impl PairingCurveAffine for $affine {
type Prepared = $prepared;
type Pair = $pairing;
type PairingResult = Fq12;
fn prepare(&self) -> Self::Prepared {
$prepared::from_affine(*self)
}
@@ -192,18 +189,18 @@ macro_rules! curve_impl {
fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
self.perform_pairing(other)
}
fn into_projective(&self) -> $projective {
(*self).into()
}
}
impl CurveProjective for $projective {
type Engine = Bls12;
type Scalar = $scalarfield;
type Base = $basefield;
type Affine = $affine;
fn random<R: RngCore>(rng: &mut R) -> Self {
impl Rand for $projective {
fn rand<R: Rng>(rng: &mut R) -> Self {
loop {
let x = $basefield::random(rng);
let greatest = rng.next_u32() % 2 != 0;
let x = rng.gen();
let greatest = rng.gen();
if let Some(p) = $affine::get_point_from_x(x, greatest) {
let p = p.scale_by_cofactor();
@@ -214,6 +211,13 @@ macro_rules! curve_impl {
}
}
}
}
impl CurveProjective for $projective {
type Engine = Bls12;
type Scalar = $scalarfield;
type Base = $basefield;
type Affine = $affine;
// The point at infinity is always represented by
// Z = 0.
@@ -221,7 +225,7 @@ macro_rules! curve_impl {
$projective {
x: $basefield::zero(),
y: $basefield::one(),
z: $basefield::zero(),
z: $basefield::zero()
}
}
@@ -239,7 +243,8 @@ macro_rules! curve_impl {
self.is_zero() || self.z == $basefield::one()
}
fn batch_normalization(v: &mut [Self]) {
fn batch_normalization(v: &mut [Self])
{
// Montgomerys Trick and Fast Implementation of Masked AES
// Genelle, Prouff and Quisquater
// Section 3.2
@@ -247,10 +252,9 @@ macro_rules! curve_impl {
// First pass: compute [a, ab, abc, ...]
let mut prod = Vec::with_capacity(v.len());
let mut tmp = $basefield::one();
for g in v
.iter_mut()
// Ignore normalized elements
.filter(|g| !g.is_normalized())
for g in v.iter_mut()
// Ignore normalized elements
.filter(|g| !g.is_normalized())
{
tmp.mul_assign(&g.z);
prod.push(tmp);
@@ -260,19 +264,13 @@ macro_rules! curve_impl {
tmp = tmp.inverse().unwrap(); // Guaranteed to be nonzero.
// Second pass: iterate backwards to compute inverses
for (g, s) in v
.iter_mut()
// Backwards
.rev()
// Ignore normalized elements
.filter(|g| !g.is_normalized())
// Backwards, skip last element, fill in one for last term.
.zip(
prod.into_iter()
.rev()
.skip(1)
.chain(Some($basefield::one())),
)
for (g, s) in v.iter_mut()
// Backwards
.rev()
// Ignore normalized elements
.filter(|g| !g.is_normalized())
// Backwards, skip last element, fill in one for last term.
.zip(prod.into_iter().rev().skip(1).chain(Some($basefield::one())))
{
// tmp := tmp * g.z; g.z := tmp * s = 1/z
let mut newtmp = tmp;
@@ -283,7 +281,9 @@ macro_rules! curve_impl {
}
// Perform affine transformations
for g in v.iter_mut().filter(|g| !g.is_normalized()) {
for g in v.iter_mut()
.filter(|g| !g.is_normalized())
{
let mut z = g.z; // 1/z
z.square(); // 1/z^2
g.x.mul_assign(&z); // x/z^2
@@ -536,7 +536,8 @@ macro_rules! curve_impl {
let mut found_one = false;
for i in BitIterator::new(other.into()) {
for i in BitIterator::new(other.into())
{
if found_one {
res.double();
} else {
@@ -574,7 +575,7 @@ macro_rules! curve_impl {
$projective {
x: p.x,
y: p.y,
z: $basefield::one(),
z: $basefield::one()
}
}
}
@@ -591,7 +592,7 @@ macro_rules! curve_impl {
$affine {
x: p.x,
y: p.y,
infinity: false,
infinity: false
}
} else {
// Z is nonzero, so it must have an inverse in a field.
@@ -611,22 +612,23 @@ macro_rules! curve_impl {
$affine {
x: x,
y: y,
infinity: false,
infinity: false
}
}
}
}
};
}
}
pub mod g1 {
use super::super::{Bls12, Fq, Fq12, FqRepr, Fr, FrRepr};
use super::g2::G2Affine;
use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField};
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
use rand_core::RngCore;
use rand::{Rand, Rng};
use std::fmt;
use {Engine, PairingCurveAffine};
use {
BitIterator, CurveAffine, CurveProjective, EncodedPoint, Engine, Field, GroupDecodingError,
PrimeField, PrimeFieldRepr, SqrtField,
};
curve_impl!(
"G1",
@@ -952,7 +954,7 @@ pub mod g1 {
let negyrepr = negy.into_repr();
let p = G1Affine {
x,
x: x,
y: if yrepr < negyrepr { y } else { negy },
infinity: false,
};
@@ -987,8 +989,7 @@ pub mod g1 {
0x9fe83b1b4a5d648d,
0xf583cc5a508f6a40,
0xc3ad2aefde0bb13,
]))
.unwrap(),
])).unwrap(),
y: Fq::from_repr(FqRepr([
0x60aa6f9552f03aae,
0xecd01d5181300d35,
@@ -996,8 +997,7 @@ pub mod g1 {
0xe760f57922998c9d,
0x953703f5795a39e5,
0xfe3ae0922df702c,
]))
.unwrap(),
])).unwrap(),
infinity: false,
};
assert!(!p.is_on_curve());
@@ -1014,8 +1014,7 @@ pub mod g1 {
0xea034ee2928b30a8,
0xbd8833dc7c79a7f7,
0xe45c9f0c0438675,
]))
.unwrap(),
])).unwrap(),
y: Fq::from_repr(FqRepr([
0x3b450eb1ab7b5dad,
0xa65cb81e975e8675,
@@ -1023,8 +1022,7 @@ pub mod g1 {
0x753ddf21a2601d20,
0x532d0b640bd3ff8b,
0x118d2c543f031102,
]))
.unwrap(),
])).unwrap(),
infinity: false,
};
assert!(!p.is_on_curve());
@@ -1042,8 +1040,7 @@ pub mod g1 {
0xf35de9ce0d6b4e84,
0x265bddd23d1dec54,
0x12a8778088458308,
]))
.unwrap(),
])).unwrap(),
y: Fq::from_repr(FqRepr([
0x8a22defa0d526256,
0xc57ca55456fcb9ae,
@@ -1051,8 +1048,7 @@ pub mod g1 {
0x921beef89d4f29df,
0x5b6fda44ad85fa78,
0xed74ab9f302cbe0,
]))
.unwrap(),
])).unwrap(),
infinity: false,
};
assert!(p.is_on_curve());
@@ -1070,8 +1066,7 @@ pub mod g1 {
0x485e77d50a5df10d,
0x4c6fcac4b55fd479,
0x86ed4d9906fb064,
]))
.unwrap(),
])).unwrap(),
y: Fq::from_repr(FqRepr([
0xd25ee6461538c65,
0x9f3bbb2ecd3719b9,
@@ -1079,8 +1074,7 @@ pub mod g1 {
0xcefca68333c35288,
0x570c8005f8573fa6,
0x152ca696fe034442,
]))
.unwrap(),
])).unwrap(),
z: Fq::one(),
};
@@ -1092,8 +1086,7 @@ pub mod g1 {
0x5f44314ec5e3fb03,
0x24e8538737c6e675,
0x8abd623a594fba8,
]))
.unwrap(),
])).unwrap(),
y: Fq::from_repr(FqRepr([
0x6b0528f088bb7044,
0x2fdeb5c82917ff9e,
@@ -1101,8 +1094,7 @@ pub mod g1 {
0xd65104c6f95a872a,
0x1f2998a5a9c61253,
0xe74846154a9e44,
]))
.unwrap(),
])).unwrap(),
z: Fq::one(),
});
@@ -1118,8 +1110,7 @@ pub mod g1 {
0xc4f9a52a428e23bb,
0xd178b28dd4f407ef,
0x17fb8905e9183c69
]))
.unwrap(),
])).unwrap(),
y: Fq::from_repr(FqRepr([
0xd0de9d65292b7710,
0xf6a05f2bcf1d9ca7,
@@ -1127,8 +1118,7 @@ pub mod g1 {
0xeec8d1a5b7466c58,
0x4bc362649dce6376,
0x430cbdc5455b00a
]))
.unwrap(),
])).unwrap(),
infinity: false,
}
);
@@ -1144,8 +1134,7 @@ pub mod g1 {
0x485e77d50a5df10d,
0x4c6fcac4b55fd479,
0x86ed4d9906fb064,
]))
.unwrap(),
])).unwrap(),
y: Fq::from_repr(FqRepr([
0xd25ee6461538c65,
0x9f3bbb2ecd3719b9,
@@ -1153,8 +1142,7 @@ pub mod g1 {
0xcefca68333c35288,
0x570c8005f8573fa6,
0x152ca696fe034442,
]))
.unwrap(),
])).unwrap(),
z: Fq::one(),
};
@@ -1172,8 +1160,7 @@ pub mod g1 {
0x4b914c16687dcde0,
0x66c8baf177d20533,
0xaf960cff3d83833
]))
.unwrap(),
])).unwrap(),
y: Fq::from_repr(FqRepr([
0x3f0675695f5177a8,
0x2b6d82ae178a1ba0,
@@ -1181,8 +1168,7 @@ pub mod g1 {
0x1771a65b60572f4e,
0x8b547c1313b27555,
0x135075589a687b1e
]))
.unwrap(),
])).unwrap(),
infinity: false,
}
);
@@ -1205,8 +1191,7 @@ pub mod g1 {
0x71ffa8021531705,
0x7418d484386d267,
0xd5108d8ff1fbd6,
]))
.unwrap(),
])).unwrap(),
y: Fq::from_repr(FqRepr([
0xa776ccbfe9981766,
0x255632964ff40f4a,
@@ -1214,8 +1199,7 @@ pub mod g1 {
0x520f74773e74c8c3,
0x484c8fc982008f0,
0xee2c3d922008cc6,
]))
.unwrap(),
])).unwrap(),
infinity: false,
};
@@ -1227,8 +1211,7 @@ pub mod g1 {
0xc6e05201e5f83991,
0xf7c75910816f207c,
0x18d4043e78103106,
]))
.unwrap(),
])).unwrap(),
y: Fq::from_repr(FqRepr([
0xa776ccbfe9981766,
0x255632964ff40f4a,
@@ -1236,8 +1219,7 @@ pub mod g1 {
0x520f74773e74c8c3,
0x484c8fc982008f0,
0xee2c3d922008cc6,
]))
.unwrap(),
])).unwrap(),
infinity: false,
};
@@ -1252,8 +1234,7 @@ pub mod g1 {
0x9676ff02ec39c227,
0x4c12c15d7e55b9f3,
0x57fd1e317db9bd,
]))
.unwrap(),
])).unwrap(),
y: Fq::from_repr(FqRepr([
0x1288334016679345,
0xf955cd68615ff0b5,
@@ -1261,8 +1242,7 @@ pub mod g1 {
0x1267d70db51049fb,
0x4696deb9ab2ba3e7,
0xb1e4e11177f59d4,
]))
.unwrap(),
])).unwrap(),
infinity: false,
};
@@ -1283,19 +1263,19 @@ pub mod g1 {
#[test]
fn g1_curve_tests() {
use group::tests::curve_tests;
curve_tests::<G1>();
::tests::curve::curve_tests::<G1>();
}
}
pub mod g2 {
use super::super::{Bls12, Fq, Fq12, Fq2, FqRepr, Fr, FrRepr};
use super::g1::G1Affine;
use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField};
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
use rand_core::RngCore;
use rand::{Rand, Rng};
use std::fmt;
use {Engine, PairingCurveAffine};
use {
BitIterator, CurveAffine, CurveProjective, EncodedPoint, Engine, Field, GroupDecodingError,
PrimeField, PrimeFieldRepr, SqrtField,
};
curve_impl!(
"G2",
@@ -1656,7 +1636,7 @@ pub mod g2 {
negy.negate();
let p = G2Affine {
x,
x: x,
y: if y < negy { y } else { negy },
infinity: false,
};
@@ -1692,8 +1672,7 @@ pub mod g2 {
0x7a17a004747e3dbe,
0xcc65406a7c2e5a73,
0x10b8c03d64db4d0c,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0xd30e70fe2f029778,
0xda30772df0f5212e,
@@ -1701,8 +1680,7 @@ pub mod g2 {
0xfb777e5b9b568608,
0x789bac1fec71a2b9,
0x1342f02e2da54405,
]))
.unwrap(),
])).unwrap(),
},
y: Fq2 {
c0: Fq::from_repr(FqRepr([
@@ -1712,8 +1690,7 @@ pub mod g2 {
0x663015d9410eb608,
0x78e82a79d829a544,
0x40a00545bb3c1e,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x4709802348e79377,
0xb5ac4dc9204bcfbd,
@@ -1721,8 +1698,7 @@ pub mod g2 {
0x15008b1dc399e8df,
0x68128fd0548a3829,
0x16a613db5c873aaa,
]))
.unwrap(),
])).unwrap(),
},
infinity: false,
};
@@ -1741,8 +1717,7 @@ pub mod g2 {
0x41abba710d6c692c,
0xffcc4b2b62ce8484,
0x6993ec01b8934ed,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0xb94e92d5f874e26,
0x44516408bc115d95,
@@ -1750,8 +1725,7 @@ pub mod g2 {
0xa5a0c2b7131f3555,
0x83800965822367e7,
0x10cf1d3ad8d90bfa,
]))
.unwrap(),
])).unwrap(),
},
y: Fq2 {
c0: Fq::from_repr(FqRepr([
@@ -1761,8 +1735,7 @@ pub mod g2 {
0x5a9171720e73eb51,
0x38eb4fd8d658adb7,
0xb649051bbc1164d,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x9225814253d7df75,
0xc196c2513477f887,
@@ -1770,8 +1743,7 @@ pub mod g2 {
0x55f2b8efad953e04,
0x7379345eda55265e,
0x377f2e6208fd4cb,
]))
.unwrap(),
])).unwrap(),
},
infinity: false,
};
@@ -1791,8 +1763,7 @@ pub mod g2 {
0x2199bc19c48c393d,
0x4a151b732a6075bf,
0x17762a3b9108c4a7,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x26f461e944bbd3d1,
0x298f3189a9cf6ed6,
@@ -1800,8 +1771,7 @@ pub mod g2 {
0x7e147f3f9e6e241,
0x72a9b63583963fff,
0x158b0083c000462,
]))
.unwrap(),
])).unwrap(),
},
y: Fq2 {
c0: Fq::from_repr(FqRepr([
@@ -1811,8 +1781,7 @@ pub mod g2 {
0x68cad19430706b4d,
0x3ccfb97b924dcea8,
0x1660f93434588f8d,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0xaaed3985b6dcb9c7,
0xc1e985d6d898d9f4,
@@ -1820,8 +1789,7 @@ pub mod g2 {
0x3940a2dbb914b529,
0xbeb88137cf34f3e7,
0x1699ee577c61b694,
]))
.unwrap(),
])).unwrap(),
},
infinity: false,
};
@@ -1841,8 +1809,7 @@ pub mod g2 {
0x72556c999f3707ac,
0x4617f2e6774e9711,
0x100b2fe5bffe030b,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x7a33555977ec608,
0xe23039d1fe9c0881,
@@ -1850,8 +1817,7 @@ pub mod g2 {
0x4637c4f417667e2e,
0x93ebe7c3e41f6acc,
0xde884f89a9a371b,
]))
.unwrap(),
])).unwrap(),
},
y: Fq2 {
c0: Fq::from_repr(FqRepr([
@@ -1861,8 +1827,7 @@ pub mod g2 {
0x25fd427b4122f231,
0xd83112aace35cae,
0x191b2432407cbb7f,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0xf68ae82fe97662f5,
0xe986057068b50b7d,
@@ -1870,8 +1835,7 @@ pub mod g2 {
0x9eaa6d19de569196,
0xf6a03d31e2ec2183,
0x3bdafaf7ca9b39b,
]))
.unwrap(),
])).unwrap(),
},
z: Fq2::one(),
};
@@ -1885,8 +1849,7 @@ pub mod g2 {
0x8e73a96b329ad190,
0x27c546f75ee1f3ab,
0xa33d27add5e7e82,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x93b1ebcd54870dfe,
0xf1578300e1342e11,
@@ -1894,8 +1857,7 @@ pub mod g2 {
0x2089faf462438296,
0x828e5848cd48ea66,
0x141ecbac1deb038b,
]))
.unwrap(),
])).unwrap(),
},
y: Fq2 {
c0: Fq::from_repr(FqRepr([
@@ -1905,8 +1867,7 @@ pub mod g2 {
0x2767032fc37cc31d,
0xd5ee2aba84fd10fe,
0x16576ccd3dd0a4e8,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x4da9b6f6a96d1dd2,
0x9657f7da77f1650e,
@@ -1914,8 +1875,7 @@ pub mod g2 {
0x31898db63f87363a,
0xabab040ddbd097cc,
0x11ad236b9ba02990,
]))
.unwrap(),
])).unwrap(),
},
z: Fq2::one(),
});
@@ -1933,8 +1893,7 @@ pub mod g2 {
0xf1273e6406eef9cc,
0xababd760ff05cb92,
0xd7c20456617e89
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0xd1a50b8572cbd2b8,
0x238f0ac6119d07df,
@@ -1942,8 +1901,7 @@ pub mod g2 {
0x8b203284c51edf6b,
0xc8a0b730bbb21f5e,
0x1a3b59d29a31274
]))
.unwrap(),
])).unwrap(),
},
y: Fq2 {
c0: Fq::from_repr(FqRepr([
@@ -1953,8 +1911,7 @@ pub mod g2 {
0x64528ab3863633dc,
0x159384333d7cba97,
0x4cb84741f3cafe8
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x242af0dc3640e1a4,
0xe90a73ad65c66919,
@@ -1962,8 +1919,7 @@ pub mod g2 {
0x38528f92b689644d,
0xb6884deec59fb21f,
0x3c075d3ec52ba90
]))
.unwrap(),
])).unwrap(),
},
infinity: false,
}
@@ -1981,8 +1937,7 @@ pub mod g2 {
0x72556c999f3707ac,
0x4617f2e6774e9711,
0x100b2fe5bffe030b,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x7a33555977ec608,
0xe23039d1fe9c0881,
@@ -1990,8 +1945,7 @@ pub mod g2 {
0x4637c4f417667e2e,
0x93ebe7c3e41f6acc,
0xde884f89a9a371b,
]))
.unwrap(),
])).unwrap(),
},
y: Fq2 {
c0: Fq::from_repr(FqRepr([
@@ -2001,8 +1955,7 @@ pub mod g2 {
0x25fd427b4122f231,
0xd83112aace35cae,
0x191b2432407cbb7f,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0xf68ae82fe97662f5,
0xe986057068b50b7d,
@@ -2010,8 +1963,7 @@ pub mod g2 {
0x9eaa6d19de569196,
0xf6a03d31e2ec2183,
0x3bdafaf7ca9b39b,
]))
.unwrap(),
])).unwrap(),
},
z: Fq2::one(),
};
@@ -2031,8 +1983,7 @@ pub mod g2 {
0xbcedcfce1e52d986,
0x9755d4a3926e9862,
0x18bab73760fd8024
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x4e7c5e0a2ae5b99e,
0x96e582a27f028961,
@@ -2040,8 +1991,7 @@ pub mod g2 {
0xeb0cf5e610ef4fe7,
0x7b4c2bae8db6e70b,
0xf136e43909fca0
]))
.unwrap(),
])).unwrap(),
},
y: Fq2 {
c0: Fq::from_repr(FqRepr([
@@ -2051,8 +2001,7 @@ pub mod g2 {
0xa5a2a51f7fde787b,
0x8b92866bc6384188,
0x81a53fe531d64ef
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x4c5d607666239b34,
0xeddb5f48304d14b3,
@@ -2060,8 +2009,7 @@ pub mod g2 {
0xb271f52f12ead742,
0x244e6c2015c83348,
0x19e2deae6eb9b441
]))
.unwrap(),
])).unwrap(),
},
infinity: false,
}
@@ -2070,8 +2018,7 @@ pub mod g2 {
#[test]
fn g2_curve_tests() {
use group::tests::curve_tests;
curve_tests::<G2>();
::tests::curve::curve_tests::<G2>();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
use super::fq::FROBENIUS_COEFF_FQ12_C1;
use super::fq2::Fq2;
use super::fq6::Fq6;
use ff::Field;
use rand_core::RngCore;
use rand::{Rand, Rng};
use Field;
/// An element of Fq12, represented by c0 + c1 * w.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -17,6 +17,15 @@ impl ::std::fmt::Display for Fq12 {
}
}
impl Rand for Fq12 {
fn rand<R: Rng>(rng: &mut R) -> Self {
Fq12 {
c0: rng.gen(),
c1: rng.gen(),
}
}
}
impl Fq12 {
pub fn conjugate(&mut self) {
self.c1.negate();
@@ -40,13 +49,6 @@ impl Fq12 {
}
impl Field for Fq12 {
fn random<R: RngCore>(rng: &mut R) -> Self {
Fq12 {
c0: Fq6::random(rng),
c1: Fq6::random(rng),
}
}
fn zero() -> Self {
Fq12 {
c0: Fq6::zero(),
@@ -147,29 +149,24 @@ impl Field for Fq12 {
}
#[cfg(test)]
use rand_core::SeedableRng;
#[cfg(test)]
use rand_xorshift::XorShiftRng;
use rand::{SeedableRng, XorShiftRng};
#[test]
fn test_fq12_mul_by_014() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let c0 = Fq2::random(&mut rng);
let c1 = Fq2::random(&mut rng);
let c5 = Fq2::random(&mut rng);
let mut a = Fq12::random(&mut rng);
let c0 = Fq2::rand(&mut rng);
let c1 = Fq2::rand(&mut rng);
let c5 = Fq2::rand(&mut rng);
let mut a = Fq12::rand(&mut rng);
let mut b = a;
a.mul_by_014(&c0, &c1, &c5);
b.mul_assign(&Fq12 {
c0: Fq6 {
c0,
c1,
c0: c0,
c1: c1,
c2: Fq2::zero(),
},
c1: Fq6 {
@@ -185,7 +182,7 @@ fn test_fq12_mul_by_014() {
#[test]
fn fq12_field_tests() {
use ff::PrimeField;
use PrimeField;
::tests::field::random_field_tests::<Fq12>();
::tests::field::random_frobenius_tests::<Fq12, _>(super::fq::Fq::char(), 13);

View File

@@ -1,6 +1,6 @@
use super::fq::{Fq, FROBENIUS_COEFF_FQ2_C1, NEGATIVE_ONE};
use ff::{Field, SqrtField};
use rand_core::RngCore;
use super::fq::{FROBENIUS_COEFF_FQ2_C1, Fq, NEGATIVE_ONE};
use rand::{Rand, Rng};
use {Field, SqrtField};
use std::cmp::Ordering;
@@ -56,14 +56,16 @@ impl Fq2 {
}
}
impl Field for Fq2 {
fn random<R: RngCore>(rng: &mut R) -> Self {
impl Rand for Fq2 {
fn rand<R: Rng>(rng: &mut R) -> Self {
Fq2 {
c0: Fq::random(rng),
c1: Fq::random(rng),
c0: rng.gen(),
c1: rng.gen(),
}
}
}
impl Field for Fq2 {
fn zero() -> Self {
Fq2 {
c0: Fq::zero(),
@@ -158,7 +160,7 @@ impl Field for Fq2 {
}
impl SqrtField for Fq2 {
fn legendre(&self) -> ::ff::LegendreSymbol {
fn legendre(&self) -> ::LegendreSymbol {
self.norm().legendre()
}
@@ -264,14 +266,13 @@ fn test_fq2_basics() {
assert!(!Fq2 {
c0: Fq::zero(),
c1: Fq::one(),
}
.is_zero());
}.is_zero());
}
#[test]
fn test_fq2_squaring() {
use super::fq::FqRepr;
use ff::PrimeField;
use PrimeField;
let mut a = Fq2 {
c0: Fq::one(),
@@ -308,8 +309,7 @@ fn test_fq2_squaring() {
0xf7f295a94e58ae7c,
0x41b76dcc1c3fbe5e,
0x7080c5fa1d8e042,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x38f473b3c870a4ab,
0x6ad3291177c8c7e5,
@@ -317,8 +317,7 @@ fn test_fq2_squaring() {
0xbfb99020604137a0,
0xfc58a7b7be815407,
0x10d1615e75250a21,
]))
.unwrap(),
])).unwrap(),
};
a.square();
assert_eq!(
@@ -331,8 +330,7 @@ fn test_fq2_squaring() {
0xcb674157618da176,
0x4cf17b5893c3d327,
0x7eac81369c43361
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0xc1579cf58e980cf8,
0xa23eb7e12dd54d98,
@@ -340,8 +338,7 @@ fn test_fq2_squaring() {
0x38d0d7275a9689e1,
0x739c983042779a65,
0x1542a61c8a8db994
]))
.unwrap(),
])).unwrap(),
}
);
}
@@ -349,7 +346,7 @@ fn test_fq2_squaring() {
#[test]
fn test_fq2_mul() {
use super::fq::FqRepr;
use ff::PrimeField;
use PrimeField;
let mut a = Fq2 {
c0: Fq::from_repr(FqRepr([
@@ -359,8 +356,7 @@ fn test_fq2_mul() {
0x9ee53e7e84d7532e,
0x1c202d8ed97afb45,
0x51d3f9253e2516f,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0xa7348a8b511aedcf,
0x143c215d8176b319,
@@ -368,8 +364,7 @@ fn test_fq2_mul() {
0x9533e4a9a5158be,
0x7a5e1ecb676d65f9,
0x180c3ee46656b008,
]))
.unwrap(),
])).unwrap(),
};
a.mul_assign(&Fq2 {
c0: Fq::from_repr(FqRepr([
@@ -379,8 +374,7 @@ fn test_fq2_mul() {
0xcd460f9f0c23e430,
0x6c9110292bfa409,
0x2c93a72eb8af83e,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x4b1c3f936d8992d4,
0x1d2a72916dba4c8a,
@@ -388,8 +382,7 @@ fn test_fq2_mul() {
0x57a06d3135a752ae,
0x634cd3c6c565096d,
0x19e17334d4e93558,
]))
.unwrap(),
])).unwrap(),
});
assert_eq!(
a,
@@ -401,8 +394,7 @@ fn test_fq2_mul() {
0x5511fe4d84ee5f78,
0x5310a202d92f9963,
0x1751afbe166e5399
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x84af0e1bd630117a,
0x6c63cd4da2c2aa7,
@@ -410,8 +402,7 @@ fn test_fq2_mul() {
0xc975106579c275ee,
0x33a9ac82ce4c5083,
0x1ef1a36c201589d
]))
.unwrap(),
])).unwrap(),
}
);
}
@@ -419,7 +410,7 @@ fn test_fq2_mul() {
#[test]
fn test_fq2_inverse() {
use super::fq::FqRepr;
use ff::PrimeField;
use PrimeField;
assert!(Fq2::zero().inverse().is_none());
@@ -431,8 +422,7 @@ fn test_fq2_inverse() {
0x9ee53e7e84d7532e,
0x1c202d8ed97afb45,
0x51d3f9253e2516f,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0xa7348a8b511aedcf,
0x143c215d8176b319,
@@ -440,8 +430,7 @@ fn test_fq2_inverse() {
0x9533e4a9a5158be,
0x7a5e1ecb676d65f9,
0x180c3ee46656b008,
]))
.unwrap(),
])).unwrap(),
};
let a = a.inverse().unwrap();
assert_eq!(
@@ -454,8 +443,7 @@ fn test_fq2_inverse() {
0xdfba703293941c30,
0xa6c3d8f9586f2636,
0x1351ef01941b70c4
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x8c39fd76a8312cb4,
0x15d7b6b95defbff0,
@@ -463,8 +451,7 @@ fn test_fq2_inverse() {
0xcbf651a0f367afb2,
0xdf4e54f0d3ef15a6,
0x103bdf241afb0019
]))
.unwrap(),
])).unwrap(),
}
);
}
@@ -472,7 +459,7 @@ fn test_fq2_inverse() {
#[test]
fn test_fq2_addition() {
use super::fq::FqRepr;
use ff::PrimeField;
use PrimeField;
let mut a = Fq2 {
c0: Fq::from_repr(FqRepr([
@@ -482,8 +469,7 @@ fn test_fq2_addition() {
0xb966ce3bc2108b13,
0xccc649c4b9532bf3,
0xf8d295b2ded9dc,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x977df6efcdaee0db,
0x946ae52d684fa7ed,
@@ -491,8 +477,7 @@ fn test_fq2_addition() {
0xb3f8afc0ee248cad,
0x4e464dea5bcfd41e,
0x12d1137b8a6a837,
]))
.unwrap(),
])).unwrap(),
};
a.add_assign(&Fq2 {
c0: Fq::from_repr(FqRepr([
@@ -502,8 +487,7 @@ fn test_fq2_addition() {
0x3b88899a42a6318f,
0x986a4a62fa82a49d,
0x13ce433fa26027f5,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x66323bf80b58b9b9,
0xa1379b6facf6e596,
@@ -511,8 +495,7 @@ fn test_fq2_addition() {
0x2236f55246d0d44d,
0x4c8c1800eb104566,
0x11d6e20e986c2085,
]))
.unwrap(),
])).unwrap(),
});
assert_eq!(
a,
@@ -524,8 +507,7 @@ fn test_fq2_addition() {
0xf4ef57d604b6bca2,
0x65309427b3d5d090,
0x14c715d5553f01d2
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0xfdb032e7d9079a94,
0x35a2809d15468d83,
@@ -533,8 +515,7 @@ fn test_fq2_addition() {
0xd62fa51334f560fa,
0x9ad265eb46e01984,
0x1303f3465112c8bc
]))
.unwrap(),
])).unwrap(),
}
);
}
@@ -542,7 +523,7 @@ fn test_fq2_addition() {
#[test]
fn test_fq2_subtraction() {
use super::fq::FqRepr;
use ff::PrimeField;
use PrimeField;
let mut a = Fq2 {
c0: Fq::from_repr(FqRepr([
@@ -552,8 +533,7 @@ fn test_fq2_subtraction() {
0xb966ce3bc2108b13,
0xccc649c4b9532bf3,
0xf8d295b2ded9dc,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x977df6efcdaee0db,
0x946ae52d684fa7ed,
@@ -561,8 +541,7 @@ fn test_fq2_subtraction() {
0xb3f8afc0ee248cad,
0x4e464dea5bcfd41e,
0x12d1137b8a6a837,
]))
.unwrap(),
])).unwrap(),
};
a.sub_assign(&Fq2 {
c0: Fq::from_repr(FqRepr([
@@ -572,8 +551,7 @@ fn test_fq2_subtraction() {
0x3b88899a42a6318f,
0x986a4a62fa82a49d,
0x13ce433fa26027f5,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x66323bf80b58b9b9,
0xa1379b6facf6e596,
@@ -581,8 +559,7 @@ fn test_fq2_subtraction() {
0x2236f55246d0d44d,
0x4c8c1800eb104566,
0x11d6e20e986c2085,
]))
.unwrap(),
])).unwrap(),
});
assert_eq!(
a,
@@ -594,8 +571,7 @@ fn test_fq2_subtraction() {
0xe255902672ef6c43,
0x7f77a718021c342d,
0x72ba14049fe9881
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0xeb4abaf7c255d1cd,
0x11df49bc6cacc256,
@@ -603,8 +579,7 @@ fn test_fq2_subtraction() {
0xf63905f39ad8cb1f,
0x4cd5dd9fb40b3b8f,
0x957411359ba6e4c
]))
.unwrap(),
])).unwrap(),
}
);
}
@@ -612,7 +587,7 @@ fn test_fq2_subtraction() {
#[test]
fn test_fq2_negation() {
use super::fq::FqRepr;
use ff::PrimeField;
use PrimeField;
let mut a = Fq2 {
c0: Fq::from_repr(FqRepr([
@@ -622,8 +597,7 @@ fn test_fq2_negation() {
0xb966ce3bc2108b13,
0xccc649c4b9532bf3,
0xf8d295b2ded9dc,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x977df6efcdaee0db,
0x946ae52d684fa7ed,
@@ -631,8 +605,7 @@ fn test_fq2_negation() {
0xb3f8afc0ee248cad,
0x4e464dea5bcfd41e,
0x12d1137b8a6a837,
]))
.unwrap(),
])).unwrap(),
};
a.negate();
assert_eq!(
@@ -645,8 +618,7 @@ fn test_fq2_negation() {
0xab107d49317487ab,
0x7e555df189f880e3,
0x19083f5486a10cbd
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x228109103250c9d0,
0x8a411ad149045812,
@@ -654,8 +626,7 @@ fn test_fq2_negation() {
0xb07e9bc405608611,
0xfcd559cbe77bd8b8,
0x18d400b280d93e62
]))
.unwrap(),
])).unwrap(),
}
);
}
@@ -663,7 +634,7 @@ fn test_fq2_negation() {
#[test]
fn test_fq2_doubling() {
use super::fq::FqRepr;
use ff::PrimeField;
use PrimeField;
let mut a = Fq2 {
c0: Fq::from_repr(FqRepr([
@@ -673,8 +644,7 @@ fn test_fq2_doubling() {
0xb966ce3bc2108b13,
0xccc649c4b9532bf3,
0xf8d295b2ded9dc,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x977df6efcdaee0db,
0x946ae52d684fa7ed,
@@ -682,8 +652,7 @@ fn test_fq2_doubling() {
0xb3f8afc0ee248cad,
0x4e464dea5bcfd41e,
0x12d1137b8a6a837,
]))
.unwrap(),
])).unwrap(),
};
a.double();
assert_eq!(
@@ -696,8 +665,7 @@ fn test_fq2_doubling() {
0x72cd9c7784211627,
0x998c938972a657e7,
0x1f1a52b65bdb3b9
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x2efbeddf9b5dc1b6,
0x28d5ca5ad09f4fdb,
@@ -705,8 +673,7 @@ fn test_fq2_doubling() {
0x67f15f81dc49195b,
0x9c8c9bd4b79fa83d,
0x25a226f714d506e
]))
.unwrap(),
])).unwrap(),
}
);
}
@@ -714,7 +681,7 @@ fn test_fq2_doubling() {
#[test]
fn test_fq2_frobenius_map() {
use super::fq::FqRepr;
use ff::PrimeField;
use PrimeField;
let mut a = Fq2 {
c0: Fq::from_repr(FqRepr([
@@ -724,8 +691,7 @@ fn test_fq2_frobenius_map() {
0xb966ce3bc2108b13,
0xccc649c4b9532bf3,
0xf8d295b2ded9dc,
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x977df6efcdaee0db,
0x946ae52d684fa7ed,
@@ -733,8 +699,7 @@ fn test_fq2_frobenius_map() {
0xb3f8afc0ee248cad,
0x4e464dea5bcfd41e,
0x12d1137b8a6a837,
]))
.unwrap(),
])).unwrap(),
};
a.frobenius_map(0);
assert_eq!(
@@ -747,8 +712,7 @@ fn test_fq2_frobenius_map() {
0xb966ce3bc2108b13,
0xccc649c4b9532bf3,
0xf8d295b2ded9dc
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x977df6efcdaee0db,
0x946ae52d684fa7ed,
@@ -756,8 +720,7 @@ fn test_fq2_frobenius_map() {
0xb3f8afc0ee248cad,
0x4e464dea5bcfd41e,
0x12d1137b8a6a837
]))
.unwrap(),
])).unwrap(),
}
);
a.frobenius_map(1);
@@ -771,8 +734,7 @@ fn test_fq2_frobenius_map() {
0xb966ce3bc2108b13,
0xccc649c4b9532bf3,
0xf8d295b2ded9dc
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x228109103250c9d0,
0x8a411ad149045812,
@@ -780,8 +742,7 @@ fn test_fq2_frobenius_map() {
0xb07e9bc405608611,
0xfcd559cbe77bd8b8,
0x18d400b280d93e62
]))
.unwrap(),
])).unwrap(),
}
);
a.frobenius_map(1);
@@ -795,8 +756,7 @@ fn test_fq2_frobenius_map() {
0xb966ce3bc2108b13,
0xccc649c4b9532bf3,
0xf8d295b2ded9dc
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x977df6efcdaee0db,
0x946ae52d684fa7ed,
@@ -804,8 +764,7 @@ fn test_fq2_frobenius_map() {
0xb3f8afc0ee248cad,
0x4e464dea5bcfd41e,
0x12d1137b8a6a837
]))
.unwrap(),
])).unwrap(),
}
);
a.frobenius_map(2);
@@ -819,8 +778,7 @@ fn test_fq2_frobenius_map() {
0xb966ce3bc2108b13,
0xccc649c4b9532bf3,
0xf8d295b2ded9dc
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0x977df6efcdaee0db,
0x946ae52d684fa7ed,
@@ -828,8 +786,7 @@ fn test_fq2_frobenius_map() {
0xb3f8afc0ee248cad,
0x4e464dea5bcfd41e,
0x12d1137b8a6a837
]))
.unwrap(),
])).unwrap(),
}
);
}
@@ -837,7 +794,7 @@ fn test_fq2_frobenius_map() {
#[test]
fn test_fq2_sqrt() {
use super::fq::FqRepr;
use ff::PrimeField;
use PrimeField;
assert_eq!(
Fq2 {
@@ -848,8 +805,7 @@ fn test_fq2_sqrt() {
0xdb4a116b5bf74aa1,
0x1e58b2159dfe10e2,
0x7ca7da1f13606ac
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0xfa8de88b7516d2c3,
0x371a75ed14f41629,
@@ -857,11 +813,9 @@ fn test_fq2_sqrt() {
0x212611bca4e99121,
0x8ee5394d77afb3d,
0xec92336650e49d5
]))
])).unwrap(),
}.sqrt()
.unwrap(),
}
.sqrt()
.unwrap(),
Fq2 {
c0: Fq::from_repr(FqRepr([
0x40b299b2704258c5,
@@ -870,8 +824,7 @@ fn test_fq2_sqrt() {
0x8d7f1f723d02c1d3,
0x881b3e01b611c070,
0x10f6963bbad2ebc5
]))
.unwrap(),
])).unwrap(),
c1: Fq::from_repr(FqRepr([
0xc099534fc209e752,
0x7670594665676447,
@@ -879,8 +832,7 @@ fn test_fq2_sqrt() {
0x6b852aeaf2afcb1b,
0xa4c93b08105d71a9,
0x8d7cfff94216330
]))
.unwrap(),
])).unwrap(),
}
);
@@ -893,12 +845,10 @@ fn test_fq2_sqrt() {
0x64774b84f38512bf,
0x4b1ba7b6434bacd7,
0x1a0111ea397fe69a
]))
.unwrap(),
])).unwrap(),
c1: Fq::zero(),
}
.sqrt()
.unwrap(),
}.sqrt()
.unwrap(),
Fq2 {
c0: Fq::zero(),
c1: Fq::from_repr(FqRepr([
@@ -908,15 +858,14 @@ fn test_fq2_sqrt() {
0x64774b84f38512bf,
0x4b1ba7b6434bacd7,
0x1a0111ea397fe69a
]))
.unwrap(),
])).unwrap(),
}
);
}
#[test]
fn test_fq2_legendre() {
use ff::LegendreSymbol::*;
use LegendreSymbol::*;
assert_eq!(Zero, Fq2::zero().legendre());
// i^2 = -1
@@ -928,16 +877,11 @@ fn test_fq2_legendre() {
}
#[cfg(test)]
use rand_core::SeedableRng;
#[cfg(test)]
use rand_xorshift::XorShiftRng;
use rand::{SeedableRng, XorShiftRng};
#[test]
fn test_fq2_mul_nonresidue() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let nqr = Fq2 {
c0: Fq::one(),
@@ -945,7 +889,7 @@ fn test_fq2_mul_nonresidue() {
};
for _ in 0..1000 {
let mut a = Fq2::random(&mut rng);
let mut a = Fq2::rand(&mut rng);
let mut b = a;
a.mul_by_nonresidue();
b.mul_assign(&nqr);
@@ -956,7 +900,7 @@ fn test_fq2_mul_nonresidue() {
#[test]
fn fq2_field_tests() {
use ff::PrimeField;
use PrimeField;
::tests::field::random_field_tests::<Fq2>();
::tests::field::random_sqrt_tests::<Fq2>();

View File

@@ -1,7 +1,7 @@
use super::fq::{FROBENIUS_COEFF_FQ6_C1, FROBENIUS_COEFF_FQ6_C2};
use super::fq2::Fq2;
use ff::Field;
use rand_core::RngCore;
use rand::{Rand, Rng};
use Field;
/// An element of Fq6, represented by c0 + c1 * v + c2 * v^(2).
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -17,6 +17,16 @@ impl ::std::fmt::Display for Fq6 {
}
}
impl Rand for Fq6 {
fn rand<R: Rng>(rng: &mut R) -> Self {
Fq6 {
c0: rng.gen(),
c1: rng.gen(),
c2: rng.gen(),
}
}
}
impl Fq6 {
/// Multiply by quadratic nonresidue v.
pub fn mul_by_nonresidue(&mut self) {
@@ -100,14 +110,6 @@ impl Fq6 {
}
impl Field for Fq6 {
fn random<R: RngCore>(rng: &mut R) -> Self {
Fq6 {
c0: Fq2::random(rng),
c1: Fq2::random(rng),
c2: Fq2::random(rng),
}
}
fn zero() -> Self {
Fq6 {
c0: Fq2::zero(),
@@ -300,16 +302,11 @@ impl Field for Fq6 {
}
#[cfg(test)]
use rand_core::SeedableRng;
#[cfg(test)]
use rand_xorshift::XorShiftRng;
use rand::{SeedableRng, XorShiftRng};
#[test]
fn test_fq6_mul_nonresidue() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let nqr = Fq6 {
c0: Fq2::zero(),
@@ -318,7 +315,7 @@ fn test_fq6_mul_nonresidue() {
};
for _ in 0..1000 {
let mut a = Fq6::random(&mut rng);
let mut a = Fq6::rand(&mut rng);
let mut b = a;
a.mul_by_nonresidue();
b.mul_assign(&nqr);
@@ -329,20 +326,17 @@ fn test_fq6_mul_nonresidue() {
#[test]
fn test_fq6_mul_by_1() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let c1 = Fq2::random(&mut rng);
let mut a = Fq6::random(&mut rng);
let c1 = Fq2::rand(&mut rng);
let mut a = Fq6::rand(&mut rng);
let mut b = a;
a.mul_by_1(&c1);
b.mul_assign(&Fq6 {
c0: Fq2::zero(),
c1,
c1: c1,
c2: Fq2::zero(),
});
@@ -352,21 +346,18 @@ fn test_fq6_mul_by_1() {
#[test]
fn test_fq6_mul_by_01() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let c0 = Fq2::random(&mut rng);
let c1 = Fq2::random(&mut rng);
let mut a = Fq6::random(&mut rng);
let c0 = Fq2::rand(&mut rng);
let c1 = Fq2::rand(&mut rng);
let mut a = Fq6::rand(&mut rng);
let mut b = a;
a.mul_by_01(&c0, &c1);
b.mul_assign(&Fq6 {
c0,
c1,
c0: c0,
c1: c1,
c2: Fq2::zero(),
});
@@ -376,7 +367,7 @@ fn test_fq6_mul_by_01() {
#[test]
fn fq6_field_tests() {
use ff::PrimeField;
use PrimeField;
::tests::field::random_field_tests::<Fq6>();
::tests::field::random_frobenius_tests::<Fq6, _>(super::fq::Fq::char(), 13);

File diff suppressed because it is too large Load Diff

View File

@@ -9,8 +9,8 @@ mod fr;
mod tests;
pub use self::ec::{
G1Affine, G1Compressed, G1Prepared, G1Uncompressed, G2Affine, G2Compressed, G2Prepared,
G2Uncompressed, G1, G2,
G1, G1Affine, G1Compressed, G1Prepared, G1Uncompressed, G2, G2Affine, G2Compressed, G2Prepared,
G2Uncompressed,
};
pub use self::fq::{Fq, FqRepr};
pub use self::fq12::Fq12;
@@ -18,10 +18,7 @@ pub use self::fq2::Fq2;
pub use self::fq6::Fq6;
pub use self::fr::{Fr, FrRepr};
use super::{Engine, PairingCurveAffine};
use ff::{BitIterator, Field, ScalarEngine};
use group::CurveAffine;
use super::{BitIterator, CurveAffine, Engine, Field};
// The BLS parameter x for BLS12-381 is -0xd201000000010000
const BLS_X: u64 = 0xd201000000010000;
@@ -30,11 +27,8 @@ const BLS_X_IS_NEGATIVE: bool = true;
#[derive(Clone, Debug)]
pub struct Bls12;
impl ScalarEngine for Bls12 {
type Fr = Fr;
}
impl Engine for Bls12 {
type Fr = Fr;
type G1 = G1;
type G1Affine = G1Affine;
type G2 = G2;
@@ -47,8 +41,8 @@ impl Engine for Bls12 {
where
I: IntoIterator<
Item = &'a (
&'a <Self::G1Affine as PairingCurveAffine>::Prepared,
&'a <Self::G2Affine as PairingCurveAffine>::Prepared,
&'a <Self::G1Affine as CurveAffine>::Prepared,
&'a <Self::G2Affine as CurveAffine>::Prepared,
),
>,
{

View File

@@ -1,6 +1,3 @@
use ff::PrimeFieldRepr;
use group::{CurveAffine, CurveProjective, EncodedPoint, GroupDecodingError};
use super::*;
use *;

View File

@@ -1,53 +1,59 @@
// `clippy` is a code linting tool for improving code quality by catching
// common mistakes or strange code patterns. If the `cargo-clippy` feature
// is provided, all compiler warnings are prohibited.
#![cfg_attr(feature = "cargo-clippy", deny(warnings))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::inline_always))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::too_many_arguments))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::unreadable_literal))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::many_single_char_names))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::write_literal))]
// common mistakes or strange code patterns. If the `clippy` feature is
// provided, it is enabled and all compiler warnings are prohibited.
#![cfg_attr(feature = "clippy", deny(warnings))]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]
#![cfg_attr(feature = "clippy", allow(inline_always))]
#![cfg_attr(feature = "clippy", allow(too_many_arguments))]
#![cfg_attr(feature = "clippy", allow(unreadable_literal))]
#![cfg_attr(feature = "clippy", allow(many_single_char_names))]
#![cfg_attr(feature = "clippy", allow(new_without_default_derive))]
#![cfg_attr(feature = "clippy", allow(write_literal))]
// Force public structures to implement Debug
#![deny(missing_debug_implementations)]
extern crate byteorder;
extern crate ff;
extern crate group;
extern crate rand_core;
#[cfg(test)]
extern crate rand_xorshift;
extern crate rand;
#[cfg(test)]
pub mod tests;
pub mod bls12_381;
use ff::{Field, PrimeField, ScalarEngine, SqrtField};
use group::{CurveAffine, CurveProjective};
mod wnaf;
pub use self::wnaf::Wnaf;
use std::error::Error;
use std::fmt;
use std::io::{self, Read, Write};
/// An "engine" is a collection of types (fields, elliptic curve groups, etc.)
/// with well-defined relationships. In particular, the G1/G2 curve groups are
/// of prime order `r`, and are equipped with a bilinear pairing function.
pub trait Engine: ScalarEngine {
pub trait Engine: Sized + 'static + Clone {
/// This is the scalar field of the G1/G2 groups.
type Fr: PrimeField + SqrtField;
/// The projective representation of an element in G1.
type G1: CurveProjective<
Engine = Self,
Base = Self::Fq,
Scalar = Self::Fr,
Affine = Self::G1Affine,
> + From<Self::G1Affine>;
>
+ From<Self::G1Affine>;
/// The affine representation of an element in G1.
type G1Affine: PairingCurveAffine<
type G1Affine: CurveAffine<
Engine = Self,
Base = Self::Fq,
Scalar = Self::Fr,
Projective = Self::G1,
Pair = Self::G2Affine,
PairingResult = Self::Fqk,
> + From<Self::G1>;
>
+ From<Self::G1>;
/// The projective representation of an element in G2.
type G2: CurveProjective<
@@ -55,17 +61,19 @@ pub trait Engine: ScalarEngine {
Base = Self::Fqe,
Scalar = Self::Fr,
Affine = Self::G2Affine,
> + From<Self::G2Affine>;
>
+ From<Self::G2Affine>;
/// The affine representation of an element in G2.
type G2Affine: PairingCurveAffine<
type G2Affine: CurveAffine<
Engine = Self,
Base = Self::Fqe,
Scalar = Self::Fr,
Projective = Self::G2,
Pair = Self::G1Affine,
PairingResult = Self::Fqk,
> + From<Self::G2>;
>
+ From<Self::G2>;
/// The base field that hosts G1.
type Fq: PrimeField + SqrtField;
@@ -81,8 +89,8 @@ pub trait Engine: ScalarEngine {
where
I: IntoIterator<
Item = &'a (
&'a <Self::G1Affine as PairingCurveAffine>::Prepared,
&'a <Self::G2Affine as PairingCurveAffine>::Prepared,
&'a <Self::G1Affine as CurveAffine>::Prepared,
&'a <Self::G2Affine as CurveAffine>::Prepared,
),
>;
@@ -96,22 +104,655 @@ pub trait Engine: ScalarEngine {
G2: Into<Self::G2Affine>,
{
Self::final_exponentiation(&Self::miller_loop(
[(&(p.into().prepare()), &(q.into().prepare()))].iter(),
))
.unwrap()
[(&(p.into().prepare()), &(q.into().prepare()))].into_iter(),
)).unwrap()
}
}
/// Affine representation of an elliptic curve point that can be used
/// to perform pairings.
pub trait PairingCurveAffine: CurveAffine {
/// Projective representation of an elliptic curve point guaranteed to be
/// in the correct prime order subgroup.
pub trait CurveProjective:
PartialEq
+ Eq
+ Sized
+ Copy
+ Clone
+ Send
+ Sync
+ fmt::Debug
+ fmt::Display
+ rand::Rand
+ 'static
{
type Engine: Engine<Fr = Self::Scalar>;
type Scalar: PrimeField + SqrtField;
type Base: SqrtField;
type Affine: CurveAffine<Projective = Self, Scalar = Self::Scalar>;
/// Returns the additive identity.
fn zero() -> Self;
/// Returns a fixed generator of unknown exponent.
fn one() -> Self;
/// Determines if this point is the point at infinity.
fn is_zero(&self) -> bool;
/// Normalizes a slice of projective elements so that
/// conversion to affine is cheap.
fn batch_normalization(v: &mut [Self]);
/// Checks if the point is already "normalized" so that
/// cheap affine conversion is possible.
fn is_normalized(&self) -> bool;
/// Doubles this element.
fn double(&mut self);
/// Adds another element to this element.
fn add_assign(&mut self, other: &Self);
/// Subtracts another element from this element.
fn sub_assign(&mut self, other: &Self) {
let mut tmp = *other;
tmp.negate();
self.add_assign(&tmp);
}
/// Adds an affine element to this element.
fn add_assign_mixed(&mut self, other: &Self::Affine);
/// Negates this element.
fn negate(&mut self);
/// Performs scalar multiplication of this element.
fn mul_assign<S: Into<<Self::Scalar as PrimeField>::Repr>>(&mut self, other: S);
/// Converts this element into its affine representation.
fn into_affine(&self) -> Self::Affine;
/// Recommends a wNAF window table size given a scalar. Always returns a number
/// between 2 and 22, inclusive.
fn recommended_wnaf_for_scalar(scalar: <Self::Scalar as PrimeField>::Repr) -> usize;
/// Recommends a wNAF window size given the number of scalars you intend to multiply
/// a base by. Always returns a number between 2 and 22, inclusive.
fn recommended_wnaf_for_num_scalars(num_scalars: usize) -> usize;
}
/// Affine representation of an elliptic curve point guaranteed to be
/// in the correct prime order subgroup.
pub trait CurveAffine:
Copy + Clone + Sized + Send + Sync + fmt::Debug + fmt::Display + PartialEq + Eq + 'static
{
type Engine: Engine<Fr = Self::Scalar>;
type Scalar: PrimeField + SqrtField;
type Base: SqrtField;
type Projective: CurveProjective<Affine = Self, Scalar = Self::Scalar>;
type Prepared: Clone + Send + Sync + 'static;
type Pair: PairingCurveAffine<Pair = Self>;
type Uncompressed: EncodedPoint<Affine = Self>;
type Compressed: EncodedPoint<Affine = Self>;
type Pair: CurveAffine<Pair = Self>;
type PairingResult: Field;
/// Returns the additive identity.
fn zero() -> Self;
/// Returns a fixed generator of unknown exponent.
fn one() -> Self;
/// Determines if this point represents the point at infinity; the
/// additive identity.
fn is_zero(&self) -> bool;
/// Negates this element.
fn negate(&mut self);
/// Performs scalar multiplication of this element with mixed addition.
fn mul<S: Into<<Self::Scalar as PrimeField>::Repr>>(&self, other: S) -> Self::Projective;
/// Prepares this element for pairing purposes.
fn prepare(&self) -> Self::Prepared;
/// Perform a pairing
fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult;
/// Converts this element into its affine representation.
fn into_projective(&self) -> Self::Projective;
/// Converts this element into its compressed encoding, so long as it's not
/// the point at infinity.
fn into_compressed(&self) -> Self::Compressed {
<Self::Compressed as EncodedPoint>::from_affine(*self)
}
/// Converts this element into its uncompressed encoding, so long as it's not
/// the point at infinity.
fn into_uncompressed(&self) -> Self::Uncompressed {
<Self::Uncompressed as EncodedPoint>::from_affine(*self)
}
}
/// An encoded elliptic curve point, which should essentially wrap a `[u8; N]`.
pub trait EncodedPoint:
Sized + Send + Sync + AsRef<[u8]> + AsMut<[u8]> + Clone + Copy + 'static
{
type Affine: CurveAffine;
/// Creates an empty representation.
fn empty() -> Self;
/// Returns the number of bytes consumed by this representation.
fn size() -> usize;
/// Converts an `EncodedPoint` into a `CurveAffine` element,
/// if the encoding represents a valid element.
fn into_affine(&self) -> Result<Self::Affine, GroupDecodingError>;
/// Converts an `EncodedPoint` into a `CurveAffine` element,
/// without guaranteeing that the encoding represents a valid
/// element. This is useful when the caller knows the encoding is
/// valid already.
///
/// If the encoding is invalid, this can break API invariants,
/// so caution is strongly encouraged.
fn into_affine_unchecked(&self) -> Result<Self::Affine, GroupDecodingError>;
/// Creates an `EncodedPoint` from an affine point, as long as the
/// point is not the point at infinity.
fn from_affine(affine: Self::Affine) -> Self;
}
/// This trait represents an element of a field.
pub trait Field:
Sized + Eq + Copy + Clone + Send + Sync + fmt::Debug + fmt::Display + 'static + rand::Rand
{
/// Returns the zero element of the field, the additive identity.
fn zero() -> Self;
/// Returns the one element of the field, the multiplicative identity.
fn one() -> Self;
/// Returns true iff this element is zero.
fn is_zero(&self) -> bool;
/// Squares this element.
fn square(&mut self);
/// Doubles this element.
fn double(&mut self);
/// Negates this element.
fn negate(&mut self);
/// Adds another element to this element.
fn add_assign(&mut self, other: &Self);
/// Subtracts another element from this element.
fn sub_assign(&mut self, other: &Self);
/// Multiplies another element by this element.
fn mul_assign(&mut self, other: &Self);
/// Computes the multiplicative inverse of this element, if nonzero.
fn inverse(&self) -> Option<Self>;
/// Exponentiates this element by a power of the base prime modulus via
/// the Frobenius automorphism.
fn frobenius_map(&mut self, power: usize);
/// Exponentiates this element by a number represented with `u64` limbs,
/// least significant digit first.
fn pow<S: AsRef<[u64]>>(&self, exp: S) -> Self {
let mut res = Self::one();
let mut found_one = false;
for i in BitIterator::new(exp) {
if found_one {
res.square();
} else {
found_one = i;
}
if i {
res.mul_assign(self);
}
}
res
}
}
/// This trait represents an element of a field that has a square root operation described for it.
pub trait SqrtField: Field {
/// Returns the Legendre symbol of the field element.
fn legendre(&self) -> LegendreSymbol;
/// Returns the square root of the field element, if it is
/// quadratic residue.
fn sqrt(&self) -> Option<Self>;
}
/// This trait represents a wrapper around a biginteger which can encode any element of a particular
/// prime field. It is a smart wrapper around a sequence of `u64` limbs, least-significant digit
/// first.
pub trait PrimeFieldRepr:
Sized
+ Copy
+ Clone
+ Eq
+ Ord
+ Send
+ Sync
+ Default
+ fmt::Debug
+ fmt::Display
+ 'static
+ rand::Rand
+ AsRef<[u64]>
+ AsMut<[u64]>
+ From<u64>
{
/// Subtract another represetation from this one.
fn sub_noborrow(&mut self, other: &Self);
/// Add another representation to this one.
fn add_nocarry(&mut self, other: &Self);
/// Compute the number of bits needed to encode this number. Always a
/// multiple of 64.
fn num_bits(&self) -> u32;
/// Returns true iff this number is zero.
fn is_zero(&self) -> bool;
/// Returns true iff this number is odd.
fn is_odd(&self) -> bool;
/// Returns true iff this number is even.
fn is_even(&self) -> bool;
/// Performs a rightwise bitshift of this number, effectively dividing
/// it by 2.
fn div2(&mut self);
/// Performs a rightwise bitshift of this number by some amount.
fn shr(&mut self, amt: u32);
/// Performs a leftwise bitshift of this number, effectively multiplying
/// it by 2. Overflow is ignored.
fn mul2(&mut self);
/// Performs a leftwise bitshift of this number by some amount.
fn shl(&mut self, amt: u32);
/// Writes this `PrimeFieldRepr` as a big endian integer.
fn write_be<W: Write>(&self, mut writer: W) -> io::Result<()> {
use byteorder::{BigEndian, WriteBytesExt};
for digit in self.as_ref().iter().rev() {
writer.write_u64::<BigEndian>(*digit)?;
}
Ok(())
}
/// Reads a big endian integer into this representation.
fn read_be<R: Read>(&mut self, mut reader: R) -> io::Result<()> {
use byteorder::{BigEndian, ReadBytesExt};
for digit in self.as_mut().iter_mut().rev() {
*digit = reader.read_u64::<BigEndian>()?;
}
Ok(())
}
/// Writes this `PrimeFieldRepr` as a little endian integer.
fn write_le<W: Write>(&self, mut writer: W) -> io::Result<()> {
use byteorder::{LittleEndian, WriteBytesExt};
for digit in self.as_ref().iter() {
writer.write_u64::<LittleEndian>(*digit)?;
}
Ok(())
}
/// Reads a little endian integer into this representation.
fn read_le<R: Read>(&mut self, mut reader: R) -> io::Result<()> {
use byteorder::{LittleEndian, ReadBytesExt};
for digit in self.as_mut().iter_mut() {
*digit = reader.read_u64::<LittleEndian>()?;
}
Ok(())
}
}
#[derive(Debug, PartialEq)]
pub enum LegendreSymbol {
Zero = 0,
QuadraticResidue = 1,
QuadraticNonResidue = -1,
}
/// An error that may occur when trying to interpret a `PrimeFieldRepr` as a
/// `PrimeField` element.
#[derive(Debug)]
pub enum PrimeFieldDecodingError {
/// The encoded value is not in the field
NotInField(String),
}
impl Error for PrimeFieldDecodingError {
fn description(&self) -> &str {
match *self {
PrimeFieldDecodingError::NotInField(..) => "not an element of the field",
}
}
}
impl fmt::Display for PrimeFieldDecodingError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
PrimeFieldDecodingError::NotInField(ref repr) => {
write!(f, "{} is not an element of the field", repr)
}
}
}
}
/// An error that may occur when trying to decode an `EncodedPoint`.
#[derive(Debug)]
pub enum GroupDecodingError {
/// The coordinate(s) do not lie on the curve.
NotOnCurve,
/// The element is not part of the r-order subgroup.
NotInSubgroup,
/// One of the coordinates could not be decoded
CoordinateDecodingError(&'static str, PrimeFieldDecodingError),
/// The compression mode of the encoded element was not as expected
UnexpectedCompressionMode,
/// The encoding contained bits that should not have been set
UnexpectedInformation,
}
impl Error for GroupDecodingError {
fn description(&self) -> &str {
match *self {
GroupDecodingError::NotOnCurve => "coordinate(s) do not lie on the curve",
GroupDecodingError::NotInSubgroup => "the element is not part of an r-order subgroup",
GroupDecodingError::CoordinateDecodingError(..) => "coordinate(s) could not be decoded",
GroupDecodingError::UnexpectedCompressionMode => {
"encoding has unexpected compression mode"
}
GroupDecodingError::UnexpectedInformation => "encoding has unexpected information",
}
}
}
impl fmt::Display for GroupDecodingError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
GroupDecodingError::CoordinateDecodingError(description, ref err) => {
write!(f, "{} decoding error: {}", description, err)
}
_ => write!(f, "{}", self.description()),
}
}
}
/// This represents an element of a prime field.
pub trait PrimeField: Field {
/// The prime field can be converted back and forth into this biginteger
/// representation.
type Repr: PrimeFieldRepr + From<Self>;
/// Interpret a string of numbers as a (congruent) prime field element.
/// Does not accept unnecessary leading zeroes or a blank string.
fn from_str(s: &str) -> Option<Self> {
if s.is_empty() {
return None;
}
if s == "0" {
return Some(Self::zero());
}
let mut res = Self::zero();
let ten = Self::from_repr(Self::Repr::from(10)).unwrap();
let mut first_digit = true;
for c in s.chars() {
match c.to_digit(10) {
Some(c) => {
if first_digit {
if c == 0 {
return None;
}
first_digit = false;
}
res.mul_assign(&ten);
res.add_assign(&Self::from_repr(Self::Repr::from(u64::from(c))).unwrap());
}
None => {
return None;
}
}
}
Some(res)
}
/// Convert this prime field element into a biginteger representation.
fn from_repr(Self::Repr) -> Result<Self, PrimeFieldDecodingError>;
/// Convert a biginteger representation into a prime field element, if
/// the number is an element of the field.
fn into_repr(&self) -> Self::Repr;
/// Returns the field characteristic; the modulus.
fn char() -> Self::Repr;
/// How many bits are needed to represent an element of this field.
const NUM_BITS: u32;
/// How many bits of information can be reliably stored in the field element.
const CAPACITY: u32;
/// Returns the multiplicative generator of `char()` - 1 order. This element
/// must also be quadratic nonresidue.
fn multiplicative_generator() -> Self;
/// 2^s * t = `char()` - 1 with t odd.
const S: u32;
/// Returns the 2^s root of unity computed by exponentiating the `multiplicative_generator()`
/// by t.
fn root_of_unity() -> Self;
}
#[derive(Debug)]
pub struct BitIterator<E> {
t: E,
n: usize,
}
impl<E: AsRef<[u64]>> BitIterator<E> {
pub fn new(t: E) -> Self {
let n = t.as_ref().len() * 64;
BitIterator { t, n }
}
}
impl<E: AsRef<[u64]>> Iterator for BitIterator<E> {
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)
}
}
}
#[test]
fn test_bit_iterator() {
let mut a = BitIterator::new([0xa953d79b83f6ab59, 0x6dea2059e200bd39]);
let expected = "01101101111010100010000001011001111000100000000010111101001110011010100101010011110101111001101110000011111101101010101101011001";
for e in expected.chars() {
assert!(a.next().unwrap() == (e == '1'));
}
assert!(a.next().is_none());
let expected = "1010010101111110101010000101101011101000011101110101001000011001100100100011011010001011011011010001011011101100110100111011010010110001000011110100110001100110011101101000101100011100100100100100001010011101010111110011101011000011101000111011011101011001";
let mut a = BitIterator::new([
0x429d5f3ac3a3b759,
0xb10f4c66768b1c92,
0x92368b6d16ecd3b4,
0xa57ea85ae8775219,
]);
for e in expected.chars() {
assert!(a.next().unwrap() == (e == '1'));
}
assert!(a.next().is_none());
}
#[cfg(not(feature = "expose-arith"))]
use self::arith_impl::*;
#[cfg(feature = "expose-arith")]
pub use self::arith_impl::*;
#[cfg(feature = "u128-support")]
mod arith_impl {
/// Calculate a - b - borrow, returning the result and modifying
/// the borrow value.
#[inline(always)]
pub fn sbb(a: u64, b: u64, borrow: &mut u64) -> u64 {
let tmp = (1u128 << 64) + u128::from(a) - u128::from(b) - u128::from(*borrow);
*borrow = if tmp >> 64 == 0 { 1 } else { 0 };
tmp as u64
}
/// Calculate a + b + carry, returning the sum and modifying the
/// carry value.
#[inline(always)]
pub fn adc(a: u64, b: u64, carry: &mut u64) -> u64 {
let tmp = u128::from(a) + u128::from(b) + u128::from(*carry);
*carry = (tmp >> 64) as u64;
tmp as u64
}
/// Calculate a + (b * c) + carry, returning the least significant digit
/// and setting carry to the most significant digit.
#[inline(always)]
pub fn mac_with_carry(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 {
let tmp = (u128::from(a)) + u128::from(b) * u128::from(c) + u128::from(*carry);
*carry = (tmp >> 64) as u64;
tmp as u64
}
}
#[cfg(not(feature = "u128-support"))]
mod arith_impl {
#[inline(always)]
fn split_u64(i: u64) -> (u64, u64) {
(i >> 32, i & 0xFFFFFFFF)
}
#[inline(always)]
fn combine_u64(hi: u64, lo: u64) -> u64 {
(hi << 32) | lo
}
/// Calculate a - b - borrow, returning the result and modifying
/// the borrow value.
#[inline(always)]
pub fn sbb(a: u64, b: u64, borrow: &mut u64) -> u64 {
let (a_hi, a_lo) = split_u64(a);
let (b_hi, b_lo) = split_u64(b);
let (b, r0) = split_u64((1 << 32) + a_lo - b_lo - *borrow);
let (b, r1) = split_u64((1 << 32) + a_hi - b_hi - ((b == 0) as u64));
*borrow = (b == 0) as u64;
combine_u64(r1, r0)
}
/// Calculate a + b + carry, returning the sum and modifying the
/// carry value.
#[inline(always)]
pub fn adc(a: u64, b: u64, carry: &mut u64) -> u64 {
let (a_hi, a_lo) = split_u64(a);
let (b_hi, b_lo) = split_u64(b);
let (carry_hi, carry_lo) = split_u64(*carry);
let (t, r0) = split_u64(a_lo + b_lo + carry_lo);
let (t, r1) = split_u64(t + a_hi + b_hi + carry_hi);
*carry = t;
combine_u64(r1, r0)
}
/// Calculate a + (b * c) + carry, returning the least significant digit
/// and setting carry to the most significant digit.
#[inline(always)]
pub fn mac_with_carry(a: u64, b: u64, c: u64, carry: &mut u64) -> u64 {
/*
[ b_hi | b_lo ]
[ c_hi | c_lo ] *
-------------------------------------------
[ b_lo * c_lo ] <-- w
[ b_hi * c_lo ] <-- x
[ b_lo * c_hi ] <-- y
[ b_hi * c_lo ] <-- z
[ a_hi | a_lo ]
[ C_hi | C_lo ]
*/
let (a_hi, a_lo) = split_u64(a);
let (b_hi, b_lo) = split_u64(b);
let (c_hi, c_lo) = split_u64(c);
let (carry_hi, carry_lo) = split_u64(*carry);
let (w_hi, w_lo) = split_u64(b_lo * c_lo);
let (x_hi, x_lo) = split_u64(b_hi * c_lo);
let (y_hi, y_lo) = split_u64(b_lo * c_hi);
let (z_hi, z_lo) = split_u64(b_hi * c_hi);
let (t, r0) = split_u64(w_lo + a_lo + carry_lo);
let (t, r1) = split_u64(t + w_hi + x_lo + y_lo + a_hi + carry_hi);
let (t, r2) = split_u64(t + x_hi + y_hi + z_lo);
let (_, r3) = split_u64(t + z_hi);
*carry = combine_u64(r3, r2);
combine_u64(r1, r0)
}
}

View File

@@ -1,14 +1,9 @@
use ff::{Field, PrimeField};
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;
use rand::{Rand, Rng, SeedableRng, XorShiftRng};
use {CurveAffine, CurveProjective, EncodedPoint};
use {CurveAffine, CurveProjective, EncodedPoint, Field};
pub fn curve_tests<G: CurveProjective>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
// Negation edge case with zero.
{
@@ -26,7 +21,7 @@ pub fn curve_tests<G: CurveProjective>() {
// Addition edge cases with zero
{
let mut r = G::random(&mut rng);
let mut r = G::rand(&mut rng);
let rcopy = r;
r.add_assign(&G::zero());
assert_eq!(r, rcopy);
@@ -50,7 +45,7 @@ pub fn curve_tests<G: CurveProjective>() {
// Transformations
{
let a = G::random(&mut rng);
let a = G::rand(&mut rng);
let b = a.into_affine().into_projective();
let c = a
.into_affine()
@@ -72,11 +67,9 @@ pub fn curve_tests<G: CurveProjective>() {
fn random_wnaf_tests<G: CurveProjective>() {
use wnaf::*;
use PrimeField;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
{
let mut table = vec![];
@@ -84,8 +77,8 @@ fn random_wnaf_tests<G: CurveProjective>() {
for w in 2..14 {
for _ in 0..100 {
let g = G::random(&mut rng);
let s = G::Scalar::random(&mut rng).into_repr();
let g = G::rand(&mut rng);
let s = G::Scalar::rand(&mut rng).into_repr();
let mut g1 = g;
g1.mul_assign(s);
@@ -102,8 +95,8 @@ fn random_wnaf_tests<G: CurveProjective>() {
fn only_compiles_if_send<S: Send>(_: &S) {}
for _ in 0..100 {
let g = G::random(&mut rng);
let s = G::Scalar::random(&mut rng).into_repr();
let g = G::rand(&mut rng);
let s = G::Scalar::rand(&mut rng).into_repr();
let mut g1 = g;
g1.mul_assign(s);
@@ -136,8 +129,7 @@ fn random_wnaf_tests<G: CurveProjective>() {
let mut wnaf = Wnaf::new();
{
// Populate the vectors.
wnaf.base(G::random(&mut rng), 1)
.scalar(G::Scalar::random(&mut rng).into_repr());
wnaf.base(rng.gen(), 1).scalar(rng.gen());
}
wnaf.base(g, 1).scalar(s)
};
@@ -145,8 +137,7 @@ fn random_wnaf_tests<G: CurveProjective>() {
let mut wnaf = Wnaf::new();
{
// Populate the vectors.
wnaf.base(G::random(&mut rng), 1)
.scalar(G::Scalar::random(&mut rng).into_repr());
wnaf.base(rng.gen(), 1).scalar(rng.gen());
}
wnaf.scalar(s).base(g)
};
@@ -154,8 +145,7 @@ fn random_wnaf_tests<G: CurveProjective>() {
let mut wnaf = Wnaf::new();
{
// Populate the vectors.
wnaf.base(G::random(&mut rng), 1)
.scalar(G::Scalar::random(&mut rng).into_repr());
wnaf.base(rng.gen(), 1).scalar(rng.gen());
}
let mut shared = wnaf.base(g, 1).shared();
@@ -167,8 +157,7 @@ fn random_wnaf_tests<G: CurveProjective>() {
let mut wnaf = Wnaf::new();
{
// Populate the vectors.
wnaf.base(G::random(&mut rng), 1)
.scalar(G::Scalar::random(&mut rng).into_repr());
wnaf.base(rng.gen(), 1).scalar(rng.gen());
}
let mut shared = wnaf.scalar(s).shared();
@@ -190,15 +179,12 @@ fn random_wnaf_tests<G: CurveProjective>() {
}
fn random_negation_tests<G: CurveProjective>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let r = G::random(&mut rng);
let r = G::rand(&mut rng);
let s = G::Scalar::random(&mut rng);
let s = G::Scalar::rand(&mut rng);
let mut sneg = s;
sneg.negate();
@@ -222,14 +208,11 @@ fn random_negation_tests<G: CurveProjective>() {
}
fn random_doubling_tests<G: CurveProjective>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let mut a = G::random(&mut rng);
let mut b = G::random(&mut rng);
let mut a = G::rand(&mut rng);
let mut b = G::rand(&mut rng);
// 2(a + b)
let mut tmp1 = a;
@@ -252,18 +235,15 @@ fn random_doubling_tests<G: CurveProjective>() {
}
fn random_multiplication_tests<G: CurveProjective>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let mut a = G::random(&mut rng);
let mut b = G::random(&mut rng);
let mut a = G::rand(&mut rng);
let mut b = G::rand(&mut rng);
let a_affine = a.into_affine();
let b_affine = b.into_affine();
let s = G::Scalar::random(&mut rng);
let s = G::Scalar::rand(&mut rng);
// s ( a + b )
let mut tmp1 = a;
@@ -287,15 +267,12 @@ fn random_multiplication_tests<G: CurveProjective>() {
}
fn random_addition_tests<G: CurveProjective>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let a = G::random(&mut rng);
let b = G::random(&mut rng);
let c = G::random(&mut rng);
let a = G::rand(&mut rng);
let b = G::rand(&mut rng);
let c = G::rand(&mut rng);
let a_affine = a.into_affine();
let b_affine = b.into_affine();
let c_affine = c.into_affine();
@@ -368,13 +345,10 @@ fn random_addition_tests<G: CurveProjective>() {
}
fn random_transformation_tests<G: CurveProjective>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let g = G::random(&mut rng);
let g = G::rand(&mut rng);
let g_affine = g.into_affine();
let g_projective = g_affine.into_projective();
assert_eq!(g, g_projective);
@@ -382,20 +356,20 @@ fn random_transformation_tests<G: CurveProjective>() {
// Batch normalization
for _ in 0..10 {
let mut v = (0..1000).map(|_| G::random(&mut rng)).collect::<Vec<_>>();
let mut v = (0..1000).map(|_| G::rand(&mut rng)).collect::<Vec<_>>();
for i in &v {
assert!(!i.is_normalized());
}
use rand::distributions::{Distribution, Uniform};
let between = Uniform::new(0, 1000);
use rand::distributions::{IndependentSample, Range};
let between = Range::new(0, 1000);
// Sprinkle in some normalized points
for _ in 0..5 {
v[between.sample(&mut rng)] = G::zero();
v[between.ind_sample(&mut rng)] = G::zero();
}
for _ in 0..5 {
let s = between.sample(&mut rng);
let s = between.ind_sample(&mut rng);
v[s] = v[s].into_affine().into_projective();
}
@@ -414,10 +388,7 @@ fn random_transformation_tests<G: CurveProjective>() {
}
fn random_encoding_tests<G: CurveAffine>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
assert_eq!(
G::zero().into_uncompressed().into_affine().unwrap(),
@@ -430,7 +401,7 @@ fn random_encoding_tests<G: CurveAffine>() {
);
for _ in 0..1000 {
let mut r = G::Projective::random(&mut rng).into_affine();
let mut r = G::Projective::rand(&mut rng).into_affine();
let uncompressed = r.into_uncompressed();
let de_uncompressed = uncompressed.into_affine().unwrap();

View File

@@ -1,18 +1,13 @@
use group::{CurveAffine, CurveProjective};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use rand::{Rand, SeedableRng, XorShiftRng};
use {Engine, Field, PairingCurveAffine, PrimeField};
use {CurveAffine, CurveProjective, Engine, Field, PrimeField};
pub fn engine_tests<E: Engine>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..10 {
let a = E::G1::random(&mut rng).into_affine();
let b = E::G2::random(&mut rng).into_affine();
let a = E::G1::rand(&mut rng).into_affine();
let b = E::G2::rand(&mut rng).into_affine();
assert!(a.pairing_with(&b) == b.pairing_with(&a));
assert!(a.pairing_with(&b) == E::pairing(a, b));
@@ -22,10 +17,10 @@ pub fn engine_tests<E: Engine>() {
let z1 = E::G1Affine::zero().prepare();
let z2 = E::G2Affine::zero().prepare();
let a = E::G1::random(&mut rng).into_affine().prepare();
let b = E::G2::random(&mut rng).into_affine().prepare();
let c = E::G1::random(&mut rng).into_affine().prepare();
let d = E::G2::random(&mut rng).into_affine().prepare();
let a = E::G1::rand(&mut rng).into_affine().prepare();
let b = E::G2::rand(&mut rng).into_affine().prepare();
let c = E::G1::rand(&mut rng).into_affine().prepare();
let d = E::G2::rand(&mut rng).into_affine().prepare();
assert_eq!(
E::Fqk::one(),
@@ -53,15 +48,12 @@ pub fn engine_tests<E: Engine>() {
}
fn random_miller_loop_tests<E: Engine>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
// Exercise the miller loop for a reduced pairing
for _ in 0..1000 {
let a = E::G1::random(&mut rng);
let b = E::G2::random(&mut rng);
let a = E::G1::rand(&mut rng);
let b = E::G2::rand(&mut rng);
let p2 = E::pairing(a, b);
@@ -75,10 +67,10 @@ fn random_miller_loop_tests<E: Engine>() {
// Exercise a double miller loop
for _ in 0..1000 {
let a = E::G1::random(&mut rng);
let b = E::G2::random(&mut rng);
let c = E::G1::random(&mut rng);
let d = E::G2::random(&mut rng);
let a = E::G1::rand(&mut rng);
let b = E::G2::rand(&mut rng);
let c = E::G1::rand(&mut rng);
let d = E::G2::rand(&mut rng);
let ab = E::pairing(a, b);
let cd = E::pairing(c, d);
@@ -99,17 +91,14 @@ fn random_miller_loop_tests<E: Engine>() {
}
fn random_bilinearity_tests<E: Engine>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let a = E::G1::random(&mut rng);
let b = E::G2::random(&mut rng);
let a = E::G1::rand(&mut rng);
let b = E::G2::rand(&mut rng);
let c = E::Fr::random(&mut rng);
let d = E::Fr::random(&mut rng);
let c = E::Fr::rand(&mut rng);
let d = E::Fr::rand(&mut rng);
let mut ac = a;
ac.mul_assign(c);

View File

@@ -1,16 +1,12 @@
use ff::{Field, LegendreSymbol, PrimeField, SqrtField};
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
use rand::{Rng, SeedableRng, XorShiftRng};
use {Field, LegendreSymbol, PrimeField, SqrtField};
pub fn random_frobenius_tests<F: Field, C: AsRef<[u64]>>(characteristic: C, maxpower: usize) {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..100 {
for i in 0..(maxpower + 1) {
let mut a = F::random(&mut rng);
let mut a = F::rand(&mut rng);
let mut b = a;
for _ in 0..i {
@@ -24,13 +20,10 @@ pub fn random_frobenius_tests<F: Field, C: AsRef<[u64]>>(characteristic: C, maxp
}
pub fn random_sqrt_tests<F: SqrtField>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..10000 {
let a = F::random(&mut rng);
let a = F::rand(&mut rng);
let mut b = a;
b.square();
assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue);
@@ -61,10 +54,7 @@ pub fn random_sqrt_tests<F: SqrtField>() {
}
pub fn random_field_tests<F: Field>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
random_multiplication_tests::<F, _>(&mut rng);
random_addition_tests::<F, _>(&mut rng);
@@ -86,14 +76,14 @@ pub fn random_field_tests<F: Field>() {
// Multiplication by zero
{
let mut a = F::random(&mut rng);
let mut a = F::rand(&mut rng);
a.mul_assign(&F::zero());
assert!(a.is_zero());
}
// Addition by zero
{
let mut a = F::random(&mut rng);
let mut a = F::rand(&mut rng);
let copy = a;
a.add_assign(&F::zero());
assert_eq!(a, copy);
@@ -116,13 +106,10 @@ pub fn from_str_tests<F: PrimeField>() {
}
{
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let n = rng.next_u64();
let n: u64 = rng.gen();
let a = F::from_str(&format!("{}", n)).unwrap();
let b = F::from_repr(n.into()).unwrap();
@@ -137,11 +124,11 @@ pub fn from_str_tests<F: PrimeField>() {
assert!(F::from_str("00000000000").is_none());
}
fn random_multiplication_tests<F: Field, R: RngCore>(rng: &mut R) {
fn random_multiplication_tests<F: Field, R: Rng>(rng: &mut R) {
for _ in 0..10000 {
let a = F::random(rng);
let b = F::random(rng);
let c = F::random(rng);
let a = F::rand(rng);
let b = F::rand(rng);
let c = F::rand(rng);
let mut t0 = a; // (a * b) * c
t0.mul_assign(&b);
@@ -160,11 +147,11 @@ fn random_multiplication_tests<F: Field, R: RngCore>(rng: &mut R) {
}
}
fn random_addition_tests<F: Field, R: RngCore>(rng: &mut R) {
fn random_addition_tests<F: Field, R: Rng>(rng: &mut R) {
for _ in 0..10000 {
let a = F::random(rng);
let b = F::random(rng);
let c = F::random(rng);
let a = F::rand(rng);
let b = F::rand(rng);
let c = F::rand(rng);
let mut t0 = a; // (a + b) + c
t0.add_assign(&b);
@@ -183,10 +170,10 @@ fn random_addition_tests<F: Field, R: RngCore>(rng: &mut R) {
}
}
fn random_subtraction_tests<F: Field, R: RngCore>(rng: &mut R) {
fn random_subtraction_tests<F: Field, R: Rng>(rng: &mut R) {
for _ in 0..10000 {
let b = F::random(rng);
let a = F::random(rng);
let a = F::rand(rng);
let b = F::rand(rng);
let mut t0 = a; // (a - b)
t0.sub_assign(&b);
@@ -201,9 +188,9 @@ fn random_subtraction_tests<F: Field, R: RngCore>(rng: &mut R) {
}
}
fn random_negation_tests<F: Field, R: RngCore>(rng: &mut R) {
fn random_negation_tests<F: Field, R: Rng>(rng: &mut R) {
for _ in 0..10000 {
let a = F::random(rng);
let a = F::rand(rng);
let mut b = a;
b.negate();
b.add_assign(&a);
@@ -212,9 +199,9 @@ fn random_negation_tests<F: Field, R: RngCore>(rng: &mut R) {
}
}
fn random_doubling_tests<F: Field, R: RngCore>(rng: &mut R) {
fn random_doubling_tests<F: Field, R: Rng>(rng: &mut R) {
for _ in 0..10000 {
let mut a = F::random(rng);
let mut a = F::rand(rng);
let mut b = a;
a.add_assign(&b);
b.double();
@@ -223,9 +210,9 @@ fn random_doubling_tests<F: Field, R: RngCore>(rng: &mut R) {
}
}
fn random_squaring_tests<F: Field, R: RngCore>(rng: &mut R) {
fn random_squaring_tests<F: Field, R: Rng>(rng: &mut R) {
for _ in 0..10000 {
let mut a = F::random(rng);
let mut a = F::rand(rng);
let mut b = a;
a.mul_assign(&b);
b.square();
@@ -234,11 +221,11 @@ fn random_squaring_tests<F: Field, R: RngCore>(rng: &mut R) {
}
}
fn random_inversion_tests<F: Field, R: RngCore>(rng: &mut R) {
fn random_inversion_tests<F: Field, R: Rng>(rng: &mut R) {
assert!(F::zero().inverse().is_none());
for _ in 0..10000 {
let mut a = F::random(rng);
let mut a = F::rand(rng);
let b = a.inverse().unwrap(); // probablistically nonzero
a.mul_assign(&b);
@@ -246,14 +233,14 @@ fn random_inversion_tests<F: Field, R: RngCore>(rng: &mut R) {
}
}
fn random_expansion_tests<F: Field, R: RngCore>(rng: &mut R) {
fn random_expansion_tests<F: Field, R: Rng>(rng: &mut R) {
for _ in 0..10000 {
// Compare (a + b)(c + d) and (a*c + b*c + a*d + b*d)
let a = F::random(rng);
let b = F::random(rng);
let c = F::random(rng);
let d = F::random(rng);
let a = F::rand(rng);
let b = F::rand(rng);
let c = F::rand(rng);
let d = F::rand(rng);
let mut t0 = a;
t0.add_assign(&b);

View File

@@ -1,3 +1,4 @@
pub mod curve;
pub mod engine;
pub mod field;
pub mod repr;

View File

@@ -1,25 +1,21 @@
use ff::{PrimeField, PrimeFieldRepr};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use rand::{SeedableRng, XorShiftRng};
use PrimeFieldRepr;
pub fn random_repr_tests<P: PrimeField>() {
random_encoding_tests::<P>();
random_shl_tests::<P>();
random_shr_tests::<P>();
pub fn random_repr_tests<R: PrimeFieldRepr>() {
random_encoding_tests::<R>();
random_shl_tests::<R>();
random_shr_tests::<R>();
}
fn random_encoding_tests<P: PrimeField>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
fn random_encoding_tests<R: PrimeFieldRepr>() {
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let r = P::random(&mut rng).into_repr();
let r = R::rand(&mut rng);
// Big endian
{
let mut rdecoded = <P as PrimeField>::Repr::default();
let mut rdecoded = R::default();
let mut v: Vec<u8> = vec![];
r.write_be(&mut v).unwrap();
@@ -30,7 +26,7 @@ fn random_encoding_tests<P: PrimeField>() {
// Little endian
{
let mut rdecoded = <P as PrimeField>::Repr::default();
let mut rdecoded = R::default();
let mut v: Vec<u8> = vec![];
r.write_le(&mut v).unwrap();
@@ -40,8 +36,8 @@ fn random_encoding_tests<P: PrimeField>() {
}
{
let mut rdecoded_le = <P as PrimeField>::Repr::default();
let mut rdecoded_be_flip = <P as PrimeField>::Repr::default();
let mut rdecoded_le = R::default();
let mut rdecoded_be_flip = R::default();
let mut v: Vec<u8> = vec![];
r.write_le(&mut v).unwrap();
@@ -59,14 +55,11 @@ fn random_encoding_tests<P: PrimeField>() {
}
}
fn random_shl_tests<P: PrimeField>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
fn random_shl_tests<R: PrimeFieldRepr>() {
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..100 {
let r = P::random(&mut rng).into_repr();
let r = R::rand(&mut rng);
for shift in 0..(r.num_bits() + 1) {
let mut r1 = r;
@@ -83,14 +76,11 @@ fn random_shl_tests<P: PrimeField>() {
}
}
fn random_shr_tests<P: PrimeField>() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
fn random_shr_tests<R: PrimeFieldRepr>() {
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..100 {
let r = P::random(&mut rng).into_repr();
let r = R::rand(&mut rng);
for shift in 0..(r.num_bits() + 1) {
let mut r1 = r;

View File

@@ -1,6 +1,4 @@
use ff::{PrimeField, PrimeFieldRepr};
use super::CurveProjective;
use super::{CurveProjective, PrimeField, PrimeFieldRepr};
/// Replaces the contents of `table` with a w-NAF window table for the given window size.
pub(crate) fn wnaf_table<G: CurveProjective>(table: &mut Vec<G>, mut base: G, window: usize) {

View File

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

14
sapling-crypto/COPYRIGHT Normal file
View File

@@ -0,0 +1,14 @@
Copyrights in the "sapling-crypto" library are retained by their contributors. No
copyright assignment is required to contribute to the "sapling-crypto" library.
The "sapling-crypto" library is licensed under either of
* Apache License, Version 2.0, (see ./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license (see ./LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in the work by you, as defined in the Apache-2.0
license, shall be dual licensed as above, without any additional terms or
conditions.

31
sapling-crypto/Cargo.toml Normal file
View File

@@ -0,0 +1,31 @@
[package]
authors = ["Sean Bowe <sean@z.cash>"]
description = "Cryptographic library for Zcash Sapling"
documentation = "https://github.com/zcash-hackworks/sapling"
homepage = "https://github.com/zcash-hackworks/sapling"
license = "MIT/Apache-2.0"
name = "sapling-crypto"
repository = "https://github.com/zcash-hackworks/sapling"
version = "0.0.1"
[dependencies.pairing]
path = "../pairing"
features = ["expose-arith"]
[dependencies]
bellman = { path = "../bellman" }
rand = "0.4"
digest = "0.7"
byteorder = "1"
[dependencies.blake2-rfc]
git = "https://github.com/gtank/blake2-rfc"
rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"
[dev-dependencies]
hex-literal = "0.1"
rust-crypto = "0.2"
[features]
default = ["u128-support"]
u128-support = ["pairing/u128-support"]

23
sapling-crypto/README.md Normal file
View File

@@ -0,0 +1,23 @@
# sapling-crypto
This repository contains a (work-in-progress) implementation of Zcash's "Sapling" cryptography.
## Security Warnings
This library is currently under development and has not been reviewed.
## License
Licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in the work by you, as defined in the Apache-2.0
license, shall be dual licensed as above, without any additional terms or
conditions.

View File

@@ -0,0 +1,23 @@
#![feature(test)]
extern crate rand;
extern crate test;
extern crate pairing;
extern crate sapling_crypto;
use rand::{Rand, thread_rng};
use pairing::bls12_381::Bls12;
use sapling_crypto::jubjub::JubjubBls12;
use sapling_crypto::pedersen_hash::{pedersen_hash, Personalization};
#[bench]
fn bench_pedersen_hash(b: &mut test::Bencher) {
let params = JubjubBls12::new();
let rng = &mut thread_rng();
let bits = (0..510).map(|_| bool::rand(rng)).collect::<Vec<_>>();
let personalization = Personalization::MerkleTree(31);
b.iter(|| {
pedersen_hash::<Bls12, _>(personalization, bits.clone(), &params)
});
}

View File

@@ -0,0 +1,102 @@
extern crate sapling_crypto;
extern crate bellman;
extern crate rand;
extern crate pairing;
use std::time::{Duration, Instant};
use sapling_crypto::jubjub::{
JubjubBls12,
edwards,
fs,
};
use sapling_crypto::circuit::sapling::{
Spend
};
use sapling_crypto::primitives::{
Diversifier,
ProofGenerationKey,
ValueCommitment
};
use bellman::groth16::*;
use rand::{XorShiftRng, SeedableRng, Rng};
use pairing::bls12_381::{Bls12, Fr};
const TREE_DEPTH: usize = 32;
fn main() {
let jubjub_params = &JubjubBls12::new();
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
println!("Creating sample parameters...");
let groth_params = generate_random_parameters::<Bls12, _, _>(
Spend {
params: jubjub_params,
value_commitment: None,
proof_generation_key: None,
payment_address: None,
commitment_randomness: None,
ar: None,
auth_path: vec![None; TREE_DEPTH],
anchor: None
},
rng
).unwrap();
const SAMPLES: u32 = 50;
let mut total_time = Duration::new(0, 0);
for _ in 0..SAMPLES {
let value_commitment = ValueCommitment {
value: 1,
randomness: rng.gen()
};
let nsk: fs::Fs = rng.gen();
let ak = edwards::Point::rand(rng, jubjub_params).mul_by_cofactor(jubjub_params);
let proof_generation_key = ProofGenerationKey {
ak: ak.clone(),
nsk: nsk.clone()
};
let viewing_key = proof_generation_key.into_viewing_key(jubjub_params);
let payment_address;
loop {
let diversifier = Diversifier(rng.gen());
if let Some(p) = viewing_key.into_payment_address(
diversifier,
jubjub_params
)
{
payment_address = p;
break;
}
}
let commitment_randomness: fs::Fs = rng.gen();
let auth_path = vec![Some((rng.gen(), rng.gen())); TREE_DEPTH];
let ar: fs::Fs = rng.gen();
let anchor: Fr = rng.gen();
let start = Instant::now();
let _ = create_random_proof(Spend {
params: jubjub_params,
value_commitment: Some(value_commitment),
proof_generation_key: Some(proof_generation_key),
payment_address: Some(payment_address),
commitment_randomness: Some(commitment_randomness),
ar: Some(ar),
auth_path: auth_path,
anchor: Some(anchor)
}, &groth_params, rng).unwrap();
total_time += start.elapsed();
}
let avg = total_time / SAMPLES;
let avg = avg.subsec_nanos() as f64 / 1_000_000_000f64
+ (avg.as_secs() as f64);
println!("Average proving time (in seconds): {}", avg);
}

View File

@@ -1,10 +1,19 @@
use pairing::Engine;
use pairing::{
Engine,
};
use crate::{ConstraintSystem, SynthesisError};
use bellman::{
SynthesisError,
ConstraintSystem
};
use super::boolean::Boolean;
use super::boolean::{
Boolean
};
use super::uint32::UInt32;
use super::uint32::{
UInt32
};
use super::multieq::MultiEq;
@@ -56,7 +65,7 @@ const SIGMA: [[usize; 16]; 10] = [
[12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
[13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
[6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
[10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
[10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0]
];
/*
@@ -89,30 +98,17 @@ fn mixing_g<E: Engine, CS: ConstraintSystem<E>, M>(
c: usize,
d: usize,
x: &UInt32,
y: &UInt32,
y: &UInt32
) -> Result<(), SynthesisError>
where
M: ConstraintSystem<E, Root = MultiEq<E, CS>>,
where M: ConstraintSystem<E, Root=MultiEq<E, CS>>
{
v[a] = UInt32::addmany(
cs.namespace(|| "mixing step 1"),
&[v[a].clone(), v[b].clone(), x.clone()],
)?;
v[a] = UInt32::addmany(cs.namespace(|| "mixing step 1"), &[v[a].clone(), v[b].clone(), x.clone()])?;
v[d] = v[d].xor(cs.namespace(|| "mixing step 2"), &v[a])?.rotr(R1);
v[c] = UInt32::addmany(
cs.namespace(|| "mixing step 3"),
&[v[c].clone(), v[d].clone()],
)?;
v[c] = UInt32::addmany(cs.namespace(|| "mixing step 3"), &[v[c].clone(), v[d].clone()])?;
v[b] = v[b].xor(cs.namespace(|| "mixing step 4"), &v[c])?.rotr(R2);
v[a] = UInt32::addmany(
cs.namespace(|| "mixing step 5"),
&[v[a].clone(), v[b].clone(), y.clone()],
)?;
v[a] = UInt32::addmany(cs.namespace(|| "mixing step 5"), &[v[a].clone(), v[b].clone(), y.clone()])?;
v[d] = v[d].xor(cs.namespace(|| "mixing step 6"), &v[a])?.rotr(R3);
v[c] = UInt32::addmany(
cs.namespace(|| "mixing step 7"),
&[v[c].clone(), v[d].clone()],
)?;
v[c] = UInt32::addmany(cs.namespace(|| "mixing step 7"), &[v[c].clone(), v[d].clone()])?;
v[b] = v[b].xor(cs.namespace(|| "mixing step 8"), &v[c])?.rotr(R4);
Ok(())
@@ -166,13 +162,15 @@ where
END FUNCTION.
*/
fn blake2s_compression<E: Engine, CS: ConstraintSystem<E>>(
mut cs: CS,
h: &mut [UInt32],
m: &[UInt32],
t: u64,
f: bool,
) -> Result<(), SynthesisError> {
f: bool
) -> Result<(), SynthesisError>
{
assert_eq!(h.len(), 8);
assert_eq!(m.len(), 16);
@@ -198,16 +196,10 @@ fn blake2s_compression<E: Engine, CS: ConstraintSystem<E>>(
assert_eq!(v.len(), 16);
v[12] = v[12].xor(cs.namespace(|| "first xor"), &UInt32::constant(t as u32))?;
v[13] = v[13].xor(
cs.namespace(|| "second xor"),
&UInt32::constant((t >> 32) as u32),
)?;
v[13] = v[13].xor(cs.namespace(|| "second xor"), &UInt32::constant((t >> 32) as u32))?;
if f {
v[14] = v[14].xor(
cs.namespace(|| "third xor"),
&UInt32::constant(u32::max_value()),
)?;
v[14] = v[14].xor(cs.namespace(|| "third xor"), &UInt32::constant(u32::max_value()))?;
}
{
@@ -218,92 +210,20 @@ fn blake2s_compression<E: Engine, CS: ConstraintSystem<E>>(
let s = SIGMA[i % 10];
mixing_g(
cs.namespace(|| "mixing invocation 1"),
&mut v,
0,
4,
8,
12,
&m[s[0]],
&m[s[1]],
)?;
mixing_g(
cs.namespace(|| "mixing invocation 2"),
&mut v,
1,
5,
9,
13,
&m[s[2]],
&m[s[3]],
)?;
mixing_g(
cs.namespace(|| "mixing invocation 3"),
&mut v,
2,
6,
10,
14,
&m[s[4]],
&m[s[5]],
)?;
mixing_g(
cs.namespace(|| "mixing invocation 4"),
&mut v,
3,
7,
11,
15,
&m[s[6]],
&m[s[7]],
)?;
mixing_g(cs.namespace(|| "mixing invocation 1"), &mut v, 0, 4, 8, 12, &m[s[ 0]], &m[s[ 1]])?;
mixing_g(cs.namespace(|| "mixing invocation 2"), &mut v, 1, 5, 9, 13, &m[s[ 2]], &m[s[ 3]])?;
mixing_g(cs.namespace(|| "mixing invocation 3"), &mut v, 2, 6, 10, 14, &m[s[ 4]], &m[s[ 5]])?;
mixing_g(cs.namespace(|| "mixing invocation 4"), &mut v, 3, 7, 11, 15, &m[s[ 6]], &m[s[ 7]])?;
mixing_g(
cs.namespace(|| "mixing invocation 5"),
&mut v,
0,
5,
10,
15,
&m[s[8]],
&m[s[9]],
)?;
mixing_g(
cs.namespace(|| "mixing invocation 6"),
&mut v,
1,
6,
11,
12,
&m[s[10]],
&m[s[11]],
)?;
mixing_g(
cs.namespace(|| "mixing invocation 7"),
&mut v,
2,
7,
8,
13,
&m[s[12]],
&m[s[13]],
)?;
mixing_g(
cs.namespace(|| "mixing invocation 8"),
&mut v,
3,
4,
9,
14,
&m[s[14]],
&m[s[15]],
)?;
mixing_g(cs.namespace(|| "mixing invocation 5"), &mut v, 0, 5, 10, 15, &m[s[ 8]], &m[s[ 9]])?;
mixing_g(cs.namespace(|| "mixing invocation 6"), &mut v, 1, 6, 11, 12, &m[s[10]], &m[s[11]])?;
mixing_g(cs.namespace(|| "mixing invocation 7"), &mut v, 2, 7, 8, 13, &m[s[12]], &m[s[13]])?;
mixing_g(cs.namespace(|| "mixing invocation 8"), &mut v, 3, 4, 9, 14, &m[s[14]], &m[s[15]])?;
}
}
for i in 0..8 {
let mut cs = cs.namespace(|| format!("h[{i}] ^ v[{i}] ^ v[{i} + 8]", i = i));
let mut cs = cs.namespace(|| format!("h[{i}] ^ v[{i}] ^ v[{i} + 8]", i=i));
h[i] = h[i].xor(cs.namespace(|| "first xor"), &v[i])?;
h[i] = h[i].xor(cs.namespace(|| "second xor"), &v[i + 8])?;
@@ -342,8 +262,9 @@ fn blake2s_compression<E: Engine, CS: ConstraintSystem<E>>(
pub fn blake2s<E: Engine, CS: ConstraintSystem<E>>(
mut cs: CS,
input: &[Boolean],
personalization: &[u8],
) -> Result<Vec<Boolean>, SynthesisError> {
personalization: &[u8]
) -> Result<Vec<Boolean>, SynthesisError>
{
use byteorder::{ByteOrder, LittleEndian};
assert_eq!(personalization.len(), 8);
@@ -358,12 +279,8 @@ pub fn blake2s<E: Engine, CS: ConstraintSystem<E>>(
h.push(UInt32::constant(0x9B05688C));
// Personalization is stored here
h.push(UInt32::constant(
0x1F83D9AB ^ LittleEndian::read_u32(&personalization[0..4]),
));
h.push(UInt32::constant(
0x5BE0CD19 ^ LittleEndian::read_u32(&personalization[4..8]),
));
h.push(UInt32::constant(0x1F83D9AB ^ LittleEndian::read_u32(&personalization[0..4])));
h.push(UInt32::constant(0x5BE0CD19 ^ LittleEndian::read_u32(&personalization[4..8])));
let mut blocks: Vec<Vec<UInt32>> = vec![];
@@ -395,13 +312,7 @@ pub fn blake2s<E: Engine, CS: ConstraintSystem<E>>(
{
let cs = cs.namespace(|| "final block");
blake2s_compression(
cs,
&mut h,
&blocks[blocks.len() - 1],
(input.len() / 8) as u64,
true,
)?;
blake2s_compression(cs, &mut h, &blocks[blocks.len() - 1], (input.len() / 8) as u64, true)?;
}
Ok(h.iter().flat_map(|b| b.into_bits()).collect())
@@ -409,15 +320,13 @@ pub fn blake2s<E: Engine, CS: ConstraintSystem<E>>(
#[cfg(test)]
mod test {
use blake2s_simd::Params as Blake2sParams;
use pairing::bls12_381::Bls12;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
use rand::{XorShiftRng, SeedableRng, Rng};
use pairing::bls12_381::{Bls12};
use ::circuit::boolean::{Boolean, AllocatedBit};
use ::circuit::test::TestConstraintSystem;
use super::blake2s;
use crate::gadgets::boolean::{AllocatedBit, Boolean};
use crate::gadgets::test::TestConstraintSystem;
use crate::ConstraintSystem;
use bellman::{ConstraintSystem};
use blake2_rfc::blake2s::Blake2s;
#[test]
fn test_blank_hash() {
@@ -445,13 +354,7 @@ mod test {
#[test]
fn test_blake2s_constraints() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let input_bits: Vec<_> = (0..512)
.map(|i| {
AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true))
.unwrap()
.into()
})
.collect();
let input_bits: Vec<_> = (0..512).map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into()).collect();
blake2s(&mut cs, &input_bits, b"12345678").unwrap();
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 21518);
@@ -463,18 +366,12 @@ mod test {
// doesn't result in more constraints.
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let input_bits: Vec<_> = (0..512)
.map(|_| Boolean::constant(rng.next_u32() % 2 != 0))
.chain((0..512).map(|i| {
AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true))
.unwrap()
.into()
}))
.collect();
.map(|_| Boolean::constant(rng.gen()))
.chain((0..512)
.map(|i| AllocatedBit::alloc(cs.namespace(|| format!("input bit {}", i)), Some(true)).unwrap().into()))
.collect();
blake2s(&mut cs, &input_bits, b"12345678").unwrap();
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 21518);
@@ -483,31 +380,21 @@ mod test {
#[test]
fn test_blake2s_constant_constraints() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let input_bits: Vec<_> = (0..512)
.map(|_| Boolean::constant(rng.next_u32() % 2 != 0))
.collect();
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let input_bits: Vec<_> = (0..512).map(|_| Boolean::constant(rng.gen())).collect();
blake2s(&mut cs, &input_bits, b"12345678").unwrap();
assert_eq!(cs.num_constraints(), 0);
}
#[test]
fn test_blake2s() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) {
let mut h = Blake2sParams::new()
.hash_length(32)
.personal(b"12345678")
.to_state();
for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0))
{
let mut h = Blake2s::with_params(32, &[], &[], b"12345678");
let data: Vec<u8> = (0..input_len).map(|_| rng.next_u32() as u8).collect();
let data: Vec<u8> = (0..input_len).map(|_| rng.gen()).collect();
h.update(&data);
@@ -521,11 +408,7 @@ mod test {
for bit_i in 0..8 {
let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i));
input_bits.push(
AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8))
.unwrap()
.into(),
);
input_bits.push(AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)).unwrap().into());
}
}
@@ -533,19 +416,17 @@ mod test {
assert!(cs.is_satisfied());
let mut s = hash_result
.as_ref()
.iter()
.flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8));
let mut s = hash_result.as_ref().iter()
.flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8));
for b in r {
match b {
Boolean::Is(b) => {
assert!(s.next().unwrap() == b.get_value().unwrap());
}
},
Boolean::Not(b) => {
assert!(s.next().unwrap() != b.get_value().unwrap());
}
},
Boolean::Constant(b) => {
assert!(input_len == 0);
assert!(s.next().unwrap() == b);

View File

@@ -1,15 +1,21 @@
use ff::Field;
use pairing::Engine;
use super::boolean::Boolean;
use super::num::{AllocatedNum, Num};
use pairing::{Engine, Field};
use super::*;
use crate::ConstraintSystem;
use super::num::{
AllocatedNum,
Num
};
use super::boolean::Boolean;
use bellman::{
ConstraintSystem
};
// Synthesize the constants for each base pattern.
fn synth<'a, E: Engine, I>(window_size: usize, constants: I, assignment: &mut [E::Fr])
where
I: IntoIterator<Item = &'a E::Fr>,
fn synth<'a, E: Engine, I>(
window_size: usize,
constants: I,
assignment: &mut [E::Fr]
)
where I: IntoIterator<Item=&'a E::Fr>
{
assert_eq!(assignment.len(), 1 << window_size);
@@ -31,20 +37,16 @@ where
pub fn lookup3_xy<E: Engine, CS>(
mut cs: CS,
bits: &[Boolean],
coords: &[(E::Fr, E::Fr)],
coords: &[(E::Fr, E::Fr)]
) -> Result<(AllocatedNum<E>, AllocatedNum<E>), SynthesisError>
where
CS: ConstraintSystem<E>,
where CS: ConstraintSystem<E>
{
assert_eq!(bits.len(), 3);
assert_eq!(coords.len(), 8);
// Calculate the index into `coords`
let i = match (
bits[0].get_value(),
bits[1].get_value(),
bits[2].get_value(),
) {
let i =
match (bits[0].get_value(), bits[1].get_value(), bits[2].get_value()) {
(Some(a_value), Some(b_value), Some(c_value)) => {
let mut tmp = 0;
if a_value {
@@ -57,15 +59,25 @@ where
tmp += 4;
}
Some(tmp)
}
_ => None,
},
_ => None
};
// Allocate the x-coordinate resulting from the lookup
let res_x = AllocatedNum::alloc(cs.namespace(|| "x"), || Ok(coords[*i.get()?].0))?;
let res_x = AllocatedNum::alloc(
cs.namespace(|| "x"),
|| {
Ok(coords[*i.get()?].0)
}
)?;
// Allocate the y-coordinate resulting from the lookup
let res_y = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(coords[*i.get()?].1))?;
let res_y = AllocatedNum::alloc(
cs.namespace(|| "y"),
|| {
Ok(coords[*i.get()?].1)
}
)?;
// Compute the coefficients for the lookup constraints
let mut x_coeffs = [E::Fr::zero(); 8];
@@ -79,38 +91,30 @@ where
cs.enforce(
|| "x-coordinate lookup",
|lc| {
lc + (x_coeffs[0b001], one)
|lc| lc + (x_coeffs[0b001], one)
+ &bits[1].lc::<E>(one, x_coeffs[0b011])
+ &bits[2].lc::<E>(one, x_coeffs[0b101])
+ &precomp.lc::<E>(one, x_coeffs[0b111])
},
+ &precomp.lc::<E>(one, x_coeffs[0b111]),
|lc| lc + &bits[0].lc::<E>(one, E::Fr::one()),
|lc| {
lc + res_x.get_variable()
|lc| lc + res_x.get_variable()
- (x_coeffs[0b000], one)
- &bits[1].lc::<E>(one, x_coeffs[0b010])
- &bits[2].lc::<E>(one, x_coeffs[0b100])
- &precomp.lc::<E>(one, x_coeffs[0b110])
},
- &precomp.lc::<E>(one, x_coeffs[0b110]),
);
cs.enforce(
|| "y-coordinate lookup",
|lc| {
lc + (y_coeffs[0b001], one)
|lc| lc + (y_coeffs[0b001], one)
+ &bits[1].lc::<E>(one, y_coeffs[0b011])
+ &bits[2].lc::<E>(one, y_coeffs[0b101])
+ &precomp.lc::<E>(one, y_coeffs[0b111])
},
+ &precomp.lc::<E>(one, y_coeffs[0b111]),
|lc| lc + &bits[0].lc::<E>(one, E::Fr::one()),
|lc| {
lc + res_y.get_variable()
|lc| lc + res_y.get_variable()
- (y_coeffs[0b000], one)
- &bits[1].lc::<E>(one, y_coeffs[0b010])
- &bits[2].lc::<E>(one, y_coeffs[0b100])
- &precomp.lc::<E>(one, y_coeffs[0b110])
},
- &precomp.lc::<E>(one, y_coeffs[0b110]),
);
Ok((res_x, res_y))
@@ -121,16 +125,16 @@ where
pub fn lookup3_xy_with_conditional_negation<E: Engine, CS>(
mut cs: CS,
bits: &[Boolean],
coords: &[(E::Fr, E::Fr)],
coords: &[(E::Fr, E::Fr)]
) -> Result<(Num<E>, Num<E>), SynthesisError>
where
CS: ConstraintSystem<E>,
where CS: ConstraintSystem<E>
{
assert_eq!(bits.len(), 3);
assert_eq!(coords.len(), 4);
// Calculate the index into `coords`
let i = match (bits[0].get_value(), bits[1].get_value()) {
let i =
match (bits[0].get_value(), bits[1].get_value()) {
(Some(a_value), Some(b_value)) => {
let mut tmp = 0;
if a_value {
@@ -140,19 +144,22 @@ where
tmp += 2;
}
Some(tmp)
}
_ => None,
},
_ => None
};
// Allocate the y-coordinate resulting from the lookup
// and conditional negation
let y = AllocatedNum::alloc(cs.namespace(|| "y"), || {
let mut tmp = coords[*i.get()?].1;
if *bits[2].get_value().get()? {
tmp.negate();
let y = AllocatedNum::alloc(
cs.namespace(|| "y"),
|| {
let mut tmp = coords[*i.get()?].1;
if *bits[2].get_value().get()? {
tmp.negate();
}
Ok(tmp)
}
Ok(tmp)
})?;
)?;
let one = CS::one();
@@ -165,21 +172,21 @@ where
let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[0], &bits[1])?;
let x = Num::zero()
.add_bool_with_coeff(one, &Boolean::constant(true), x_coeffs[0b00])
.add_bool_with_coeff(one, &bits[0], x_coeffs[0b01])
.add_bool_with_coeff(one, &bits[1], x_coeffs[0b10])
.add_bool_with_coeff(one, &precomp, x_coeffs[0b11]);
.add_bool_with_coeff(one, &Boolean::constant(true), x_coeffs[0b00])
.add_bool_with_coeff(one, &bits[0], x_coeffs[0b01])
.add_bool_with_coeff(one, &bits[1], x_coeffs[0b10])
.add_bool_with_coeff(one, &precomp, x_coeffs[0b11]);
let y_lc = precomp.lc::<E>(one, y_coeffs[0b11])
+ &bits[1].lc::<E>(one, y_coeffs[0b10])
+ &bits[0].lc::<E>(one, y_coeffs[0b01])
+ (y_coeffs[0b00], one);
let y_lc = precomp.lc::<E>(one, y_coeffs[0b11]) +
&bits[1].lc::<E>(one, y_coeffs[0b10]) +
&bits[0].lc::<E>(one, y_coeffs[0b01]) +
(y_coeffs[0b00], one);
cs.enforce(
|| "y-coordinate lookup",
|lc| lc + &y_lc + &y_lc,
|lc| lc + &bits[2].lc::<E>(one, E::Fr::one()),
|lc| lc + &y_lc - y.get_variable(),
|lc| lc + &y_lc - y.get_variable()
);
Ok((x, y.into()))
@@ -187,52 +194,46 @@ where
#[cfg(test)]
mod test {
use rand::{SeedableRng, Rand, Rng, XorShiftRng};
use super::*;
use crate::gadgets::boolean::{AllocatedBit, Boolean};
use crate::gadgets::test::*;
use ::circuit::test::*;
use ::circuit::boolean::{Boolean, AllocatedBit};
use pairing::bls12_381::{Bls12, Fr};
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
#[test]
fn test_lookup3_xy() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0656]);
for _ in 0..100 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let a_val = rng.next_u32() % 2 != 0;
let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap());
let a_val = rng.gen();
let a = Boolean::from(
AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap()
);
let b_val = rng.next_u32() % 2 != 0;
let b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap());
let b_val = rng.gen();
let b = Boolean::from(
AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap()
);
let c_val = rng.next_u32() % 2 != 0;
let c = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap());
let c_val = rng.gen();
let c = Boolean::from(
AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap()
);
let bits = vec![a, b, c];
let points: Vec<(Fr, Fr)> = (0..8)
.map(|_| (Fr::random(&mut rng), Fr::random(&mut rng)))
.collect();
let points: Vec<(Fr, Fr)> = (0..8).map(|_| (rng.gen(), rng.gen())).collect();
let res = lookup3_xy(&mut cs, &bits, &points).unwrap();
assert!(cs.is_satisfied());
let mut index = 0;
if a_val {
index += 1
}
if b_val {
index += 2
}
if c_val {
index += 4
}
if a_val { index += 1 }
if b_val { index += 2 }
if c_val { index += 4 }
assert_eq!(res.0.get_value().unwrap(), points[index].0);
assert_eq!(res.1.get_value().unwrap(), points[index].1);
@@ -241,63 +242,53 @@ mod test {
#[test]
fn test_lookup3_xy_with_conditional_negation() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..100 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let a_val = rng.next_u32() % 2 != 0;
let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap());
let a_val = rng.gen();
let a = Boolean::from(
AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap()
);
let b_val = rng.next_u32() % 2 != 0;
let b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap());
let b_val = rng.gen();
let b = Boolean::from(
AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap()
);
let c_val = rng.next_u32() % 2 != 0;
let c = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap());
let c_val = rng.gen();
let c = Boolean::from(
AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap()
);
let bits = vec![a, b, c];
let points: Vec<(Fr, Fr)> = (0..4)
.map(|_| (Fr::random(&mut rng), Fr::random(&mut rng)))
.collect();
let points: Vec<(Fr, Fr)> = (0..4).map(|_| (rng.gen(), rng.gen())).collect();
let res = lookup3_xy_with_conditional_negation(&mut cs, &bits, &points).unwrap();
assert!(cs.is_satisfied());
let mut index = 0;
if a_val {
index += 1
}
if b_val {
index += 2
}
if a_val { index += 1 }
if b_val { index += 2 }
assert_eq!(res.0.get_value().unwrap(), points[index].0);
let mut tmp = points[index].1;
if c_val {
tmp.negate()
}
if c_val { tmp.negate() }
assert_eq!(res.1.get_value().unwrap(), tmp);
}
}
#[test]
fn test_synth() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let window_size = 4;
let mut assignment = vec![Fr::zero(); 1 << window_size];
let constants: Vec<_> = (0..(1 << window_size))
.map(|_| Fr::random(&mut rng))
.collect();
let constants: Vec<_> = (0..(1 << window_size)).map(|_| Fr::rand(&mut rng)).collect();
synth::<Bls12, _>(window_size, &constants, &mut assignment);

View File

@@ -1,15 +1,23 @@
#[cfg(test)]
pub mod test;
pub mod blake2s;
pub mod boolean;
pub mod lookup;
pub mod multieq;
pub mod multipack;
pub mod num;
pub mod sha256;
pub mod uint32;
pub mod blake2s;
pub mod num;
pub mod lookup;
pub mod ecc;
pub mod pedersen_hash;
pub mod multipack;
pub mod sha256;
use crate::SynthesisError;
pub mod sapling;
pub mod sprout;
use bellman::{
SynthesisError
};
// TODO: This should probably be removed and we
// should use existing helper methods on `Option`
@@ -17,7 +25,7 @@ use crate::SynthesisError;
/// This basically is just an extension to `Option`
/// which allows for a convenient mapping to an
/// error on `None`.
pub trait Assignment<T> {
trait Assignment<T> {
fn get(&self) -> Result<&T, SynthesisError>;
}
@@ -25,7 +33,7 @@ impl<T> Assignment<T> for Option<T> {
fn get(&self) -> Result<&T, SynthesisError> {
match *self {
Some(ref v) => Ok(v),
None => Err(SynthesisError::AssignmentMissing),
None => Err(SynthesisError::AssignmentMissing)
}
}
}

View File

@@ -1,9 +1,17 @@
use ff::{Field, PrimeField};
use pairing::Engine;
use pairing::{
Engine,
Field,
PrimeField
};
use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
use bellman::{
SynthesisError,
ConstraintSystem,
LinearCombination,
Variable
};
pub struct MultiEq<E: Engine, CS: ConstraintSystem<E>> {
pub struct MultiEq<E: Engine, CS: ConstraintSystem<E>>{
cs: CS,
ops: usize,
bits_used: usize,
@@ -18,11 +26,12 @@ impl<E: Engine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
ops: 0,
bits_used: 0,
lhs: LinearCombination::zero(),
rhs: LinearCombination::zero(),
rhs: LinearCombination::zero()
}
}
fn accumulate(&mut self) {
fn accumulate(&mut self)
{
let ops = self.ops;
let lhs = self.lhs.clone();
let rhs = self.rhs.clone();
@@ -30,7 +39,7 @@ impl<E: Engine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
|| format!("multieq {}", ops),
|_| lhs,
|lc| lc + CS::one(),
|_| rhs,
|_| rhs
);
self.lhs = LinearCombination::zero();
self.rhs = LinearCombination::zero();
@@ -42,8 +51,9 @@ impl<E: Engine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
&mut self,
num_bits: usize,
lhs: &LinearCombination<E>,
rhs: &LinearCombination<E>,
) {
rhs: &LinearCombination<E>
)
{
// Check if we will exceed the capacity
if (E::Fr::CAPACITY as usize) <= (self.bits_used + num_bits) {
self.accumulate();
@@ -61,60 +71,67 @@ impl<E: Engine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
impl<E: Engine, CS: ConstraintSystem<E>> Drop for MultiEq<E, CS> {
fn drop(&mut self) {
if self.bits_used > 0 {
self.accumulate();
self.accumulate();
}
}
}
impl<E: Engine, CS: ConstraintSystem<E>> ConstraintSystem<E> for MultiEq<E, CS> {
impl<E: Engine, CS: ConstraintSystem<E>> ConstraintSystem<E> for MultiEq<E, CS>
{
type Root = Self;
fn one() -> Variable {
CS::one()
}
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
fn alloc<F, A, AR>(
&mut self,
annotation: A,
f: F
) -> Result<Variable, SynthesisError>
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
{
self.cs.alloc(annotation, f)
}
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
fn alloc_input<F, A, AR>(
&mut self,
annotation: A,
f: F
) -> Result<Variable, SynthesisError>
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
{
self.cs.alloc_input(annotation, f)
}
fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: A, a: LA, b: LB, c: LC)
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
fn enforce<A, AR, LA, LB, LC>(
&mut self,
annotation: A,
a: LA,
b: LB,
c: LC
)
where A: FnOnce() -> AR, AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>
{
self.cs.enforce(annotation, a, b, c)
}
fn push_namespace<NR, N>(&mut self, name_fn: N)
where
NR: Into<String>,
N: FnOnce() -> NR,
where NR: Into<String>, N: FnOnce() -> NR
{
self.cs.get_root().push_namespace(name_fn)
}
fn pop_namespace(&mut self) {
fn pop_namespace(&mut self)
{
self.cs.get_root().pop_namespace()
}
fn get_root(&mut self) -> &mut Self::Root {
fn get_root(&mut self) -> &mut Self::Root
{
self
}
}

View File

@@ -0,0 +1,113 @@
use pairing::{Engine, Field, PrimeField};
use bellman::{ConstraintSystem, SynthesisError};
use super::boolean::{Boolean};
use super::num::Num;
use super::Assignment;
/// Takes a sequence of booleans and exposes them as compact
/// public inputs
pub fn pack_into_inputs<E, CS>(
mut cs: CS,
bits: &[Boolean]
) -> Result<(), SynthesisError>
where E: Engine, CS: ConstraintSystem<E>
{
for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate()
{
let mut num = Num::<E>::zero();
let mut coeff = E::Fr::one();
for bit in bits {
num = num.add_bool_with_coeff(CS::one(), bit, coeff);
coeff.double();
}
let input = cs.alloc_input(|| format!("input {}", i), || {
Ok(*num.get_value().get()?)
})?;
// num * 1 = input
cs.enforce(
|| format!("packing constraint {}", i),
|_| num.lc(E::Fr::one()),
|lc| lc + CS::one(),
|lc| lc + input
);
}
Ok(())
}
pub fn bytes_to_bits(bytes: &[u8]) -> Vec<bool>
{
bytes.iter()
.flat_map(|&v| (0..8).rev().map(move |i| (v >> i) & 1 == 1))
.collect()
}
pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec<bool>
{
bytes.iter()
.flat_map(|&v| (0..8).map(move |i| (v >> i) & 1 == 1))
.collect()
}
pub fn compute_multipacking<E: Engine>(
bits: &[bool]
) -> Vec<E::Fr>
{
let mut result = vec![];
for bits in bits.chunks(E::Fr::CAPACITY as usize)
{
let mut cur = E::Fr::zero();
let mut coeff = E::Fr::one();
for bit in bits {
if *bit {
cur.add_assign(&coeff);
}
coeff.double();
}
result.push(cur);
}
result
}
#[test]
fn test_multipacking() {
use rand::{SeedableRng, Rng, XorShiftRng};
use bellman::{ConstraintSystem};
use pairing::bls12_381::{Bls12};
use ::circuit::test::*;
use super::boolean::{AllocatedBit, Boolean};
let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for num_bits in 0..1500 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let bits: Vec<bool> = (0..num_bits).map(|_| rng.gen()).collect();
let circuit_bits = bits.iter().enumerate()
.map(|(i, &b)| {
Boolean::from(
AllocatedBit::alloc(
cs.namespace(|| format!("bit {}", i)),
Some(b)
).unwrap()
)
})
.collect::<Vec<_>>();
let expected_inputs = compute_multipacking::<Bls12>(&bits);
pack_into_inputs(cs.namespace(|| "pack"), &circuit_bits).unwrap();
assert!(cs.is_satisfied());
assert!(cs.verify(&expected_inputs));
}
}

View File

@@ -1,61 +1,83 @@
use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr};
use pairing::Engine;
use pairing::{
Engine,
Field,
PrimeField,
PrimeFieldRepr,
BitIterator
};
use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
use bellman::{
SynthesisError,
ConstraintSystem,
LinearCombination,
Variable
};
use super::Assignment;
use super::{
Assignment
};
use super::boolean::{self, AllocatedBit, Boolean};
use super::boolean::{
self,
Boolean,
AllocatedBit
};
pub struct AllocatedNum<E: Engine> {
value: Option<E::Fr>,
variable: Variable,
variable: Variable
}
impl<E: Engine> Clone for AllocatedNum<E> {
fn clone(&self) -> Self {
AllocatedNum {
value: self.value,
variable: self.variable,
variable: self.variable
}
}
}
impl<E: Engine> AllocatedNum<E> {
pub fn alloc<CS, F>(mut cs: CS, value: F) -> Result<Self, SynthesisError>
where
CS: ConstraintSystem<E>,
F: FnOnce() -> Result<E::Fr, SynthesisError>,
pub fn alloc<CS, F>(
mut cs: CS,
value: F,
) -> Result<Self, SynthesisError>
where CS: ConstraintSystem<E>,
F: FnOnce() -> Result<E::Fr, SynthesisError>
{
let mut new_value = None;
let var = cs.alloc(
|| "num",
|| {
let tmp = value()?;
let var = cs.alloc(|| "num", || {
let tmp = value()?;
new_value = Some(tmp);
new_value = Some(tmp);
Ok(tmp)
},
)?;
Ok(tmp)
})?;
Ok(AllocatedNum {
value: new_value,
variable: var,
variable: var
})
}
pub fn inputize<CS>(&self, mut cs: CS) -> Result<(), SynthesisError>
where
CS: ConstraintSystem<E>,
pub fn inputize<CS>(
&self,
mut cs: CS
) -> Result<(), SynthesisError>
where CS: ConstraintSystem<E>
{
let input = cs.alloc_input(|| "input variable", || Ok(*self.value.get()?))?;
let input = cs.alloc_input(
|| "input variable",
|| {
Ok(*self.value.get()?)
}
)?;
cs.enforce(
|| "enforce input is correct",
|lc| lc + input,
|lc| lc + CS::one(),
|lc| lc + self.variable,
|lc| lc + self.variable
);
Ok(())
@@ -66,17 +88,18 @@ impl<E: Engine> AllocatedNum<E> {
/// order, requiring that the representation
/// strictly exists "in the field" (i.e., a
/// congruency is not allowed.)
pub fn into_bits_le_strict<CS>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError>
where
CS: ConstraintSystem<E>,
pub fn into_bits_le_strict<CS>(
&self,
mut cs: CS
) -> Result<Vec<Boolean>, SynthesisError>
where CS: ConstraintSystem<E>
{
pub fn kary_and<E, CS>(
mut cs: CS,
v: &[AllocatedBit],
v: &[AllocatedBit]
) -> Result<AllocatedBit, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
where E: Engine,
CS: ConstraintSystem<E>
{
assert!(v.len() > 0);
@@ -91,7 +114,7 @@ impl<E: Engine> AllocatedNum<E> {
cur = Some(AllocatedBit::and(
cs.namespace(|| format!("and {}", i)),
cur.as_ref().unwrap(),
v,
v
)?);
}
}
@@ -127,7 +150,10 @@ impl<E: Engine> AllocatedNum<E> {
if b {
// This is part of a run of ones. Let's just
// allocate the boolean with the expected value.
let a_bit = AllocatedBit::alloc(cs.namespace(|| format!("bit {}", i)), a_bit)?;
let a_bit = AllocatedBit::alloc(
cs.namespace(|| format!("bit {}", i)),
a_bit
)?;
// ... and add it to the current run of ones.
current_run.push(a_bit.clone());
result.push(a_bit);
@@ -141,7 +167,7 @@ impl<E: Engine> AllocatedNum<E> {
}
last_run = Some(kary_and(
cs.namespace(|| format!("run ending at {}", i)),
&current_run,
&current_run
)?);
current_run.truncate(0);
}
@@ -154,7 +180,7 @@ impl<E: Engine> AllocatedNum<E> {
let a_bit = AllocatedBit::alloc_conditionally(
cs.namespace(|| format!("bit {}", i)),
a_bit,
&last_run.as_ref().expect("char always starts with a one"),
&last_run.as_ref().expect("char always starts with a one")
)?;
result.push(a_bit);
}
@@ -180,7 +206,12 @@ impl<E: Engine> AllocatedNum<E> {
lc = lc - self.variable;
cs.enforce(|| "unpacking constraint", |lc| lc, |lc| lc, |_| lc);
cs.enforce(
|| "unpacking constraint",
|lc| lc,
|lc| lc,
|_| lc
);
// Convert into booleans, and reverse for little-endian bit order
Ok(result.into_iter().map(|b| Boolean::from(b)).rev().collect())
@@ -189,11 +220,16 @@ impl<E: Engine> AllocatedNum<E> {
/// Convert the allocated number into its little-endian representation.
/// Note that this does not strongly enforce that the commitment is
/// "in the field."
pub fn into_bits_le<CS>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError>
where
CS: ConstraintSystem<E>,
pub fn into_bits_le<CS>(
&self,
mut cs: CS
) -> Result<Vec<Boolean>, SynthesisError>
where CS: ConstraintSystem<E>
{
let bits = boolean::field_into_allocated_bits_le(&mut cs, self.value)?;
let bits = boolean::field_into_allocated_bits_le(
&mut cs,
self.value
)?;
let mut lc = LinearCombination::zero();
let mut coeff = E::Fr::one();
@@ -206,91 +242,94 @@ impl<E: Engine> AllocatedNum<E> {
lc = lc - self.variable;
cs.enforce(|| "unpacking constraint", |lc| lc, |lc| lc, |_| lc);
cs.enforce(
|| "unpacking constraint",
|lc| lc,
|lc| lc,
|_| lc
);
Ok(bits.into_iter().map(|b| Boolean::from(b)).collect())
}
pub fn mul<CS>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError>
where
CS: ConstraintSystem<E>,
pub fn mul<CS>(
&self,
mut cs: CS,
other: &Self
) -> Result<Self, SynthesisError>
where CS: ConstraintSystem<E>
{
let mut value = None;
let var = cs.alloc(
|| "product num",
|| {
let mut tmp = *self.value.get()?;
tmp.mul_assign(other.value.get()?);
let var = cs.alloc(|| "product num", || {
let mut tmp = *self.value.get()?;
tmp.mul_assign(other.value.get()?);
value = Some(tmp);
value = Some(tmp);
Ok(tmp)
},
)?;
Ok(tmp)
})?;
// Constrain: a * b = ab
cs.enforce(
|| "multiplication constraint",
|lc| lc + self.variable,
|lc| lc + other.variable,
|lc| lc + var,
|lc| lc + var
);
Ok(AllocatedNum {
value: value,
variable: var,
variable: var
})
}
pub fn square<CS>(&self, mut cs: CS) -> Result<Self, SynthesisError>
where
CS: ConstraintSystem<E>,
pub fn square<CS>(
&self,
mut cs: CS
) -> Result<Self, SynthesisError>
where CS: ConstraintSystem<E>
{
let mut value = None;
let var = cs.alloc(
|| "squared num",
|| {
let mut tmp = *self.value.get()?;
tmp.square();
let var = cs.alloc(|| "squared num", || {
let mut tmp = *self.value.get()?;
tmp.square();
value = Some(tmp);
value = Some(tmp);
Ok(tmp)
},
)?;
Ok(tmp)
})?;
// Constrain: a * a = aa
cs.enforce(
|| "squaring constraint",
|lc| lc + self.variable,
|lc| lc + self.variable,
|lc| lc + var,
|lc| lc + var
);
Ok(AllocatedNum {
value: value,
variable: var,
variable: var
})
}
pub fn assert_nonzero<CS>(&self, mut cs: CS) -> Result<(), SynthesisError>
where
CS: ConstraintSystem<E>,
pub fn assert_nonzero<CS>(
&self,
mut cs: CS
) -> Result<(), SynthesisError>
where CS: ConstraintSystem<E>
{
let inv = cs.alloc(
|| "ephemeral inverse",
|| {
let tmp = *self.value.get()?;
if tmp.is_zero() {
Err(SynthesisError::DivisionByZero)
} else {
Ok(tmp.inverse().unwrap())
}
},
)?;
let inv = cs.alloc(|| "ephemeral inverse", || {
let tmp = *self.value.get()?;
if tmp.is_zero() {
Err(SynthesisError::DivisionByZero)
} else {
Ok(tmp.inverse().unwrap())
}
})?;
// Constrain a * inv = 1, which is only valid
// iff a has a multiplicative inverse, untrue
@@ -299,7 +338,7 @@ impl<E: Engine> AllocatedNum<E> {
|| "nonzero assertion constraint",
|lc| lc + self.variable,
|lc| lc + inv,
|lc| lc + CS::one(),
|lc| lc + CS::one()
);
Ok(())
@@ -312,39 +351,44 @@ impl<E: Engine> AllocatedNum<E> {
mut cs: CS,
a: &Self,
b: &Self,
condition: &Boolean,
condition: &Boolean
) -> Result<(Self, Self), SynthesisError>
where
CS: ConstraintSystem<E>,
where CS: ConstraintSystem<E>
{
let c = Self::alloc(cs.namespace(|| "conditional reversal result 1"), || {
if *condition.get_value().get()? {
Ok(*b.value.get()?)
} else {
Ok(*a.value.get()?)
let c = Self::alloc(
cs.namespace(|| "conditional reversal result 1"),
|| {
if *condition.get_value().get()? {
Ok(*b.value.get()?)
} else {
Ok(*a.value.get()?)
}
}
})?;
)?;
cs.enforce(
|| "first conditional reversal",
|lc| lc + a.variable - b.variable,
|_| condition.lc(CS::one(), E::Fr::one()),
|lc| lc + a.variable - c.variable,
|lc| lc + a.variable - c.variable
);
let d = Self::alloc(cs.namespace(|| "conditional reversal result 2"), || {
if *condition.get_value().get()? {
Ok(*a.value.get()?)
} else {
Ok(*b.value.get()?)
let d = Self::alloc(
cs.namespace(|| "conditional reversal result 2"),
|| {
if *condition.get_value().get()? {
Ok(*a.value.get()?)
} else {
Ok(*b.value.get()?)
}
}
})?;
)?;
cs.enforce(
|| "second conditional reversal",
|lc| lc + b.variable - a.variable,
|_| condition.lc(CS::one(), E::Fr::one()),
|lc| lc + b.variable - d.variable,
|lc| lc + b.variable - d.variable
);
Ok((c, d))
@@ -361,14 +405,14 @@ impl<E: Engine> AllocatedNum<E> {
pub struct Num<E: Engine> {
value: Option<E::Fr>,
lc: LinearCombination<E>,
lc: LinearCombination<E>
}
impl<E: Engine> From<AllocatedNum<E>> for Num<E> {
fn from(num: AllocatedNum<E>) -> Num<E> {
Num {
value: num.value,
lc: LinearCombination::<E>::zero() + num.variable,
lc: LinearCombination::<E>::zero() + num.variable
}
}
}
@@ -377,7 +421,7 @@ impl<E: Engine> Num<E> {
pub fn zero() -> Self {
Num {
value: Some(E::Fr::zero()),
lc: LinearCombination::zero(),
lc: LinearCombination::zero()
}
}
@@ -389,7 +433,13 @@ impl<E: Engine> Num<E> {
LinearCombination::zero() + (coeff, &self.lc)
}
pub fn add_bool_with_coeff(self, one: Variable, bit: &Boolean, coeff: E::Fr) -> Self {
pub fn add_bool_with_coeff(
self,
one: Variable,
bit: &Boolean,
coeff: E::Fr
) -> Self
{
let newval = match (self.value, bit.get_value()) {
(Some(mut curval), Some(bval)) => {
if bval {
@@ -397,27 +447,25 @@ impl<E: Engine> Num<E> {
}
Some(curval)
}
_ => None,
},
_ => None
};
Num {
value: newval,
lc: self.lc + &bit.lc(one, coeff),
lc: self.lc + &bit.lc(one, coeff)
}
}
}
#[cfg(test)]
mod test {
use crate::ConstraintSystem;
use ff::{BitIterator, Field, PrimeField};
use rand::{SeedableRng, Rand, Rng, XorShiftRng};
use bellman::{ConstraintSystem};
use pairing::bls12_381::{Bls12, Fr};
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use pairing::{Field, PrimeField, BitIterator};
use ::circuit::test::*;
use super::{AllocatedNum, Boolean};
use crate::gadgets::test::*;
#[test]
fn test_allocated_num() {
@@ -446,10 +494,8 @@ mod test {
fn test_num_multiplication() {
let mut cs = TestConstraintSystem::<Bls12>::new();
let n =
AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::from_str("12").unwrap())).unwrap();
let n2 =
AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::from_str("10").unwrap())).unwrap();
let n = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::from_str("12").unwrap())).unwrap();
let n2 = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::from_str("10").unwrap())).unwrap();
let n3 = n.mul(&mut cs, &n2).unwrap();
assert!(cs.is_satisfied());
@@ -461,15 +507,12 @@ mod test {
#[test]
fn test_num_conditional_reversal() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
{
let mut cs = TestConstraintSystem::<Bls12>::new();
let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::random(&mut rng))).unwrap();
let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::random(&mut rng))).unwrap();
let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(rng.gen())).unwrap();
let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(rng.gen())).unwrap();
let condition = Boolean::constant(false);
let (c, d) = AllocatedNum::conditionally_reverse(&mut cs, &a, &b, &condition).unwrap();
@@ -482,8 +525,8 @@ mod test {
{
let mut cs = TestConstraintSystem::<Bls12>::new();
let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(Fr::random(&mut rng))).unwrap();
let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(Fr::random(&mut rng))).unwrap();
let a = AllocatedNum::alloc(cs.namespace(|| "a"), || Ok(rng.gen())).unwrap();
let b = AllocatedNum::alloc(cs.namespace(|| "b"), || Ok(rng.gen())).unwrap();
let condition = Boolean::constant(true);
let (c, d) = AllocatedNum::conditionally_reverse(&mut cs, &a, &b, &condition).unwrap();
@@ -530,21 +573,15 @@ mod test {
cs.set("bit 254/boolean", Fr::one());
// this makes the conditional boolean constraint fail
assert_eq!(
cs.which_is_unsatisfied().unwrap(),
"bit 254/boolean constraint"
);
assert_eq!(cs.which_is_unsatisfied().unwrap(), "bit 254/boolean constraint");
}
#[test]
fn test_into_bits() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for i in 0..200 {
let r = Fr::random(&mut rng);
let r = Fr::rand(&mut rng);
let mut cs = TestConstraintSystem::<Bls12>::new();
let n = AllocatedNum::alloc(&mut cs, || Ok(r)).unwrap();
@@ -557,10 +594,7 @@ mod test {
assert!(cs.is_satisfied());
for (b, a) in BitIterator::new(r.into_repr())
.skip(1)
.zip(bits.iter().rev())
{
for (b, a) in BitIterator::new(r.into_repr()).skip(1).zip(bits.iter().rev()) {
if let &Boolean::Is(ref a) = a {
assert_eq!(b, a.get_value().unwrap());
} else {
@@ -568,7 +602,7 @@ mod test {
}
}
cs.set("num", Fr::random(&mut rng));
cs.set("num", Fr::rand(&mut rng));
assert!(!cs.is_satisfied());
cs.set("num", r);
assert!(cs.is_satisfied());

View File

@@ -0,0 +1,194 @@
use super::*;
use super::ecc::{
MontgomeryPoint,
EdwardsPoint
};
use super::boolean::Boolean;
use ::jubjub::*;
use bellman::{
ConstraintSystem
};
use super::lookup::*;
pub use pedersen_hash::Personalization;
impl Personalization {
fn get_constant_bools(&self) -> Vec<Boolean> {
self.get_bits()
.into_iter()
.map(|e| Boolean::constant(e))
.collect()
}
}
pub fn pedersen_hash<E: JubjubEngine, CS>(
mut cs: CS,
personalization: Personalization,
bits: &[Boolean],
params: &E::Params
) -> Result<EdwardsPoint<E>, SynthesisError>
where CS: ConstraintSystem<E>
{
let personalization = personalization.get_constant_bools();
assert_eq!(personalization.len(), 6);
let mut edwards_result = None;
let mut bits = personalization.iter().chain(bits.iter());
let mut segment_generators = params.pedersen_circuit_generators().iter();
let boolean_false = Boolean::constant(false);
let mut segment_i = 0;
loop {
let mut segment_result = None;
let mut segment_windows = &segment_generators.next()
.expect("enough segments")[..];
let mut window_i = 0;
while let Some(a) = bits.next() {
let b = bits.next().unwrap_or(&boolean_false);
let c = bits.next().unwrap_or(&boolean_false);
let tmp = lookup3_xy_with_conditional_negation(
cs.namespace(|| format!("segment {}, window {}", segment_i, window_i)),
&[a.clone(), b.clone(), c.clone()],
&segment_windows[0]
)?;
let tmp = MontgomeryPoint::interpret_unchecked(tmp.0, tmp.1);
match segment_result {
None => {
segment_result = Some(tmp);
},
Some(ref mut segment_result) => {
*segment_result = tmp.add(
cs.namespace(|| format!("addition of segment {}, window {}", segment_i, window_i)),
segment_result,
params
)?;
}
}
segment_windows = &segment_windows[1..];
if segment_windows.len() == 0 {
break;
}
window_i += 1;
}
match segment_result {
Some(segment_result) => {
// Convert this segment into twisted Edwards form.
let segment_result = segment_result.into_edwards(
cs.namespace(|| format!("conversion of segment {} into edwards", segment_i)),
params
)?;
match edwards_result {
Some(ref mut edwards_result) => {
*edwards_result = segment_result.add(
cs.namespace(|| format!("addition of segment {} to accumulator", segment_i)),
edwards_result,
params
)?;
},
None => {
edwards_result = Some(segment_result);
}
}
},
None => {
// We didn't process any new bits.
break;
}
}
segment_i += 1;
}
Ok(edwards_result.unwrap())
}
#[cfg(test)]
mod test {
use rand::{SeedableRng, Rng, XorShiftRng};
use super::*;
use ::circuit::test::*;
use ::circuit::boolean::{Boolean, AllocatedBit};
use pairing::bls12_381::{Bls12, Fr};
use pairing::PrimeField;
#[test]
fn test_pedersen_hash_constraints() {
let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let params = &JubjubBls12::new();
let mut cs = TestConstraintSystem::<Bls12>::new();
let input: Vec<bool> = (0..(Fr::NUM_BITS * 2)).map(|_| rng.gen()).collect();
let input_bools: Vec<Boolean> = input.iter().enumerate().map(|(i, b)| {
Boolean::from(
AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap()
)
}).collect();
pedersen_hash(
cs.namespace(|| "pedersen hash"),
Personalization::NoteCommitment,
&input_bools,
params
).unwrap();
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 1377);
}
#[test]
fn test_pedersen_hash() {
let mut rng = XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let params = &JubjubBls12::new();
for length in 0..751 {
for _ in 0..5 {
let mut input: Vec<bool> = (0..length).map(|_| rng.gen()).collect();
let mut cs = TestConstraintSystem::<Bls12>::new();
let input_bools: Vec<Boolean> = input.iter().enumerate().map(|(i, b)| {
Boolean::from(
AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)).unwrap()
)
}).collect();
let res = pedersen_hash(
cs.namespace(|| "pedersen hash"),
Personalization::MerkleTree(1),
&input_bools,
params
).unwrap();
assert!(cs.is_satisfied());
let expected = ::pedersen_hash::pedersen_hash::<Bls12, _>(
Personalization::MerkleTree(1),
input.clone().into_iter(),
params
).into_xy();
assert_eq!(res.get_x().get_value().unwrap(), expected.0);
assert_eq!(res.get_y().get_value().unwrap(), expected.1);
// Test against the output of a different personalization
let unexpected = ::pedersen_hash::pedersen_hash::<Bls12, _>(
Personalization::MerkleTree(0),
input.into_iter(),
params
).into_xy();
assert!(res.get_x().get_value().unwrap() != unexpected.0);
assert!(res.get_y().get_value().unwrap() != unexpected.1);
}
}
}
}

View File

@@ -1,22 +1,35 @@
use ff::{Field, PrimeField, PrimeFieldRepr};
use pairing::{
PrimeField,
PrimeFieldRepr,
Field,
};
use bellman::{Circuit, ConstraintSystem, SynthesisError};
use bellman::{
SynthesisError,
ConstraintSystem,
Circuit
};
use zcash_primitives::jubjub::{FixedGenerators, JubjubEngine};
use jubjub::{
JubjubEngine,
FixedGenerators
};
use zcash_primitives::constants;
use constants;
use zcash_primitives::primitives::{PaymentAddress, ProofGenerationKey, ValueCommitment};
use primitives::{
ValueCommitment,
ProofGenerationKey,
PaymentAddress
};
use super::Assignment;
use super::boolean;
use super::ecc;
use super::pedersen_hash;
use bellman::gadgets::blake2s;
use bellman::gadgets::boolean;
use bellman::gadgets::multipack;
use bellman::gadgets::num;
use bellman::gadgets::Assignment;
pub const TREE_DEPTH: usize = zcash_primitives::sapling::SAPLING_COMMITMENT_TREE_DEPTH;
use super::blake2s;
use super::num;
use super::multipack;
/// This is an instance of the `Spend` circuit.
pub struct Spend<'a, E: JubjubEngine> {
@@ -43,7 +56,7 @@ pub struct Spend<'a, E: JubjubEngine> {
/// The anchor; the root of the tree. If the note being
/// spent is zero-value, this can be anything.
pub anchor: Option<E::Fr>,
pub anchor: Option<E::Fr>
}
/// This is an output circuit instance.
@@ -60,7 +73,7 @@ pub struct Output<'a, E: JubjubEngine> {
pub commitment_randomness: Option<E::Fs>,
/// The ephemeral secret key for DH with recipient
pub esk: Option<E::Fs>,
pub esk: Option<E::Fs>
}
/// Exposes a Pedersen commitment to the value as an
@@ -68,16 +81,15 @@ pub struct Output<'a, E: JubjubEngine> {
fn expose_value_commitment<E, CS>(
mut cs: CS,
value_commitment: Option<ValueCommitment<E>>,
params: &E::Params,
params: &E::Params
) -> Result<Vec<boolean::Boolean>, SynthesisError>
where
E: JubjubEngine,
CS: ConstraintSystem<E>,
where E: JubjubEngine,
CS: ConstraintSystem<E>
{
// Booleanize the value into little-endian bit order
let value_bits = boolean::u64_into_boolean_vec_le(
cs.namespace(|| "value"),
value_commitment.as_ref().map(|c| c.value),
value_commitment.as_ref().map(|c| c.value)
)?;
// Compute the note value in the exponent
@@ -85,7 +97,7 @@ where
cs.namespace(|| "compute the value in the exponent"),
FixedGenerators::ValueCommitmentValue,
&value_bits,
params,
params
)?;
// Booleanize the randomness. This does not ensure
@@ -93,7 +105,7 @@ where
// it doesn't matter for security.
let rcv = boolean::field_into_boolean_vec_le(
cs.namespace(|| "rcv"),
value_commitment.as_ref().map(|c| c.randomness),
value_commitment.as_ref().map(|c| c.randomness)
)?;
// Compute the randomness in the exponent
@@ -101,11 +113,15 @@ where
cs.namespace(|| "computation of rcv"),
FixedGenerators::ValueCommitmentRandomness,
&rcv,
params,
params
)?;
// Compute the Pedersen commitment to the value
let cv = value.add(cs.namespace(|| "computation of cv"), &rcv, params)?;
let cv = value.add(
cs.namespace(|| "computation of cv"),
&rcv,
params
)?;
// Expose the commitment as an input to the circuit
cv.inputize(cs.namespace(|| "commitment point"))?;
@@ -114,32 +130,43 @@ where
}
impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError>
{
// Prover witnesses ak (ensures that it's on the curve)
let ak = ecc::EdwardsPoint::witness(
cs.namespace(|| "ak"),
self.proof_generation_key.as_ref().map(|k| k.ak.clone()),
self.params,
self.params
)?;
// There are no sensible attacks on small order points
// of ak (that we're aware of!) but it's a cheap check,
// so we do it.
ak.assert_not_small_order(cs.namespace(|| "ak not small order"), self.params)?;
ak.assert_not_small_order(
cs.namespace(|| "ak not small order"),
self.params
)?;
// Rerandomize ak and expose it as an input to the circuit
{
let ar = boolean::field_into_boolean_vec_le(cs.namespace(|| "ar"), self.ar)?;
let ar = boolean::field_into_boolean_vec_le(
cs.namespace(|| "ar"),
self.ar
)?;
// Compute the randomness in the exponent
let ar = ecc::fixed_base_multiplication(
cs.namespace(|| "computation of randomization for the signing key"),
FixedGenerators::SpendingKeyGenerator,
&ar,
self.params,
self.params
)?;
let rk = ak.add(cs.namespace(|| "computation of rk"), &ar, self.params)?;
let rk = ak.add(
cs.namespace(|| "computation of rk"),
&ar,
self.params
)?;
rk.inputize(cs.namespace(|| "rk"))?;
}
@@ -150,7 +177,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
// Witness nsk as bits
let nsk = boolean::field_into_boolean_vec_le(
cs.namespace(|| "nsk"),
self.proof_generation_key.as_ref().map(|k| k.nsk.clone()),
self.proof_generation_key.as_ref().map(|k| k.nsk.clone())
)?;
// NB: We don't ensure that the bit representation of nsk
@@ -163,7 +190,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
cs.namespace(|| "computation of nk"),
FixedGenerators::ProofGenerationKey,
&nsk,
self.params,
self.params
)?;
}
@@ -171,7 +198,9 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
let mut ivk_preimage = vec![];
// Place ak in the preimage for CRH^ivk
ivk_preimage.extend(ak.repr(cs.namespace(|| "representation of ak"))?);
ivk_preimage.extend(
ak.repr(cs.namespace(|| "representation of ak"))?
);
// This is the nullifier preimage for PRF^nf
let mut nf_preimage = vec![];
@@ -179,7 +208,9 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
// Extend ivk and nf preimages with the representation of
// nk.
{
let repr_nk = nk.repr(cs.namespace(|| "representation of nk"))?;
let repr_nk = nk.repr(
cs.namespace(|| "representation of nk")
)?;
ivk_preimage.extend(repr_nk.iter().cloned());
nf_preimage.extend(repr_nk);
@@ -192,7 +223,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
let mut ivk = blake2s::blake2s(
cs.namespace(|| "computation of ivk"),
&ivk_preimage,
constants::CRH_IVK_PERSONALIZATION,
constants::CRH_IVK_PERSONALIZATION
)?;
// drop_5 to ensure it's in the field
@@ -210,7 +241,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
ecc::EdwardsPoint::witness(
cs.namespace(|| "witness g_d"),
self.payment_address.as_ref().and_then(|a| a.g_d(params)),
self.params,
self.params
)?
};
@@ -218,10 +249,17 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
// is already done in the Output circuit, and this proof ensures
// g_d is bound to a product of that check, but for defense in
// depth let's check it anyway. It's cheap.
g_d.assert_not_small_order(cs.namespace(|| "g_d not small order"), self.params)?;
g_d.assert_not_small_order(
cs.namespace(|| "g_d not small order"),
self.params
)?;
// Compute pk_d = g_d^ivk
let pk_d = g_d.mul(cs.namespace(|| "compute pk_d"), &ivk, self.params)?;
let pk_d = g_d.mul(
cs.namespace(|| "compute pk_d"),
&ivk,
self.params
)?;
// Compute note contents:
// value (in big endian) followed by g_d and pk_d
@@ -235,14 +273,18 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
let value_bits = expose_value_commitment(
cs.namespace(|| "value commitment"),
self.value_commitment,
self.params,
self.params
)?;
// Compute the note's value as a linear combination
// of the bits.
let mut coeff = E::Fr::one();
for bit in &value_bits {
value_num = value_num.add_bool_with_coeff(CS::one(), bit, coeff);
value_num = value_num.add_bool_with_coeff(
CS::one(),
bit,
coeff
);
coeff.double();
}
@@ -251,10 +293,14 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
}
// Place g_d in the note
note_contents.extend(g_d.repr(cs.namespace(|| "representation of g_d"))?);
note_contents.extend(
g_d.repr(cs.namespace(|| "representation of g_d"))?
);
// Place pk_d in the note
note_contents.extend(pk_d.repr(cs.namespace(|| "representation of pk_d"))?);
note_contents.extend(
pk_d.repr(cs.namespace(|| "representation of pk_d"))?
);
assert_eq!(
note_contents.len(),
@@ -268,14 +314,14 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
cs.namespace(|| "note content hash"),
pedersen_hash::Personalization::NoteCommitment,
&note_contents,
self.params,
self.params
)?;
{
// Booleanize the randomness for the note commitment
let rcm = boolean::field_into_boolean_vec_le(
cs.namespace(|| "rcm"),
self.commitment_randomness,
self.commitment_randomness
)?;
// Compute the note commitment randomness in the exponent
@@ -283,7 +329,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
cs.namespace(|| "computation of commitment randomness"),
FixedGenerators::NoteCommitmentRandomness,
&rcm,
self.params,
self.params
)?;
// Randomize the note commitment. Pedersen hashes are not
@@ -291,7 +337,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
cm = cm.add(
cs.namespace(|| "randomization of note commitment"),
&rcm,
self.params,
self.params
)?;
}
@@ -312,7 +358,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
// depth of the tree.
let cur_is_right = boolean::Boolean::from(boolean::AllocatedBit::alloc(
cs.namespace(|| "position bit"),
e.map(|e| e.1),
e.map(|e| e.1)
)?);
// Push this boolean for nullifier computation later
@@ -320,15 +366,19 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
// Witness the authentication path element adjacent
// at this depth.
let path_element =
num::AllocatedNum::alloc(cs.namespace(|| "path element"), || Ok(e.get()?.0))?;
let path_element = num::AllocatedNum::alloc(
cs.namespace(|| "path element"),
|| {
Ok(e.get()?.0)
}
)?;
// Swap the two if the current subtree is on the right
let (xl, xr) = num::AllocatedNum::conditionally_reverse(
cs.namespace(|| "conditional reversal of preimage"),
&cur,
&path_element,
&cur_is_right,
&cur_is_right
)?;
// We don't need to be strict, because the function is
@@ -344,19 +394,20 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
cs.namespace(|| "computation of pedersen hash"),
pedersen_hash::Personalization::MerkleTree(i),
&preimage,
self.params,
)?
.get_x()
.clone(); // Injective encoding
self.params
)?.get_x().clone(); // Injective encoding
}
{
let real_anchor_value = self.anchor;
// Allocate the "real" anchor that will be exposed.
let rt = num::AllocatedNum::alloc(cs.namespace(|| "conditional anchor"), || {
Ok(*real_anchor_value.get()?)
})?;
let rt = num::AllocatedNum::alloc(
cs.namespace(|| "conditional anchor"),
|| {
Ok(*real_anchor_value.get()?)
}
)?;
// (cur - rt) * value = 0
// if value is zero, cur and rt can be different
@@ -365,7 +416,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
|| "conditionally enforce correct root",
|lc| lc + cur.get_variable() - rt.get_variable(),
|lc| lc + &value_num.lc(E::Fr::one()),
|lc| lc,
|lc| lc
);
// Expose the anchor
@@ -381,27 +432,29 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
cs.namespace(|| "g^position"),
FixedGenerators::NullifierPosition,
&position_bits,
self.params,
self.params
)?;
// Add the position to the commitment
rho = rho.add(
cs.namespace(|| "faerie gold prevention"),
&position,
self.params,
self.params
)?;
}
// Let's compute nf = BLAKE2s(nk || rho)
nf_preimage.extend(rho.repr(cs.namespace(|| "representation of rho"))?);
nf_preimage.extend(
rho.repr(cs.namespace(|| "representation of rho"))?
);
assert_eq!(nf_preimage.len(), 512);
// Compute nf
let nf = blake2s::blake2s(
cs.namespace(|| "nf computation"),
&nf_preimage,
constants::PRF_NF_PERSONALIZATION,
constants::PRF_NF_PERSONALIZATION
)?;
multipack::pack_into_inputs(cs.namespace(|| "pack nullifier"), &nf)
@@ -409,7 +462,8 @@ impl<'a, E: JubjubEngine> Circuit<E> for Spend<'a, E> {
}
impl<'a, E: JubjubEngine> Circuit<E> for Output<'a, E> {
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError>
{
// Let's start to construct our note, which contains
// value (big endian)
let mut note_contents = vec![];
@@ -419,7 +473,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Output<'a, E> {
note_contents.extend(expose_value_commitment(
cs.namespace(|| "value commitment"),
self.value_commitment,
self.params,
self.params
)?);
// Let's deal with g_d
@@ -431,7 +485,7 @@ impl<'a, E: JubjubEngine> Circuit<E> for Output<'a, E> {
let g_d = ecc::EdwardsPoint::witness(
cs.namespace(|| "witness g_d"),
self.payment_address.as_ref().and_then(|a| a.g_d(params)),
self.params,
self.params
)?;
// g_d is ensured to be large order. The relationship
@@ -443,17 +497,29 @@ impl<'a, E: JubjubEngine> Circuit<E> for Output<'a, E> {
//
// Further, if it were small order, epk would be
// small order too!
g_d.assert_not_small_order(cs.namespace(|| "g_d not small order"), self.params)?;
g_d.assert_not_small_order(
cs.namespace(|| "g_d not small order"),
self.params
)?;
// Extend our note contents with the representation of
// g_d.
note_contents.extend(g_d.repr(cs.namespace(|| "representation of g_d"))?);
note_contents.extend(
g_d.repr(cs.namespace(|| "representation of g_d"))?
);
// Booleanize our ephemeral secret key
let esk = boolean::field_into_boolean_vec_le(cs.namespace(|| "esk"), self.esk)?;
let esk = boolean::field_into_boolean_vec_le(
cs.namespace(|| "esk"),
self.esk
)?;
// Create the ephemeral public key from g_d.
let epk = g_d.mul(cs.namespace(|| "epk computation"), &esk, self.params)?;
let epk = g_d.mul(
cs.namespace(|| "epk computation"),
&esk,
self.params
)?;
// Expose epk publicly.
epk.inputize(cs.namespace(|| "epk"))?;
@@ -470,13 +536,13 @@ impl<'a, E: JubjubEngine> Circuit<E> for Output<'a, E> {
// endian bits (to match the representation)
let y_contents = boolean::field_into_boolean_vec_le(
cs.namespace(|| "pk_d bits of y"),
pk_d.map(|e| e.1),
pk_d.map(|e| e.1)
)?;
// Witness the sign bit
let sign_bit = boolean::Boolean::from(boolean::AllocatedBit::alloc(
cs.namespace(|| "pk_d bit of x"),
pk_d.map(|e| e.0.into_repr().is_odd()),
pk_d.map(|e| e.0.into_repr().is_odd())
)?);
// Extend the note with pk_d representation
@@ -496,14 +562,14 @@ impl<'a, E: JubjubEngine> Circuit<E> for Output<'a, E> {
cs.namespace(|| "note content hash"),
pedersen_hash::Personalization::NoteCommitment,
&note_contents,
self.params,
self.params
)?;
{
// Booleanize the randomness
let rcm = boolean::field_into_boolean_vec_le(
cs.namespace(|| "rcm"),
self.commitment_randomness,
self.commitment_randomness
)?;
// Compute the note commitment randomness in the exponent
@@ -511,14 +577,14 @@ impl<'a, E: JubjubEngine> Circuit<E> for Output<'a, E> {
cs.namespace(|| "computation of commitment randomness"),
FixedGenerators::NoteCommitmentRandomness,
&rcm,
self.params,
self.params
)?;
// Randomize our note commitment
cm = cm.add(
cs.namespace(|| "randomization of note commitment"),
&rcm,
self.params,
self.params
)?;
}
@@ -534,37 +600,29 @@ impl<'a, E: JubjubEngine> Circuit<E> for Output<'a, E> {
#[test]
fn test_input_circuit_with_bls12_381() {
use bellman::gadgets::test::*;
use ff::{BitIterator, Field};
use pairing::{Field, BitIterator};
use pairing::bls12_381::*;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
use zcash_primitives::{
jubjub::{edwards, fs, JubjubBls12},
pedersen_hash,
primitives::{Diversifier, Note, ProofGenerationKey},
};
use rand::{SeedableRng, Rng, XorShiftRng};
use ::circuit::test::*;
use jubjub::{JubjubBls12, fs, edwards};
let params = &JubjubBls12::new();
let rng = &mut XorShiftRng::from_seed([
0x58, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let tree_depth = 32;
for _ in 0..10 {
let value_commitment = ValueCommitment {
value: rng.next_u64(),
randomness: fs::Fs::random(rng),
value: rng.gen(),
randomness: rng.gen()
};
let nsk = fs::Fs::random(rng);
let nsk: fs::Fs = rng.gen();
let ak = edwards::Point::rand(rng, params).mul_by_cofactor(params);
let proof_generation_key = ProofGenerationKey {
let proof_generation_key = ::primitives::ProofGenerationKey {
ak: ak.clone(),
nsk: nsk.clone(),
nsk: nsk.clone()
};
let viewing_key = proof_generation_key.into_viewing_key(params);
@@ -572,38 +630,39 @@ fn test_input_circuit_with_bls12_381() {
let payment_address;
loop {
let diversifier = {
let mut d = [0; 11];
rng.fill_bytes(&mut d);
Diversifier(d)
};
let diversifier = ::primitives::Diversifier(rng.gen());
if let Some(p) = viewing_key.into_payment_address(diversifier, params) {
if let Some(p) = viewing_key.into_payment_address(
diversifier,
params
)
{
payment_address = p;
break;
}
}
let g_d = payment_address.diversifier.g_d(params).unwrap();
let commitment_randomness = fs::Fs::random(rng);
let auth_path = vec![Some((Fr::random(rng), rng.next_u32() % 2 != 0)); tree_depth];
let ar = fs::Fs::random(rng);
let commitment_randomness: fs::Fs = rng.gen();
let auth_path = vec![Some((rng.gen(), rng.gen())); tree_depth];
let ar: fs::Fs = rng.gen();
{
let rk = viewing_key.rk(ar, params).into_xy();
let expected_value_cm = value_commitment.cm(params).into_xy();
let note = Note {
let note = ::primitives::Note {
value: value_commitment.value,
g_d: g_d.clone(),
pk_d: payment_address.pk_d.clone(),
r: commitment_randomness.clone(),
r: commitment_randomness.clone()
};
let mut position = 0u64;
let cm: Fr = note.cm(params);
let mut cur = cm.clone();
for (i, val) in auth_path.clone().into_iter().enumerate() {
for (i, val) in auth_path.clone().into_iter().enumerate()
{
let (uncle, b) = val.unwrap();
let mut lhs = cur;
@@ -619,15 +678,13 @@ fn test_input_circuit_with_bls12_381() {
lhs.reverse();
rhs.reverse();
cur = pedersen_hash::pedersen_hash::<Bls12, _>(
pedersen_hash::Personalization::MerkleTree(i),
cur = ::pedersen_hash::pedersen_hash::<Bls12, _>(
::pedersen_hash::Personalization::MerkleTree(i),
lhs.into_iter()
.take(Fr::NUM_BITS as usize)
.chain(rhs.into_iter().take(Fr::NUM_BITS as usize)),
params,
)
.into_xy()
.0;
.take(Fr::NUM_BITS as usize)
.chain(rhs.into_iter().take(Fr::NUM_BITS as usize)),
params
).into_xy().0;
if b {
position |= 1 << i;
@@ -649,17 +706,14 @@ fn test_input_circuit_with_bls12_381() {
commitment_randomness: Some(commitment_randomness),
ar: Some(ar),
auth_path: auth_path.clone(),
anchor: Some(cur),
anchor: Some(cur)
};
instance.synthesize(&mut cs).unwrap();
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 98777);
assert_eq!(
cs.hash(),
"d37c738e83df5d9b0bb6495ac96abf21bcb2697477e2c15c2c7916ff7a3b6a89"
);
assert_eq!(cs.hash(), "d37c738e83df5d9b0bb6495ac96abf21bcb2697477e2c15c2c7916ff7a3b6a89");
assert_eq!(cs.get("randomization of note commitment/x3/num"), cm);
@@ -667,14 +721,8 @@ fn test_input_circuit_with_bls12_381() {
assert_eq!(cs.get_input(0, "ONE"), Fr::one());
assert_eq!(cs.get_input(1, "rk/x/input variable"), rk.0);
assert_eq!(cs.get_input(2, "rk/y/input variable"), rk.1);
assert_eq!(
cs.get_input(3, "value commitment/commitment point/x/input variable"),
expected_value_cm.0
);
assert_eq!(
cs.get_input(4, "value commitment/commitment point/y/input variable"),
expected_value_cm.1
);
assert_eq!(cs.get_input(3, "value commitment/commitment point/x/input variable"), expected_value_cm.0);
assert_eq!(cs.get_input(4, "value commitment/commitment point/y/input variable"), expected_value_cm.1);
assert_eq!(cs.get_input(5, "anchor/input variable"), cur);
assert_eq!(cs.get_input(6, "pack nullifier/input 0"), expected_nf[0]);
assert_eq!(cs.get_input(7, "pack nullifier/input 1"), expected_nf[1]);
@@ -684,34 +732,27 @@ fn test_input_circuit_with_bls12_381() {
#[test]
fn test_output_circuit_with_bls12_381() {
use bellman::gadgets::test::*;
use ff::Field;
use pairing::{Field};
use pairing::bls12_381::*;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
use zcash_primitives::{
jubjub::{edwards, fs, JubjubBls12},
primitives::{Diversifier, ProofGenerationKey},
};
use rand::{SeedableRng, Rng, XorShiftRng};
use ::circuit::test::*;
use jubjub::{JubjubBls12, fs, edwards};
let params = &JubjubBls12::new();
let rng = &mut XorShiftRng::from_seed([
0x58, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let rng = &mut XorShiftRng::from_seed([0x3dbe6258, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..100 {
let value_commitment = ValueCommitment {
value: rng.next_u64(),
randomness: fs::Fs::random(rng),
value: rng.gen(),
randomness: rng.gen()
};
let nsk = fs::Fs::random(rng);
let nsk: fs::Fs = rng.gen();
let ak = edwards::Point::rand(rng, params).mul_by_cofactor(params);
let proof_generation_key = ProofGenerationKey {
let proof_generation_key = ::primitives::ProofGenerationKey {
ak: ak.clone(),
nsk: nsk.clone(),
nsk: nsk.clone()
};
let viewing_key = proof_generation_key.into_viewing_key(params);
@@ -719,20 +760,20 @@ fn test_output_circuit_with_bls12_381() {
let payment_address;
loop {
let diversifier = {
let mut d = [0; 11];
rng.fill_bytes(&mut d);
Diversifier(d)
};
let diversifier = ::primitives::Diversifier(rng.gen());
if let Some(p) = viewing_key.into_payment_address(diversifier, params) {
if let Some(p) = viewing_key.into_payment_address(
diversifier,
params
)
{
payment_address = p;
break;
}
}
let commitment_randomness = fs::Fs::random(rng);
let esk = fs::Fs::random(rng);
let commitment_randomness: fs::Fs = rng.gen();
let esk: fs::Fs = rng.gen();
{
let mut cs = TestConstraintSystem::<Bls12>::new();
@@ -742,41 +783,30 @@ fn test_output_circuit_with_bls12_381() {
value_commitment: Some(value_commitment.clone()),
payment_address: Some(payment_address.clone()),
commitment_randomness: Some(commitment_randomness),
esk: Some(esk.clone()),
esk: Some(esk.clone())
};
instance.synthesize(&mut cs).unwrap();
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 7827);
assert_eq!(
cs.hash(),
"c26d5cdfe6ccd65c03390902c02e11393ea6bb96aae32a7f2ecb12eb9103faee"
);
assert_eq!(cs.hash(), "c26d5cdfe6ccd65c03390902c02e11393ea6bb96aae32a7f2ecb12eb9103faee");
let expected_cm = payment_address
.create_note(value_commitment.value, commitment_randomness, params)
.expect("should be valid")
.cm(params);
let expected_cm = payment_address.create_note(
value_commitment.value,
commitment_randomness,
params
).expect("should be valid").cm(params);
let expected_value_cm = value_commitment.cm(params).into_xy();
let expected_epk = payment_address
.g_d(params)
.expect("should be valid")
.mul(esk, params);
let expected_epk = payment_address.g_d(params).expect("should be valid").mul(esk, params);
let expected_epk_xy = expected_epk.into_xy();
assert_eq!(cs.num_inputs(), 6);
assert_eq!(cs.get_input(0, "ONE"), Fr::one());
assert_eq!(
cs.get_input(1, "value commitment/commitment point/x/input variable"),
expected_value_cm.0
);
assert_eq!(
cs.get_input(2, "value commitment/commitment point/y/input variable"),
expected_value_cm.1
);
assert_eq!(cs.get_input(1, "value commitment/commitment point/x/input variable"), expected_value_cm.0);
assert_eq!(cs.get_input(2, "value commitment/commitment point/y/input variable"), expected_value_cm.1);
assert_eq!(cs.get_input(3, "epk/x/input variable"), expected_epk_xy.0);
assert_eq!(cs.get_input(4, "epk/y/input variable"), expected_epk_xy.1);
assert_eq!(cs.get_input(5, "commitment/input variable"), expected_cm);

View File

@@ -1,7 +1,7 @@
use super::boolean::Boolean;
use super::multieq::MultiEq;
use super::uint32::UInt32;
use crate::{ConstraintSystem, SynthesisError};
use super::multieq::MultiEq;
use super::boolean::Boolean;
use bellman::{ConstraintSystem, SynthesisError};
use pairing::Engine;
const ROUND_CONSTANTS: [u32; 64] = [
@@ -12,35 +12,37 @@ const ROUND_CONSTANTS: [u32; 64] = [
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
];
const IV: [u32; 8] = [
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
];
pub fn sha256_block_no_padding<E, CS>(
mut cs: CS,
input: &[Boolean],
input: &[Boolean]
) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
where E: Engine, CS: ConstraintSystem<E>
{
assert_eq!(input.len(), 512);
Ok(
sha256_compression_function(&mut cs, &input, &get_sha256_iv())?
.into_iter()
.flat_map(|e| e.into_bits_be())
.collect(),
)
Ok(sha256_compression_function(
&mut cs,
&input,
&get_sha256_iv()
)?
.into_iter()
.flat_map(|e| e.into_bits_be())
.collect())
}
pub fn sha256<E, CS>(mut cs: CS, input: &[Boolean]) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
pub fn sha256<E, CS>(
mut cs: CS,
input: &[Boolean]
) -> Result<Vec<Boolean>, SynthesisError>
where E: Engine, CS: ConstraintSystem<E>
{
assert!(input.len() % 8 == 0);
@@ -60,10 +62,16 @@ where
let mut cur = get_sha256_iv();
for (i, block) in padded.chunks(512).enumerate() {
cur = sha256_compression_function(cs.namespace(|| format!("block {}", i)), block, &cur)?;
cur = sha256_compression_function(
cs.namespace(|| format!("block {}", i)),
block,
&cur
)?;
}
Ok(cur.into_iter().flat_map(|e| e.into_bits_be()).collect())
Ok(cur.into_iter()
.flat_map(|e| e.into_bits_be())
.collect())
}
fn get_sha256_iv() -> Vec<UInt32> {
@@ -73,19 +81,16 @@ fn get_sha256_iv() -> Vec<UInt32> {
fn sha256_compression_function<E, CS>(
cs: CS,
input: &[Boolean],
current_hash_value: &[UInt32],
current_hash_value: &[UInt32]
) -> Result<Vec<UInt32>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
where E: Engine, CS: ConstraintSystem<E>
{
assert_eq!(input.len(), 512);
assert_eq!(current_hash_value.len(), 8);
let mut w = input
.chunks(32)
.map(|e| UInt32::from_bits_be(e))
.collect::<Vec<_>>();
let mut w = input.chunks(32)
.map(|e| UInt32::from_bits_be(e))
.collect::<Vec<_>>();
// We can save some constraints by combining some of
// the constraints in different u32 additions
@@ -95,18 +100,30 @@ where
let cs = &mut cs.namespace(|| format!("w extension {}", i));
// s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor (w[i-15] rightshift 3)
let mut s0 = w[i - 15].rotr(7);
s0 = s0.xor(cs.namespace(|| "first xor for s0"), &w[i - 15].rotr(18))?;
s0 = s0.xor(cs.namespace(|| "second xor for s0"), &w[i - 15].shr(3))?;
let mut s0 = w[i-15].rotr(7);
s0 = s0.xor(
cs.namespace(|| "first xor for s0"),
&w[i-15].rotr(18)
)?;
s0 = s0.xor(
cs.namespace(|| "second xor for s0"),
&w[i-15].shr(3)
)?;
// s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor (w[i-2] rightshift 10)
let mut s1 = w[i - 2].rotr(17);
s1 = s1.xor(cs.namespace(|| "first xor for s1"), &w[i - 2].rotr(19))?;
s1 = s1.xor(cs.namespace(|| "second xor for s1"), &w[i - 2].shr(10))?;
let mut s1 = w[i-2].rotr(17);
s1 = s1.xor(
cs.namespace(|| "first xor for s1"),
&w[i-2].rotr(19)
)?;
s1 = s1.xor(
cs.namespace(|| "second xor for s1"),
&w[i-2].shr(10)
)?;
let tmp = UInt32::addmany(
cs.namespace(|| "computation of w[i]"),
&[w[i - 16].clone(), s0, w[i - 7].clone(), s1],
&[w[i-16].clone(), s0, w[i-7].clone(), s1]
)?;
// w[i] := w[i-16] + s0 + w[i-7] + s1
@@ -117,21 +134,29 @@ where
enum Maybe {
Deferred(Vec<UInt32>),
Concrete(UInt32),
Concrete(UInt32)
}
impl Maybe {
fn compute<E, CS, M>(self, cs: M, others: &[UInt32]) -> Result<UInt32, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
M: ConstraintSystem<E, Root = MultiEq<E, CS>>,
fn compute<E, CS, M>(
self,
cs: M,
others: &[UInt32]
) -> Result<UInt32, SynthesisError>
where E: Engine,
CS: ConstraintSystem<E>,
M: ConstraintSystem<E, Root=MultiEq<E, CS>>
{
Ok(match self {
Maybe::Concrete(ref v) => return Ok(v.clone()),
Maybe::Concrete(ref v) => {
return Ok(v.clone())
},
Maybe::Deferred(mut v) => {
v.extend(others.into_iter().cloned());
UInt32::addmany(cs, &v)?
UInt32::addmany(
cs,
&v
)?
}
})
}
@@ -152,11 +177,22 @@ where
// S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)
let new_e = e.compute(cs.namespace(|| "deferred e computation"), &[])?;
let mut s1 = new_e.rotr(6);
s1 = s1.xor(cs.namespace(|| "first xor for s1"), &new_e.rotr(11))?;
s1 = s1.xor(cs.namespace(|| "second xor for s1"), &new_e.rotr(25))?;
s1 = s1.xor(
cs.namespace(|| "first xor for s1"),
&new_e.rotr(11)
)?;
s1 = s1.xor(
cs.namespace(|| "second xor for s1"),
&new_e.rotr(25)
)?;
// ch := (e and f) xor ((not e) and g)
let ch = UInt32::sha256_ch(cs.namespace(|| "ch"), &new_e, &f, &g)?;
let ch = UInt32::sha256_ch(
cs.namespace(|| "ch"),
&new_e,
&f,
&g
)?;
// temp1 := h + S1 + ch + k[i] + w[i]
let temp1 = vec![
@@ -164,17 +200,28 @@ where
s1,
ch,
UInt32::constant(ROUND_CONSTANTS[i]),
w[i].clone(),
w[i].clone()
];
// S0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)
let new_a = a.compute(cs.namespace(|| "deferred a computation"), &[])?;
let mut s0 = new_a.rotr(2);
s0 = s0.xor(cs.namespace(|| "first xor for s0"), &new_a.rotr(13))?;
s0 = s0.xor(cs.namespace(|| "second xor for s0"), &new_a.rotr(22))?;
s0 = s0.xor(
cs.namespace(|| "first xor for s0"),
&new_a.rotr(13)
)?;
s0 = s0.xor(
cs.namespace(|| "second xor for s0"),
&new_a.rotr(22)
)?;
// maj := (a and b) xor (a and c) xor (b and c)
let maj = UInt32::sha256_maj(cs.namespace(|| "maj"), &new_a, &b, &c)?;
let maj = UInt32::sha256_maj(
cs.namespace(|| "maj"),
&new_a,
&b,
&c
)?;
// temp2 := S0 + maj
let temp2 = vec![s0, maj];
@@ -197,13 +244,7 @@ where
d = c;
c = b;
b = new_a;
a = Maybe::Deferred(
temp1
.iter()
.cloned()
.chain(temp2.iter().cloned())
.collect::<Vec<_>>(),
);
a = Maybe::Deferred(temp1.iter().cloned().chain(temp2.iter().cloned()).collect::<Vec<_>>());
}
/*
@@ -220,42 +261,42 @@ where
let h0 = a.compute(
cs.namespace(|| "deferred h0 computation"),
&[current_hash_value[0].clone()],
&[current_hash_value[0].clone()]
)?;
let h1 = UInt32::addmany(
cs.namespace(|| "new h1"),
&[current_hash_value[1].clone(), b],
&[current_hash_value[1].clone(), b]
)?;
let h2 = UInt32::addmany(
cs.namespace(|| "new h2"),
&[current_hash_value[2].clone(), c],
&[current_hash_value[2].clone(), c]
)?;
let h3 = UInt32::addmany(
cs.namespace(|| "new h3"),
&[current_hash_value[3].clone(), d],
&[current_hash_value[3].clone(), d]
)?;
let h4 = e.compute(
cs.namespace(|| "deferred h4 computation"),
&[current_hash_value[4].clone()],
&[current_hash_value[4].clone()]
)?;
let h5 = UInt32::addmany(
cs.namespace(|| "new h5"),
&[current_hash_value[5].clone(), f],
&[current_hash_value[5].clone(), f]
)?;
let h6 = UInt32::addmany(
cs.namespace(|| "new h6"),
&[current_hash_value[6].clone(), g],
&[current_hash_value[6].clone(), g]
)?;
let h7 = UInt32::addmany(
cs.namespace(|| "new h7"),
&[current_hash_value[7].clone(), h],
&[current_hash_value[7].clone(), h]
)?;
Ok(vec![h0, h1, h2, h3, h4, h5, h6, h7])
@@ -264,11 +305,10 @@ where
#[cfg(test)]
mod test {
use super::*;
use crate::gadgets::boolean::AllocatedBit;
use crate::gadgets::test::TestConstraintSystem;
use circuit::boolean::AllocatedBit;
use pairing::bls12_381::Bls12;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
use circuit::test::TestConstraintSystem;
use rand::{XorShiftRng, SeedableRng, Rng};
#[test]
fn test_blank_hash() {
@@ -277,7 +317,11 @@ mod test {
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut input_bits: Vec<_> = (0..512).map(|_| Boolean::Constant(false)).collect();
input_bits[0] = Boolean::Constant(true);
let out = sha256_compression_function(&mut cs, &input_bits, &iv).unwrap();
let out = sha256_compression_function(
&mut cs,
&input_bits,
&iv
).unwrap();
let out_bits: Vec<_> = out.into_iter().flat_map(|e| e.into_bits_be()).collect();
assert!(cs.is_satisfied());
@@ -297,27 +341,25 @@ mod test {
#[test]
fn test_full_block() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let iv = get_sha256_iv();
let mut cs = TestConstraintSystem::<Bls12>::new();
let input_bits: Vec<_> = (0..512)
.map(|i| {
Boolean::from(
AllocatedBit::alloc(
cs.namespace(|| format!("input bit {}", i)),
Some(rng.next_u32() % 2 != 0),
)
.unwrap(),
)
})
.collect();
let input_bits: Vec<_> = (0..512).map(|i| {
Boolean::from(
AllocatedBit::alloc(
cs.namespace(|| format!("input bit {}", i)),
Some(rng.gen())
).unwrap()
)
}).collect();
sha256_compression_function(cs.namespace(|| "sha256"), &input_bits, &iv).unwrap();
sha256_compression_function(
cs.namespace(|| "sha256"),
&input_bits,
&iv
).unwrap();
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints() - 512, 25840);
@@ -325,18 +367,18 @@ mod test {
#[test]
fn test_against_vectors() {
use sha2::{Digest, Sha256};
use crypto::sha2::Sha256;
use crypto::digest::Digest;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) {
for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0))
{
let mut h = Sha256::new();
let data: Vec<u8> = (0..input_len).map(|_| rng.next_u32() as u8).collect();
let data: Vec<u8> = (0..input_len).map(|_| rng.gen()).collect();
h.input(&data);
let hash_result = h.result();
let mut hash_result = [0u8; 32];
h.result(&mut hash_result[..]);
let mut cs = TestConstraintSystem::<Bls12>::new();
let mut input_bits = vec![];
@@ -345,11 +387,7 @@ mod test {
for bit_i in (0..8).rev() {
let cs = cs.namespace(|| format!("input bit {} {}", byte_i, bit_i));
input_bits.push(
AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8))
.unwrap()
.into(),
);
input_bits.push(AllocatedBit::alloc(cs, Some((input_byte >> bit_i) & 1u8 == 1u8)).unwrap().into());
}
}
@@ -357,19 +395,17 @@ mod test {
assert!(cs.is_satisfied());
let mut s = hash_result
.as_ref()
.iter()
.flat_map(|&byte| (0..8).rev().map(move |i| (byte >> i) & 1u8 == 1u8));
let mut s = hash_result.as_ref().iter()
.flat_map(|&byte| (0..8).rev().map(move |i| (byte >> i) & 1u8 == 1u8));
for b in r {
match b {
Boolean::Is(b) => {
assert!(s.next().unwrap() == b.get_value().unwrap());
}
},
Boolean::Not(b) => {
assert!(s.next().unwrap() != b.get_value().unwrap());
}
},
Boolean::Constant(b) => {
assert!(input_len == 0);
assert!(s.next().unwrap() == b);

View File

@@ -1,18 +1,20 @@
use bellman::gadgets::boolean::Boolean;
use bellman::gadgets::sha256::sha256;
use pairing::{Engine};
use bellman::{ConstraintSystem, SynthesisError};
use pairing::Engine;
use circuit::sha256::{
sha256
};
use circuit::boolean::{
Boolean
};
pub fn note_comm<E, CS>(
cs: CS,
a_pk: &[Boolean],
value: &[Boolean],
rho: &[Boolean],
r: &[Boolean],
r: &[Boolean]
) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
where E: Engine, CS: ConstraintSystem<E>
{
assert_eq!(a_pk.len(), 256);
assert_eq!(value.len(), 64);
@@ -33,5 +35,8 @@ where
image.extend(rho.iter().cloned());
image.extend(r.iter().cloned());
sha256(cs, &image)
sha256(
cs,
&image
)
}

View File

@@ -1,11 +1,16 @@
use bellman::gadgets::boolean::{AllocatedBit, Boolean};
use bellman::gadgets::sha256::sha256_block_no_padding;
use pairing::{Engine};
use bellman::{ConstraintSystem, SynthesisError};
use pairing::Engine;
use circuit::sha256::{
sha256_block_no_padding
};
use circuit::boolean::{
AllocatedBit,
Boolean
};
use super::commitment::note_comm;
use super::prfs::*;
use super::*;
use super::prfs::*;
use super::commitment::note_comm;
pub struct InputNote {
pub nf: Vec<Boolean>,
@@ -22,33 +27,49 @@ impl InputNote {
h_sig: &[Boolean],
nonce: bool,
auth_path: [Option<([u8; 32], bool)>; TREE_DEPTH],
rt: &[Boolean],
rt: &[Boolean]
) -> Result<InputNote, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
where E: Engine, CS: ConstraintSystem<E>
{
let a_sk = witness_u252(
cs.namespace(|| "a_sk"),
a_sk.as_ref().map(|a_sk| &a_sk.0[..]),
a_sk.as_ref().map(|a_sk| &a_sk.0[..])
)?;
let rho = witness_u256(cs.namespace(|| "rho"), rho.as_ref().map(|rho| &rho.0[..]))?;
let rho = witness_u256(
cs.namespace(|| "rho"),
rho.as_ref().map(|rho| &rho.0[..])
)?;
let r = witness_u256(cs.namespace(|| "r"), r.as_ref().map(|r| &r.0[..]))?;
let r = witness_u256(
cs.namespace(|| "r"),
r.as_ref().map(|r| &r.0[..])
)?;
let a_pk = prf_a_pk(cs.namespace(|| "a_pk computation"), &a_sk)?;
let a_pk = prf_a_pk(
cs.namespace(|| "a_pk computation"),
&a_sk
)?;
let nf = prf_nf(cs.namespace(|| "nf computation"), &a_sk, &rho)?;
let nf = prf_nf(
cs.namespace(|| "nf computation"),
&a_sk,
&rho
)?;
let mac = prf_pk(cs.namespace(|| "mac computation"), &a_sk, h_sig, nonce)?;
let mac = prf_pk(
cs.namespace(|| "mac computation"),
&a_sk,
h_sig,
nonce
)?;
let cm = note_comm(
cs.namespace(|| "cm computation"),
&a_pk,
&value.bits_le(),
&rho,
&r,
&r
)?;
// Witness into the merkle tree
@@ -59,13 +80,13 @@ impl InputNote {
let cur_is_right = AllocatedBit::alloc(
cs.namespace(|| "cur is right"),
layer.as_ref().map(|&(_, p)| p),
layer.as_ref().map(|&(_, p)| p)
)?;
let lhs = cur;
let rhs = witness_u256(
cs.namespace(|| "sibling"),
layer.as_ref().map(|&(ref sibling, _)| &sibling[..]),
layer.as_ref().map(|&(ref sibling, _)| &sibling[..])
)?;
// Conditionally swap if cur is right
@@ -73,16 +94,19 @@ impl InputNote {
cs.namespace(|| "conditional swap"),
&lhs[..],
&rhs[..],
&cur_is_right,
&cur_is_right
)?;
cur = sha256_block_no_padding(cs.namespace(|| "hash of this layer"), &preimage)?;
cur = sha256_block_no_padding(
cs.namespace(|| "hash of this layer"),
&preimage
)?;
}
// enforce must be true if the value is nonzero
let enforce = AllocatedBit::alloc(
cs.namespace(|| "enforce"),
value.get_value().map(|n| n != 0),
value.get_value().map(|n| n != 0)
)?;
// value * (1 - enforce) = 0
@@ -92,7 +116,7 @@ impl InputNote {
|| "enforce validity",
|_| value.lc(),
|lc| lc + CS::one() - enforce.get_variable(),
|lc| lc,
|lc| lc
);
assert_eq!(cur.len(), rt.len());
@@ -108,11 +132,14 @@ impl InputNote {
|| format!("conditionally enforce correct root for bit {}", i),
|_| cur.lc(CS::one(), E::Fr::one()) - &rt.lc(CS::one(), E::Fr::one()),
|lc| lc + enforce.get_variable(),
|lc| lc,
|lc| lc
);
}
Ok(InputNote { mac: mac, nf: nf })
Ok(InputNote {
mac: mac,
nf: nf
})
}
}
@@ -122,11 +149,9 @@ pub fn conditionally_swap_u256<E, CS>(
mut cs: CS,
lhs: &[Boolean],
rhs: &[Boolean],
condition: &AllocatedBit,
condition: &AllocatedBit
) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
where E: Engine, CS: ConstraintSystem<E>,
{
assert_eq!(lhs.len(), 256);
assert_eq!(rhs.len(), 256);
@@ -139,9 +164,13 @@ where
let x = Boolean::from(AllocatedBit::alloc(
cs.namespace(|| "x"),
condition
.get_value()
.and_then(|v| if v { rhs.get_value() } else { lhs.get_value() }),
condition.get_value().and_then(|v| {
if v {
rhs.get_value()
} else {
lhs.get_value()
}
})
)?);
// x = (1-condition)lhs + (condition)rhs
@@ -155,25 +184,33 @@ where
// x = rhs
cs.enforce(
|| "conditional swap for x",
|lc| lc + &rhs.lc(CS::one(), E::Fr::one()) - &lhs.lc(CS::one(), E::Fr::one()),
|lc| lc + &rhs.lc(CS::one(), E::Fr::one())
- &lhs.lc(CS::one(), E::Fr::one()),
|lc| lc + condition.get_variable(),
|lc| lc + &x.lc(CS::one(), E::Fr::one()) - &lhs.lc(CS::one(), E::Fr::one()),
|lc| lc + &x.lc(CS::one(), E::Fr::one())
- &lhs.lc(CS::one(), E::Fr::one())
);
let y = Boolean::from(AllocatedBit::alloc(
cs.namespace(|| "y"),
condition
.get_value()
.and_then(|v| if v { lhs.get_value() } else { rhs.get_value() }),
condition.get_value().and_then(|v| {
if v {
lhs.get_value()
} else {
rhs.get_value()
}
})
)?);
// y = (1-condition)rhs + (condition)lhs
// y - rhs = condition (lhs - rhs)
cs.enforce(
|| "conditional swap for y",
|lc| lc + &lhs.lc(CS::one(), E::Fr::one()) - &rhs.lc(CS::one(), E::Fr::one()),
|lc| lc + &lhs.lc(CS::one(), E::Fr::one())
- &rhs.lc(CS::one(), E::Fr::one()),
|lc| lc + condition.get_variable(),
|lc| lc + &y.lc(CS::one(), E::Fr::one()) - &rhs.lc(CS::one(), E::Fr::one()),
|lc| lc + &y.lc(CS::one(), E::Fr::one())
- &rhs.lc(CS::one(), E::Fr::one())
);
new_lhs.push(x);

View File

@@ -1,13 +1,15 @@
use bellman::gadgets::boolean::{AllocatedBit, Boolean};
use bellman::gadgets::multipack::pack_into_inputs;
use bellman::{Circuit, ConstraintSystem, LinearCombination, SynthesisError};
use ff::Field;
use pairing::Engine;
use pairing::{Engine, Field};
use bellman::{ConstraintSystem, SynthesisError, Circuit, LinearCombination};
use circuit::boolean::{
AllocatedBit,
Boolean
};
use circuit::multipack::pack_into_inputs;
mod prfs;
mod commitment;
mod input;
mod output;
mod prfs;
use self::input::*;
use self::output::*;
@@ -34,29 +36,39 @@ pub struct JSInput {
pub a_sk: Option<SpendingKey>,
pub rho: Option<UniqueRandomness>,
pub r: Option<CommitmentRandomness>,
pub auth_path: [Option<([u8; 32], bool)>; TREE_DEPTH],
pub auth_path: [Option<([u8; 32], bool)>; TREE_DEPTH]
}
pub struct JSOutput {
pub value: Option<u64>,
pub a_pk: Option<PayingKey>,
pub r: Option<CommitmentRandomness>,
pub r: Option<CommitmentRandomness>
}
impl<E: Engine> Circuit<E> for JoinSplit {
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
fn synthesize<CS: ConstraintSystem<E>>(
self,
cs: &mut CS
) -> Result<(), SynthesisError>
{
assert_eq!(self.inputs.len(), 2);
assert_eq!(self.outputs.len(), 2);
// vpub_old is the value entering the
// JoinSplit from the "outside" value
// pool
let vpub_old = NoteValue::new(cs.namespace(|| "vpub_old"), self.vpub_old)?;
let vpub_old = NoteValue::new(
cs.namespace(|| "vpub_old"),
self.vpub_old
)?;
// vpub_new is the value leaving the
// JoinSplit into the "outside" value
// pool
let vpub_new = NoteValue::new(cs.namespace(|| "vpub_new"), self.vpub_new)?;
let vpub_new = NoteValue::new(
cs.namespace(|| "vpub_new"),
self.vpub_new
)?;
// The left hand side of the balance equation
// vpub_old + inputs[0].value + inputs[1].value
@@ -67,17 +79,22 @@ impl<E: Engine> Circuit<E> for JoinSplit {
let mut rhs = vpub_new.lc();
// Witness rt (merkle tree root)
let rt = witness_u256(cs.namespace(|| "rt"), self.rt.as_ref().map(|v| &v[..])).unwrap();
let rt = witness_u256(
cs.namespace(|| "rt"),
self.rt.as_ref().map(|v| &v[..])
).unwrap();
// Witness h_sig
let h_sig = witness_u256(
cs.namespace(|| "h_sig"),
self.h_sig.as_ref().map(|v| &v[..]),
)
.unwrap();
self.h_sig.as_ref().map(|v| &v[..])
).unwrap();
// Witness phi
let phi = witness_u252(cs.namespace(|| "phi"), self.phi.as_ref().map(|v| &v[..])).unwrap();
let phi = witness_u252(
cs.namespace(|| "phi"),
self.phi.as_ref().map(|v| &v[..])
).unwrap();
let mut input_notes = vec![];
let mut lhs_total = self.vpub_old;
@@ -92,14 +109,17 @@ impl<E: Engine> Circuit<E> for JoinSplit {
}
// Allocate the value of the note
let value = NoteValue::new(cs.namespace(|| "value"), input.value)?;
let value = NoteValue::new(
cs.namespace(|| "value"),
input.value
)?;
// Compute the nonce (for PRF inputs) which is false
// for the first input, and true for the second input.
let nonce = match i {
0 => false,
1 => true,
_ => unreachable!(),
_ => unreachable!()
};
// Perform input note computations
@@ -112,7 +132,7 @@ impl<E: Engine> Circuit<E> for JoinSplit {
&h_sig,
nonce,
input.auth_path,
&rt,
&rt
)?);
// Add the note value to the left hand side of
@@ -127,8 +147,10 @@ impl<E: Engine> Circuit<E> for JoinSplit {
{
// Expected sum of the left hand side of the balance
// equation, expressed as a 64-bit unsigned integer
let lhs_total =
NoteValue::new(cs.namespace(|| "total value of left hand side"), lhs_total)?;
let lhs_total = NoteValue::new(
cs.namespace(|| "total value of left hand side"),
lhs_total
)?;
// Enforce that the left hand side can be expressed as a 64-bit
// integer
@@ -136,7 +158,7 @@ impl<E: Engine> Circuit<E> for JoinSplit {
|| "left hand side can be expressed as a 64-bit unsigned integer",
|_| lhs.clone(),
|lc| lc + CS::one(),
|_| lhs_total.lc(),
|_| lhs_total.lc()
);
}
@@ -146,14 +168,17 @@ impl<E: Engine> Circuit<E> for JoinSplit {
for (i, output) in self.outputs.into_iter().enumerate() {
let cs = &mut cs.namespace(|| format!("output {}", i));
let value = NoteValue::new(cs.namespace(|| "value"), output.value)?;
let value = NoteValue::new(
cs.namespace(|| "value"),
output.value
)?;
// Compute the nonce (for PRF inputs) which is false
// for the first output, and true for the second output.
let nonce = match i {
0 => false,
1 => true,
_ => unreachable!(),
_ => unreachable!()
};
// Perform output note computations
@@ -164,7 +189,7 @@ impl<E: Engine> Circuit<E> for JoinSplit {
output.r,
&phi,
&h_sig,
nonce,
nonce
)?);
// Add the note value to the right hand side of
@@ -177,7 +202,7 @@ impl<E: Engine> Circuit<E> for JoinSplit {
|| "balance equation",
|_| lhs.clone(),
|lc| lc + CS::one(),
|_| rhs,
|_| rhs
);
let mut public_inputs = vec![];
@@ -203,14 +228,15 @@ impl<E: Engine> Circuit<E> for JoinSplit {
pub struct NoteValue {
value: Option<u64>,
// Least significant digit first
bits: Vec<AllocatedBit>,
bits: Vec<AllocatedBit>
}
impl NoteValue {
fn new<E, CS>(mut cs: CS, value: Option<u64>) -> Result<NoteValue, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
fn new<E, CS>(
mut cs: CS,
value: Option<u64>
) -> Result<NoteValue, SynthesisError>
where E: Engine, CS: ConstraintSystem<E>,
{
let mut values;
match value {
@@ -220,7 +246,7 @@ impl NoteValue {
values.push(Some(val & 1 == 1));
val >>= 1;
}
}
},
None => {
values = vec![None; 64];
}
@@ -228,27 +254,28 @@ impl NoteValue {
let mut bits = vec![];
for (i, value) in values.into_iter().enumerate() {
bits.push(AllocatedBit::alloc(
cs.namespace(|| format!("bit {}", i)),
value,
)?);
bits.push(
AllocatedBit::alloc(
cs.namespace(|| format!("bit {}", i)),
value
)?
);
}
Ok(NoteValue {
value: value,
bits: bits,
bits: bits
})
}
/// Encodes the bits of the value into little-endian
/// byte order.
fn bits_le(&self) -> Vec<Boolean> {
self.bits
.chunks(8)
.flat_map(|v| v.iter().rev())
.cloned()
.map(|e| Boolean::from(e))
.collect()
self.bits.chunks(8)
.flat_map(|v| v.iter().rev())
.cloned()
.map(|e| Boolean::from(e))
.collect()
}
/// Computes this value as a linear combination of
@@ -276,18 +303,15 @@ fn witness_bits<E, CS>(
mut cs: CS,
value: Option<&[u8]>,
num_bits: usize,
skip_bits: usize,
skip_bits: usize
) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
where E: Engine, CS: ConstraintSystem<E>,
{
let bit_values = if let Some(value) = value {
let mut tmp = vec![];
for b in value
.iter()
.flat_map(|&m| (0..8).rev().map(move |i| m >> i & 1 == 1))
.skip(skip_bits)
for b in value.iter()
.flat_map(|&m| (0..8).rev().map(move |i| m >> i & 1 == 1))
.skip(skip_bits)
{
tmp.push(Some(b));
}
@@ -302,35 +326,37 @@ where
for (i, value) in bit_values.into_iter().enumerate() {
bits.push(Boolean::from(AllocatedBit::alloc(
cs.namespace(|| format!("bit {}", i)),
value,
value
)?));
}
Ok(bits)
}
fn witness_u256<E, CS>(cs: CS, value: Option<&[u8]>) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
fn witness_u256<E, CS>(
cs: CS,
value: Option<&[u8]>,
) -> Result<Vec<Boolean>, SynthesisError>
where E: Engine, CS: ConstraintSystem<E>,
{
witness_bits(cs, value, 256, 0)
}
fn witness_u252<E, CS>(cs: CS, value: Option<&[u8]>) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
fn witness_u252<E, CS>(
cs: CS,
value: Option<&[u8]>,
) -> Result<Vec<Boolean>, SynthesisError>
where E: Engine, CS: ConstraintSystem<E>,
{
witness_bits(cs, value, 252, 4)
}
#[test]
fn test_sprout_constraints() {
use bellman::gadgets::test::*;
use pairing::bls12_381::Bls12;
use pairing::bls12_381::{Bls12};
use ::circuit::test::*;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian};
let test_vector = include_bytes!("test_vectors.dat");
let mut test_vector = &test_vector[..];
@@ -366,7 +392,9 @@ fn test_sprout_constraints() {
}
let mut position = test_vector.read_u64::<LittleEndian>().unwrap();
for i in 0..TREE_DEPTH {
auth_path[i].as_mut().map(|p| p.1 = (position & 1) == 1);
auth_path[i].as_mut().map(|p| {
p.1 = (position & 1) == 1
});
position >>= 1;
}
@@ -378,13 +406,15 @@ fn test_sprout_constraints() {
let r = Some(CommitmentRandomness(get_u256(&mut test_vector)));
let a_sk = Some(SpendingKey(get_u256(&mut test_vector)));
inputs.push(JSInput {
value: value,
a_sk: a_sk,
rho: rho,
r: r,
auth_path: auth_path,
});
inputs.push(
JSInput {
value: value,
a_sk: a_sk,
rho: rho,
r: r,
auth_path: auth_path
}
);
}
let mut outputs = vec![];
@@ -395,11 +425,13 @@ fn test_sprout_constraints() {
get_u256(&mut test_vector);
let r = Some(CommitmentRandomness(get_u256(&mut test_vector)));
outputs.push(JSOutput {
value: value,
a_pk: a_pk,
r: r,
});
outputs.push(
JSOutput {
value: value,
a_pk: a_pk,
r: r
}
);
}
let vpub_old = Some(test_vector.read_u64::<LittleEndian>().unwrap());
@@ -421,7 +453,7 @@ fn test_sprout_constraints() {
phi: phi,
inputs: inputs,
outputs: outputs,
rt: rt,
rt: rt
};
js.synthesize(&mut cs).unwrap();
@@ -432,10 +464,7 @@ fn test_sprout_constraints() {
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 1989085);
assert_eq!(cs.num_inputs(), 10);
assert_eq!(
cs.hash(),
"1a228d3c6377130d1778c7885811dc8b8864049cb5af8aff7e6cd46c5bc4b84c"
);
assert_eq!(cs.hash(), "1a228d3c6377130d1778c7885811dc8b8864049cb5af8aff7e6cd46c5bc4b84c");
let mut expected_inputs = vec![];
expected_inputs.extend(rt.unwrap().to_vec());
@@ -446,14 +475,10 @@ fn test_sprout_constraints() {
expected_inputs.extend(mac2.to_vec());
expected_inputs.extend(cm1.to_vec());
expected_inputs.extend(cm2.to_vec());
expected_inputs
.write_u64::<LittleEndian>(vpub_old.unwrap())
.unwrap();
expected_inputs
.write_u64::<LittleEndian>(vpub_new.unwrap())
.unwrap();
expected_inputs.write_u64::<LittleEndian>(vpub_old.unwrap()).unwrap();
expected_inputs.write_u64::<LittleEndian>(vpub_new.unwrap()).unwrap();
use bellman::gadgets::multipack;
use circuit::multipack;
let expected_inputs = multipack::bytes_to_bits(&expected_inputs);
let expected_inputs = multipack::compute_multipacking::<Bls12>(&expected_inputs);

View File

@@ -1,13 +1,13 @@
use bellman::gadgets::boolean::Boolean;
use pairing::{Engine};
use bellman::{ConstraintSystem, SynthesisError};
use pairing::Engine;
use circuit::boolean::{Boolean};
use super::commitment::note_comm;
use super::prfs::*;
use super::*;
use super::prfs::*;
use super::commitment::note_comm;
pub struct OutputNote {
pub cm: Vec<Boolean>,
pub cm: Vec<Boolean>
}
impl OutputNote {
@@ -18,29 +18,37 @@ impl OutputNote {
r: Option<CommitmentRandomness>,
phi: &[Boolean],
h_sig: &[Boolean],
nonce: bool,
nonce: bool
) -> Result<Self, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
where E: Engine, CS: ConstraintSystem<E>,
{
let rho = prf_rho(cs.namespace(|| "rho"), phi, h_sig, nonce)?;
let rho = prf_rho(
cs.namespace(|| "rho"),
phi,
h_sig,
nonce
)?;
let a_pk = witness_u256(
cs.namespace(|| "a_pk"),
a_pk.as_ref().map(|a_pk| &a_pk.0[..]),
a_pk.as_ref().map(|a_pk| &a_pk.0[..])
)?;
let r = witness_u256(cs.namespace(|| "r"), r.as_ref().map(|r| &r.0[..]))?;
let r = witness_u256(
cs.namespace(|| "r"),
r.as_ref().map(|r| &r.0[..])
)?;
let cm = note_comm(
cs.namespace(|| "cm computation"),
&a_pk,
&value.bits_le(),
&rho,
&r,
&r
)?;
Ok(OutputNote { cm: cm })
Ok(OutputNote {
cm: cm
})
}
}

View File

@@ -1,7 +1,11 @@
use bellman::gadgets::boolean::Boolean;
use bellman::gadgets::sha256::sha256_block_no_padding;
use pairing::{Engine};
use bellman::{ConstraintSystem, SynthesisError};
use pairing::Engine;
use circuit::sha256::{
sha256_block_no_padding
};
use circuit::boolean::{
Boolean
};
fn prf<E, CS>(
cs: CS,
@@ -10,11 +14,9 @@ fn prf<E, CS>(
c: bool,
d: bool,
x: &[Boolean],
y: &[Boolean],
y: &[Boolean]
) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
where E: Engine, CS: ConstraintSystem<E>
{
assert_eq!(x.len(), 252);
assert_eq!(y.len(), 256);
@@ -29,35 +31,27 @@ where
assert_eq!(image.len(), 512);
sha256_block_no_padding(cs, &image)
sha256_block_no_padding(
cs,
&image
)
}
pub fn prf_a_pk<E, CS>(cs: CS, a_sk: &[Boolean]) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
pub fn prf_a_pk<E, CS>(
cs: CS,
a_sk: &[Boolean]
) -> Result<Vec<Boolean>, SynthesisError>
where E: Engine, CS: ConstraintSystem<E>
{
prf(
cs,
true,
true,
false,
false,
a_sk,
&(0..256)
.map(|_| Boolean::constant(false))
.collect::<Vec<_>>(),
)
prf(cs, true, true, false, false, a_sk, &(0..256).map(|_| Boolean::constant(false)).collect::<Vec<_>>())
}
pub fn prf_nf<E, CS>(
cs: CS,
a_sk: &[Boolean],
rho: &[Boolean],
rho: &[Boolean]
) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
where E: Engine, CS: ConstraintSystem<E>
{
prf(cs, true, true, true, false, a_sk, rho)
}
@@ -66,11 +60,9 @@ pub fn prf_pk<E, CS>(
cs: CS,
a_sk: &[Boolean],
h_sig: &[Boolean],
nonce: bool,
nonce: bool
) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
where E: Engine, CS: ConstraintSystem<E>
{
prf(cs, false, nonce, false, false, a_sk, h_sig)
}
@@ -79,11 +71,9 @@ pub fn prf_rho<E, CS>(
cs: CS,
phi: &[Boolean],
h_sig: &[Boolean],
nonce: bool,
nonce: bool
) -> Result<Vec<Boolean>, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
where E: Engine, CS: ConstraintSystem<E>
{
prf(cs, false, nonce, true, false, phi, h_sig)
}

View File

@@ -1,7 +1,17 @@
use ff::{Field, PrimeField, PrimeFieldRepr};
use pairing::Engine;
use pairing::{
Engine,
Field,
PrimeField,
PrimeFieldRepr
};
use crate::{ConstraintSystem, Index, LinearCombination, SynthesisError, Variable};
use bellman::{
LinearCombination,
SynthesisError,
ConstraintSystem,
Variable,
Index
};
use std::collections::HashMap;
use std::fmt::Write;
@@ -10,13 +20,13 @@ use byteorder::{BigEndian, ByteOrder};
use std::cmp::Ordering;
use std::collections::BTreeMap;
use blake2s_simd::{Params as Blake2sParams, State as Blake2sState};
use blake2_rfc::blake2s::Blake2s;
#[derive(Debug)]
enum NamedObject {
Constraint(usize),
Var(Variable),
Namespace,
Namespace
}
/// Constraint system for testing purposes.
@@ -27,10 +37,10 @@ pub struct TestConstraintSystem<E: Engine> {
LinearCombination<E>,
LinearCombination<E>,
LinearCombination<E>,
String,
String
)>,
inputs: Vec<(E::Fr, String)>,
aux: Vec<(E::Fr, String)>,
aux: Vec<(E::Fr, String)>
}
#[derive(Clone, Copy)]
@@ -42,7 +52,7 @@ impl PartialEq for OrderedVariable {
match (self.0.get_unchecked(), other.0.get_unchecked()) {
(Index::Input(ref a), Index::Input(ref b)) => a == b,
(Index::Aux(ref a), Index::Aux(ref b)) => a == b,
_ => false,
_ => false
}
}
}
@@ -57,17 +67,20 @@ impl Ord for OrderedVariable {
(Index::Input(ref a), Index::Input(ref b)) => a.cmp(b),
(Index::Aux(ref a), Index::Aux(ref b)) => a.cmp(b),
(Index::Input(_), Index::Aux(_)) => Ordering::Less,
(Index::Aux(_), Index::Input(_)) => Ordering::Greater,
(Index::Aux(_), Index::Input(_)) => Ordering::Greater
}
}
}
fn proc_lc<E: Engine>(terms: &[(Variable, E::Fr)]) -> BTreeMap<OrderedVariable, E::Fr> {
fn proc_lc<E: Engine>(
terms: &[(Variable, E::Fr)],
) -> BTreeMap<OrderedVariable, E::Fr>
{
let mut map = BTreeMap::new();
for &(var, coeff) in terms {
map.entry(OrderedVariable(var))
.or_insert(E::Fr::zero())
.add_assign(&coeff);
.or_insert(E::Fr::zero())
.add_assign(&coeff);
}
// Remove terms that have a zero coefficient to normalize
@@ -85,7 +98,11 @@ fn proc_lc<E: Engine>(terms: &[(Variable, E::Fr)]) -> BTreeMap<OrderedVariable,
map
}
fn hash_lc<E: Engine>(terms: &[(Variable, E::Fr)], h: &mut Blake2sState) {
fn hash_lc<E: Engine>(
terms: &[(Variable, E::Fr)],
h: &mut Blake2s
)
{
let map = proc_lc::<E>(terms);
let mut buf = [0u8; 9 + 32];
@@ -97,13 +114,13 @@ fn hash_lc<E: Engine>(terms: &[(Variable, E::Fr)], h: &mut Blake2sState) {
Index::Input(i) => {
buf[0] = b'I';
BigEndian::write_u64(&mut buf[1..9], i as u64);
}
},
Index::Aux(i) => {
buf[0] = b'A';
BigEndian::write_u64(&mut buf[1..9], i as u64);
}
}
coeff.into_repr().write_be(&mut buf[9..]).unwrap();
h.update(&buf);
@@ -113,14 +130,15 @@ fn hash_lc<E: Engine>(terms: &[(Variable, E::Fr)], h: &mut Blake2sState) {
fn eval_lc<E: Engine>(
terms: &[(Variable, E::Fr)],
inputs: &[(E::Fr, String)],
aux: &[(E::Fr, String)],
) -> E::Fr {
aux: &[(E::Fr, String)]
) -> E::Fr
{
let mut acc = E::Fr::zero();
for &(var, ref coeff) in terms {
let mut tmp = match var.get_unchecked() {
Index::Input(index) => inputs[index].0,
Index::Aux(index) => aux[index].0,
Index::Aux(index) => aux[index].0
};
tmp.mul_assign(&coeff);
@@ -133,17 +151,14 @@ fn eval_lc<E: Engine>(
impl<E: Engine> TestConstraintSystem<E> {
pub fn new() -> TestConstraintSystem<E> {
let mut map = HashMap::new();
map.insert(
"ONE".into(),
NamedObject::Var(TestConstraintSystem::<E>::one()),
);
map.insert("ONE".into(), NamedObject::Var(TestConstraintSystem::<E>::one()));
TestConstraintSystem {
named_objects: map,
current_namespace: vec![],
constraints: vec![],
inputs: vec![(E::Fr::one(), "ONE".into())],
aux: vec![],
aux: vec![]
}
}
@@ -156,9 +171,9 @@ impl<E: Engine> TestConstraintSystem<E> {
tmp
};
let powers_of_two = (0..E::Fr::NUM_BITS)
.map(|i| E::Fr::from_str("2").unwrap().pow(&[i as u64]))
.collect::<Vec<_>>();
let powers_of_two = (0..E::Fr::NUM_BITS).map(|i| {
E::Fr::from_str("2").unwrap().pow(&[i as u64])
}).collect::<Vec<_>>();
let pp = |s: &mut String, lc: &LinearCombination<E>| {
write!(s, "(").unwrap();
@@ -185,7 +200,7 @@ impl<E: Engine> TestConstraintSystem<E> {
match var.0.get_unchecked() {
Index::Input(i) => {
write!(s, "`{}`", &self.inputs[i].1).unwrap();
}
},
Index::Aux(i) => {
write!(s, "`{}`", &self.aux[i].1).unwrap();
}
@@ -215,7 +230,7 @@ impl<E: Engine> TestConstraintSystem<E> {
}
pub fn hash(&self) -> String {
let mut h = Blake2sParams::new().hash_length(32).to_state();
let mut h = Blake2s::new(32);
{
let mut buf = [0u8; 24];
@@ -248,41 +263,45 @@ impl<E: Engine> TestConstraintSystem<E> {
a.mul_assign(&b);
if a != c {
return Some(&*path);
return Some(&*path)
}
}
None
}
pub fn is_satisfied(&self) -> bool {
pub fn is_satisfied(&self) -> bool
{
self.which_is_unsatisfied().is_none()
}
pub fn num_constraints(&self) -> usize {
pub fn num_constraints(&self) -> usize
{
self.constraints.len()
}
pub fn set(&mut self, path: &str, to: E::Fr) {
pub fn set(&mut self, path: &str, to: E::Fr)
{
match self.named_objects.get(path) {
Some(&NamedObject::Var(ref v)) => match v.get_unchecked() {
Index::Input(index) => self.inputs[index].0 = to,
Index::Aux(index) => self.aux[index].0 = to,
},
Some(e) => panic!(
"tried to set path `{}` to value, but `{:?}` already exists there.",
path, e
),
_ => panic!("no variable exists at path: {}", path),
Some(&NamedObject::Var(ref v)) => {
match v.get_unchecked() {
Index::Input(index) => self.inputs[index].0 = to,
Index::Aux(index) => self.aux[index].0 = to
}
}
Some(e) => panic!("tried to set path `{}` to value, but `{:?}` already exists there.", path, e),
_ => panic!("no variable exists at path: {}", path)
}
}
pub fn verify(&self, expected: &[E::Fr]) -> bool {
pub fn verify(&self, expected: &[E::Fr]) -> bool
{
assert_eq!(expected.len() + 1, self.inputs.len());
for (a, b) in self.inputs.iter().skip(1).zip(expected.iter()) {
for (a, b) in self.inputs.iter().skip(1).zip(expected.iter())
{
if &a.0 != b {
return false;
return false
}
}
@@ -293,7 +312,8 @@ impl<E: Engine> TestConstraintSystem<E> {
self.inputs.len()
}
pub fn get_input(&mut self, index: usize, path: &str) -> E::Fr {
pub fn get_input(&mut self, index: usize, path: &str) -> E::Fr
{
let (assignment, name) = self.inputs[index].clone();
assert_eq!(path, name);
@@ -301,17 +321,17 @@ impl<E: Engine> TestConstraintSystem<E> {
assignment
}
pub fn get(&mut self, path: &str) -> E::Fr {
pub fn get(&mut self, path: &str) -> E::Fr
{
match self.named_objects.get(path) {
Some(&NamedObject::Var(ref v)) => match v.get_unchecked() {
Index::Input(index) => self.inputs[index].0,
Index::Aux(index) => self.aux[index].0,
},
Some(e) => panic!(
"tried to get value of path `{}`, but `{:?}` exists there (not a variable)",
path, e
),
_ => panic!("no variable exists at path: {}", path),
Some(&NamedObject::Var(ref v)) => {
match v.get_unchecked() {
Index::Input(index) => self.inputs[index].0,
Index::Aux(index) => self.aux[index].0
}
}
Some(e) => panic!("tried to get value of path `{}`, but `{:?}` exists there (not a variable)", path, e),
_ => panic!("no variable exists at path: {}", path)
}
}
@@ -332,7 +352,8 @@ fn compute_path(ns: &[String], this: String) -> String {
let mut name = String::new();
let mut needs_separation = false;
for ns in ns.iter().chain(Some(&this).into_iter()) {
for ns in ns.iter().chain(Some(&this).into_iter())
{
if needs_separation {
name += "/";
}
@@ -347,11 +368,12 @@ fn compute_path(ns: &[String], this: String) -> String {
impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
type Root = Self;
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
fn alloc<F, A, AR>(
&mut self,
annotation: A,
f: F
) -> Result<Variable, SynthesisError>
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
{
let index = self.aux.len();
let path = compute_path(&self.current_namespace, annotation().into());
@@ -362,11 +384,12 @@ impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
Ok(var)
}
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
fn alloc_input<F, A, AR>(
&mut self,
annotation: A,
f: F
) -> Result<Variable, SynthesisError>
where F: FnOnce() -> Result<E::Fr, SynthesisError>, A: FnOnce() -> AR, AR: Into<String>
{
let index = self.inputs.len();
let path = compute_path(&self.current_namespace, annotation().into());
@@ -377,13 +400,17 @@ impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
Ok(var)
}
fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: A, a: LA, b: LB, c: LC)
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
fn enforce<A, AR, LA, LB, LC>(
&mut self,
annotation: A,
a: LA,
b: LB,
c: LC
)
where A: FnOnce() -> AR, AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>
{
let path = compute_path(&self.current_namespace, annotation().into());
let index = self.constraints.len();
@@ -397,9 +424,7 @@ impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
}
fn push_namespace<NR, N>(&mut self, name_fn: N)
where
NR: Into<String>,
N: FnOnce() -> NR,
where NR: Into<String>, N: FnOnce() -> NR
{
let name = name_fn().into();
let path = compute_path(&self.current_namespace, name.clone());
@@ -407,43 +432,47 @@ impl<E: Engine> ConstraintSystem<E> for TestConstraintSystem<E> {
self.current_namespace.push(name);
}
fn pop_namespace(&mut self) {
fn pop_namespace(&mut self)
{
assert!(self.current_namespace.pop().is_some());
}
fn get_root(&mut self) -> &mut Self::Root {
fn get_root(&mut self) -> &mut Self::Root
{
self
}
}
#[test]
fn test_cs() {
use ff::PrimeField;
use pairing::bls12_381::{Bls12, Fr};
use pairing::PrimeField;
let mut cs = TestConstraintSystem::<Bls12>::new();
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 0);
let a = cs
.namespace(|| "a")
.alloc(|| "var", || Ok(Fr::from_str("10").unwrap()))
.unwrap();
let b = cs
.namespace(|| "b")
.alloc(|| "var", || Ok(Fr::from_str("4").unwrap()))
.unwrap();
let c = cs
.alloc(|| "product", || Ok(Fr::from_str("40").unwrap()))
.unwrap();
let a = cs.namespace(|| "a").alloc(|| "var", || Ok(Fr::from_str("10").unwrap())).unwrap();
let b = cs.namespace(|| "b").alloc(|| "var", || Ok(Fr::from_str("4").unwrap())).unwrap();
let c = cs.alloc(|| "product", || Ok(Fr::from_str("40").unwrap())).unwrap();
cs.enforce(|| "mult", |lc| lc + a, |lc| lc + b, |lc| lc + c);
cs.enforce(
|| "mult",
|lc| lc + a,
|lc| lc + b,
|lc| lc + c
);
assert!(cs.is_satisfied());
assert_eq!(cs.num_constraints(), 1);
cs.set("a/var", Fr::from_str("4").unwrap());
let one = TestConstraintSystem::<Bls12>::one();
cs.enforce(|| "eq", |lc| lc + a, |lc| lc + one, |lc| lc + b);
cs.enforce(
|| "eq",
|lc| lc + a,
|lc| lc + one,
|lc| lc + b
);
assert!(!cs.is_satisfied());
assert!(cs.which_is_unsatisfied() == Some("mult"));

View File

@@ -1,9 +1,19 @@
use ff::{Field, PrimeField};
use pairing::Engine;
use pairing::{
Engine,
Field,
PrimeField
};
use crate::{ConstraintSystem, LinearCombination, SynthesisError};
use bellman::{
SynthesisError,
ConstraintSystem,
LinearCombination
};
use super::boolean::{AllocatedBit, Boolean};
use super::boolean::{
Boolean,
AllocatedBit
};
use super::multieq::MultiEq;
@@ -13,12 +23,13 @@ use super::multieq::MultiEq;
pub struct UInt32 {
// Least significant bit first
bits: Vec<Boolean>,
value: Option<u32>,
value: Option<u32>
}
impl UInt32 {
/// Construct a constant `UInt32` from a `u32`
pub fn constant(value: u32) -> Self {
pub fn constant(value: u32) -> Self
{
let mut bits = Vec::with_capacity(32);
let mut tmp = value;
@@ -34,15 +45,17 @@ impl UInt32 {
UInt32 {
bits: bits,
value: Some(value),
value: Some(value)
}
}
/// Allocate a `UInt32` in the constraint system
pub fn alloc<E, CS>(mut cs: CS, value: Option<u32>) -> Result<Self, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
pub fn alloc<E, CS>(
mut cs: CS,
value: Option<u32>
) -> Result<Self, SynthesisError>
where E: Engine,
CS: ConstraintSystem<E>
{
let values = match value {
Some(mut val) => {
@@ -54,24 +67,23 @@ impl UInt32 {
}
v
}
None => vec![None; 32],
},
None => vec![None; 32]
};
let bits = values
.into_iter()
.enumerate()
.map(|(i, v)| {
Ok(Boolean::from(AllocatedBit::alloc(
cs.namespace(|| format!("allocated bit {}", i)),
v,
)?))
})
.collect::<Result<Vec<_>, SynthesisError>>()?;
let bits = values.into_iter()
.enumerate()
.map(|(i, v)| {
Ok(Boolean::from(AllocatedBit::alloc(
cs.namespace(|| format!("allocated bit {}", i)),
v
)?))
})
.collect::<Result<Vec<_>, SynthesisError>>()?;
Ok(UInt32 {
bits: bits,
value: value,
value: value
})
}
@@ -87,22 +99,19 @@ impl UInt32 {
value.as_mut().map(|v| *v <<= 1);
match b.get_value() {
Some(true) => {
value.as_mut().map(|v| *v |= 1);
}
Some(false) => {}
None => {
value = None;
}
Some(true) => { value.as_mut().map(|v| *v |= 1); },
Some(false) => {},
None => { value = None; }
}
}
UInt32 {
value: value,
bits: bits.iter().rev().cloned().collect(),
bits: bits.iter().rev().cloned().collect()
}
}
/// Turns this `UInt32` into its little-endian byte order representation.
pub fn into_bits(&self) -> Vec<Boolean> {
self.bits.clone()
@@ -110,7 +119,8 @@ impl UInt32 {
/// Converts a little-endian byte order representation of bits into a
/// `UInt32`.
pub fn from_bits(bits: &[Boolean]) -> Self {
pub fn from_bits(bits: &[Boolean]) -> Self
{
assert_eq!(bits.len(), 32);
let new_bits = bits.to_vec();
@@ -124,45 +134,43 @@ impl UInt32 {
if b {
value.as_mut().map(|v| *v |= 1);
}
},
&Boolean::Is(ref b) => {
match b.get_value() {
Some(true) => { value.as_mut().map(|v| *v |= 1); },
Some(false) => {},
None => { value = None }
}
},
&Boolean::Not(ref b) => {
match b.get_value() {
Some(false) => { value.as_mut().map(|v| *v |= 1); },
Some(true) => {},
None => { value = None }
}
}
&Boolean::Is(ref b) => match b.get_value() {
Some(true) => {
value.as_mut().map(|v| *v |= 1);
}
Some(false) => {}
None => value = None,
},
&Boolean::Not(ref b) => match b.get_value() {
Some(false) => {
value.as_mut().map(|v| *v |= 1);
}
Some(true) => {}
None => value = None,
},
}
}
UInt32 {
value: value,
bits: new_bits,
bits: new_bits
}
}
pub fn rotr(&self, by: usize) -> Self {
let by = by % 32;
let new_bits = self
.bits
.iter()
.skip(by)
.chain(self.bits.iter())
.take(32)
.cloned()
.collect();
let new_bits = self.bits.iter()
.skip(by)
.chain(self.bits.iter())
.take(32)
.cloned()
.collect();
UInt32 {
bits: new_bits,
value: self.value.map(|v| v.rotate_right(by as u32)),
value: self.value.map(|v| v.rotate_right(by as u32))
}
}
@@ -171,18 +179,17 @@ impl UInt32 {
let fill = Boolean::constant(false);
let new_bits = self
.bits
.iter() // The bits are least significant first
.skip(by) // Skip the bits that will be lost during the shift
.chain(Some(&fill).into_iter().cycle()) // Rest will be zeros
.take(32) // Only 32 bits needed!
.cloned()
.collect();
let new_bits = self.bits
.iter() // The bits are least significant first
.skip(by) // Skip the bits that will be lost during the shift
.chain(Some(&fill).into_iter().cycle()) // Rest will be zeros
.take(32) // Only 32 bits needed!
.cloned()
.collect();
UInt32 {
bits: new_bits,
value: self.value.map(|v| v >> by as u32),
value: self.value.map(|v| v >> by as u32)
}
}
@@ -192,99 +199,121 @@ impl UInt32 {
b: &Self,
c: &Self,
tri_fn: F,
circuit_fn: U,
circuit_fn: U
) -> Result<Self, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
F: Fn(u32, u32, u32) -> u32,
U: Fn(&mut CS, usize, &Boolean, &Boolean, &Boolean) -> Result<Boolean, SynthesisError>,
where E: Engine,
CS: ConstraintSystem<E>,
F: Fn(u32, u32, u32) -> u32,
U: Fn(&mut CS, usize, &Boolean, &Boolean, &Boolean) -> Result<Boolean, SynthesisError>
{
let new_value = match (a.value, b.value, c.value) {
(Some(a), Some(b), Some(c)) => Some(tri_fn(a, b, c)),
_ => None,
(Some(a), Some(b), Some(c)) => {
Some(tri_fn(a, b, c))
},
_ => None
};
let bits = a
.bits
.iter()
.zip(b.bits.iter())
.zip(c.bits.iter())
.enumerate()
.map(|(i, ((a, b), c))| circuit_fn(&mut cs, i, a, b, c))
.collect::<Result<_, _>>()?;
let bits = a.bits.iter()
.zip(b.bits.iter())
.zip(c.bits.iter())
.enumerate()
.map(|(i, ((a, b), c))| circuit_fn(&mut cs, i, a, b, c))
.collect::<Result<_, _>>()?;
Ok(UInt32 {
bits: bits,
value: new_value,
value: new_value
})
}
/// Compute the `maj` value (a and b) xor (a and c) xor (b and c)
/// during SHA256.
pub fn sha256_maj<E, CS>(cs: CS, a: &Self, b: &Self, c: &Self) -> Result<Self, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
pub fn sha256_maj<E, CS>(
cs: CS,
a: &Self,
b: &Self,
c: &Self
) -> Result<Self, SynthesisError>
where E: Engine,
CS: ConstraintSystem<E>
{
Self::triop(
cs,
a,
b,
c,
|a, b, c| (a & b) ^ (a & c) ^ (b & c),
|cs, i, a, b, c| Boolean::sha256_maj(cs.namespace(|| format!("maj {}", i)), a, b, c),
Self::triop(cs, a, b, c, |a, b, c| (a & b) ^ (a & c) ^ (b & c),
|cs, i, a, b, c| {
Boolean::sha256_maj(
cs.namespace(|| format!("maj {}", i)),
a,
b,
c
)
}
)
}
/// Compute the `ch` value `(a and b) xor ((not a) and c)`
/// during SHA256.
pub fn sha256_ch<E, CS>(cs: CS, a: &Self, b: &Self, c: &Self) -> Result<Self, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
pub fn sha256_ch<E, CS>(
cs: CS,
a: &Self,
b: &Self,
c: &Self
) -> Result<Self, SynthesisError>
where E: Engine,
CS: ConstraintSystem<E>
{
Self::triop(
cs,
a,
b,
c,
|a, b, c| (a & b) ^ ((!a) & c),
|cs, i, a, b, c| Boolean::sha256_ch(cs.namespace(|| format!("ch {}", i)), a, b, c),
Self::triop(cs, a, b, c, |a, b, c| (a & b) ^ ((!a) & c),
|cs, i, a, b, c| {
Boolean::sha256_ch(
cs.namespace(|| format!("ch {}", i)),
a,
b,
c
)
}
)
}
/// XOR this `UInt32` with another `UInt32`
pub fn xor<E, CS>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
pub fn xor<E, CS>(
&self,
mut cs: CS,
other: &Self
) -> Result<Self, SynthesisError>
where E: Engine,
CS: ConstraintSystem<E>
{
let new_value = match (self.value, other.value) {
(Some(a), Some(b)) => Some(a ^ b),
_ => None,
(Some(a), Some(b)) => {
Some(a ^ b)
},
_ => None
};
let bits = self
.bits
.iter()
.zip(other.bits.iter())
.enumerate()
.map(|(i, (a, b))| Boolean::xor(cs.namespace(|| format!("xor of bit {}", i)), a, b))
.collect::<Result<_, _>>()?;
let bits = self.bits.iter()
.zip(other.bits.iter())
.enumerate()
.map(|(i, (a, b))| {
Boolean::xor(
cs.namespace(|| format!("xor of bit {}", i)),
a,
b
)
})
.collect::<Result<_, _>>()?;
Ok(UInt32 {
bits: bits,
value: new_value,
value: new_value
})
}
/// Perform modular addition of several `UInt32` objects.
pub fn addmany<E, CS, M>(mut cs: M, operands: &[Self]) -> Result<Self, SynthesisError>
where
E: Engine,
CS: ConstraintSystem<E>,
M: ConstraintSystem<E, Root = MultiEq<E, CS>>,
pub fn addmany<E, CS, M>(
mut cs: M,
operands: &[Self]
) -> Result<Self, SynthesisError>
where E: Engine,
CS: ConstraintSystem<E>,
M: ConstraintSystem<E, Root=MultiEq<E, CS>>
{
// Make some arbitrary bounds for ourselves to avoid overflows
// in the scalar field
@@ -311,7 +340,7 @@ impl UInt32 {
match op.value {
Some(val) => {
result_value.as_mut().map(|v| *v += val as u64);
}
},
None => {
// If any of our operands have unknown value, we won't
// know the value of the result
@@ -355,7 +384,7 @@ impl UInt32 {
// Allocate the bit
let b = AllocatedBit::alloc(
cs.namespace(|| format!("result bit {}", i)),
result_value.map(|v| (v >> i) & 1 == 1),
result_value.map(|v| (v >> i) & 1 == 1)
)?;
// Add this bit to the result combination
@@ -376,34 +405,28 @@ impl UInt32 {
Ok(UInt32 {
bits: result_bits,
value: modular_value,
value: modular_value
})
}
}
#[cfg(test)]
mod test {
use super::UInt32;
use crate::gadgets::boolean::Boolean;
use crate::gadgets::multieq::MultiEq;
use crate::gadgets::test::*;
use crate::ConstraintSystem;
use ff::Field;
use pairing::bls12_381::Bls12;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
use rand::{XorShiftRng, SeedableRng, Rng};
use ::circuit::boolean::{Boolean};
use super::{UInt32};
use pairing::bls12_381::{Bls12};
use pairing::{Field};
use ::circuit::test::*;
use bellman::{ConstraintSystem};
use circuit::multieq::MultiEq;
#[test]
fn test_uint32_from_bits_be() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]);
for _ in 0..1000 {
let mut v = (0..32)
.map(|_| Boolean::constant(rng.next_u32() % 2 != 0))
.collect::<Vec<_>>();
let mut v = (0..32).map(|_| Boolean::constant(rng.gen())).collect::<Vec<_>>();
let b = UInt32::from_bits_be(&v);
@@ -411,18 +434,19 @@ mod test {
match bit {
&Boolean::Constant(bit) => {
assert!(bit == ((b.value.unwrap() >> i) & 1 == 1));
}
_ => unreachable!(),
},
_ => unreachable!()
}
}
let expected_to_be_same = b.into_bits_be();
for x in v.iter().zip(expected_to_be_same.iter()) {
for x in v.iter().zip(expected_to_be_same.iter())
{
match x {
(&Boolean::Constant(true), &Boolean::Constant(true)) => {}
(&Boolean::Constant(false), &Boolean::Constant(false)) => {}
_ => unreachable!(),
(&Boolean::Constant(true), &Boolean::Constant(true)) => {},
(&Boolean::Constant(false), &Boolean::Constant(false)) => {},
_ => unreachable!()
}
}
}
@@ -430,15 +454,10 @@ mod test {
#[test]
fn test_uint32_from_bits() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]);
for _ in 0..1000 {
let mut v = (0..32)
.map(|_| Boolean::constant(rng.next_u32() % 2 != 0))
.collect::<Vec<_>>();
let mut v = (0..32).map(|_| Boolean::constant(rng.gen())).collect::<Vec<_>>();
let b = UInt32::from_bits(&v);
@@ -446,18 +465,19 @@ mod test {
match bit {
&Boolean::Constant(bit) => {
assert!(bit == ((b.value.unwrap() >> i) & 1 == 1));
}
_ => unreachable!(),
},
_ => unreachable!()
}
}
let expected_to_be_same = b.into_bits();
for x in v.iter().zip(expected_to_be_same.iter()) {
for x in v.iter().zip(expected_to_be_same.iter())
{
match x {
(&Boolean::Constant(true), &Boolean::Constant(true)) => {}
(&Boolean::Constant(false), &Boolean::Constant(false)) => {}
_ => unreachable!(),
(&Boolean::Constant(true), &Boolean::Constant(true)) => {},
(&Boolean::Constant(false), &Boolean::Constant(false)) => {},
_ => unreachable!()
}
}
}
@@ -465,17 +485,14 @@ mod test {
#[test]
fn test_uint32_xor() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]);
for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let a = rng.next_u32();
let b = rng.next_u32();
let c = rng.next_u32();
let a: u32 = rng.gen();
let b: u32 = rng.gen();
let c: u32 = rng.gen();
let mut expected = a ^ b ^ c;
@@ -494,10 +511,10 @@ mod test {
match b {
&Boolean::Is(ref b) => {
assert!(b.get_value().unwrap() == (expected & 1 == 1));
}
},
&Boolean::Not(ref b) => {
assert!(!b.get_value().unwrap() == (expected & 1 == 1));
}
},
&Boolean::Constant(b) => {
assert!(b == (expected & 1 == 1));
}
@@ -510,17 +527,14 @@ mod test {
#[test]
fn test_uint32_addmany_constants() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let a = rng.next_u32();
let b = rng.next_u32();
let c = rng.next_u32();
let a: u32 = rng.gen();
let b: u32 = rng.gen();
let c: u32 = rng.gen();
let a_bit = UInt32::constant(a);
let b_bit = UInt32::constant(b);
@@ -530,8 +544,7 @@ mod test {
let r = {
let mut cs = MultiEq::new(&mut cs);
let r =
UInt32::addmany(cs.namespace(|| "addition"), &[a_bit, b_bit, c_bit]).unwrap();
let r = UInt32::addmany(cs.namespace(|| "addition"), &[a_bit, b_bit, c_bit]).unwrap();
r
};
@@ -553,18 +566,15 @@ mod test {
#[test]
fn test_uint32_addmany() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let a = rng.next_u32();
let b = rng.next_u32();
let c = rng.next_u32();
let d = rng.next_u32();
let a: u32 = rng.gen();
let b: u32 = rng.gen();
let c: u32 = rng.gen();
let d: u32 = rng.gen();
let mut expected = (a ^ b).wrapping_add(c).wrapping_add(d);
@@ -588,11 +598,13 @@ mod test {
match b {
&Boolean::Is(ref b) => {
assert!(b.get_value().unwrap() == (expected & 1 == 1));
}
},
&Boolean::Not(ref b) => {
assert!(!b.get_value().unwrap() == (expected & 1 == 1));
},
&Boolean::Constant(_) => {
unreachable!()
}
&Boolean::Constant(_) => unreachable!(),
}
expected >>= 1;
@@ -611,12 +623,9 @@ mod test {
#[test]
fn test_uint32_rotr() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let mut num = rng.next_u32();
let mut num = rng.gen();
let a = UInt32::constant(num);
@@ -631,8 +640,8 @@ mod test {
match b {
&Boolean::Constant(b) => {
assert_eq!(b, tmp & 1 == 1);
}
_ => unreachable!(),
},
_ => unreachable!()
}
tmp >>= 1;
@@ -644,18 +653,15 @@ mod test {
#[test]
fn test_uint32_shr() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..50 {
for i in 0..60 {
let num = rng.next_u32();
let num = rng.gen();
let a = UInt32::constant(num).shr(i);
let b = UInt32::constant(num.wrapping_shr(i as u32));
let b = UInt32::constant(num >> i);
assert_eq!(a.value.unwrap(), num.wrapping_shr(i as u32));
assert_eq!(a.value.unwrap(), num >> i);
assert_eq!(a.bits.len(), b.bits.len());
for (a, b) in a.bits.iter().zip(b.bits.iter()) {
@@ -667,17 +673,14 @@ mod test {
#[test]
fn test_uint32_sha256_maj() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]);
for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let a = rng.next_u32();
let b = rng.next_u32();
let c = rng.next_u32();
let a: u32 = rng.gen();
let b: u32 = rng.gen();
let c: u32 = rng.gen();
let mut expected = (a & b) ^ (a & c) ^ (b & c);
@@ -695,10 +698,10 @@ mod test {
match b {
&Boolean::Is(ref b) => {
assert!(b.get_value().unwrap() == (expected & 1 == 1));
}
},
&Boolean::Not(ref b) => {
assert!(!b.get_value().unwrap() == (expected & 1 == 1));
}
},
&Boolean::Constant(b) => {
assert!(b == (expected & 1 == 1));
}
@@ -711,17 +714,14 @@ mod test {
#[test]
fn test_uint32_sha256_ch() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0653]);
for _ in 0..1000 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let a = rng.next_u32();
let b = rng.next_u32();
let c = rng.next_u32();
let a: u32 = rng.gen();
let b: u32 = rng.gen();
let c: u32 = rng.gen();
let mut expected = (a & b) ^ ((!a) & c);
@@ -739,10 +739,10 @@ mod test {
match b {
&Boolean::Is(ref b) => {
assert!(b.get_value().unwrap() == (expected & 1 == 1));
}
},
&Boolean::Not(ref b) => {
assert!(!b.get_value().unwrap() == (expected & 1 == 1));
}
},
&Boolean::Constant(b) => {
assert!(b == (expected & 1 == 1));
}

View File

@@ -2,31 +2,39 @@
/// This is chosen to be some random string that we couldn't have anticipated when we designed
/// the algorithm, for rigidity purposes.
/// We deliberately use an ASCII hex string of 32 bytes here.
pub const GH_FIRST_BLOCK: &'static [u8; 64] =
b"096b36a5804bfacef1691e173c366a47ff5ba84a44f26ddd7e8d9f79d5b42df0";
pub const GH_FIRST_BLOCK: &'static [u8; 64]
= b"096b36a5804bfacef1691e173c366a47ff5ba84a44f26ddd7e8d9f79d5b42df0";
// BLAKE2s invocation personalizations
/// BLAKE2s Personalization for CRH^ivk = BLAKE2s(ak | nk)
pub const CRH_IVK_PERSONALIZATION: &'static [u8; 8] = b"Zcashivk";
pub const CRH_IVK_PERSONALIZATION: &'static [u8; 8]
= b"Zcashivk";
/// BLAKE2s Personalization for PRF^nf = BLAKE2s(nk | rho)
pub const PRF_NF_PERSONALIZATION: &'static [u8; 8] = b"Zcash_nf";
pub const PRF_NF_PERSONALIZATION: &'static [u8; 8]
= b"Zcash_nf";
// Group hash personalizations
/// BLAKE2s Personalization for Pedersen hash generators.
pub const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &'static [u8; 8] = b"Zcash_PH";
pub const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &'static [u8; 8]
= b"Zcash_PH";
/// BLAKE2s Personalization for the group hash for key diversification
pub const KEY_DIVERSIFICATION_PERSONALIZATION: &'static [u8; 8] = b"Zcash_gd";
pub const KEY_DIVERSIFICATION_PERSONALIZATION: &'static [u8; 8]
= b"Zcash_gd";
/// BLAKE2s Personalization for the spending key base point
pub const SPENDING_KEY_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_G_";
pub const SPENDING_KEY_GENERATOR_PERSONALIZATION: &'static [u8; 8]
= b"Zcash_G_";
/// BLAKE2s Personalization for the proof generation key base point
pub const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_H_";
pub const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &'static [u8; 8]
= b"Zcash_H_";
/// BLAKE2s Personalization for the value commitment generator for the value
pub const VALUE_COMMITMENT_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_cv";
pub const VALUE_COMMITMENT_GENERATOR_PERSONALIZATION: &'static [u8; 8]
= b"Zcash_cv";
/// BLAKE2s Personalization for the nullifier position generator (for computing rho)
pub const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &'static [u8; 8] = b"Zcash_J_";
pub const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &'static [u8; 8]
= b"Zcash_J_";

View File

@@ -1,8 +1,14 @@
use jubjub::{edwards, JubjubEngine, PrimeOrder};
use jubjub::{
JubjubEngine,
PrimeOrder,
edwards
};
use ff::PrimeField;
use pairing::{
PrimeField
};
use blake2s_simd::Params;
use blake2_rfc::blake2s::Blake2s;
use constants;
/// Produces a random point in the Jubjub curve.
@@ -11,22 +17,21 @@ use constants;
pub fn group_hash<E: JubjubEngine>(
tag: &[u8],
personalization: &[u8],
params: &E::Params,
) -> Option<edwards::Point<E, PrimeOrder>> {
params: &E::Params
) -> Option<edwards::Point<E, PrimeOrder>>
{
assert_eq!(personalization.len(), 8);
// Check to see that scalar field is 255 bits
assert!(E::Fr::NUM_BITS == 255);
let h = Params::new()
.hash_length(32)
.personal(personalization)
.to_state()
.update(constants::GH_FIRST_BLOCK)
.update(tag)
.finalize();
let mut h = Blake2s::with_params(32, &[], &[], personalization);
h.update(constants::GH_FIRST_BLOCK);
h.update(tag);
let h = h.finalize().as_ref().to_vec();
assert!(h.len() == 32);
match edwards::Point::<E, _>::read(h.as_ref(), params) {
match edwards::Point::<E, _>::read(&h[..], params) {
Ok(p) => {
let p = p.mul_by_cofactor(params);
@@ -35,7 +40,7 @@ pub fn group_hash<E: JubjubEngine>(
} else {
None
}
}
Err(_) => None,
},
Err(_) => None
}
}

View File

@@ -1,56 +1,65 @@
use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField};
use pairing::{
Field,
SqrtField,
PrimeField,
PrimeFieldRepr,
BitIterator
};
use super::{montgomery, JubjubEngine, JubjubParams, PrimeOrder, Unknown};
use super::{
JubjubEngine,
JubjubParams,
Unknown,
PrimeOrder,
montgomery
};
use rand_core::RngCore;
use rand::{
Rng
};
use std::marker::PhantomData;
use std::io::{self, Read, Write};
use std::io::{
self,
Write,
Read
};
// Represents the affine point (X/Z, Y/Z) via the extended
// twisted Edwards coordinates.
//
// See "Twisted Edwards Curves Revisited"
// Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson
#[derive(Debug)]
pub struct Point<E: JubjubEngine, Subgroup> {
x: E::Fr,
y: E::Fr,
t: E::Fr,
z: E::Fr,
_marker: PhantomData<Subgroup>,
_marker: PhantomData<Subgroup>
}
fn convert_subgroup<E: JubjubEngine, S1, S2>(from: &Point<E, S1>) -> Point<E, S2> {
fn convert_subgroup<E: JubjubEngine, S1, S2>(from: &Point<E, S1>) -> Point<E, S2>
{
Point {
x: from.x,
y: from.y,
t: from.t,
z: from.z,
_marker: PhantomData,
_marker: PhantomData
}
}
impl<E: JubjubEngine> From<&Point<E, Unknown>> for Point<E, Unknown> {
fn from(p: &Point<E, Unknown>) -> Point<E, Unknown> {
p.clone()
}
}
impl<E: JubjubEngine> From<Point<E, PrimeOrder>> for Point<E, Unknown> {
fn from(p: Point<E, PrimeOrder>) -> Point<E, Unknown> {
impl<E: JubjubEngine> From<Point<E, PrimeOrder>> for Point<E, Unknown>
{
fn from(p: Point<E, PrimeOrder>) -> Point<E, Unknown>
{
convert_subgroup(&p)
}
}
impl<E: JubjubEngine> From<&Point<E, PrimeOrder>> for Point<E, Unknown> {
fn from(p: &Point<E, PrimeOrder>) -> Point<E, Unknown> {
convert_subgroup(p)
}
}
impl<E: JubjubEngine, Subgroup> Clone for Point<E, Subgroup> {
impl<E: JubjubEngine, Subgroup> Clone for Point<E, Subgroup>
{
fn clone(&self) -> Self {
convert_subgroup(self)
}
@@ -81,7 +90,11 @@ impl<E: JubjubEngine, Subgroup> PartialEq for Point<E, Subgroup> {
}
impl<E: JubjubEngine> Point<E, Unknown> {
pub fn read<R: Read>(reader: R, params: &E::Params) -> io::Result<Self> {
pub fn read<R: Read>(
reader: R,
params: &E::Params
) -> io::Result<Self>
{
let mut y_repr = <E::Fr as PrimeField>::Repr::default();
y_repr.read_le(reader)?;
@@ -89,18 +102,22 @@ impl<E: JubjubEngine> Point<E, Unknown> {
y_repr.as_mut()[3] &= 0x7fffffffffffffff;
match E::Fr::from_repr(y_repr) {
Ok(y) => match Self::get_for_y(y, x_sign, params) {
Some(p) => Ok(p),
None => Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve")),
Ok(y) => {
match Self::get_for_y(y, x_sign, params) {
Some(p) => Ok(p),
None => {
Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve"))
}
}
},
Err(_) => Err(io::Error::new(
io::ErrorKind::InvalidInput,
"y is not in field",
)),
Err(_) => {
Err(io::Error::new(io::ErrorKind::InvalidInput, "y is not in field"))
}
}
}
pub fn get_for_y(y: E::Fr, sign: bool, params: &E::Params) -> Option<Self> {
pub fn get_for_y(y: E::Fr, sign: bool, params: &E::Params) -> Option<Self>
{
// Given a y on the curve, x^2 = (y^2 - 1) / (dy^2 + 1)
// This is defined for all valid y-coordinates,
// as dy^2 + 1 = 0 has no solution in Fr.
@@ -136,30 +153,33 @@ impl<E: JubjubEngine> Point<E, Unknown> {
y: y,
t: t,
z: E::Fr::one(),
_marker: PhantomData,
_marker: PhantomData
})
}
None => None,
},
None => None
}
}
None => None,
},
None => None
}
}
/// This guarantees the point is in the prime order subgroup
#[must_use]
pub fn mul_by_cofactor(&self, params: &E::Params) -> Point<E, PrimeOrder> {
let tmp = self.double(params).double(params).double(params);
pub fn mul_by_cofactor(&self, params: &E::Params) -> Point<E, PrimeOrder>
{
let tmp = self.double(params)
.double(params)
.double(params);
convert_subgroup(&tmp)
}
pub fn rand<R: RngCore>(rng: &mut R, params: &E::Params) -> Self {
pub fn rand<R: Rng>(rng: &mut R, params: &E::Params) -> Self
{
loop {
let y = E::Fr::random(rng);
let sign = rng.next_u32() % 2 != 0;
let y: E::Fr = rng.gen();
if let Some(p) = Self::get_for_y(y, sign, params) {
if let Some(p) = Self::get_for_y(y, rng.gen(), params) {
return p;
}
}
@@ -167,7 +187,11 @@ impl<E: JubjubEngine> Point<E, Unknown> {
}
impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
pub fn write<W: Write>(&self, writer: W) -> io::Result<()> {
pub fn write<W: Write>(
&self,
writer: W
) -> io::Result<()>
{
let (x, y) = self.into_xy();
assert_eq!(E::Fr::NUM_BITS, 255);
@@ -182,12 +206,16 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
}
/// Convert from a Montgomery point
pub fn from_montgomery(m: &montgomery::Point<E, Subgroup>, params: &E::Params) -> Self {
pub fn from_montgomery(
m: &montgomery::Point<E, Subgroup>,
params: &E::Params
) -> Self
{
match m.into_xy() {
None => {
// Map the point at infinity to the neutral element.
Point::zero()
}
},
Some((x, y)) => {
// The map from a Montgomery curve is defined as:
// (x, y) -> (u, v) where
@@ -220,7 +248,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
y: neg1,
t: E::Fr::zero(),
z: E::Fr::one(),
_marker: PhantomData,
_marker: PhantomData
}
} else {
// Otherwise, as stated above, the mapping is still
@@ -279,7 +307,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
y: v,
t: t,
z: z,
_marker: PhantomData,
_marker: PhantomData
}
}
}
@@ -302,11 +330,12 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
y: E::Fr::one(),
t: E::Fr::zero(),
z: E::Fr::one(),
_marker: PhantomData,
_marker: PhantomData
}
}
pub fn into_xy(&self) -> (E::Fr, E::Fr) {
pub fn into_xy(&self) -> (E::Fr, E::Fr)
{
let zinv = self.z.inverse().unwrap();
let mut x = self.x;
@@ -393,12 +422,13 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
y: y3,
t: t3,
z: z3,
_marker: PhantomData,
_marker: PhantomData
}
}
#[must_use]
pub fn add(&self, other: &Self, params: &E::Params) -> Self {
pub fn add(&self, other: &Self, params: &E::Params) -> Self
{
// See "Twisted Edwards Curves Revisited"
// Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, and Ed Dawson
// 3.1 Unified Addition in E^e
@@ -465,12 +495,17 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
y: y3,
t: t3,
z: z3,
_marker: PhantomData,
_marker: PhantomData
}
}
#[must_use]
pub fn mul<S: Into<<E::Fs as PrimeField>::Repr>>(&self, scalar: S, params: &E::Params) -> Self {
pub fn mul<S: Into<<E::Fs as PrimeField>::Repr>>(
&self,
scalar: S,
params: &E::Params
) -> Self
{
// Standard double-and-add scalar multiplication
let mut res = Self::zero();

View File

@@ -17,14 +17,21 @@
//! the Montgomery curve forms a group isomorphism, allowing points
//! to be freely converted between the two forms.
use ff::{Field, PrimeField, SqrtField};
use pairing::Engine;
use pairing::{
Engine,
Field,
PrimeField,
SqrtField
};
use group_hash::group_hash;
use constants;
use pairing::bls12_381::{Bls12, Fr};
use pairing::bls12_381::{
Bls12,
Fr
};
/// This is an implementation of the twisted Edwards Jubjub curve.
pub mod edwards;
@@ -40,12 +47,10 @@ pub mod fs;
pub mod tests;
/// Point of unknown order.
#[derive(Debug)]
pub enum Unknown {}
pub enum Unknown { }
/// Point of prime order.
#[derive(Debug)]
pub enum PrimeOrder {}
pub enum PrimeOrder { }
/// Fixed generators of the Jubjub curve of unknown
/// exponent.
@@ -77,7 +82,7 @@ pub enum FixedGenerators {
/// base at spend time.
SpendingKeyGenerator = 5,
Max = 6,
Max = 6
}
pub trait ToUniform {
@@ -148,18 +153,10 @@ pub struct JubjubBls12 {
}
impl JubjubParams<Bls12> for JubjubBls12 {
fn edwards_d(&self) -> &Fr {
&self.edwards_d
}
fn montgomery_a(&self) -> &Fr {
&self.montgomery_a
}
fn montgomery_2a(&self) -> &Fr {
&self.montgomery_2a
}
fn scale(&self) -> &Fr {
&self.scale
}
fn edwards_d(&self) -> &Fr { &self.edwards_d }
fn montgomery_a(&self) -> &Fr { &self.montgomery_a }
fn montgomery_2a(&self) -> &Fr { &self.montgomery_2a }
fn scale(&self) -> &Fr { &self.scale }
fn pedersen_hash_generators(&self) -> &[edwards::Point<Bls12, PrimeOrder>] {
&self.pedersen_hash_generators
}
@@ -175,10 +172,12 @@ impl JubjubParams<Bls12> for JubjubBls12 {
fn pedersen_circuit_generators(&self) -> &[Vec<Vec<(Fr, Fr)>>] {
&self.pedersen_circuit_generators
}
fn generator(&self, base: FixedGenerators) -> &edwards::Point<Bls12, PrimeOrder> {
fn generator(&self, base: FixedGenerators) -> &edwards::Point<Bls12, PrimeOrder>
{
&self.fixed_base_generators[base as usize]
}
fn circuit_generators(&self, base: FixedGenerators) -> &[Vec<(Fr, Fr)>] {
fn circuit_generators(&self, base: FixedGenerators) -> &[Vec<(Fr, Fr)>]
{
&self.fixed_base_circuit_generators[base as usize][..]
}
fn pedersen_hash_exp_window_size() -> u32 {
@@ -194,19 +193,13 @@ impl JubjubBls12 {
let mut tmp_params = JubjubBls12 {
// d = -(10240/10241)
edwards_d: Fr::from_str(
"19257038036680949359750312669786877991949435402254120286184196891950884077233",
)
.unwrap(),
edwards_d: Fr::from_str("19257038036680949359750312669786877991949435402254120286184196891950884077233").unwrap(),
// A = 40962
montgomery_a: montgomery_a,
// 2A = 2.A
montgomery_2a: montgomery_2a,
// scaling factor = sqrt(4 / (a - d))
scale: Fr::from_str(
"17814886934372412843466061268024708274627479829237077604635722030778476050649",
)
.unwrap(),
scale: Fr::from_str("17814886934372412843466061268024708274627479829237077604635722030778476050649").unwrap(),
// We'll initialize these below
pedersen_hash_generators: vec![],
@@ -219,14 +212,19 @@ impl JubjubBls12 {
fn find_group_hash<E: JubjubEngine>(
m: &[u8],
personalization: &[u8; 8],
params: &E::Params,
) -> edwards::Point<E, PrimeOrder> {
params: &E::Params
) -> edwards::Point<E, PrimeOrder>
{
let mut tag = m.to_vec();
let i = tag.len();
tag.push(0u8);
loop {
let gh = group_hash(&tag, personalization, params);
let gh = group_hash(
&tag,
personalization,
params
);
// We don't want to overflow and start reusing generators
assert!(tag[i] != u8::max_value());
@@ -243,18 +241,18 @@ impl JubjubBls12 {
let mut pedersen_hash_generators = vec![];
for m in 0..5 {
use byteorder::{LittleEndian, WriteBytesExt};
use byteorder::{WriteBytesExt, LittleEndian};
let mut segment_number = [0u8; 4];
(&mut segment_number[0..4])
.write_u32::<LittleEndian>(m)
.unwrap();
(&mut segment_number[0..4]).write_u32::<LittleEndian>(m).unwrap();
pedersen_hash_generators.push(find_group_hash(
&segment_number,
constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION,
&tmp_params,
));
pedersen_hash_generators.push(
find_group_hash(
&segment_number,
constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION,
&tmp_params
)
);
}
// Check for duplicates, far worse than spec inconsistencies!
@@ -263,7 +261,7 @@ impl JubjubBls12 {
panic!("Neutral element!");
}
for p2 in pedersen_hash_generators.iter().skip(i + 1) {
for p2 in pedersen_hash_generators.iter().skip(i+1) {
if p1 == p2 {
panic!("Duplicate generator!");
}
@@ -311,46 +309,25 @@ impl JubjubBls12 {
// Create the bases for other parts of the protocol
{
let mut fixed_base_generators =
vec![edwards::Point::zero(); FixedGenerators::Max as usize];
let mut fixed_base_generators = vec![edwards::Point::zero(); FixedGenerators::Max as usize];
fixed_base_generators[FixedGenerators::ProofGenerationKey as usize] = find_group_hash(
&[],
constants::PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION,
&tmp_params,
);
fixed_base_generators[FixedGenerators::ProofGenerationKey as usize] =
find_group_hash(&[], constants::PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION, &tmp_params);
fixed_base_generators[FixedGenerators::NoteCommitmentRandomness as usize] =
find_group_hash(
b"r",
constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION,
&tmp_params,
);
find_group_hash(b"r", constants::PEDERSEN_HASH_GENERATORS_PERSONALIZATION, &tmp_params);
fixed_base_generators[FixedGenerators::NullifierPosition as usize] = find_group_hash(
&[],
constants::NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION,
&tmp_params,
);
fixed_base_generators[FixedGenerators::NullifierPosition as usize] =
find_group_hash(&[], constants::NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION, &tmp_params);
fixed_base_generators[FixedGenerators::ValueCommitmentValue as usize] = find_group_hash(
b"v",
constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION,
&tmp_params,
);
fixed_base_generators[FixedGenerators::ValueCommitmentValue as usize] =
find_group_hash(b"v", constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, &tmp_params);
fixed_base_generators[FixedGenerators::ValueCommitmentRandomness as usize] =
find_group_hash(
b"r",
constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION,
&tmp_params,
);
find_group_hash(b"r", constants::VALUE_COMMITMENT_GENERATOR_PERSONALIZATION, &tmp_params);
fixed_base_generators[FixedGenerators::SpendingKeyGenerator as usize] = find_group_hash(
&[],
constants::SPENDING_KEY_GENERATOR_PERSONALIZATION,
&tmp_params,
);
fixed_base_generators[FixedGenerators::SpendingKeyGenerator as usize] =
find_group_hash(&[], constants::SPENDING_KEY_GENERATOR_PERSONALIZATION, &tmp_params);
// Check for duplicates, far worse than spec inconsistencies!
for (i, p1) in fixed_base_generators.iter().enumerate() {
@@ -358,7 +335,7 @@ impl JubjubBls12 {
panic!("Neutral element!");
}
for p2 in fixed_base_generators.iter().skip(i + 1) {
for p2 in fixed_base_generators.iter().skip(i+1) {
if p1 == p2 {
panic!("Duplicate generator!");
}
@@ -438,14 +415,10 @@ fn test_jubjub_bls12() {
let test_repr = hex!("9d12b88b08dcbef8a11ee0712d94cb236ee2f4ca17317075bfafc82ce3139d31");
let p = edwards::Point::<Bls12, _>::read(&test_repr[..], &params).unwrap();
let q = edwards::Point::<Bls12, _>::get_for_y(
Fr::from_str(
"22440861827555040311190986994816762244378363690614952020532787748720529117853",
)
.unwrap(),
Fr::from_str("22440861827555040311190986994816762244378363690614952020532787748720529117853").unwrap(),
false,
&params,
)
.unwrap();
&params
).unwrap();
assert!(p == q);
@@ -453,14 +426,10 @@ fn test_jubjub_bls12() {
let test_repr = hex!("9d12b88b08dcbef8a11ee0712d94cb236ee2f4ca17317075bfafc82ce3139db1");
let p = edwards::Point::<Bls12, _>::read(&test_repr[..], &params).unwrap();
let q = edwards::Point::<Bls12, _>::get_for_y(
Fr::from_str(
"22440861827555040311190986994816762244378363690614952020532787748720529117853",
)
.unwrap(),
Fr::from_str("22440861827555040311190986994816762244378363690614952020532787748720529117853").unwrap(),
true,
&params,
)
.unwrap();
&params
).unwrap();
assert!(p == q);
}

View File

@@ -1,8 +1,22 @@
use ff::{BitIterator, Field, PrimeField, PrimeFieldRepr, SqrtField};
use pairing::{
Field,
SqrtField,
PrimeField,
PrimeFieldRepr,
BitIterator
};
use super::{edwards, JubjubEngine, JubjubParams, PrimeOrder, Unknown};
use super::{
JubjubEngine,
JubjubParams,
Unknown,
PrimeOrder,
edwards
};
use rand_core::RngCore;
use rand::{
Rng
};
use std::marker::PhantomData;
@@ -11,25 +25,29 @@ pub struct Point<E: JubjubEngine, Subgroup> {
x: E::Fr,
y: E::Fr,
infinity: bool,
_marker: PhantomData<Subgroup>,
_marker: PhantomData<Subgroup>
}
fn convert_subgroup<E: JubjubEngine, S1, S2>(from: &Point<E, S1>) -> Point<E, S2> {
fn convert_subgroup<E: JubjubEngine, S1, S2>(from: &Point<E, S1>) -> Point<E, S2>
{
Point {
x: from.x,
y: from.y,
infinity: from.infinity,
_marker: PhantomData,
_marker: PhantomData
}
}
impl<E: JubjubEngine> From<Point<E, PrimeOrder>> for Point<E, Unknown> {
fn from(p: Point<E, PrimeOrder>) -> Point<E, Unknown> {
impl<E: JubjubEngine> From<Point<E, PrimeOrder>> for Point<E, Unknown>
{
fn from(p: Point<E, PrimeOrder>) -> Point<E, Unknown>
{
convert_subgroup(&p)
}
}
impl<E: JubjubEngine, Subgroup> Clone for Point<E, Subgroup> {
impl<E: JubjubEngine, Subgroup> Clone for Point<E, Subgroup>
{
fn clone(&self) -> Self {
convert_subgroup(self)
}
@@ -40,13 +58,16 @@ impl<E: JubjubEngine, Subgroup> PartialEq for Point<E, Subgroup> {
match (self.infinity, other.infinity) {
(true, true) => true,
(true, false) | (false, true) => false,
(false, false) => self.x == other.x && self.y == other.y,
(false, false) => {
self.x == other.x && self.y == other.y
}
}
}
}
impl<E: JubjubEngine> Point<E, Unknown> {
pub fn get_for_x(x: E::Fr, sign: bool, params: &E::Params) -> Option<Self> {
pub fn get_for_x(x: E::Fr, sign: bool, params: &E::Params) -> Option<Self>
{
// Given an x on the curve, y = sqrt(x^3 + A*x^2 + x)
let mut x2 = x;
@@ -68,28 +89,33 @@ impl<E: JubjubEngine> Point<E, Unknown> {
x: x,
y: y,
infinity: false,
_marker: PhantomData,
});
}
None => None,
_marker: PhantomData
})
},
None => None
}
}
/// This guarantees the point is in the prime order subgroup
#[must_use]
pub fn mul_by_cofactor(&self, params: &E::Params) -> Point<E, PrimeOrder> {
let tmp = self.double(params).double(params).double(params);
pub fn mul_by_cofactor(&self, params: &E::Params) -> Point<E, PrimeOrder>
{
let tmp = self.double(params)
.double(params)
.double(params);
convert_subgroup(&tmp)
}
pub fn rand<R: RngCore>(rng: &mut R, params: &E::Params) -> Self {
pub fn rand<R: Rng>(rng: &mut R, params: &E::Params) -> Self
{
loop {
let x = E::Fr::random(rng);
let sign = rng.next_u32() % 2 != 0;
let x: E::Fr = rng.gen();
match Self::get_for_x(x, sign, params) {
Some(p) => return p,
match Self::get_for_x(x, rng.gen(), params) {
Some(p) => {
return p
},
None => {}
}
}
@@ -98,7 +124,11 @@ impl<E: JubjubEngine> Point<E, Unknown> {
impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
/// Convert from an Edwards point
pub fn from_edwards(e: &edwards::Point<E, Subgroup>, params: &E::Params) -> Self {
pub fn from_edwards(
e: &edwards::Point<E, Subgroup>,
params: &E::Params
) -> Self
{
let (x, y) = e.into_xy();
if y == E::Fr::one() {
@@ -126,7 +156,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
x: E::Fr::zero(),
y: E::Fr::zero(),
infinity: false,
_marker: PhantomData,
_marker: PhantomData
}
} else {
// The mapping is defined as above.
@@ -153,7 +183,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
x: u,
y: v,
infinity: false,
_marker: PhantomData,
_marker: PhantomData
}
}
}
@@ -174,11 +204,12 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
x: E::Fr::zero(),
y: E::Fr::zero(),
infinity: true,
_marker: PhantomData,
_marker: PhantomData
}
}
pub fn into_xy(&self) -> Option<(E::Fr, E::Fr)> {
pub fn into_xy(&self) -> Option<(E::Fr, E::Fr)>
{
if self.infinity {
None
} else {
@@ -248,12 +279,13 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
x: x3,
y: y3,
infinity: false,
_marker: PhantomData,
_marker: PhantomData
}
}
#[must_use]
pub fn add(&self, other: &Self, params: &E::Params) -> Self {
pub fn add(&self, other: &Self, params: &E::Params) -> Self
{
// This is a standard affine point addition formula
// See 4.3.2 The group law for Weierstrass curves
// Montgomery curves and the Montgomery Ladder
@@ -276,10 +308,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
{
let mut tmp = other.x;
tmp.sub_assign(&self.x);
delta.mul_assign(
&tmp.inverse()
.expect("self.x != other.x, so this must be nonzero"),
);
delta.mul_assign(&tmp.inverse().expect("self.x != other.x, so this must be nonzero"));
}
let mut x3 = delta;
@@ -298,7 +327,7 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
x: x3,
y: y3,
infinity: false,
_marker: PhantomData,
_marker: PhantomData
}
}
}
@@ -306,7 +335,12 @@ impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
}
#[must_use]
pub fn mul<S: Into<<E::Fs as PrimeField>::Repr>>(&self, scalar: S, params: &E::Params) -> Self {
pub fn mul<S: Into<<E::Fs as PrimeField>::Repr>>(
&self,
scalar: S,
params: &E::Params
) -> Self
{
// Standard double-and-add scalar multiplication
let mut res = Self::zero();

View File

@@ -1,9 +1,20 @@
use super::{edwards, montgomery, JubjubEngine, JubjubParams, PrimeOrder};
use super::{
JubjubEngine,
JubjubParams,
PrimeOrder,
montgomery,
edwards
};
use ff::{Field, LegendreSymbol, PrimeField, PrimeFieldRepr, SqrtField};
use pairing::{
Field,
PrimeField,
PrimeFieldRepr,
SqrtField,
LegendreSymbol
};
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
use rand::{XorShiftRng, SeedableRng, Rand};
pub fn test_suite<E: JubjubEngine>(params: &E::Params) {
test_back_and_forth::<E>(params);
@@ -18,7 +29,12 @@ pub fn test_suite<E: JubjubEngine>(params: &E::Params) {
test_read_write::<E>(params);
}
fn is_on_mont_curve<E: JubjubEngine, P: JubjubParams<E>>(x: E::Fr, y: E::Fr, params: &P) -> bool {
fn is_on_mont_curve<E: JubjubEngine, P: JubjubParams<E>>(
x: E::Fr,
y: E::Fr,
params: &P
) -> bool
{
let mut lhs = y;
lhs.square();
@@ -39,8 +55,9 @@ fn is_on_mont_curve<E: JubjubEngine, P: JubjubParams<E>>(x: E::Fr, y: E::Fr, par
fn is_on_twisted_edwards_curve<E: JubjubEngine, P: JubjubParams<E>>(
x: E::Fr,
y: E::Fr,
params: &P,
) -> bool {
params: &P
) -> bool
{
let mut x2 = x;
x2.square();
@@ -61,10 +78,7 @@ fn is_on_twisted_edwards_curve<E: JubjubEngine, P: JubjubParams<E>>(
}
fn test_loworder<E: JubjubEngine>(params: &E::Params) {
let rng = &mut XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let inf = montgomery::Point::zero();
// try to find a point of order 8
@@ -95,18 +109,15 @@ fn test_loworder<E: JubjubEngine>(params: &E::Params) {
fn test_mul_associativity<E: JubjubEngine>(params: &E::Params) {
use self::edwards::Point;
let rng = &mut XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..100 {
// Pick a random point and multiply it by the cofactor
let base = Point::<E, _>::rand(rng, params).mul_by_cofactor(params);
let mut a = E::Fs::random(rng);
let b = E::Fs::random(rng);
let c = E::Fs::random(rng);
let mut a = E::Fs::rand(rng);
let b = E::Fs::rand(rng);
let c = E::Fs::rand(rng);
let res1 = base.mul(a, params).mul(b, params).mul(c, params);
let res2 = base.mul(b, params).mul(c, params).mul(a, params);
@@ -132,15 +143,10 @@ fn test_mul_associativity<E: JubjubEngine>(params: &E::Params) {
fn test_order<E: JubjubEngine>(params: &E::Params) {
use self::edwards::Point;
let rng = &mut XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
// The neutral element is in the prime order subgroup.
assert!(Point::<E, PrimeOrder>::zero()
.as_prime_order(params)
.is_some());
assert!(Point::<E, PrimeOrder>::zero().as_prime_order(params).is_some());
for _ in 0..50 {
// Pick a random point and multiply it by the cofactor
@@ -164,10 +170,7 @@ fn test_order<E: JubjubEngine>(params: &E::Params) {
}
fn test_addition_associativity<E: JubjubEngine>(params: &E::Params) {
let rng = &mut XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
use self::montgomery::Point;
@@ -191,10 +194,7 @@ fn test_addition_associativity<E: JubjubEngine>(params: &E::Params) {
}
fn test_identities<E: JubjubEngine>(params: &E::Params) {
let rng = &mut XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
{
use self::edwards::Point;
@@ -228,28 +228,26 @@ fn test_identities<E: JubjubEngine>(params: &E::Params) {
}
fn test_get_for<E: JubjubEngine>(params: &E::Params) {
let rng = &mut XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let y = E::Fr::random(rng);
let sign = rng.next_u32() % 2 == 1;
let y = E::Fr::rand(rng);
let sign = bool::rand(rng);
if let Some(mut p) = edwards::Point::<E, _>::get_for_y(y, sign, params) {
assert!(p.into_xy().0.into_repr().is_odd() == sign);
p = p.negate();
assert!(edwards::Point::<E, _>::get_for_y(y, !sign, params).unwrap() == p);
assert!(
edwards::Point::<E, _>::get_for_y(y, !sign, params).unwrap()
==
p
);
}
}
}
fn test_read_write<E: JubjubEngine>(params: &E::Params) {
let rng = &mut XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let e = edwards::Point::<E, _>::rand(rng, params);
@@ -264,10 +262,7 @@ fn test_read_write<E: JubjubEngine>(params: &E::Params) {
}
fn test_rand<E: JubjubEngine>(params: &E::Params) {
let rng = &mut XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let p = montgomery::Point::<E, _>::rand(rng, params);
@@ -286,13 +281,10 @@ fn test_rand<E: JubjubEngine>(params: &E::Params) {
}
fn test_back_and_forth<E: JubjubEngine>(params: &E::Params) {
let rng = &mut XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x5d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
let rng = &mut XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let s = E::Fs::random(rng);
let s = E::Fs::rand(rng);
let edwards_p1 = edwards::Point::<E, _>::rand(rng, params);
let mont_p1 = montgomery::Point::from_edwards(&edwards_p1, params);
let mont_p2 = montgomery::Point::<E, _>::rand(rng, params);
@@ -301,9 +293,13 @@ fn test_back_and_forth<E: JubjubEngine>(params: &E::Params) {
let mont = mont_p1.add(&mont_p2, params).mul(s, params);
let edwards = edwards_p1.add(&edwards_p2, params).mul(s, params);
assert!(montgomery::Point::from_edwards(&edwards, params) == mont);
assert!(
montgomery::Point::from_edwards(&edwards, params) == mont
);
assert!(edwards::Point::from_montgomery(&mont, params) == edwards);
assert!(
edwards::Point::from_montgomery(&mont, params) == edwards
);
}
}
@@ -387,7 +383,8 @@ fn test_jubjub_params<E: JubjubEngine>(params: &E::Params) {
let mut pacc = E::Fs::zero().into_repr();
let mut nacc = E::Fs::char();
for _ in 0..params.pedersen_hash_chunks_per_generator() {
for _ in 0..params.pedersen_hash_chunks_per_generator()
{
// tmp = cur * 4
let mut tmp = cur;
tmp.mul2();

22
sapling-crypto/src/lib.rs Normal file
View File

@@ -0,0 +1,22 @@
extern crate pairing;
extern crate bellman;
extern crate blake2_rfc;
extern crate digest;
extern crate rand;
extern crate byteorder;
#[cfg(test)]
#[macro_use]
extern crate hex_literal;
#[cfg(test)]
extern crate crypto;
pub mod jubjub;
pub mod group_hash;
pub mod circuit;
pub mod pedersen_hash;
pub mod primitives;
pub mod constants;
pub mod redjubjub;
pub mod util;

View File

@@ -1,16 +1,17 @@
use ff::{Field, PrimeField, PrimeFieldRepr};
use jubjub::*;
use pairing::*;
#[derive(Copy, Clone)]
pub enum Personalization {
NoteCommitment,
MerkleTree(usize),
MerkleTree(usize)
}
impl Personalization {
pub fn get_bits(&self) -> Vec<bool> {
match *self {
Personalization::NoteCommitment => vec![true, true, true, true, true, true],
Personalization::NoteCommitment =>
vec![true, true, true, true, true, true],
Personalization::MerkleTree(num) => {
assert!(num < 63);
@@ -23,16 +24,12 @@ impl Personalization {
pub fn pedersen_hash<E, I>(
personalization: Personalization,
bits: I,
params: &E::Params,
params: &E::Params
) -> edwards::Point<E, PrimeOrder>
where
I: IntoIterator<Item = bool>,
E: JubjubEngine,
where I: IntoIterator<Item=bool>,
E: JubjubEngine
{
let mut bits = personalization
.get_bits()
.into_iter()
.chain(bits.into_iter());
let mut bits = personalization.get_bits().into_iter().chain(bits.into_iter());
let mut result = edwards::Point::zero();
let mut generators = params.pedersen_hash_exp_table().iter();
@@ -82,13 +79,12 @@ where
break;
}
let mut table: &[Vec<edwards::Point<E, _>>] =
&generators.next().expect("we don't have enough generators");
let mut table: &[Vec<edwards::Point<E, _>>] = &generators.next().expect("we don't have enough generators");
let window = JubjubBls12::pedersen_hash_exp_window_size();
let window_mask = (1 << window) - 1;
let mut acc = acc.into_repr();
let mut tmp = edwards::Point::zero();
while !acc.is_zero() {

View File

@@ -1,67 +1,86 @@
use ff::{Field, PrimeField, PrimeFieldRepr};
use pairing::{
Field,
PrimeField,
PrimeFieldRepr
};
use constants;
use group_hash::group_hash;
use pedersen_hash::{pedersen_hash, Personalization};
use pedersen_hash::{
pedersen_hash,
Personalization
};
use byteorder::{LittleEndian, WriteBytesExt};
use byteorder::{
LittleEndian,
WriteBytesExt
};
use jubjub::{edwards, FixedGenerators, JubjubEngine, JubjubParams, PrimeOrder};
use jubjub::{
JubjubEngine,
JubjubParams,
edwards,
PrimeOrder,
FixedGenerators
};
use blake2s_simd::Params as Blake2sParams;
use blake2_rfc::blake2s::Blake2s;
#[derive(Clone)]
pub struct ValueCommitment<E: JubjubEngine> {
pub value: u64,
pub randomness: E::Fs,
pub randomness: E::Fs
}
impl<E: JubjubEngine> ValueCommitment<E> {
pub fn cm(&self, params: &E::Params) -> edwards::Point<E, PrimeOrder> {
params
.generator(FixedGenerators::ValueCommitmentValue)
.mul(self.value, params)
.add(
&params
.generator(FixedGenerators::ValueCommitmentRandomness)
.mul(self.randomness, params),
params,
)
pub fn cm(
&self,
params: &E::Params
) -> edwards::Point<E, PrimeOrder>
{
params.generator(FixedGenerators::ValueCommitmentValue)
.mul(self.value, params)
.add(
&params.generator(FixedGenerators::ValueCommitmentRandomness)
.mul(self.randomness, params),
params
)
}
}
#[derive(Clone)]
pub struct ProofGenerationKey<E: JubjubEngine> {
pub ak: edwards::Point<E, PrimeOrder>,
pub nsk: E::Fs,
pub nsk: E::Fs
}
impl<E: JubjubEngine> ProofGenerationKey<E> {
pub fn into_viewing_key(&self, params: &E::Params) -> ViewingKey<E> {
ViewingKey {
ak: self.ak.clone(),
nk: params
.generator(FixedGenerators::ProofGenerationKey)
.mul(self.nsk, params),
nk: params.generator(FixedGenerators::ProofGenerationKey)
.mul(self.nsk, params)
}
}
}
#[derive(Debug)]
pub struct ViewingKey<E: JubjubEngine> {
pub ak: edwards::Point<E, PrimeOrder>,
pub nk: edwards::Point<E, PrimeOrder>,
pub nk: edwards::Point<E, PrimeOrder>
}
impl<E: JubjubEngine> ViewingKey<E> {
pub fn rk(&self, ar: E::Fs, params: &E::Params) -> edwards::Point<E, PrimeOrder> {
pub fn rk(
&self,
ar: E::Fs,
params: &E::Params
) -> edwards::Point<E, PrimeOrder> {
self.ak.add(
&params
.generator(FixedGenerators::SpendingKeyGenerator)
.mul(ar, params),
params,
&params.generator(FixedGenerators::SpendingKeyGenerator)
.mul(ar, params),
params
)
}
@@ -71,14 +90,9 @@ impl<E: JubjubEngine> ViewingKey<E> {
self.ak.write(&mut preimage[0..32]).unwrap();
self.nk.write(&mut preimage[32..64]).unwrap();
let mut h = [0; 32];
h.copy_from_slice(
Blake2sParams::new()
.hash_length(32)
.personal(constants::CRH_IVK_PERSONALIZATION)
.hash(&preimage)
.as_bytes(),
);
let mut h = Blake2s::with_params(32, &[], &[], constants::CRH_IVK_PERSONALIZATION);
h.update(&preimage);
let mut h = h.finalize().as_ref().to_vec();
// Drop the most significant five bits, so it can be interpreted as a scalar.
h[31] &= 0b0000_0111;
@@ -92,49 +106,45 @@ impl<E: JubjubEngine> ViewingKey<E> {
pub fn into_payment_address(
&self,
diversifier: Diversifier,
params: &E::Params,
) -> Option<PaymentAddress<E>> {
params: &E::Params
) -> Option<PaymentAddress<E>>
{
diversifier.g_d(params).map(|g_d| {
let pk_d = g_d.mul(self.ivk(), params);
PaymentAddress {
pk_d: pk_d,
diversifier: diversifier,
diversifier: diversifier
}
})
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone)]
pub struct Diversifier(pub [u8; 11]);
impl Diversifier {
pub fn g_d<E: JubjubEngine>(
&self,
params: &E::Params,
) -> Option<edwards::Point<E, PrimeOrder>> {
group_hash::<E>(
&self.0,
constants::KEY_DIVERSIFICATION_PERSONALIZATION,
params,
)
params: &E::Params
) -> Option<edwards::Point<E, PrimeOrder>>
{
group_hash::<E>(&self.0, constants::KEY_DIVERSIFICATION_PERSONALIZATION, params)
}
}
#[derive(Clone, Debug)]
#[derive(Clone)]
pub struct PaymentAddress<E: JubjubEngine> {
pub pk_d: edwards::Point<E, PrimeOrder>,
pub diversifier: Diversifier,
}
impl<E: JubjubEngine> PartialEq for PaymentAddress<E> {
fn eq(&self, other: &Self) -> bool {
self.pk_d == other.pk_d && self.diversifier == other.diversifier
}
pub diversifier: Diversifier
}
impl<E: JubjubEngine> PaymentAddress<E> {
pub fn g_d(&self, params: &E::Params) -> Option<edwards::Point<E, PrimeOrder>> {
pub fn g_d(
&self,
params: &E::Params
) -> Option<edwards::Point<E, PrimeOrder>>
{
self.diversifier.g_d(params)
}
@@ -142,18 +152,20 @@ impl<E: JubjubEngine> PaymentAddress<E> {
&self,
value: u64,
randomness: E::Fs,
params: &E::Params,
) -> Option<Note<E>> {
self.g_d(params).map(|g_d| Note {
value: value,
r: randomness,
g_d: g_d,
pk_d: self.pk_d.clone(),
params: &E::Params
) -> Option<Note<E>>
{
self.g_d(params).map(|g_d| {
Note {
value: value,
r: randomness,
g_d: g_d,
pk_d: self.pk_d.clone()
}
})
}
}
#[derive(Clone, Debug)]
pub struct Note<E: JubjubEngine> {
/// The value of the note
pub value: u64,
@@ -162,16 +174,7 @@ pub struct Note<E: JubjubEngine> {
/// The public key of the address, g_d^ivk
pub pk_d: edwards::Point<E, PrimeOrder>,
/// The commitment randomness
pub r: E::Fs,
}
impl<E: JubjubEngine> PartialEq for Note<E> {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
&& self.g_d == other.g_d
&& self.pk_d == other.pk_d
&& self.r == other.r
}
pub r: E::Fs
}
impl<E: JubjubEngine> Note<E> {
@@ -185,14 +188,13 @@ impl<E: JubjubEngine> Note<E> {
}
/// Computes the note commitment, returning the full point.
fn cm_full_point(&self, params: &E::Params) -> edwards::Point<E, PrimeOrder> {
fn cm_full_point(&self, params: &E::Params) -> edwards::Point<E, PrimeOrder>
{
// Calculate the note contents, as bytes
let mut note_contents = vec![];
// Writing the value in little endian
(&mut note_contents)
.write_u64::<LittleEndian>(self.value)
.unwrap();
(&mut note_contents).write_u64::<LittleEndian>(self.value).unwrap();
// Write g_d
self.g_d.write(&mut note_contents).unwrap();
@@ -205,44 +207,50 @@ impl<E: JubjubEngine> Note<E> {
// Compute the Pedersen hash of the note contents
let hash_of_contents = pedersen_hash(
Personalization::NoteCommitment,
note_contents
.into_iter()
.flat_map(|byte| (0..8).map(move |i| ((byte >> i) & 1) == 1)),
params,
note_contents.into_iter()
.flat_map(|byte| {
(0..8).map(move |i| ((byte >> i) & 1) == 1)
}),
params
);
// Compute final commitment
params
.generator(FixedGenerators::NoteCommitmentRandomness)
.mul(self.r, params)
.add(&hash_of_contents, params)
params.generator(FixedGenerators::NoteCommitmentRandomness)
.mul(self.r, params)
.add(&hash_of_contents, params)
}
/// Computes the nullifier given the viewing key and
/// note position
pub fn nf(&self, viewing_key: &ViewingKey<E>, position: u64, params: &E::Params) -> Vec<u8> {
pub fn nf(
&self,
viewing_key: &ViewingKey<E>,
position: u64,
params: &E::Params
) -> Vec<u8>
{
// Compute rho = cm + position.G
let rho = self.cm_full_point(params).add(
&params
.generator(FixedGenerators::NullifierPosition)
.mul(position, params),
params,
);
let rho = self
.cm_full_point(params)
.add(
&params.generator(FixedGenerators::NullifierPosition)
.mul(position, params),
params
);
// Compute nf = BLAKE2s(nk | rho)
let mut nf_preimage = [0u8; 64];
viewing_key.nk.write(&mut nf_preimage[0..32]).unwrap();
rho.write(&mut nf_preimage[32..64]).unwrap();
Blake2sParams::new()
.hash_length(32)
.personal(constants::PRF_NF_PERSONALIZATION)
.hash(&nf_preimage)
.as_bytes()
.to_vec()
let mut h = Blake2s::with_params(32, &[], &[], constants::PRF_NF_PERSONALIZATION);
h.update(&nf_preimage);
h.finalize().as_ref().to_vec()
}
/// Computes the note commitment
pub fn cm(&self, params: &E::Params) -> E::Fr {
pub fn cm(&self, params: &E::Params) -> E::Fr
{
// The commitment is in the prime order subgroup, so mapping the
// commitment to the x-coordinate is an injective encoding.
self.cm_full_point(params).into_xy().0

View File

@@ -1,12 +1,12 @@
//! Implementation of RedJubjub, a specialization of RedDSA to the Jubjub curve.
//! See section 5.4.6 of the Sapling protocol specification.
use crate::jubjub::{edwards::Point, FixedGenerators, JubjubEngine, JubjubParams, Unknown};
use ff::{Field, PrimeField, PrimeFieldRepr};
use rand_core::RngCore;
use pairing::{Field, PrimeField, PrimeFieldRepr};
use rand::{Rng, Rand};
use std::io::{self, Read, Write};
use util::hash_to_scalar;
use jubjub::{FixedGenerators, JubjubEngine, JubjubParams, Unknown, edwards::Point};
use util::{hash_to_scalar};
fn read_scalar<E: JubjubEngine, R: Read>(reader: R) -> io::Result<E::Fs> {
let mut s_repr = <E::Fs as PrimeField>::Repr::default();
@@ -29,7 +29,7 @@ fn h_star<E: JubjubEngine>(a: &[u8], b: &[u8]) -> E::Fs {
hash_to_scalar::<E>(b"Zcash_RedJubjubH", a, b)
}
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone)]
pub struct Signature {
rbar: [u8; 32],
sbar: [u8; 32],
@@ -37,7 +37,6 @@ pub struct Signature {
pub struct PrivateKey<E: JubjubEngine>(pub E::Fs);
#[derive(Debug)]
pub struct PublicKey<E: JubjubEngine>(pub Point<E, Unknown>);
impl Signature {
@@ -71,7 +70,7 @@ impl<E: JubjubEngine> PrivateKey<E> {
write_scalar::<E, W>(&self.0, writer)
}
pub fn sign<R: RngCore>(
pub fn sign<R: Rng>(
&self,
msg: &[u8],
rng: &mut R,
@@ -148,15 +147,10 @@ impl<E: JubjubEngine> PublicKey<E> {
Err(_) => return false,
};
// 0 = h_G(-S . P_G + R + c . vk)
self.0
.mul(c, params)
.add(&r, params)
.add(
&params.generator(p_g).mul(s, params).negate().into(),
params,
)
.mul_by_cofactor(params)
.eq(&Point::zero())
self.0.mul(c, params).add(&r, params).add(
&params.generator(p_g).mul(s, params).negate().into(),
params
).mul_by_cofactor(params).eq(&Point::zero())
}
}
@@ -168,12 +162,13 @@ pub struct BatchEntry<'a, E: JubjubEngine> {
// TODO: #82: This is a naive implementation currently,
// and doesn't use multiexp.
pub fn batch_verify<'a, E: JubjubEngine, R: RngCore>(
pub fn batch_verify<'a, E: JubjubEngine, R: Rng>(
rng: &mut R,
batch: &[BatchEntry<'a, E>],
p_g: FixedGenerators,
params: &E::Params,
) -> bool {
) -> bool
{
let mut acc = Point::<E, Unknown>::zero();
for entry in batch {
@@ -188,7 +183,7 @@ pub fn batch_verify<'a, E: JubjubEngine, R: RngCore>(
let mut c = h_star::<E>(&entry.sig.rbar[..], entry.msg);
let z = E::Fs::random(rng);
let z = E::Fs::rand(rng);
s.mul_assign(&z);
s.negate();
@@ -210,45 +205,33 @@ pub fn batch_verify<'a, E: JubjubEngine, R: RngCore>(
#[cfg(test)]
mod tests {
use pairing::bls12_381::Bls12;
use rand_core::SeedableRng;
use rand_xorshift::XorShiftRng;
use rand::thread_rng;
use crate::jubjub::{edwards, fs::Fs, JubjubBls12};
use jubjub::{JubjubBls12, fs::Fs, edwards};
use super::*;
#[test]
fn test_batch_verify() {
let rng = &mut XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let rng = &mut thread_rng();
let params = &JubjubBls12::new();
let p_g = FixedGenerators::SpendingKeyGenerator;
let sk1 = PrivateKey::<Bls12>(Fs::random(rng));
let sk1 = PrivateKey::<Bls12>(rng.gen());
let vk1 = PublicKey::from_private(&sk1, p_g, params);
let msg1 = b"Foo bar";
let sig1 = sk1.sign(msg1, rng, p_g, params);
assert!(vk1.verify(msg1, &sig1, p_g, params));
let sk2 = PrivateKey::<Bls12>(Fs::random(rng));
let sk2 = PrivateKey::<Bls12>(rng.gen());
let vk2 = PublicKey::from_private(&sk2, p_g, params);
let msg2 = b"Foo bar";
let sig2 = sk2.sign(msg2, rng, p_g, params);
assert!(vk2.verify(msg2, &sig2, p_g, params));
let mut batch = vec![
BatchEntry {
vk: vk1,
msg: msg1,
sig: sig1,
},
BatchEntry {
vk: vk2,
msg: msg2,
sig: sig2,
},
BatchEntry { vk: vk1, msg: msg1, sig: sig1 },
BatchEntry { vk: vk2, msg: msg2, sig: sig2 }
];
assert!(batch_verify(rng, &batch, p_g, params));
@@ -260,10 +243,7 @@ mod tests {
#[test]
fn cofactor_check() {
let rng = &mut XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let rng = &mut thread_rng();
let params = &JubjubBls12::new();
let zero = edwards::Point::zero();
let p_g = FixedGenerators::SpendingKeyGenerator;
@@ -281,7 +261,7 @@ mod tests {
}
};
let sk = PrivateKey::<Bls12>(Fs::random(rng));
let sk = PrivateKey::<Bls12>(rng.gen());
let vk = PublicKey::from_private(&sk, p_g, params);
// TODO: This test will need to change when #77 is fixed
@@ -295,15 +275,12 @@ mod tests {
#[test]
fn round_trip_serialization() {
let rng = &mut XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let rng = &mut thread_rng();
let p_g = FixedGenerators::SpendingKeyGenerator;
let params = &JubjubBls12::new();
for _ in 0..1000 {
let sk = PrivateKey::<Bls12>(Fs::random(rng));
let sk = PrivateKey::<Bls12>(rng.gen());
let vk = PublicKey::from_private(&sk, p_g, params);
let msg = b"Foo bar";
let sig = sk.sign(msg, rng, p_g, params);
@@ -331,15 +308,12 @@ mod tests {
#[test]
fn random_signatures() {
let rng = &mut XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let rng = &mut thread_rng();
let p_g = FixedGenerators::SpendingKeyGenerator;
let params = &JubjubBls12::new();
for _ in 0..1000 {
let sk = PrivateKey::<Bls12>(Fs::random(rng));
let sk = PrivateKey::<Bls12>(rng.gen());
let vk = PublicKey::from_private(&sk, p_g, params);
let msg1 = b"Foo bar";
@@ -353,7 +327,7 @@ mod tests {
assert!(!vk.verify(msg1, &sig2, p_g, params));
assert!(!vk.verify(msg2, &sig1, p_g, params));
let alpha = Fs::random(rng);
let alpha = rng.gen();
let rsk = sk.randomize(alpha);
let rvk = vk.randomize(alpha, p_g, params);

View File

@@ -1,9 +1,9 @@
use blake2b_simd::Params;
use blake2_rfc::blake2b::Blake2b;
use crate::jubjub::{JubjubEngine, ToUniform};
use jubjub::{JubjubEngine, ToUniform};
pub fn hash_to_scalar<E: JubjubEngine>(persona: &[u8], a: &[u8], b: &[u8]) -> E::Fs {
let mut hasher = Params::new().hash_length(64).personal(persona).to_state();
let mut hasher = Blake2b::with_params(64, &[], &[], persona);
hasher.update(a);
hasher.update(b);
let ret = hasher.finalize();

View File

@@ -1,2 +0,0 @@
# Protobufs
src/proto/

View File

@@ -1,25 +0,0 @@
[package]
name = "zcash_client_backend"
version = "0.0.0"
authors = [
"Jack Grigg <jack@z.cash>",
]
edition = "2018"
[dependencies]
bech32 = "0.7"
bs58 = { version = "0.2", features = ["check"] }
ff = { path = "../ff" }
hex = "0.3"
pairing = { path = "../pairing" }
protobuf = "2"
subtle = "2"
zcash_primitives = { path = "../zcash_primitives" }
[build-dependencies]
protobuf-codegen-pure = "2"
[dev-dependencies]
rand_core = "0.5"
rand_os = "0.2"
rand_xorshift = "0.2"

View File

@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2017-2019 Electric Coin Company
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Some files were not shown because too many files have changed in this diff Show More