make custom transcript that is implementable as SC
This commit is contained in:
parent
528f0623ef
commit
7239a60044
@ -22,5 +22,11 @@ pairing = { git = 'https://github.com/matterinc/pairing' }
|
|||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
ff = { git = 'https://github.com/matterinc/ff', features = ["derive"] }
|
ff = { git = 'https://github.com/matterinc/ff', features = ["derive"] }
|
||||||
|
|
||||||
|
tiny-keccak = "1.4.2"
|
||||||
|
|
||||||
|
[dependencies.blake2-rfc]
|
||||||
|
git = "https://github.com/gtank/blake2-rfc"
|
||||||
|
rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
@ -126,3 +126,39 @@ impl<E: Engine> Batch<E> {
|
|||||||
])).unwrap() == E::Fqk::one()
|
])).unwrap() == E::Fqk::one()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct VerificationKey<E:Engine> {
|
||||||
|
alpha_x: E::G2Affine,
|
||||||
|
|
||||||
|
alpha: E::G2Affine,
|
||||||
|
|
||||||
|
neg_h: E::G2Affine,
|
||||||
|
|
||||||
|
neg_x_n_minus_d: E::G2Affine
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E: Engine> VerificationKey<E> {
|
||||||
|
pub fn new(srs: &SRS<E>, n: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
alpha_x: srs.h_positive_x_alpha[1],
|
||||||
|
|
||||||
|
alpha: srs.h_positive_x_alpha[0],
|
||||||
|
|
||||||
|
neg_h: {
|
||||||
|
let mut tmp = srs.h_negative_x[0];
|
||||||
|
tmp.negate();
|
||||||
|
|
||||||
|
tmp
|
||||||
|
},
|
||||||
|
|
||||||
|
neg_x_n_minus_d: {
|
||||||
|
let mut tmp = srs.h_negative_x[srs.d - n];
|
||||||
|
tmp.negate();
|
||||||
|
|
||||||
|
tmp
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
228
src/sonic/helped/helper.rs
Normal file
228
src/sonic/helped/helper.rs
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
use ff::{Field};
|
||||||
|
use pairing::{Engine, CurveProjective};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use super::{Proof, SxyAdvice};
|
||||||
|
use super::batch::Batch;
|
||||||
|
use super::poly::{SxEval, SyEval};
|
||||||
|
|
||||||
|
use crate::SynthesisError;
|
||||||
|
|
||||||
|
use crate::sonic::transcript::{Transcript, TranscriptProtocol};
|
||||||
|
use crate::sonic::util::*;
|
||||||
|
use crate::sonic::cs::{Backend, SynthesisDriver};
|
||||||
|
use crate::sonic::cs::{Circuit, Variable, Coeff};
|
||||||
|
use crate::sonic::srs::SRS;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Aggregate<E: Engine> {
|
||||||
|
// Commitment to s(z, Y)
|
||||||
|
pub c: E::G1Affine,
|
||||||
|
// We have to open each of the S commitments to a random point `z`
|
||||||
|
pub s_opening: E::G1Affine,
|
||||||
|
// We have to open C to each constituent `y`
|
||||||
|
pub c_openings: Vec<(E::G1Affine, E::Fr)>,
|
||||||
|
// Then we have to finally open C
|
||||||
|
pub opening: E::G1Affine,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_aggregate<E: Engine, C: Circuit<E>, S: SynthesisDriver>(
|
||||||
|
circuit: &C,
|
||||||
|
inputs: &[(Proof<E>, SxyAdvice<E>)],
|
||||||
|
srs: &SRS<E>,
|
||||||
|
) -> Aggregate<E>
|
||||||
|
{
|
||||||
|
// TODO: precompute this?
|
||||||
|
let (n, q) = {
|
||||||
|
struct CountN {
|
||||||
|
n: usize,
|
||||||
|
q: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, E: Engine> Backend<E> for &'a mut CountN {
|
||||||
|
fn new_multiplication_gate(&mut self) {
|
||||||
|
self.n += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_linear_constraint(&mut self) {
|
||||||
|
self.q += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut tmp = CountN{n:0,q:0};
|
||||||
|
S::synthesize(&mut tmp, circuit).unwrap(); // TODO
|
||||||
|
|
||||||
|
(tmp.n, tmp.q)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut transcript = Transcript::new(&[]);
|
||||||
|
let mut y_values: Vec<E::Fr> = Vec::with_capacity(inputs.len());
|
||||||
|
for &(ref proof, ref sxyadvice) in inputs {
|
||||||
|
{
|
||||||
|
let mut transcript = Transcript::new(&[]);
|
||||||
|
transcript.commit_point(&proof.r);
|
||||||
|
y_values.push(transcript.get_challenge_scalar());
|
||||||
|
}
|
||||||
|
|
||||||
|
transcript.commit_point(&sxyadvice.s);
|
||||||
|
}
|
||||||
|
|
||||||
|
let z: E::Fr = transcript.get_challenge_scalar();
|
||||||
|
|
||||||
|
// Compute s(z, Y)
|
||||||
|
let (s_poly_negative, s_poly_positive) = {
|
||||||
|
let mut tmp = SyEval::new(z, n, q);
|
||||||
|
S::synthesize(&mut tmp, circuit).unwrap(); // TODO
|
||||||
|
|
||||||
|
tmp.poly()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Compute C = g^{s(z, x)}
|
||||||
|
let c = multiexp(
|
||||||
|
srs.g_positive_x_alpha[0..(n + q)]
|
||||||
|
.iter()
|
||||||
|
.chain_ext(srs.g_negative_x_alpha[0..n].iter()),
|
||||||
|
s_poly_positive.iter().chain_ext(s_poly_negative.iter())
|
||||||
|
).into_affine();
|
||||||
|
|
||||||
|
transcript.commit_point(&c);
|
||||||
|
|
||||||
|
// Open C at w
|
||||||
|
let w: E::Fr = transcript.get_challenge_scalar();
|
||||||
|
|
||||||
|
let value = compute_value::<E>(&w, &s_poly_positive, &s_poly_negative);
|
||||||
|
|
||||||
|
let opening = {
|
||||||
|
let mut value = value;
|
||||||
|
value.negate();
|
||||||
|
|
||||||
|
let poly = kate_divison(
|
||||||
|
s_poly_negative.iter().rev().chain_ext(Some(value).iter()).chain_ext(s_poly_positive.iter()),
|
||||||
|
w,
|
||||||
|
);
|
||||||
|
|
||||||
|
let negative_poly = poly[0..n].iter().rev();
|
||||||
|
let positive_poly = poly[n..].iter();
|
||||||
|
multiexp(
|
||||||
|
srs.g_negative_x[1..(negative_poly.len() + 1)].iter().chain_ext(
|
||||||
|
srs.g_positive_x[0..positive_poly.len()].iter()
|
||||||
|
),
|
||||||
|
negative_poly.chain_ext(positive_poly)
|
||||||
|
).into_affine()
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: parallelize
|
||||||
|
// Let's open up C to every y.
|
||||||
|
fn compute_value<E: Engine>(y: &E::Fr, poly_positive: &[E::Fr], poly_negative: &[E::Fr]) -> E::Fr {
|
||||||
|
let mut value = E::Fr::zero();
|
||||||
|
|
||||||
|
let yinv = y.inverse().unwrap(); // TODO
|
||||||
|
let mut tmp = yinv;
|
||||||
|
for &coeff in poly_negative {
|
||||||
|
let mut coeff = coeff;
|
||||||
|
coeff.mul_assign(&tmp);
|
||||||
|
value.add_assign(&coeff);
|
||||||
|
tmp.mul_assign(&yinv);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut tmp = *y;
|
||||||
|
for &coeff in poly_positive {
|
||||||
|
let mut coeff = coeff;
|
||||||
|
coeff.mul_assign(&tmp);
|
||||||
|
value.add_assign(&coeff);
|
||||||
|
tmp.mul_assign(&y);
|
||||||
|
}
|
||||||
|
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut c_openings = vec![];
|
||||||
|
for y in &y_values {
|
||||||
|
let value = compute_value::<E>(y, &s_poly_positive, &s_poly_negative);
|
||||||
|
|
||||||
|
let opening = {
|
||||||
|
let mut value = value;
|
||||||
|
value.negate();
|
||||||
|
|
||||||
|
let poly = kate_divison(
|
||||||
|
s_poly_negative.iter().rev().chain_ext(Some(value).iter()).chain_ext(s_poly_positive.iter()),
|
||||||
|
*y,
|
||||||
|
);
|
||||||
|
|
||||||
|
let negative_poly = poly[0..n].iter().rev();
|
||||||
|
let positive_poly = poly[n..].iter();
|
||||||
|
multiexp(
|
||||||
|
srs.g_negative_x[1..(negative_poly.len() + 1)].iter().chain_ext(
|
||||||
|
srs.g_positive_x[0..positive_poly.len()].iter()
|
||||||
|
),
|
||||||
|
negative_poly.chain_ext(positive_poly)
|
||||||
|
).into_affine()
|
||||||
|
};
|
||||||
|
|
||||||
|
c_openings.push((opening, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Okay, great. Now we need to open up each S at the same point z to the same value.
|
||||||
|
// Since we're opening up all the S's at the same point, we create a bunch of random
|
||||||
|
// challenges instead and open up a random linear combination.
|
||||||
|
|
||||||
|
let mut poly_negative = vec![E::Fr::zero(); n];
|
||||||
|
let mut poly_positive = vec![E::Fr::zero(); 2*n];
|
||||||
|
let mut expected_value = E::Fr::zero();
|
||||||
|
|
||||||
|
for (y, c_opening) in y_values.iter().zip(c_openings.iter()) {
|
||||||
|
// Compute s(X, y_i)
|
||||||
|
let (s_poly_negative, s_poly_positive) = {
|
||||||
|
let mut tmp = SxEval::new(*y, n);
|
||||||
|
S::synthesize(&mut tmp, circuit).unwrap(); // TODO
|
||||||
|
|
||||||
|
tmp.poly()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut value = c_opening.1;
|
||||||
|
let r: E::Fr = transcript.get_challenge_scalar();
|
||||||
|
value.mul_assign(&r);
|
||||||
|
expected_value.add_assign(&value);
|
||||||
|
|
||||||
|
for (mut coeff, target) in s_poly_negative.into_iter().zip(poly_negative.iter_mut()) {
|
||||||
|
coeff.mul_assign(&r);
|
||||||
|
target.add_assign(&coeff);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (mut coeff, target) in s_poly_positive.into_iter().zip(poly_positive.iter_mut()) {
|
||||||
|
coeff.mul_assign(&r);
|
||||||
|
target.add_assign(&coeff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: parallelize
|
||||||
|
let s_opening = {
|
||||||
|
let mut value = expected_value;
|
||||||
|
value.negate();
|
||||||
|
|
||||||
|
let poly = kate_divison(
|
||||||
|
poly_negative.iter().rev().chain_ext(Some(value).iter()).chain_ext(poly_positive.iter()),
|
||||||
|
z,
|
||||||
|
);
|
||||||
|
|
||||||
|
let negative_poly = poly[0..n].iter().rev();
|
||||||
|
let positive_poly = poly[n..].iter();
|
||||||
|
multiexp(
|
||||||
|
srs.g_negative_x[1..(negative_poly.len() + 1)].iter().chain_ext(
|
||||||
|
srs.g_positive_x[0..positive_poly.len()].iter()
|
||||||
|
),
|
||||||
|
negative_poly.chain_ext(positive_poly)
|
||||||
|
).into_affine()
|
||||||
|
};
|
||||||
|
|
||||||
|
Aggregate {
|
||||||
|
// Commitment to s(z, Y)
|
||||||
|
c,
|
||||||
|
// We have to open each of the S commitments to a random point `z`
|
||||||
|
s_opening,
|
||||||
|
// We have to open C to each constituent `y`
|
||||||
|
c_openings,
|
||||||
|
// Then we have to finally open C
|
||||||
|
opening,
|
||||||
|
}
|
||||||
|
}
|
@ -1,25 +1,20 @@
|
|||||||
extern crate ff;
|
extern crate ff;
|
||||||
extern crate pairing;
|
extern crate pairing;
|
||||||
// extern crate merlin;
|
|
||||||
|
|
||||||
use ff::{Field};
|
use ff::{Field};
|
||||||
use pairing::{Engine, CurveProjective};
|
use pairing::{Engine, CurveProjective};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
// use merlin::{Transcript};
|
|
||||||
|
|
||||||
mod verifier;
|
mod verifier;
|
||||||
mod prover;
|
mod prover;
|
||||||
mod batch;
|
mod batch;
|
||||||
mod poly;
|
mod poly;
|
||||||
|
mod helper;
|
||||||
|
|
||||||
pub use self::verifier::{MultiVerifier, create_aggregate};
|
pub use self::batch::{Batch, VerificationKey};
|
||||||
pub use self::prover::{Aggregate, create_proof, create_advice};
|
pub use self::helper::{Aggregate, create_aggregate};
|
||||||
|
pub use self::verifier::{MultiVerifier};
|
||||||
// use super::super::util::*;
|
pub use self::prover::{create_proof, create_advice};
|
||||||
// pub use super::batch::Batch;
|
|
||||||
// use crate::synthesis::{Backend, SynthesisDriver};
|
|
||||||
// use crate::{Circuit, SynthesisError, Variable, Coeff};
|
|
||||||
// use crate::srs::SRS;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SxyAdvice<E: Engine> {
|
pub struct SxyAdvice<E: Engine> {
|
||||||
|
@ -14,217 +14,6 @@ use crate::sonic::cs::{Backend, SynthesisDriver};
|
|||||||
use crate::sonic::cs::{Circuit, Variable, Coeff};
|
use crate::sonic::cs::{Circuit, Variable, Coeff};
|
||||||
use crate::sonic::srs::SRS;
|
use crate::sonic::srs::SRS;
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Aggregate<E: Engine> {
|
|
||||||
// Commitment to s(z, Y)
|
|
||||||
c: E::G1Affine,
|
|
||||||
// We have to open each of the S commitments to a random point `z`
|
|
||||||
s_opening: E::G1Affine,
|
|
||||||
// We have to open C to each constituent `y`
|
|
||||||
c_openings: Vec<(E::G1Affine, E::Fr)>,
|
|
||||||
// Then we have to finally open C
|
|
||||||
opening: E::G1Affine,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_aggregate<E: Engine, C: Circuit<E>, S: SynthesisDriver>(
|
|
||||||
circuit: &C,
|
|
||||||
inputs: &[(Proof<E>, SxyAdvice<E>)],
|
|
||||||
srs: &SRS<E>,
|
|
||||||
) -> Aggregate<E>
|
|
||||||
{
|
|
||||||
// TODO: precompute this?
|
|
||||||
let (n, q) = {
|
|
||||||
struct CountN {
|
|
||||||
n: usize,
|
|
||||||
q: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, E: Engine> Backend<E> for &'a mut CountN {
|
|
||||||
fn new_multiplication_gate(&mut self) {
|
|
||||||
self.n += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_linear_constraint(&mut self) {
|
|
||||||
self.q += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut tmp = CountN{n:0,q:0};
|
|
||||||
S::synthesize(&mut tmp, circuit).unwrap(); // TODO
|
|
||||||
|
|
||||||
(tmp.n, tmp.q)
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut transcript = Transcript::new(&[]);
|
|
||||||
let mut y_values: Vec<E::Fr> = Vec::with_capacity(inputs.len());
|
|
||||||
for &(ref proof, ref sxyadvice) in inputs {
|
|
||||||
{
|
|
||||||
let mut transcript = Transcript::new(&[]);
|
|
||||||
transcript.commit_point(&proof.r);
|
|
||||||
y_values.push(transcript.get_challenge_scalar());
|
|
||||||
}
|
|
||||||
|
|
||||||
transcript.commit_point(&sxyadvice.s);
|
|
||||||
}
|
|
||||||
|
|
||||||
let z: E::Fr = transcript.get_challenge_scalar();
|
|
||||||
|
|
||||||
// Compute s(z, Y)
|
|
||||||
let (s_poly_negative, s_poly_positive) = {
|
|
||||||
let mut tmp = SyEval::new(z, n, q);
|
|
||||||
S::synthesize(&mut tmp, circuit).unwrap(); // TODO
|
|
||||||
|
|
||||||
tmp.poly()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Compute C = g^{s(z, x)}
|
|
||||||
let c = multiexp(
|
|
||||||
srs.g_positive_x_alpha[0..(n + q)]
|
|
||||||
.iter()
|
|
||||||
.chain_ext(srs.g_negative_x_alpha[0..n].iter()),
|
|
||||||
s_poly_positive.iter().chain_ext(s_poly_negative.iter())
|
|
||||||
).into_affine();
|
|
||||||
|
|
||||||
transcript.commit_point(&c);
|
|
||||||
|
|
||||||
// Open C at w
|
|
||||||
let w: E::Fr = transcript.get_challenge_scalar();
|
|
||||||
|
|
||||||
let value = compute_value::<E>(&w, &s_poly_positive, &s_poly_negative);
|
|
||||||
|
|
||||||
let opening = {
|
|
||||||
let mut value = value;
|
|
||||||
value.negate();
|
|
||||||
|
|
||||||
let poly = kate_divison(
|
|
||||||
s_poly_negative.iter().rev().chain_ext(Some(value).iter()).chain_ext(s_poly_positive.iter()),
|
|
||||||
w,
|
|
||||||
);
|
|
||||||
|
|
||||||
let negative_poly = poly[0..n].iter().rev();
|
|
||||||
let positive_poly = poly[n..].iter();
|
|
||||||
multiexp(
|
|
||||||
srs.g_negative_x[1..(negative_poly.len() + 1)].iter().chain_ext(
|
|
||||||
srs.g_positive_x[0..positive_poly.len()].iter()
|
|
||||||
),
|
|
||||||
negative_poly.chain_ext(positive_poly)
|
|
||||||
).into_affine()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Let's open up C to every y.
|
|
||||||
fn compute_value<E: Engine>(y: &E::Fr, poly_positive: &[E::Fr], poly_negative: &[E::Fr]) -> E::Fr {
|
|
||||||
let mut value = E::Fr::zero();
|
|
||||||
|
|
||||||
let yinv = y.inverse().unwrap(); // TODO
|
|
||||||
let mut tmp = yinv;
|
|
||||||
for &coeff in poly_negative {
|
|
||||||
let mut coeff = coeff;
|
|
||||||
coeff.mul_assign(&tmp);
|
|
||||||
value.add_assign(&coeff);
|
|
||||||
tmp.mul_assign(&yinv);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut tmp = *y;
|
|
||||||
for &coeff in poly_positive {
|
|
||||||
let mut coeff = coeff;
|
|
||||||
coeff.mul_assign(&tmp);
|
|
||||||
value.add_assign(&coeff);
|
|
||||||
tmp.mul_assign(&y);
|
|
||||||
}
|
|
||||||
|
|
||||||
value
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut c_openings = vec![];
|
|
||||||
for y in &y_values {
|
|
||||||
let value = compute_value::<E>(y, &s_poly_positive, &s_poly_negative);
|
|
||||||
|
|
||||||
let opening = {
|
|
||||||
let mut value = value;
|
|
||||||
value.negate();
|
|
||||||
|
|
||||||
let poly = kate_divison(
|
|
||||||
s_poly_negative.iter().rev().chain_ext(Some(value).iter()).chain_ext(s_poly_positive.iter()),
|
|
||||||
*y,
|
|
||||||
);
|
|
||||||
|
|
||||||
let negative_poly = poly[0..n].iter().rev();
|
|
||||||
let positive_poly = poly[n..].iter();
|
|
||||||
multiexp(
|
|
||||||
srs.g_negative_x[1..(negative_poly.len() + 1)].iter().chain_ext(
|
|
||||||
srs.g_positive_x[0..positive_poly.len()].iter()
|
|
||||||
),
|
|
||||||
negative_poly.chain_ext(positive_poly)
|
|
||||||
).into_affine()
|
|
||||||
};
|
|
||||||
|
|
||||||
c_openings.push((opening, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Okay, great. Now we need to open up each S at the same point z to the same value.
|
|
||||||
// Since we're opening up all the S's at the same point, we create a bunch of random
|
|
||||||
// challenges instead and open up a random linear combination.
|
|
||||||
|
|
||||||
let mut poly_negative = vec![E::Fr::zero(); n];
|
|
||||||
let mut poly_positive = vec![E::Fr::zero(); 2*n];
|
|
||||||
let mut expected_value = E::Fr::zero();
|
|
||||||
|
|
||||||
for (y, c_opening) in y_values.iter().zip(c_openings.iter()) {
|
|
||||||
// Compute s(X, y_i)
|
|
||||||
let (s_poly_negative, s_poly_positive) = {
|
|
||||||
let mut tmp = SxEval::new(*y, n);
|
|
||||||
S::synthesize(&mut tmp, circuit).unwrap(); // TODO
|
|
||||||
|
|
||||||
tmp.poly()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut value = c_opening.1;
|
|
||||||
let r: E::Fr = transcript.get_challenge_scalar();
|
|
||||||
value.mul_assign(&r);
|
|
||||||
expected_value.add_assign(&value);
|
|
||||||
|
|
||||||
for (mut coeff, target) in s_poly_negative.into_iter().zip(poly_negative.iter_mut()) {
|
|
||||||
coeff.mul_assign(&r);
|
|
||||||
target.add_assign(&coeff);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (mut coeff, target) in s_poly_positive.into_iter().zip(poly_positive.iter_mut()) {
|
|
||||||
coeff.mul_assign(&r);
|
|
||||||
target.add_assign(&coeff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let s_opening = {
|
|
||||||
let mut value = expected_value;
|
|
||||||
value.negate();
|
|
||||||
|
|
||||||
let poly = kate_divison(
|
|
||||||
poly_negative.iter().rev().chain_ext(Some(value).iter()).chain_ext(poly_positive.iter()),
|
|
||||||
z,
|
|
||||||
);
|
|
||||||
|
|
||||||
let negative_poly = poly[0..n].iter().rev();
|
|
||||||
let positive_poly = poly[n..].iter();
|
|
||||||
multiexp(
|
|
||||||
srs.g_negative_x[1..(negative_poly.len() + 1)].iter().chain_ext(
|
|
||||||
srs.g_positive_x[0..positive_poly.len()].iter()
|
|
||||||
),
|
|
||||||
negative_poly.chain_ext(positive_poly)
|
|
||||||
).into_affine()
|
|
||||||
};
|
|
||||||
|
|
||||||
Aggregate {
|
|
||||||
// Commitment to s(z, Y)
|
|
||||||
c,
|
|
||||||
// We have to open each of the S commitments to a random point `z`
|
|
||||||
s_opening,
|
|
||||||
// We have to open C to each constituent `y`
|
|
||||||
c_openings,
|
|
||||||
// Then we have to finally open C
|
|
||||||
opening,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_advice<E: Engine, C: Circuit<E>, S: SynthesisDriver>(
|
pub fn create_advice<E: Engine, C: Circuit<E>, S: SynthesisDriver>(
|
||||||
circuit: &C,
|
circuit: &C,
|
||||||
proof: &Proof<E>,
|
proof: &Proof<E>,
|
||||||
|
@ -5,6 +5,7 @@ use std::marker::PhantomData;
|
|||||||
use super::{Proof, SxyAdvice};
|
use super::{Proof, SxyAdvice};
|
||||||
use super::batch::Batch;
|
use super::batch::Batch;
|
||||||
use super::poly::{SxEval, SyEval};
|
use super::poly::{SxEval, SyEval};
|
||||||
|
use super::helper::Aggregate;
|
||||||
|
|
||||||
use crate::SynthesisError;
|
use crate::SynthesisError;
|
||||||
|
|
||||||
@ -250,216 +251,3 @@ impl<E: Engine, C: Circuit<E>, S: SynthesisDriver> MultiVerifier<E, C, S> {
|
|||||||
self.batch.check_all()
|
self.batch.check_all()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Aggregate<E: Engine> {
|
|
||||||
// Commitment to s(z, Y)
|
|
||||||
c: E::G1Affine,
|
|
||||||
// We have to open each of the S commitments to a random point `z`
|
|
||||||
s_opening: E::G1Affine,
|
|
||||||
// We have to open C to each constituent `y`
|
|
||||||
c_openings: Vec<(E::G1Affine, E::Fr)>,
|
|
||||||
// Then we have to finally open C
|
|
||||||
opening: E::G1Affine,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_aggregate<E: Engine, C: Circuit<E>, S: SynthesisDriver>(
|
|
||||||
circuit: &C,
|
|
||||||
inputs: &[(Proof<E>, SxyAdvice<E>)],
|
|
||||||
srs: &SRS<E>,
|
|
||||||
) -> Aggregate<E>
|
|
||||||
{
|
|
||||||
// TODO: precompute this?
|
|
||||||
let (n, q) = {
|
|
||||||
struct CountN {
|
|
||||||
n: usize,
|
|
||||||
q: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, E: Engine> Backend<E> for &'a mut CountN {
|
|
||||||
fn new_multiplication_gate(&mut self) {
|
|
||||||
self.n += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_linear_constraint(&mut self) {
|
|
||||||
self.q += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut tmp = CountN{n:0,q:0};
|
|
||||||
S::synthesize(&mut tmp, circuit).unwrap(); // TODO
|
|
||||||
|
|
||||||
(tmp.n, tmp.q)
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut transcript = Transcript::new(&[]);
|
|
||||||
let mut y_values: Vec<E::Fr> = Vec::with_capacity(inputs.len());
|
|
||||||
for &(ref proof, ref sxyadvice) in inputs {
|
|
||||||
{
|
|
||||||
let mut transcript = Transcript::new(&[]);
|
|
||||||
transcript.commit_point(&proof.r);
|
|
||||||
y_values.push(transcript.get_challenge_scalar());
|
|
||||||
}
|
|
||||||
|
|
||||||
transcript.commit_point(&sxyadvice.s);
|
|
||||||
}
|
|
||||||
|
|
||||||
let z: E::Fr = transcript.get_challenge_scalar();
|
|
||||||
|
|
||||||
// Compute s(z, Y)
|
|
||||||
let (s_poly_negative, s_poly_positive) = {
|
|
||||||
let mut tmp = SyEval::new(z, n, q);
|
|
||||||
S::synthesize(&mut tmp, circuit).unwrap(); // TODO
|
|
||||||
|
|
||||||
tmp.poly()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Compute C = g^{s(z, x)}
|
|
||||||
let c = multiexp(
|
|
||||||
srs.g_positive_x_alpha[0..(n + q)]
|
|
||||||
.iter()
|
|
||||||
.chain_ext(srs.g_negative_x_alpha[0..n].iter()),
|
|
||||||
s_poly_positive.iter().chain_ext(s_poly_negative.iter())
|
|
||||||
).into_affine();
|
|
||||||
|
|
||||||
transcript.commit_point(&c);
|
|
||||||
|
|
||||||
// Open C at w
|
|
||||||
let w: E::Fr = transcript.get_challenge_scalar();
|
|
||||||
|
|
||||||
let value = compute_value::<E>(&w, &s_poly_positive, &s_poly_negative);
|
|
||||||
|
|
||||||
let opening = {
|
|
||||||
let mut value = value;
|
|
||||||
value.negate();
|
|
||||||
|
|
||||||
let poly = kate_divison(
|
|
||||||
s_poly_negative.iter().rev().chain_ext(Some(value).iter()).chain_ext(s_poly_positive.iter()),
|
|
||||||
w,
|
|
||||||
);
|
|
||||||
|
|
||||||
let negative_poly = poly[0..n].iter().rev();
|
|
||||||
let positive_poly = poly[n..].iter();
|
|
||||||
multiexp(
|
|
||||||
srs.g_negative_x[1..(negative_poly.len() + 1)].iter().chain_ext(
|
|
||||||
srs.g_positive_x[0..positive_poly.len()].iter()
|
|
||||||
),
|
|
||||||
negative_poly.chain_ext(positive_poly)
|
|
||||||
).into_affine()
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: parallelize
|
|
||||||
// Let's open up C to every y.
|
|
||||||
fn compute_value<E: Engine>(y: &E::Fr, poly_positive: &[E::Fr], poly_negative: &[E::Fr]) -> E::Fr {
|
|
||||||
let mut value = E::Fr::zero();
|
|
||||||
|
|
||||||
let yinv = y.inverse().unwrap(); // TODO
|
|
||||||
let mut tmp = yinv;
|
|
||||||
for &coeff in poly_negative {
|
|
||||||
let mut coeff = coeff;
|
|
||||||
coeff.mul_assign(&tmp);
|
|
||||||
value.add_assign(&coeff);
|
|
||||||
tmp.mul_assign(&yinv);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut tmp = *y;
|
|
||||||
for &coeff in poly_positive {
|
|
||||||
let mut coeff = coeff;
|
|
||||||
coeff.mul_assign(&tmp);
|
|
||||||
value.add_assign(&coeff);
|
|
||||||
tmp.mul_assign(&y);
|
|
||||||
}
|
|
||||||
|
|
||||||
value
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut c_openings = vec![];
|
|
||||||
for y in &y_values {
|
|
||||||
let value = compute_value::<E>(y, &s_poly_positive, &s_poly_negative);
|
|
||||||
|
|
||||||
let opening = {
|
|
||||||
let mut value = value;
|
|
||||||
value.negate();
|
|
||||||
|
|
||||||
let poly = kate_divison(
|
|
||||||
s_poly_negative.iter().rev().chain_ext(Some(value).iter()).chain_ext(s_poly_positive.iter()),
|
|
||||||
*y,
|
|
||||||
);
|
|
||||||
|
|
||||||
let negative_poly = poly[0..n].iter().rev();
|
|
||||||
let positive_poly = poly[n..].iter();
|
|
||||||
multiexp(
|
|
||||||
srs.g_negative_x[1..(negative_poly.len() + 1)].iter().chain_ext(
|
|
||||||
srs.g_positive_x[0..positive_poly.len()].iter()
|
|
||||||
),
|
|
||||||
negative_poly.chain_ext(positive_poly)
|
|
||||||
).into_affine()
|
|
||||||
};
|
|
||||||
|
|
||||||
c_openings.push((opening, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Okay, great. Now we need to open up each S at the same point z to the same value.
|
|
||||||
// Since we're opening up all the S's at the same point, we create a bunch of random
|
|
||||||
// challenges instead and open up a random linear combination.
|
|
||||||
|
|
||||||
let mut poly_negative = vec![E::Fr::zero(); n];
|
|
||||||
let mut poly_positive = vec![E::Fr::zero(); 2*n];
|
|
||||||
let mut expected_value = E::Fr::zero();
|
|
||||||
|
|
||||||
for (y, c_opening) in y_values.iter().zip(c_openings.iter()) {
|
|
||||||
// Compute s(X, y_i)
|
|
||||||
let (s_poly_negative, s_poly_positive) = {
|
|
||||||
let mut tmp = SxEval::new(*y, n);
|
|
||||||
S::synthesize(&mut tmp, circuit).unwrap(); // TODO
|
|
||||||
|
|
||||||
tmp.poly()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut value = c_opening.1;
|
|
||||||
let r: E::Fr = transcript.get_challenge_scalar();
|
|
||||||
value.mul_assign(&r);
|
|
||||||
expected_value.add_assign(&value);
|
|
||||||
|
|
||||||
for (mut coeff, target) in s_poly_negative.into_iter().zip(poly_negative.iter_mut()) {
|
|
||||||
coeff.mul_assign(&r);
|
|
||||||
target.add_assign(&coeff);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (mut coeff, target) in s_poly_positive.into_iter().zip(poly_positive.iter_mut()) {
|
|
||||||
coeff.mul_assign(&r);
|
|
||||||
target.add_assign(&coeff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: parallelize
|
|
||||||
let s_opening = {
|
|
||||||
let mut value = expected_value;
|
|
||||||
value.negate();
|
|
||||||
|
|
||||||
let poly = kate_divison(
|
|
||||||
poly_negative.iter().rev().chain_ext(Some(value).iter()).chain_ext(poly_positive.iter()),
|
|
||||||
z,
|
|
||||||
);
|
|
||||||
|
|
||||||
let negative_poly = poly[0..n].iter().rev();
|
|
||||||
let positive_poly = poly[n..].iter();
|
|
||||||
multiexp(
|
|
||||||
srs.g_negative_x[1..(negative_poly.len() + 1)].iter().chain_ext(
|
|
||||||
srs.g_positive_x[0..positive_poly.len()].iter()
|
|
||||||
),
|
|
||||||
negative_poly.chain_ext(positive_poly)
|
|
||||||
).into_affine()
|
|
||||||
};
|
|
||||||
|
|
||||||
Aggregate {
|
|
||||||
// Commitment to s(z, Y)
|
|
||||||
c,
|
|
||||||
// We have to open each of the S commitments to a random point `z`
|
|
||||||
s_opening,
|
|
||||||
// We have to open C to each constituent `y`
|
|
||||||
c_openings,
|
|
||||||
// Then we have to finally open C
|
|
||||||
opening,
|
|
||||||
}
|
|
||||||
}
|
|
73
src/sonic/transcript/hasher.rs
Normal file
73
src/sonic/transcript/hasher.rs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
extern crate tiny_keccak;
|
||||||
|
extern crate blake2_rfc;
|
||||||
|
|
||||||
|
use self::tiny_keccak::Keccak;
|
||||||
|
use self::blake2_rfc::blake2s::Blake2s;
|
||||||
|
|
||||||
|
pub trait Hasher {
|
||||||
|
fn new(personalization: &[u8]) -> Self;
|
||||||
|
fn update(&mut self, data: &[u8]);
|
||||||
|
fn finalize(&mut self) -> Vec<u8>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct BlakeHasher {
|
||||||
|
h: Blake2s
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hasher for BlakeHasher {
|
||||||
|
fn new(personalization: &[u8]) -> Self {
|
||||||
|
let h = Blake2s::with_params(32, &[], &[], personalization);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
h: h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, data: &[u8]) {
|
||||||
|
self.h.update(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalize(&mut self) -> Vec<u8> {
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
let new_h = Blake2s::with_params(32, &[], &[], &[]);
|
||||||
|
let h = std::mem::replace(&mut self.h, new_h);
|
||||||
|
|
||||||
|
let result = h.finalize();
|
||||||
|
|
||||||
|
result.as_ref().to_vec().clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Keccak256Hasher {
|
||||||
|
h: Keccak
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hasher for Keccak256Hasher {
|
||||||
|
fn new(personalization: &[u8]) -> Self {
|
||||||
|
let mut h = Keccak::new_keccak256();
|
||||||
|
h.update(personalization);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
h: h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, data: &[u8]) {
|
||||||
|
self.h.update(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn finalize(&mut self) -> Vec<u8> {
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
let new_h = Keccak::new_keccak256();
|
||||||
|
let h = std::mem::replace(&mut self.h, new_h);
|
||||||
|
|
||||||
|
let mut res: [u8; 32] = [0; 32];
|
||||||
|
h.finalize(&mut res);
|
||||||
|
|
||||||
|
res[..].to_vec()
|
||||||
|
}
|
||||||
|
}
|
@ -5,25 +5,77 @@ use ff::{Field, PrimeField, PrimeFieldRepr};
|
|||||||
use pairing::{CurveAffine, CurveProjective, Engine};
|
use pairing::{CurveAffine, CurveProjective, Engine};
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
// transcript is mocked for now
|
mod hasher;
|
||||||
|
|
||||||
|
use self::hasher::{Hasher, Keccak256Hasher, BlakeHasher};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Transcript {
|
pub struct Transcript {
|
||||||
buffer: Vec<u8>
|
transcriptor: RollingHashTranscript<Keccak256Hasher>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Transcript {
|
impl Transcript {
|
||||||
pub fn new(personalization: &[u8]) -> Self {
|
pub fn new(personalization: &[u8]) -> Self {
|
||||||
Self {
|
Self {
|
||||||
buffer: vec![]
|
transcriptor: RollingHashTranscript::new(personalization)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TranscriptProtocol for Transcript {
|
||||||
|
fn commit_point<G: CurveAffine>(&mut self, point: &G) {
|
||||||
|
self.transcriptor.commit_point(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn commit_scalar<F: PrimeField>(&mut self, scalar: &F) {
|
||||||
|
self.transcriptor.commit_scalar(scalar);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_challenge_scalar<F: PrimeField>(&mut self) -> F {
|
||||||
|
self.transcriptor.get_challenge_scalar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct RollingHashTranscript<H: Hasher> {
|
||||||
|
buffer: Vec<u8>,
|
||||||
|
last_finalized_value: Vec<u8>,
|
||||||
|
_marker: PhantomData<H>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<H: Hasher> RollingHashTranscript<H> {
|
||||||
|
pub fn new(personalization: &[u8]) -> Self {
|
||||||
|
let mut h = H::new(personalization);
|
||||||
|
let buffer = h.finalize();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
buffer: buffer,
|
||||||
|
last_finalized_value: vec![],
|
||||||
|
_marker: PhantomData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn commit_bytes(&mut self, personalization: &[u8], bytes: &[u8]) {
|
pub fn commit_bytes(&mut self, personalization: &[u8], bytes: &[u8]) {
|
||||||
|
let mut h = H::new(personalization);
|
||||||
|
h.update(&self.buffer);
|
||||||
|
h.update(personalization);
|
||||||
|
h.update(bytes);
|
||||||
|
|
||||||
|
self.buffer = h.finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn challenge_bytes(&mut self, personalization: &[u8], bytes: &[u8]) {
|
pub fn get_challenge_bytes(&mut self, nonce: &[u8]) -> Vec<u8> {
|
||||||
|
let challenge_bytes = &self.buffer;
|
||||||
|
|
||||||
|
let mut h = H::new(&[]);
|
||||||
|
h.update(challenge_bytes);
|
||||||
|
h.update(nonce);
|
||||||
|
|
||||||
|
let challenge_bytes = h.finalize();
|
||||||
|
|
||||||
|
challenge_bytes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,37 +85,48 @@ pub trait TranscriptProtocol {
|
|||||||
fn get_challenge_scalar<F: PrimeField>(&mut self) -> F;
|
fn get_challenge_scalar<F: PrimeField>(&mut self) -> F;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TranscriptProtocol for Transcript {
|
impl<H:Hasher> TranscriptProtocol for RollingHashTranscript<H> {
|
||||||
fn commit_point<G: CurveAffine>(&mut self, point: &G) {
|
fn commit_point<G: CurveAffine>(&mut self, point: &G) {
|
||||||
self.commit_bytes(b"point", point.into_compressed().as_ref());
|
self.commit_bytes(b"point", point.into_uncompressed().as_ref());
|
||||||
|
// self.commit_bytes(b"point", point.into_compressed().as_ref());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn commit_scalar<F: PrimeField>(&mut self, scalar: &F) {
|
fn commit_scalar<F: PrimeField>(&mut self, scalar: &F) {
|
||||||
let mut v = vec![];
|
let mut v = vec![];
|
||||||
scalar.into_repr().write_le(&mut v).unwrap();
|
scalar.into_repr().write_be(&mut v).unwrap();
|
||||||
|
// scalar.into_repr().write_le(&mut v).unwrap();
|
||||||
|
|
||||||
self.commit_bytes(b"scalar", &v);
|
self.commit_bytes(b"scalar", &v);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_challenge_scalar<F: PrimeField>(&mut self) -> F {
|
fn get_challenge_scalar<F: PrimeField>(&mut self) -> F {
|
||||||
return F::one();
|
use byteorder::ByteOrder;
|
||||||
// loop {
|
|
||||||
// let mut repr: F::Repr = Default::default();
|
|
||||||
// repr.read_be(TranscriptReader(self)).unwrap();
|
|
||||||
|
|
||||||
// if let Ok(result) = F::from_repr(repr) {
|
let mut nonce = 0u32;
|
||||||
// return result;
|
loop {
|
||||||
// }
|
let mut nonce_bytes = vec![0u8; 4];
|
||||||
// }
|
byteorder::BigEndian::write_u32(&mut nonce_bytes, nonce);
|
||||||
|
let mut repr: F::Repr = Default::default();
|
||||||
|
let challenge_bytes = self.get_challenge_bytes(&nonce_bytes);
|
||||||
|
repr.read_be(&challenge_bytes[..]).unwrap();
|
||||||
|
|
||||||
|
if let Ok(result) = F::from_repr(repr) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if nonce == (0xffffffff as u32) {
|
||||||
|
panic!("can not make challenge scalar");
|
||||||
|
}
|
||||||
|
nonce += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TranscriptReader<'a>(&'a mut Transcript);
|
// struct TranscriptReader<'a, H:Hasher>(&'a mut Transcript<H>);
|
||||||
|
|
||||||
impl<'a> io::Read for TranscriptReader<'a> {
|
// impl<'a, H:Hasher> io::Read for TranscriptReader<'a, H: Hasher> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
// fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
self.0.challenge_bytes(b"read", buf);
|
// self.0.challenge_bytes(b"read", buf);
|
||||||
|
|
||||||
Ok(buf.len())
|
// Ok(buf.len())
|
||||||
}
|
// }
|
||||||
}
|
// }
|
Loading…
Reference in New Issue
Block a user