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"
|
||||
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]
|
||||
default = []
|
||||
|
@ -126,3 +126,39 @@ impl<E: Engine> Batch<E> {
|
||||
])).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 pairing;
|
||||
// extern crate merlin;
|
||||
|
||||
use ff::{Field};
|
||||
use pairing::{Engine, CurveProjective};
|
||||
use std::marker::PhantomData;
|
||||
// use merlin::{Transcript};
|
||||
|
||||
mod verifier;
|
||||
mod prover;
|
||||
mod batch;
|
||||
mod poly;
|
||||
mod helper;
|
||||
|
||||
pub use self::verifier::{MultiVerifier, create_aggregate};
|
||||
pub use self::prover::{Aggregate, create_proof, create_advice};
|
||||
|
||||
// use super::super::util::*;
|
||||
// pub use super::batch::Batch;
|
||||
// use crate::synthesis::{Backend, SynthesisDriver};
|
||||
// use crate::{Circuit, SynthesisError, Variable, Coeff};
|
||||
// use crate::srs::SRS;
|
||||
pub use self::batch::{Batch, VerificationKey};
|
||||
pub use self::helper::{Aggregate, create_aggregate};
|
||||
pub use self::verifier::{MultiVerifier};
|
||||
pub use self::prover::{create_proof, create_advice};
|
||||
|
||||
#[derive(Clone)]
|
||||
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::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>(
|
||||
circuit: &C,
|
||||
proof: &Proof<E>,
|
||||
|
@ -5,6 +5,7 @@ use std::marker::PhantomData;
|
||||
use super::{Proof, SxyAdvice};
|
||||
use super::batch::Batch;
|
||||
use super::poly::{SxEval, SyEval};
|
||||
use super::helper::Aggregate;
|
||||
|
||||
use crate::SynthesisError;
|
||||
|
||||
@ -249,217 +250,4 @@ impl<E: Engine, C: Circuit<E>, S: SynthesisDriver> MultiVerifier<E, C, S> {
|
||||
pub fn check_all(self) -> bool {
|
||||
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 std::io;
|
||||
|
||||
// transcript is mocked for now
|
||||
mod hasher;
|
||||
|
||||
use self::hasher::{Hasher, Keccak256Hasher, BlakeHasher};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Transcript {
|
||||
buffer: Vec<u8>
|
||||
transcriptor: RollingHashTranscript<Keccak256Hasher>
|
||||
}
|
||||
|
||||
impl Transcript {
|
||||
pub fn new(personalization: &[u8]) -> 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]) {
|
||||
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;
|
||||
}
|
||||
|
||||
impl TranscriptProtocol for Transcript {
|
||||
impl<H:Hasher> TranscriptProtocol for RollingHashTranscript<H> {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
fn get_challenge_scalar<F: PrimeField>(&mut self) -> F {
|
||||
return F::one();
|
||||
// loop {
|
||||
// let mut repr: F::Repr = Default::default();
|
||||
// repr.read_be(TranscriptReader(self)).unwrap();
|
||||
use byteorder::ByteOrder;
|
||||
|
||||
// if let Ok(result) = F::from_repr(repr) {
|
||||
// return result;
|
||||
// }
|
||||
// }
|
||||
let mut nonce = 0u32;
|
||||
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> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.challenge_bytes(b"read", buf);
|
||||
// impl<'a, H:Hasher> io::Read for TranscriptReader<'a, H: Hasher> {
|
||||
// fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
// self.0.challenge_bytes(b"read", buf);
|
||||
|
||||
Ok(buf.len())
|
||||
}
|
||||
}
|
||||
// Ok(buf.len())
|
||||
// }
|
||||
// }
|
Loading…
Reference in New Issue
Block a user