add working pinnochio verifiable computation

This commit is contained in:
exfinen
2023-10-20 16:40:22 +09:00
parent b77abf5eea
commit 4ff0d092d6
9 changed files with 97 additions and 154 deletions

View File

@@ -7,9 +7,10 @@ use crate::building_block::{
rational_function::RationalFunction,
},
to_biguint::ToBigUint,
zero::Zero,
};
use num_bigint::BigUint;
use num_traits::Zero;
use num_traits::Zero as NumTraitsZero;
pub struct Pairing {
l_bits: Vec<bool>,
@@ -73,6 +74,10 @@ impl Pairing {
pub fn weil(&self, p1: &G1Point, p2: &G2Point) -> Fq12 {
println!("Started Weil pairing");
println!("Running Miller loop G1-G2...");
if p1 == &G1Point::zero() || p2 == &G2Point::zero() {
return Fq12::from(&1u8 as &dyn ToBigUint);
}
let num = self.calc_g1_g2(p1, p2);
println!("Running Miller loop G2-G1...");
let deno = self.calc_g2_g1(p2, p1);
@@ -82,7 +87,11 @@ impl Pairing {
pub fn tate(&self, p1: &G1Point, p2: &G2Point) -> Fq12 {
println!("Started Tate pairing");
println!("Running Miller loop G1-G2...");
let intmed = self.calc_g1_g2(p1, p2);
if p1 == &G1Point::zero() || p2 == &G2Point::zero() {
return Fq12::from(&1u8 as &dyn ToBigUint);
}
let intmed = self.calc_g1_g2(&p1, &p2);
// apply final exponentiation
println!("Applying final exponentiation...");

View File

@@ -22,6 +22,7 @@ pub struct EvaluationKeys {
}
pub struct VerificationKeys {
pub one_g1: G1Point,
pub one: G2Point,
pub e_alpha: G2Point,
pub e_gamma: G2Point,
@@ -51,14 +52,14 @@ impl CRS {
let E1 = |n: &PrimeFieldElem| -> G1Point { g1 * n };
let E2 = |n: &PrimeFieldElem| -> G2Point { g2 * n };
let s = &f.rand_elem(true);
let s = &f.elem(&2u8); // &f.rand_elem(true);
let alpha = &f.rand_elem(true);
let beta_v = &f.rand_elem(true);
let beta_w = &f.rand_elem(true);
let beta_y = &f.rand_elem(true);
let gamma = &f.rand_elem(true);
let s_pows = &s.pow_seq(&p.max_degree);
let s_pows = &s.pow_seq(&(&p.max_degree + 5));
let mid: &Vec<usize> = &(*&p.mid_beg..*&p.num_constraints).collect();
let io: &Vec<usize> = &(1usize..*&p.mid_beg).collect();
@@ -90,7 +91,7 @@ impl CRS {
let beta_y_gamma = E2(gamma) * beta_y;
let t = E2(&p.t.eval_at(s));
let const_witness = &p.witness.const_witness();
let const_witness = &p.witness.one();
let v_0 = E1(&p.vi[0].eval_at(s)) * const_witness;
let w_0 = E2(&p.wi[0].eval_at(s)) * const_witness;
let y_0 = E1(&p.yi[0].eval_at(s)) * const_witness;
@@ -112,6 +113,7 @@ impl CRS {
let vk = VerificationKeys {
one,
one_g1: E1(&f.elem(&1u8)),
e_alpha,
e_gamma,
beta_v_gamma,

View File

@@ -13,5 +13,6 @@ pub struct PinocchioProof {
pub beta_y_mid: G1Point,
pub h: G1Point,
pub alpha_h: G1Point,
pub ht: G1Point,
}

View File

@@ -68,55 +68,8 @@ impl PinocchioProver {
};
let witness = Witness::new(&r1cs.witness.clone(), &tmpl.mid_beg);
let num_constraints = tmpl.constraints.len();
//// EXPERIMENT ZONE
{
use crate::zk::w_trusted_setup::pinocchio::sparse_vec::SparseVec;
let p_div_t = &p.divide_by(&t);
let h = match &p_div_t {
DivResult::Quotient(h) => h,
DivResult::QuotientRemainder(_) => panic!("p must be divisible by t"),
};
let s = &f.elem(&11u8);
let eval = |ps: &[Polynomial], ws: &SparseVec| -> PrimeFieldElem {
let mut sum = f.elem(&0u8);
for i in 0..ps.len() {
let p = ps[i].eval_at(s);
let w = &ws[&f.elem(&i)];
sum = sum + p * w;
}
sum
};
let v_0 = &qap.vi[0].eval_at(s) * witness.const_witness();
let w_0 = &qap.wi[0].eval_at(s) * witness.const_witness();
let y_0 = &qap.yi[0].eval_at(s) * witness.const_witness();
let mid_beg: usize = (&tmpl.mid_beg.e).try_into().unwrap();
let v_io = eval(&qap.vi[1..mid_beg], &witness.io());
let w_io = eval(&qap.wi[1..mid_beg], &witness.io());
let y_io = eval(&qap.yi[1..mid_beg], &witness.io());
let v_mid = eval(&qap.vi[mid_beg..], &witness.mid());
let w_mid = eval(&qap.vi[mid_beg..], &witness.mid());
let y_mid = eval(&qap.vi[mid_beg..], &witness.mid());
let v = v_0 + v_io + v_mid;
let w = w_0 + w_io + w_mid;
let y = y_0 + y_io + y_mid;
let lhs = v * w - y;
let rhs = &h.eval_at(s) * &t.eval_at(s);
assert!(lhs == rhs);
}
//// EXPERIMENT ZONE
PinocchioProver {
f: f.clone(),
max_degree: (&max_degree.e).try_into().unwrap(),
@@ -165,6 +118,9 @@ impl PinocchioProver {
DivResult::QuotientRemainder(_) => panic!("p must be divisible by t"),
};
let ht_poly = &h * &self.t;
let ht = ht_poly.eval_with_g1_hidings(&crs.ek.si);
let h_hiding = h.eval_with_g1_hidings(&crs.ek.si);
let alpha_h = h.eval_with_g1_hidings(&crs.ek.alpha_si);
@@ -178,6 +134,7 @@ impl PinocchioProver {
beta_y_mid,
h: h_hiding,
alpha_h,
ht,
}
}
}
@@ -189,7 +146,7 @@ mod tests {
#[test]
fn test_generate_proof_and_verify() {
let f = &PrimeField::new(&3911u16);
let f = &G1Point::curve_group();
let expr = "(x * x * x) + x + 5 == 35";
let eq = EquationParser::parse(f, expr).unwrap();
@@ -225,7 +182,7 @@ mod tests {
&prover.witness.io(),
);
assert!(result == true);
assert!(result);
}
}

View File

@@ -24,63 +24,62 @@ impl PinocchioVerifier {
&self,
proof: &PinocchioProof,
crs: &CRS,
public_io_inputs: &SparseVec,
io_inputs: &SparseVec,
) -> bool {
println!("Verifying Pinnochio proof...");
let e = |a, b| self.pairing.tate(a, b);
// e(E(αh(s)),E(1)) =? e(E(h(s)),E(α))
// if e(&proof.alpha_h, &crs.vk.one) != e(&proof.h, &crs.vk.e_alpha) {
// return false;
// }
println!("--> Checking if e(E(αh(s)),E(1)) =? e(E(h(s)),E(α))...");
if e(&proof.alpha_h, &crs.vk.one) != e(&proof.h, &crs.vk.e_alpha) {
return false;
}
// e(E(βv v_mid(s), E(γ)) =? e(v_mid(s),E(βvγ))
// if e(&proof.beta_v_mid, &crs.vk.e_gamma) != e(&proof.v_mid, &crs.vk.beta_v_gamma) {
// return false;
// }
println!("--> Checking if e(E(βv v_mid(s), E(γ)) =? e(v_mid(s),E(βvγ))...");
if e(&proof.beta_v_mid, &crs.vk.e_gamma) != e(&proof.v_mid, &crs.vk.beta_v_gamma) {
return false;
}
// e(E(βw w_mid(s)), E(γ)) =? e(w_mid(s),E(βwγ))
// if e(&proof.beta_w_mid, &crs.vk.e_gamma) != e(&proof.w_mid, &crs.vk.beta_w_gamma) {
// return false;
// }
println!("--> Checking if e(E(βw w_mid(s)), E(γ)) =? e(w_mid(s),E(βwγ))...");
if e(&proof.beta_w_mid_e1, &crs.vk.e_gamma) != e(&proof.w_mid_e1, &crs.vk.beta_w_gamma) {
return false;
}
// e(E(βy y_mid(s)), E(γ)) =? e(y_mid(s),E(βyγ))
// if e(&proof.beta_y_mid, &crs.vk.e_gamma) != e(&proof.y_mid, &crs.vk.beta_y_gamma) {
// return false;
// }
println!("--> Checking if e(E(βy y_mid(s)), E(γ)) =? e(y_mid(s),E(βyγ))...");
if e(&proof.beta_y_mid, &crs.vk.e_gamma) != e(&proof.y_mid, &crs.vk.beta_y_gamma) {
return false;
}
// v_e = E(v_0(s) + E(v_io(s)) + E(v_mid(s))
// w_e = E(w_0(s) + E(w_io(s)) + E(w_mid(s))
// y_e = E(y_0(s) + E(y_io(s)) + E(y_mid(s))
// e(v_e, w_e)/e(y_e, E(1)) ?= e(E(h(s)), E(t(s)))
let f = &public_io_inputs.f;
println!("--> Checking if e(v_e, w_e)/e(y_e, E(1)) ?= e(E(h*t(s)), E(1))...");
let f = &io_inputs.f;
let mut v_e = &crs.vk.v_0 + &proof.v_mid;
for i in 0..crs.vk.vi_io.len() {
let w = &public_io_inputs[&f.elem(&i)];
let w = &io_inputs[&f.elem(&i)];
let p = &crs.vk.vi_io[i];
v_e = v_e + p * w;
}
let mut w_e = &crs.vk.w_0 + &proof.w_mid_e2;
for i in 0..crs.vk.wi_io.len() {
let w = &public_io_inputs[&f.elem(&i)];
let w = &io_inputs[&f.elem(&i)];
let p = &crs.vk.wi_io[i];
w_e = w_e + p * w;
}
let mut y_e = &crs.vk.y_0 + &proof.y_mid;
for i in 0..crs.vk.yi_io.len() {
let w = &public_io_inputs[&f.elem(&i)];
let w = &io_inputs[&f.elem(&i)];
let p = &crs.vk.yi_io[i];
y_e = y_e + p * w;
}
true
// let lhs = e(&v_e, &w_e) - e(&y_e, &crs.vk.one);
// let rhs = e(&proof.h, &crs.vk.t);
//
// lhs == rhs
let lhs1 = e(&v_e, &w_e);
let lhs2 = e(&y_e, &crs.vk.one);
let lhs = lhs1 * lhs2.inv();
let rhs = e(&proof.ht, &crs.vk.one);
lhs == rhs
}
}

View File

@@ -3,10 +3,7 @@ use crate::building_block::{
prime_field::PrimeField,
prime_field_elem::PrimeFieldElem,
},
curves::bls12_381::{
g1_point::G1Point,
g2_point::G2Point,
},
curves::bls12_381::g1_point::G1Point,
to_biguint::ToBigUint, zero::Zero,
};
use num_bigint::BigUint;
@@ -274,20 +271,7 @@ impl Polynomial {
) -> G1Point {
let mut sum = G1Point::zero();
for i in 0..self.coeffs.len() {
sum = sum + &g1_powers[i] * &self.coeffs[i];
}
sum
}
// TODO avoid duplicating code
#[allow(non_snake_case)]
pub fn eval_with_g2_hidings(
&self,
g2_powers: &[G2Point]
) -> G2Point {
let mut sum = G2Point::zero();
for i in 0..self.coeffs.len() {
sum = sum + &g2_powers[i] * &self.coeffs[i];
sum = sum + (&g1_powers[i] * &self.coeffs[i]);
}
sum
}
@@ -320,14 +304,21 @@ impl<'a> Add<&Polynomial> for &Polynomial {
}
}
// TODO avoid duplicating code
impl<'a> Mul<&Polynomial> for Polynomial {
type Output = Polynomial;
macro_rules! impl_mul {
($rhs: ty, $target: ty) => {
impl<'a> Mul<$rhs> for $target {
type Output = Polynomial;
fn mul(self, rhs: &Polynomial) -> Self::Output {
self.multiply_by(rhs)
}
fn mul(self, rhs: $rhs) -> Self::Output {
self.multiply_by(&rhs)
}
}
};
}
impl_mul!(Polynomial, Polynomial);
impl_mul!(Polynomial, &Polynomial);
impl_mul!(&Polynomial, Polynomial);
impl_mul!(&Polynomial, &Polynomial);
impl<'a> Mul<&PrimeFieldElem> for &Polynomial {
type Output = Polynomial;
@@ -1217,7 +1208,7 @@ mod tests {
}
#[test]
fn test_eval_with_g1_hidings() {
fn test_eval_with_g1_hidings_1() {
let f = &PrimeField::new(&3299u16);
let s = f.elem(&3u8);
let s0g = &G1Point::g();
@@ -1253,41 +1244,36 @@ mod tests {
assert!(act == exp);
}
// TODO share code with g1 couterpart
#[test]
fn test_eval_with_g2_hidings() {
let f = &PrimeField::new(&3299u16);
fn test_eval_with_g1_hidings_2() {
let f = &G1Point::curve_group();
let s = f.elem(&3u8);
let s0g = &G2Point::g();
let s1g = s0g * &s;
let s2g = s0g * &s.pow(&2u8);
let s3g = s0g * &s.pow(&3u8);
let pows = vec![
s0g.clone(),
s1g.clone(),
s2g.clone(),
s3g.clone(),
];
let two = f.elem(&2u8);
let three = f.elem(&3u8);
let four = f.elem(&4u8);
let five = f.elem(&5u8);
let exp =
s0g * &two
+ &s1g * &three
+ &s2g * &four
+ &s3g * &five
;
// 5x^3 + 4x^2 + 3x + 2
let e1549 = f.elem(&1549u16);
let e3361 = f.elem(&3361u16);
let e3607 = f.elem(&3607u16);
let e822 = f.elem(&822u16);
let e1990 = f.elem(&1990u16);
let e496 = f.elem(&496u16);
let e1698 = f.elem(&1698u16);
let e2362 = f.elem(&2362u16);
let e3670 = f.elem(&3670u16);
// 3670x^8 + 2362x^7 + 1698x^6 + 496x^5 + 1990x^4 + 822x^3 + 3607x^2 + 3361x + 1549
let p = Polynomial::new(f, &vec![
two,
three,
four,
five,
e1549,
e3361,
e3607,
e822,
e1990,
e496,
e1698,
e2362,
e3670,
]);
let act = p.eval_with_g2_hidings(&pows);
println!("p(s) = {:?}", p.eval_at(&s));
assert!(p.eval_at(&s) == f.elem(&0u8));
assert!(act == exp);
}
}

View File

@@ -112,7 +112,7 @@ impl QAP {
let mut p = zero.clone();
for i in 0..self.wi.len() {
let w = &witness[&self.f.elem(&i)];
p = &p + &(&self.wi[i] * &w);
p = &p + &(&self.wi[i] * w);
};
p
};
@@ -120,7 +120,7 @@ impl QAP {
let mut p = zero.clone();
for i in 0..self.yi.len() {
let w = &witness[&self.f.elem(&i)];
p = &p + &(&self.yi[i] * &w);
p = &p + &(&self.yi[i] * w);
};
p
};

View File

@@ -63,17 +63,6 @@ impl R1CS {
let b = &(&constraint.b * &self.witness).sum();
let c = &(&constraint.c * &self.witness).sum();
println!("r1cs: ({:?}*{:?})={:?}) * ({:?}*{:?}={:?}) = ({:?}*{:?}={:?})",
&constraint.a,
&self.witness,
&a,
&constraint.b,
&self.witness,
&b,
&constraint.c,
&self.witness,
&c,
);
if &(a * b) != c {
return Err(format!("Constraint a ({:?}) * b ({:?}) = c ({:?}) doesn't hold", a, b, c));
}

View File

@@ -16,7 +16,7 @@ impl Witness {
}
}
pub fn const_witness(&self) -> PrimeFieldElem {
pub fn one(&self) -> PrimeFieldElem {
let f = &self.mid_beg.f;
self.sv[&f.elem(&0u8)].clone()
}