diff --git a/src/lib.rs b/src/lib.rs index d7a846e..c5f5a26 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,7 +41,7 @@ impl> FRI { ); } - pub fn prove(rng: &mut R, p: &P) -> (Vec, [F; 2]) { + pub fn prove(rng: &mut R, p: &P) -> (Vec, Vec, [F; 2]) { // f_0(x) = fL_0(x^2) + x fR_0(x^2) let mut f_i1 = p.clone(); @@ -59,15 +59,84 @@ impl> FRI { let aux = DensePolynomial::from_coefficients_slice(fR_i.coeffs()); f_i1 = fL_i.clone() + P::from_coefficients_slice(aux.mul(alpha_i).coeffs()); f_is.push(f_i1.clone()); + + // commit to f_{i+1}(x) = fL_i(x) + alpha_i * fR_i(x) + let (cm_i, mt_i) = MT::commit(f_i1.coeffs()); + commitments.push(cm_i); + mts.push(mt_i); } let (fL_i, fR_i) = Self::split(&f_i1); let constant_fL_l: F = fL_i.coeffs()[0].clone(); let constant_fR_l: F = fR_i.coeffs()[0].clone(); - // TODO evaluate f_i(z^{2^i}) - let evals: Vec = Vec::new(); + // TODO this will be a hash from the transcript + // V sets rand z \in \mathbb{F} challenge + let z = F::from(10_u64); + + let mut evals: Vec = Vec::new(); + // TODO this will be done inside the prev loop, now it is here just for clarity + // evaluate f_i(z^{2^i}) + for i in 0..f_is.len() { + // TODO check usage of .pow(u64) + let z_2i = z.pow([2_u64.pow(i as u32)]); // z^{2^i} + let neg_z_2i = z_2i.neg(); + let eval_i = f_is[i].evaluate(&z_2i); + evals.push(eval_i); + let eval_i = f_is[i].evaluate(&neg_z_2i); + evals.push(eval_i); + } + + // TODO return also the commitment_proofs + // return: Comm(f_i(x)), f_i(+-z^{2^i}), constant values {f_l^L, f_l^R} + (commitments, evals, [constant_fL_l, constant_fR_l]) + } + + pub fn verify(commitments: Vec, evals: Vec, constants: [F; 2]) -> bool { + let z = F::from(10_u64); // TODO this will be a hash from the transcript + + // TODO check commitments.len()==evals.len()/2 + + for i in (0..evals.len()).step_by(2) { + let alpha_i = F::from(3_u64); // TODO: WIP, defined by Verifier (well, hash transcript) + + let z_2i = z.pow([2_u64.pow((i as u32) / 2)]); // z^{2^i} + // take f_i(z^2) from evals + let fi_z = evals[i]; + let neg_fi_z = evals[i + 1]; + // compute f_i^L(z^2), f_i^R(z^2) from the linear combination + let L = (fi_z + neg_fi_z) * F::from(2_u32).inverse().unwrap(); + let R = (fi_z - neg_fi_z) * (F::from(2_u32) * z_2i).inverse().unwrap(); + + // compute f_{i+1}(z^2) = f_i^L(z^2) + a_i f_i^R(z^2) + let next_fi_z2 = L + alpha_i * R; + + // check: obtained f_{i+1}(z^2) == evals.f_{i+1}(z^2) (=evals[i+2]) + if i < evals.len() - 2 { + if next_fi_z2 != evals[i + 2] { + println!("\nerr, i={:?}", i); + println!(" next_fi^z2 {:?}", next_fi_z2.to_string()); + println!(" e[i] {:?}", evals[i + 2].to_string()); + panic!("should f_i+1(z^2) == evals.f_i+1(z^2) (=evals[i+2])"); + } + } + + // check commitment opening + // TODO + + // last iteration, check constant values equal to the obtained f_i^L(z^{2^i}), + // f_i^R(z^{2^i}) + if i == evals.len() - 2 { + if L != constants[0] { + panic!("constant L not equal"); + } + if R != constants[1] { + println!("R {:?}\n {:?}", R.to_string(), constants[1].to_string()); + panic!("constant R not equal"); + } + } + } - (evals, [constant_fL_l, constant_fR_l]) + true } } @@ -97,4 +166,24 @@ mod tests { pL.evaluate(&z.square()) + z * pR.evaluate(&z.square()) ); } + + #[test] + fn test_prove() { + let mut rng = ark_std::test_rng(); + + let deg = 15; + let p = DensePolynomial::::rand(deg, &mut rng); + assert_eq!(p.degree(), deg); + // println!("p {:?}", p); + + type FRIC = FRI>; + // prover + let (commitments, evals, constvals) = FRIC::prove(&mut rng, &p); + // commitments contains the commitments to each f_0, f_1, ..., f_n, with n=log2(d) + assert_eq!(commitments.len(), log2(p.coeffs().len()) as usize - 1); + assert_eq!(evals.len(), 2 * log2(p.coeffs().len()) as usize); + + let v = FRIC::verify(commitments, evals, constvals); + assert!(v); + } }