diff --git a/spartan_parallel/src/dense_mlpoly.rs b/spartan_parallel/src/dense_mlpoly.rs index 9ef128b2..78a0886f 100644 --- a/spartan_parallel/src/dense_mlpoly.rs +++ b/spartan_parallel/src/dense_mlpoly.rs @@ -3,7 +3,6 @@ use crate::scalar::SpartanExtensionField; use super::errors::ProofVerifyError; use super::math::Math; -use super::nizk::DotProductProofLog; use super::random::RandomTape; use super::transcript::ProofTranscript; use core::ops::Index; @@ -21,10 +20,6 @@ pub struct DensePolynomial { Z: Vec, // evaluations of the polynomial in all the 2^num_vars Boolean inputs } -pub struct PolyCommitmentBlinds { - pub(crate) blinds: Vec, -} - pub struct EqPolynomial { r: Vec, } @@ -258,7 +253,12 @@ impl DensePolynomial { assert_eq!(r.len(), self.get_num_vars()); let chis = EqPolynomial::new(r.to_vec()).evals(); assert_eq!(chis.len(), self.Z.len()); - DotProductProofLog::compute_dotproduct(&self.Z, &chis) + Self::compute_dotproduct(&self.Z, &chis) + } + + fn compute_dotproduct(a: &[S], b: &[S]) -> S { + assert_eq!(a.len(), b.len()); + (0..a.len()).map(|i| a[i] * b[i]).sum() } fn vec(&self) -> &Vec { @@ -311,7 +311,7 @@ impl Index for DensePolynomial { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct PolyEvalProof { - proof: DotProductProofLog, + _phantom: S, } impl PolyEvalProof { @@ -320,52 +320,16 @@ impl PolyEvalProof { } pub fn prove( - poly: &DensePolynomial, - blinds_opt: Option<&PolyCommitmentBlinds>, - r: &[S], // point at which the polynomial is evaluated - Zr: &S, // evaluation of \widetilde{Z}(r) - blind_Zr_opt: Option<&S>, // specifies a blind for Zr - transcript: &mut Transcript, - random_tape: &mut RandomTape, + _poly: &DensePolynomial, + _r: &[S], // point at which the polynomial is evaluated + _Zr: &S, // evaluation of \widetilde{Z}(r) + _transcript: &mut Transcript, + _random_tape: &mut RandomTape, ) -> PolyEvalProof { - >::append_protocol_name( - transcript, - PolyEvalProof::::protocol_name(), - ); - - // assert vectors are of the right size - assert_eq!(poly.get_num_vars(), r.len()); - - let (left_num_vars, right_num_vars) = EqPolynomial::::compute_factored_lens(r.len()); - let L_size = left_num_vars.pow2(); - let R_size = right_num_vars.pow2(); - - let default_blinds = PolyCommitmentBlinds { - blinds: vec![S::field_zero(); L_size], - }; - let blinds = blinds_opt.map_or(&default_blinds, |p| p); - - assert_eq!(blinds.blinds.len(), L_size); - - let zero = S::field_zero(); - let blind_Zr = blind_Zr_opt.map_or(&zero, |p| p); - - // compute the L and R vectors - let eq = EqPolynomial::new(r.to_vec()); - let (L, R) = eq.compute_factored_evals(); - assert_eq!(L.len(), L_size); - assert_eq!(R.len(), R_size); - - // compute the vector underneath L*Z and the L*blinds - // compute vector-matrix product between L and Z viewed as a matrix - let LZ = poly.bound(&L); - let LZ_blind: S = (0..L.len()).map(|i| blinds.blinds[i] * L[i]).sum(); - - // a dot product proof of size R_size - let proof = - DotProductProofLog::prove(transcript, random_tape, &LZ, &LZ_blind, &R, Zr, blind_Zr); - - PolyEvalProof { proof } + // TODO: Alternative evaluation proof scheme + PolyEvalProof { + _phantom: S::field_zero(), + } } pub fn verify( @@ -373,18 +337,7 @@ impl PolyEvalProof { transcript: &mut Transcript, r: &[S], // point at which the polynomial is evaluated ) -> Result<(), ProofVerifyError> { - >::append_protocol_name( - transcript, - PolyEvalProof::::protocol_name(), - ); - - // compute L and R - let eq = EqPolynomial::new(r.to_vec()); - let (L, R) = eq.compute_factored_evals(); - - let _ = self.proof.verify(R.len(), transcript, &R); - - // TODO: Alternative PCS Verification + // TODO: Alternative evaluation proof scheme Ok(()) } @@ -394,634 +347,105 @@ impl PolyEvalProof { r: &[S], // point at which the polynomial is evaluated _Zr: &S, // evaluation \widetilde{Z}(r) ) -> Result<(), ProofVerifyError> { - self.verify(transcript, r); - - // TODO: Alternative PCS Verification - Ok(()) + self.verify(transcript, r) } // Evaluation of multiple points on the same instance pub fn prove_batched_points( - poly: &DensePolynomial, - blinds_opt: Option<&PolyCommitmentBlinds>, - r_list: Vec>, // point at which the polynomial is evaluated - Zr_list: Vec, // evaluation of \widetilde{Z}(r) on each point - blind_Zr_opt: Option<&S>, // specifies a blind for Zr - transcript: &mut Transcript, - random_tape: &mut RandomTape, + _poly: &DensePolynomial, + _r_list: Vec>, // point at which the polynomial is evaluated + _Zr_list: Vec, // evaluation of \widetilde{Z}(r) on each point + _transcript: &mut Transcript, + _random_tape: &mut RandomTape, ) -> Vec> { - >::append_protocol_name( - transcript, - PolyEvalProof::::protocol_name(), - ); - - // assert vectors are of the right size - assert_eq!(r_list.len(), Zr_list.len()); - for r in &r_list { - assert_eq!(poly.get_num_vars(), r.len()); - } - - let (left_num_vars, right_num_vars) = EqPolynomial::::compute_factored_lens(r_list[0].len()); - let L_size = left_num_vars.pow2(); - let R_size = right_num_vars.pow2(); - - let default_blinds = PolyCommitmentBlinds { - blinds: vec![S::field_zero(); L_size], - }; - let blinds = blinds_opt.map_or(&default_blinds, |p| p); - - assert_eq!(blinds.blinds.len(), L_size); - - let zero = S::field_zero(); - let blind_Zr = blind_Zr_opt.map_or(&zero, |p| p); - - // compute the L and R vectors - // We can perform batched opening if L is the same, so we regroup the proofs by L vector - // Map from the left half of the r to index in L_list - let mut index_map: HashMap, usize> = HashMap::new(); - let mut L_list: Vec> = Vec::new(); - let mut R_list: Vec> = Vec::new(); - let mut Zc_list: Vec = Vec::new(); - - let c_base: S = transcript.challenge_scalar(b"challenge_c"); - let mut c = S::field_one(); - for i in 0..r_list.len() { - let eq = EqPolynomial::new(r_list[i].to_vec()); - let (Li, Ri) = eq.compute_factored_evals(); - assert_eq!(Li.len(), L_size); - assert_eq!(Ri.len(), R_size); - if let Some(index) = index_map.get(&r_list[i][..left_num_vars]) { - // L already exist - // generate coefficient for RLC - c = c * c_base; - R_list[*index] = (0..R_size).map(|j| R_list[*index][j] + c * Ri[j]).collect(); - Zc_list[*index] = Zc_list[*index] + c * Zr_list[i]; - } else { - let next_index = L_list.len(); - index_map.insert(r_list[i][..left_num_vars].to_vec(), next_index); - L_list.push(Li); - R_list.push(Ri); - Zc_list.push(Zr_list[i]); - } - } - - let mut proof_list = Vec::new(); - for i in 0..L_list.len() { - let L = &L_list[i]; - let R = &R_list[i]; - // compute the vector underneath L*Z and the L*blinds - // compute vector-matrix product between L and Z viewed as a matrix - let LZ = poly.bound(L); - let LZ_blind: S = (0..L.len()).map(|i| blinds.blinds[i] * L[i]).sum(); - - // a dot product proof of size R_size - let proof = DotProductProofLog::prove( - transcript, - random_tape, - &LZ, - &LZ_blind, - R, - &Zc_list[i], - blind_Zr, - ); - proof_list.push(proof); - } - - proof_list - .iter() - .map(|proof| PolyEvalProof { - proof: proof.clone(), - }) - .collect() + // TODO: Alternative evaluation proof scheme + vec![] } pub fn verify_plain_batched_points( - proof_list: &Vec>, - transcript: &mut Transcript, - r_list: Vec>, // point at which the polynomial is evaluated - Zr_list: Vec, // commitment to \widetilde{Z}(r) on each point + _proof_list: &Vec>, + _transcript: &mut Transcript, + _r_list: Vec>, // point at which the polynomial is evaluated + _Zr_list: Vec, // commitment to \widetilde{Z}(r) on each point ) -> Result<(), ProofVerifyError> { - >::append_protocol_name( - transcript, - PolyEvalProof::::protocol_name(), - ); - - let (left_num_vars, _) = EqPolynomial::::compute_factored_lens(r_list[0].len()); - - // compute the L and R - // We can perform batched opening if L is the same, so we regroup the proofs by L vector - // Map from the left half of the r to index in L_list - let mut index_map: HashMap, usize> = HashMap::new(); - let mut L_list: Vec> = Vec::new(); - let mut R_list: Vec> = Vec::new(); - let mut Zc_list: Vec = Vec::new(); - - let c_base: S = transcript.challenge_scalar(b"challenge_c"); - let mut c = S::field_one(); - for i in 0..r_list.len() { - let eq = EqPolynomial::new(r_list[i].to_vec()); - let (Li, Ri) = eq.compute_factored_evals(); - if let Some(index) = index_map.get(&r_list[i][..left_num_vars]) { - // L already exist - // generate coefficient for RLC - c = c * c_base; - R_list[*index] = (0..Ri.len()) - .map(|j| R_list[*index][j] + c * Ri[j]) - .collect(); - Zc_list[*index] = Zc_list[*index] + c * Zr_list[i]; - } else { - let next_index = L_list.len(); - index_map.insert(r_list[i][..left_num_vars].to_vec(), next_index); - L_list.push(Li); - R_list.push(Ri); - Zc_list.push(Zr_list[i]); - } - } - assert_eq!(L_list.len(), proof_list.len()); - + // TODO: Alternative evaluation proof scheme Ok(()) } // Evaluation on multiple instances, each at different point // Size of each instance might be different, but all are larger than the evaluation point pub fn prove_batched_instances( - poly_list: &Vec>, // list of instances - blinds_opt: Option<&PolyCommitmentBlinds>, - r_list: Vec<&Vec>, // point at which the polynomial is evaluated - Zr_list: &Vec, // evaluation of \widetilde{Z}(r) on each instance - blind_Zr_opt: Option<&S>, // specifies a blind for Zr - transcript: &mut Transcript, - random_tape: &mut RandomTape, + _poly_list: &Vec>, // list of instances + _r_list: Vec<&Vec>, // point at which the polynomial is evaluated + _Zr_list: &Vec, // evaluation of \widetilde{Z}(r) on each instance + _transcript: &mut Transcript, + _random_tape: &mut RandomTape, ) -> Vec> { - >::append_protocol_name( - transcript, - PolyEvalProof::::protocol_name(), - ); - - // assert vectors are of the right size - assert_eq!(poly_list.len(), r_list.len()); - assert_eq!(poly_list.len(), Zr_list.len()); - - // We need one proof per poly size & R - let mut index_map: HashMap<(usize, Vec), usize> = HashMap::new(); - let mut LZ_list: Vec> = Vec::new(); - let mut Zc_list = Vec::new(); - let mut L_list: Vec> = Vec::new(); - let mut R_list: Vec> = Vec::new(); - - // generate coefficient for RLC - let c_base: S = transcript.challenge_scalar(b"challenge_c"); - let mut c = S::field_one(); - let zero = S::field_zero(); - for i in 0..poly_list.len() { - let poly = &poly_list[i]; - let num_vars = poly.get_num_vars(); - - // compute L and R - let (L, R) = { - let r = r_list[i]; - // pad or trim r to correct length - let r = { - if num_vars >= r.len() { - [vec![zero; num_vars - r.len()], r.to_vec()].concat() - } else { - r[r.len() - num_vars..].to_vec() - } - }; - let eq = EqPolynomial::new(r); - eq.compute_factored_evals() - }; - - if let Some(index) = index_map.get(&(num_vars, R.clone())) { - c = c * c_base; - let LZ = poly.bound(&L); - LZ_list[*index] = (0..LZ.len()) - .map(|j| LZ_list[*index][j] + c * LZ[j]) - .collect(); - Zc_list[*index] = Zc_list[*index] + c * Zr_list[i]; - } else { - index_map.insert((num_vars, R.clone()), LZ_list.len()); - Zc_list.push(Zr_list[i]); - // compute a weighted sum of commitments and L - let LZ = poly.bound(&L); - L_list.push(L); - R_list.push(R); - LZ_list.push(LZ); - } - } - - let mut proof_list = Vec::new(); - for i in 0..LZ_list.len() { - let L = &L_list[i]; - let L_size = L.len(); - - let default_blinds = PolyCommitmentBlinds { - blinds: vec![S::field_zero(); L_size], - }; - let blinds = blinds_opt.map_or(&default_blinds, |p| p); - assert_eq!(blinds.blinds.len(), L_size); - let blind_Zr = blind_Zr_opt.map_or(&zero, |p| p); - let LZ_blind: S = (0..L.len()).map(|i| blinds.blinds[i] * L[i]).sum(); - - // a dot product proof of size R_size - let proof = DotProductProofLog::prove( - transcript, - random_tape, - &LZ_list[i], - &LZ_blind, - &R_list[i], - &Zc_list[i], - blind_Zr, - ); - proof_list.push(PolyEvalProof { proof }); - } - - proof_list + // TODO: Alternative evaluation proof scheme + vec![] } pub fn verify_plain_batched_instances( - proof_list: &Vec>, - transcript: &mut Transcript, - r_list: Vec<&Vec>, // point at which the polynomial is evaluated - Zr_list: &Vec, // commitment to \widetilde{Z}(r) of each instance - num_vars_list: &Vec, // size of each polynomial + _proof_list: &Vec>, + _transcript: &mut Transcript, + _r_list: Vec<&Vec>, // point at which the polynomial is evaluated + _Zr_list: &Vec, // commitment to \widetilde{Z}(r) of each instance + _num_vars_list: &Vec, // size of each polynomial ) -> Result<(), ProofVerifyError> { - >::append_protocol_name( - transcript, - PolyEvalProof::::protocol_name(), - ); - - // We need one proof per poly size + L size - let mut index_map: HashMap<(usize, Vec), usize> = HashMap::new(); - let mut Zc_list = Vec::new(); - let mut L_list: Vec> = Vec::new(); - let mut R_list: Vec> = Vec::new(); - - // generate coefficient for RLC - let c_base: S = transcript.challenge_scalar(b"challenge_c"); - let mut c = S::field_one(); - let zero = S::field_zero(); - - for i in 0..r_list.len() { - let num_vars = num_vars_list[i]; - - // compute L and R - let (L, R) = { - let r = r_list[i]; - // pad or trim r to correct length - let r = { - if num_vars >= r.len() { - [vec![zero; num_vars - r.len()], r.to_vec()].concat() - } else { - r[r.len() - num_vars..].to_vec() - } - }; - let eq = EqPolynomial::new(r); - eq.compute_factored_evals() - }; - - if let Some(index) = index_map.get(&(num_vars, R.clone())) { - c = c * c_base; - Zc_list[*index] = Zc_list[*index] + c * Zr_list[i]; - } else { - Zc_list.push(Zr_list[i]); - // compute a weighted sum of commitments and L - L_list.push(L); - R_list.push(R); - } - } - + // TODO: Alternative evaluation proof scheme Ok(()) } // Like prove_batched_instances, but r is divided into rq ++ ry // Each polynomial is supplemented with num_proofs and num_inputs pub fn prove_batched_instances_disjoint_rounds( - poly_list: &Vec<&DensePolynomial>, - num_proofs_list: &Vec, - num_inputs_list: &Vec, - blinds_opt: Option<&PolyCommitmentBlinds>, - rq: &[S], - ry: &[S], - Zr_list: &Vec, - blind_Zr_opt: Option<&S>, - transcript: &mut Transcript, - random_tape: &mut RandomTape, + _poly_list: &Vec<&DensePolynomial>, + _num_proofs_list: &Vec, + _num_inputs_list: &Vec, + _rq: &[S], + _ry: &[S], + _Zr_list: &Vec, + _transcript: &mut Transcript, + _random_tape: &mut RandomTape, ) -> Vec> { - >::append_protocol_name( - transcript, - PolyEvalProof::::protocol_name(), - ); - - // assert vectors are of the right size - assert_eq!(poly_list.len(), Zr_list.len()); - - // We need one proof per (num_proofs, num_inputs) pair - let mut index_map: HashMap<(usize, usize), usize> = HashMap::new(); - let mut LZ_list: Vec> = Vec::new(); - let mut Zc_list = Vec::new(); - let mut L_list: Vec> = Vec::new(); - let mut R_list = Vec::new(); - - // generate coefficient for RLC - let c_base: S = transcript.challenge_scalar(b"challenge_c"); - let mut c = S::field_one(); - let zero = S::field_zero(); - for i in 0..poly_list.len() { - let poly = poly_list[i]; - let num_proofs = num_proofs_list[i]; - let num_inputs = num_inputs_list[i]; - if let Some(index) = index_map.get(&(num_proofs, num_inputs)) { - c = c * c_base; - let L = &L_list[*index].to_vec(); - let LZ = poly.bound(&L); - LZ_list[*index] = (0..LZ.len()) - .map(|j| LZ_list[*index][j] + c * LZ[j]) - .collect(); - Zc_list[*index] = Zc_list[*index] + c * Zr_list[i]; - } else { - index_map.insert((num_proofs, num_inputs), LZ_list.len()); - Zc_list.push(Zr_list[i]); - let num_vars_q = num_proofs.log_2(); - let num_vars_y = num_inputs.log_2(); - // pad or trim rq and ry to correct length - let (L, R) = { - let ry_short = { - if num_vars_y >= ry.len() { - let ry_pad = &vec![zero; num_vars_y - ry.len()]; - [ry_pad, ry].concat() - } - // Else ry_short is the last w.num_inputs[p].log_2() entries of ry - // thus, to obtain the actual ry, need to multiply by (1 - ry2)(1 - ry3)..., which is ry_factors[num_rounds_y - w.num_inputs[p]] - else { - ry[ry.len() - num_vars_y..].to_vec() - } - }; - let rq_short = rq[rq.len() - num_vars_q..].to_vec(); - let r = [rq_short, ry_short.clone()].concat(); - let eq = EqPolynomial::new(r); - eq.compute_factored_evals() - }; - // compute a weighted sum of commitments and L - let LZ = poly.bound(&L); - L_list.push(L); - R_list.push(R); - LZ_list.push(LZ); - } - } - - let mut proof_list = Vec::new(); - - for i in 0..LZ_list.len() { - let L = &L_list[i]; - let L_size = L.len(); - let default_blinds = PolyCommitmentBlinds { - blinds: vec![S::field_zero(); L_size], - }; - let blinds = blinds_opt.map_or(&default_blinds, |p| p); - - assert_eq!(blinds.blinds.len(), L_size); - - let blind_Zr = blind_Zr_opt.map_or(&zero, |p| p); - let LZ_blind: S = (0..L.len()).map(|i| blinds.blinds[i] * L[i]).sum(); - - // a dot product proof of size R_size - let proof = DotProductProofLog::prove( - transcript, - random_tape, - &LZ_list[i], - &LZ_blind, - &R_list[i], - &Zc_list[i], - blind_Zr, - ); - - proof_list.push(PolyEvalProof { proof }); - } - - proof_list + // TODO: Alternative evaluation proof scheme + vec![] } pub fn verify_batched_instances_disjoint_rounds( - proof_list: &Vec>, - num_proofs_list: &Vec, - num_inputs_list: &Vec, - transcript: &mut Transcript, - rq: &[S], - ry: &[S], + _proof_list: &Vec>, + _num_proofs_list: &Vec, + _num_inputs_list: &Vec, + _transcript: &mut Transcript, + _rq: &[S], + _ry: &[S], ) -> Result<(), ProofVerifyError> { - >::append_protocol_name( - transcript, - PolyEvalProof::::protocol_name(), - ); - - // We need one proof per poly size - let mut index_map: HashMap<(usize, usize), usize> = HashMap::new(); - let mut LZ_list: Vec = Vec::new(); - let mut L_list = Vec::new(); - let mut R_list = Vec::new(); - - // generate coefficient for RLC - let c_base: S = transcript.challenge_scalar(b"challenge_c"); - let mut c = S::field_one(); - let zero = S::field_zero(); - - for i in 0..num_proofs_list.len() { - let num_proofs = num_proofs_list[i]; - let num_inputs = num_inputs_list[i]; - if let Some(index) = index_map.get(&(num_proofs, num_inputs)) { - c = c * c_base; - let _L = &L_list[*index]; - - let LZ = S::field_zero(); - LZ_list[*index] = LZ_list[*index] + c * LZ; - } else { - index_map.insert((num_proofs, num_inputs), LZ_list.len()); - let num_vars_q = num_proofs.log_2(); - let num_vars_y = num_inputs.log_2(); - // pad or trim rq and ry to correct length - let (L, R) = { - let ry_short = { - if num_vars_y >= ry.len() { - let ry_pad = &vec![zero; num_vars_y - ry.len()]; - [ry_pad, ry].concat() - } - // Else ry_short is the last w.num_inputs[p].log_2() entries of ry - // thus, to obtain the actual ry, need to multiply by (1 - ry2)(1 - ry3)..., which is ry_factors[num_rounds_y - w.num_inputs[p]] - else { - ry[ry.len() - num_vars_y..].to_vec() - } - }; - let rq_short = rq[rq.len() - num_vars_q..].to_vec(); - let r = [rq_short, ry_short.clone()].concat(); - let eq = EqPolynomial::new(r); - eq.compute_factored_evals() - }; - // compute a weighted sum of commitments and L - let LZ = S::field_zero(); - L_list.push(L); - R_list.push(R); - LZ_list.push(LZ); - } - } - - assert_eq!(LZ_list.len(), proof_list.len()); - - // Verify proofs - for i in 0..LZ_list.len() { - let R = &R_list[i]; - - proof_list[i].proof.verify(R.len(), transcript, R)?; - } - + // TODO: Alternative evaluation proof scheme Ok(()) } // Treat the polynomial(s) as univariate and open on a single point pub fn prove_uni_batched_instances( - poly_list: &Vec<&DensePolynomial>, - r: &S, // point at which the polynomial is evaluated - Zr: &Vec, // evaluation of \widetilde{Z}(r) - transcript: &mut Transcript, - random_tape: &mut RandomTape, + _poly_list: &Vec<&DensePolynomial>, + _r: &S, // point at which the polynomial is evaluated + _Zr: &Vec, // evaluation of \widetilde{Z}(r) + _transcript: &mut Transcript, + _random_tape: &mut RandomTape, ) -> PolyEvalProof { - >::append_protocol_name( - transcript, - PolyEvalProof::::protocol_name(), - ); - - let max_num_vars = poly_list.iter().fold(0, |m, p| { - if p.get_num_vars() > m { - p.get_num_vars() - } else { - m - } - }); - let zero = S::field_zero(); - - // L differs depending on size of the polynomial, but R always stay the same - let (_, right_num_vars) = EqPolynomial::::compute_factored_lens(max_num_vars); - let R_size = right_num_vars.pow2(); - - // compute R = <1, r, r^2, ...> - let R = { - let mut r_base = S::field_one(); - let mut R = Vec::new(); - for _ in 0..R_size { - R.push(r_base); - r_base = r_base * *r; - } - R - }; - let mut L_map: HashMap> = HashMap::new(); - - // compute the vector underneath L*Z - // compute vector-matrix product between L and Z viewed as a matrix - let c_base: S = transcript.challenge_scalar(b"challenge_c"); - let mut c = S::field_one(); - let mut LZ_comb = vec![zero; R_size]; - let mut Zr_comb = zero; - - for i in 0..poly_list.len() { - let poly = &poly_list[i]; - let num_vars = poly.get_num_vars(); - let L = if let Some(L) = L_map.get(&num_vars) { - L - } else { - let (left_num_vars, right_num_vars) = EqPolynomial::::compute_factored_lens(num_vars); - let L_size = left_num_vars.pow2(); - let R_size = right_num_vars.pow2(); - let r_base = (0..R_size).fold(S::field_one(), |p, _| p * *r); - // L is 1, r^k, r^2k, ... - let mut l_base = S::field_one(); - let mut L = Vec::new(); - for _ in 0..L_size { - L.push(l_base); - l_base = l_base * r_base; - } - L_map.insert(num_vars, L.clone()); - L_map.get(&num_vars).unwrap() - }; - - let LZ = poly.bound(&L); - LZ_comb = (0..R_size) - .map(|i| LZ_comb[i] + if i < LZ.len() { c * LZ[i] } else { zero }) - .collect(); - Zr_comb = Zr_comb + c * Zr[i]; - c = c * c_base; + // TODO: Alternative evaluation proof scheme + PolyEvalProof { + _phantom: S::field_zero(), } - - // a dot product proof of size R_size - let proof = DotProductProofLog::prove( - transcript, - random_tape, - &LZ_comb, - &zero, - &R, - &Zr_comb, - &zero, - ); - - PolyEvalProof { proof } } pub fn verify_uni_batched_instances( &self, - transcript: &mut Transcript, - r: &S, // point at which the polynomial is evaluated - poly_size: Vec, + _transcript: &mut Transcript, + _r: &S, // point at which the polynomial is evaluated + _poly_size: Vec, ) -> Result<(), ProofVerifyError> { - >::append_protocol_name( - transcript, - PolyEvalProof::::protocol_name(), - ); - - let max_poly_size = poly_size.iter().fold(0, |m, i| if *i > m { *i } else { m }); - // compute L and R - let (_, right_num_vars) = - EqPolynomial::::compute_factored_lens(max_poly_size.next_power_of_two().log_2()); - let R_size = right_num_vars.pow2(); - - // compute R = <1, r, r^2, ...> - let R = { - let mut r_base = S::field_one(); - let mut R = Vec::new(); - for _ in 0..R_size { - R.push(r_base); - r_base = r_base * *r; - } - R - }; - let mut L_map: HashMap> = HashMap::new(); - - // compute a weighted sum of commitments and L - let c_base: S = transcript.challenge_scalar(b"challenge_c"); - let mut c = S::field_one(); - - for i in 0..poly_size.len() { - let num_vars = poly_size[i].next_power_of_two().log_2(); - let _L = if let Some(L) = L_map.get(&num_vars) { - L - } else { - let (left_num_vars, right_num_vars) = EqPolynomial::::compute_factored_lens(num_vars); - let L_size = left_num_vars.pow2(); - let R_size = right_num_vars.pow2(); - let r_base = (0..R_size).fold(S::field_one(), |p, _| p * *r); - // L is 1, r^k, r^2k, ... - let mut l_base = S::field_one(); - let mut L = Vec::new(); - for _ in 0..L_size { - L.push(l_base); - l_base = l_base * r_base; - } - L_map.insert(num_vars, L.clone()); - L_map.get(&num_vars).unwrap() - }; - - c = c * c_base; - } - - self.proof.verify(R.len(), transcript, &R) + // TODO: Alternative evaluation proof scheme + Ok(()) } } @@ -1049,7 +473,7 @@ mod tests { .collect::>(); // compute dot product between LZ and R - DotProductProofLog::compute_dotproduct(&LZ, &R) + DensePolynomial::compute_dotproduct(&LZ, &R) } #[test] diff --git a/spartan_parallel/src/lib.rs b/spartan_parallel/src/lib.rs index 67d56c6f..3c41496b 100644 --- a/spartan_parallel/src/lib.rs +++ b/spartan_parallel/src/lib.rs @@ -25,7 +25,6 @@ mod errors; /// R1CS instance used by libspartan pub mod instance; mod math; -mod nizk; mod product_tree; mod r1csinstance; mod r1csproof; @@ -205,7 +204,6 @@ impl IOProofs { // batch prove all proofs let proofs = PolyEvalProof::prove_batched_points( exec_poly_inputs, - None, [ vec![ 0, // input valid @@ -231,7 +229,6 @@ impl IOProofs { live_input, ] .concat(), - None, transcript, random_tape, ); @@ -613,7 +610,7 @@ pub struct SNARK { perm_poly_poly_list: Vec, proof_eval_perm_poly_prod_list: Vec>, - shift_proof: ShiftProofs, + // shift_proof: ShiftProofs, io_proof: IOProofs, } @@ -1857,7 +1854,6 @@ impl SNARK { block_wit_secs, &block_inst.inst, transcript, - &mut random_tape, ) }; @@ -1972,7 +1968,6 @@ impl SNARK { ], &pairwise_check_inst.inst, transcript, - &mut random_tape, ) }; @@ -2099,7 +2094,6 @@ impl SNARK { ], &perm_root_inst.inst, transcript, - &mut random_tape, ) }; @@ -2200,10 +2194,8 @@ impl SNARK { .collect(); let proof_eval_perm_poly_prod_list = PolyEvalProof::prove_batched_instances( &perm_poly_w3_prover.poly_w, - None, r_list, &perm_poly_poly_list, - None, transcript, &mut random_tape, ); @@ -2265,6 +2257,7 @@ impl SNARK { shifted_polys.push(&vir_mem_addr_w3_shifted_prover.poly_w[0]); header_len_list.push(6); } + /* let shift_proof = ShiftProofs::prove( orig_polys, shifted_polys, @@ -2273,6 +2266,7 @@ impl SNARK { &mut random_tape, ); shift_proof + */ }; timer_proof.stop(); @@ -2319,7 +2313,7 @@ impl SNARK { perm_poly_poly_list, proof_eval_perm_poly_prod_list, - shift_proof, + // shift_proof, io_proof, } } @@ -3261,9 +3255,11 @@ impl SNARK { header_len_list.push(6); } + /* self .shift_proof .verify(poly_size_list, shift_size_list, header_len_list, transcript)?; + */ } timer_proof.stop(); diff --git a/spartan_parallel/src/nizk/bullet.rs b/spartan_parallel/src/nizk/bullet.rs deleted file mode 100644 index 549c924d..00000000 --- a/spartan_parallel/src/nizk/bullet.rs +++ /dev/null @@ -1,159 +0,0 @@ -//! This module is an adaptation of code from the bulletproofs crate. -//! See NOTICE.md for more details -#![allow(non_snake_case)] -#![allow(clippy::type_complexity)] -#![allow(clippy::too_many_arguments)] -use super::super::errors::ProofVerifyError; -use super::super::scalar::SpartanExtensionField; -use super::super::transcript::ProofTranscript; -use merlin::Transcript; -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct BulletReductionProof { - _phantom: S, -} - -impl BulletReductionProof { - /// Create an inner-product proof. - /// - /// The proof is created with respect to the bases \\(G\\). - /// - /// The `transcript` is passed in as a parameter so that the - /// challenges depend on the *entire* transcript (including parent - /// protocols). - /// - /// The lengths of the vectors must all be the same, and must all be - /// either 0 or a power of 2. - pub fn prove( - transcript: &mut Transcript, - a_vec: &[S], - b_vec: &[S], - blind: &S, - blinds_vec: &[(S, S)], - ) -> (S, S, S) { - // Create slices G, H, a, b backed by their respective - // vectors. This lets us reslice as we compress the lengths - // of the vectors in the main loop below. - let mut a: &mut [S] = &mut a_vec.to_owned()[..]; - let mut b: &mut [S] = &mut b_vec.to_owned()[..]; - - let mut blinds_iter = blinds_vec.iter(); - let mut blind_fin: S = *blind; - - let mut n = a.len(); - assert_eq!(a.len(), n); - assert_eq!(b.len(), n); - - while n != 1 { - n /= 2; - let (a_L, a_R) = a.split_at_mut(n); - let (b_L, b_R) = b.split_at_mut(n); - - let _c_L = inner_product(a_L, b_R); - let _c_R = inner_product(a_R, b_L); - - let (blind_L, blind_R) = blinds_iter.next().unwrap(); - - let u: S = transcript.challenge_scalar(b"u"); - - let u_inv = u.invert().unwrap(); - - for i in 0..n { - a_L[i] = a_L[i] * u + u_inv * a_R[i]; - b_L[i] = b_L[i] * u_inv + u * b_R[i]; - } - - blind_fin = blind_fin + *blind_L * u * u + *blind_R * u_inv * u_inv; - - a = a_L; - b = b_L; - } - - (a[0], b[0], blind_fin) - } - - /// Computes three vectors of verification scalars \\([u\_{i}^{2}]\\), \\([u\_{i}^{-2}]\\) and \\([s\_{i}]\\) for combined multiscalar multiplication - /// in a parent protocol. See [inner product protocol notes](index.html#verification-equation) for details. - /// The verifier must provide the input length \\(n\\) explicitly to avoid unbounded allocation within the inner product proof. - fn verification_scalars( - &self, - n: usize, - transcript: &mut Transcript, - ) -> Result<(Vec, Vec, Vec), ProofVerifyError> { - let mut lg_n = 0usize; - assert!(n > 0, "n must not be 0"); - - let mut value = n; - while value > 1 { - value >>= 1; // Divide value by 2 - lg_n += 1; - } - - // 1. Recompute x_k,...,x_1 based on the proof transcript - let mut challenges = Vec::with_capacity(lg_n); - for _i in 0..lg_n { - challenges.push(transcript.challenge_scalar(b"u")); - } - - // 2. Compute 1/(u_k...u_1) and 1/u_k, ..., 1/u_1 - let mut challenges_inv = challenges.clone(); - let allinv = S::batch_invert(&mut challenges_inv); - - // 3. Compute u_i^2 and (1/u_i)^2 - for i in 0..lg_n { - challenges[i] = challenges[i].square(); - challenges_inv[i] = challenges_inv[i].square(); - } - let challenges_sq = challenges; - let challenges_inv_sq = challenges_inv; - - // 4. Compute s values inductively. - let mut s = Vec::with_capacity(n); - s.push(allinv); - for i in 1..n { - let lg_i = (32 - 1 - (i as u32).leading_zeros()) as usize; - let k = 1 << lg_i; - // The challenges are stored in "creation order" as [u_k,...,u_1], - // so u_{lg(i)+1} = is indexed by (lg_n-1) - lg_i - let u_lg_i_sq = challenges_sq[(lg_n - 1) - lg_i]; - s.push(s[i - k] * u_lg_i_sq); - } - - Ok((challenges_sq, challenges_inv_sq, s)) - } - - /// This method is for testing that proof generation work, - /// but for efficiency the actual protocols would use `verification_scalars` - /// method to combine inner product verification with other checks - /// in a single multiscalar multiplication. - pub fn verify( - &self, - n: usize, - a: &[S], - transcript: &mut Transcript, - ) -> Result { - let (_u_sq, _u_inv_sq, s) = self.verification_scalars(n, transcript)?; - - let a_hat = inner_product(a, &s); - - Ok(a_hat) - } -} - -/// Computes an inner product of two vectors -/// \\[ -/// {\langle {\mathbf{a}}, {\mathbf{b}} \rangle} = \sum\_{i=0}^{n-1} a\_i \cdot b\_i. -/// \\] -/// Panics if the lengths of \\(\mathbf{a}\\) and \\(\mathbf{b}\\) are not equal. -pub fn inner_product(a: &[S], b: &[S]) -> S { - assert!( - a.len() == b.len(), - "inner_product(a,b): lengths of vectors do not match" - ); - let mut out = S::field_zero(); - for i in 0..a.len() { - out = out + a[i] * b[i]; - } - out -} diff --git a/spartan_parallel/src/nizk/mod.rs b/spartan_parallel/src/nizk/mod.rs deleted file mode 100644 index a57b1d94..00000000 --- a/spartan_parallel/src/nizk/mod.rs +++ /dev/null @@ -1,346 +0,0 @@ -#![allow(clippy::too_many_arguments)] -use crate::scalar::SpartanExtensionField; - -use super::errors::ProofVerifyError; -use super::math::Math; -use super::random::RandomTape; -use super::transcript::ProofTranscript; -use merlin::Transcript; -use serde::{Deserialize, Serialize}; -mod bullet; -use bullet::BulletReductionProof; - -#[derive(Serialize, Deserialize, Debug)] -pub struct KnowledgeProof { - z1: S, - z2: S, -} - -impl KnowledgeProof { - fn protocol_name() -> &'static [u8] { - b"knowledge proof" - } - - pub fn prove( - transcript: &mut Transcript, - random_tape: &mut RandomTape, - x: &S, - r: &S, - ) -> KnowledgeProof { - >::append_protocol_name( - transcript, - KnowledgeProof::::protocol_name(), - ); - - // produce two random Scalars - let t1 = random_tape.random_scalar(b"t1"); - let t2 = random_tape.random_scalar(b"t2"); - - let c: S = transcript.challenge_scalar(b"c"); - - let z1 = *x * c + t1; - let z2 = *r * c + t2; - - KnowledgeProof { z1, z2 } - } - - pub fn verify(&self, transcript: &mut Transcript) -> Result<(), ProofVerifyError> { - // Transcript operations to preserve consistency for the verify function - { - >::append_protocol_name( - transcript, - KnowledgeProof::::protocol_name(), - ); - - let _c: S = transcript.challenge_scalar(b"c"); - } - - // TODO: Alternative PCS Verification - Ok(()) - } -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct EqualityProof { - z: S, -} - -impl EqualityProof { - fn protocol_name() -> &'static [u8] { - b"equality proof" - } - - pub fn prove( - transcript: &mut Transcript, - random_tape: &mut RandomTape, - _v1: &S, - s1: &S, - _v2: &S, - s2: &S, - ) -> EqualityProof { - >::append_protocol_name( - transcript, - EqualityProof::::protocol_name(), - ); - - // produce a random Scalar - let r = random_tape.random_scalar(b"r"); - let c: S = transcript.challenge_scalar(b"c"); - let z = c * (*s1 - *s2) + r; - - EqualityProof { z } - } - - pub fn verify(&self, transcript: &mut Transcript) -> Result<(), ProofVerifyError> { - // Transcript operations to preserve consistency for the verify function - { - >::append_protocol_name( - transcript, - EqualityProof::::protocol_name(), - ); - - let _c: S = transcript.challenge_scalar(b"c"); - } - - // TODO: Alternative PCS Verification - Ok(()) - } -} - -#[derive(Serialize, Deserialize, Debug)] -pub struct ProductProof { - z: [S; 5], -} - -impl ProductProof { - fn protocol_name() -> &'static [u8] { - b"product proof" - } - - pub fn prove( - transcript: &mut Transcript, - random_tape: &mut RandomTape, - x: &S, - rX: &S, - y: &S, - rY: &S, - _z: &S, - rZ: &S, - ) -> ProductProof { - >::append_protocol_name( - transcript, - ProductProof::::protocol_name(), - ); - - // produce five random Scalar - let b1 = random_tape.random_scalar(b"b1"); - let b2 = random_tape.random_scalar(b"b2"); - let b3 = random_tape.random_scalar(b"b3"); - let b4 = random_tape.random_scalar(b"b4"); - let b5 = random_tape.random_scalar(b"b5"); - - let c: S = transcript.challenge_scalar(b"c"); - - let z1 = b1 + c * *x; - let z2 = b2 + c * *rX; - let z3 = b3 + c * *y; - let z4 = b4 + c * *rY; - let z5 = b5 + c * (*rZ - *rX * *y); - let z = [z1, z2, z3, z4, z5]; - - ProductProof { z } - } - - fn _check_equality(_c: &S, _z1: &S, _z2: &S) -> bool { - // TODO: Alternative PCS Verification - true - } - - pub fn verify(&self, transcript: &mut Transcript) -> Result<(), ProofVerifyError> { - // Transcript operations to preserve consistency for the verify function - { - >::append_protocol_name( - transcript, - ProductProof::::protocol_name(), - ); - - let _c: S = transcript.challenge_scalar(b"c"); - } - - // TODO: Alternative PCS Verification - Ok(()) - } -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct DotProductProof { - z: Vec, - z_delta: S, - z_beta: S, -} - -impl DotProductProof { - fn protocol_name() -> &'static [u8] { - b"dot product proof" - } - - pub fn compute_dotproduct(a: &[S], b: &[S]) -> S { - assert_eq!(a.len(), b.len()); - (0..a.len()).map(|i| a[i] * b[i]).sum() - } - - pub fn prove( - transcript: &mut Transcript, - random_tape: &mut RandomTape, - x_vec: &[S], - blind_x: &S, - a_vec: &[S], - _y: &S, - blind_y: &S, - ) -> DotProductProof { - >::append_protocol_name( - transcript, - DotProductProof::::protocol_name(), - ); - - let n = x_vec.len(); - assert_eq!(x_vec.len(), a_vec.len()); - - // produce randomness for the proofs - let d_vec = random_tape.random_vector(b"d_vec", n); - let r_delta = random_tape.random_scalar(b"r_delta"); - let r_beta = random_tape.random_scalar(b"r_beta"); - - let _dotproduct_a_d = DotProductProof::compute_dotproduct(a_vec, &d_vec); - - S::append_field_vector_to_transcript(b"a", transcript, a_vec); - let c: S = transcript.challenge_scalar(b"c"); - - let z = (0..d_vec.len()) - .map(|i| c * x_vec[i] + d_vec[i]) - .collect::>(); - - let z_delta = c * *blind_x + r_delta; - let z_beta = c * *blind_y + r_beta; - - DotProductProof { z, z_delta, z_beta } - } - - pub fn verify(&self, transcript: &mut Transcript, a: &[S]) -> Result<(), ProofVerifyError> { - // Transcript operations to preserve consistency for the verify function - { - >::append_protocol_name( - transcript, - DotProductProof::::protocol_name(), - ); - S::append_field_vector_to_transcript(b"a", transcript, a); - let _c: S = transcript.challenge_scalar(b"c"); - } - - let _dotproduct_z_a = DotProductProof::compute_dotproduct(&self.z, a); - - // TODO: Alternative PCS Verification - Ok(()) - } -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct DotProductProofLog { - z1: S, - z2: S, -} - -impl DotProductProofLog { - fn protocol_name() -> &'static [u8] { - b"dot product proof (log)" - } - - pub fn compute_dotproduct(a: &[S], b: &[S]) -> S { - assert_eq!(a.len(), b.len()); - (0..a.len()).map(|i| a[i] * b[i]).sum() - } - - pub fn prove( - transcript: &mut Transcript, - random_tape: &mut RandomTape, - x_vec: &[S], - blind_x: &S, - a_vec: &[S], - _y: &S, - blind_y: &S, - ) -> DotProductProofLog { - >::append_protocol_name( - transcript, - DotProductProofLog::::protocol_name(), - ); - - let n = x_vec.len(); - assert_eq!(x_vec.len(), a_vec.len()); - - // produce randomness for generating a proof - let d = random_tape.random_scalar(b"d"); - let r_delta = random_tape.random_scalar(b"r_delta"); - let r_beta = random_tape.random_scalar(b"r_delta"); - let blinds_vec = { - let v1 = random_tape.random_vector(b"blinds_vec_1", 2 * n.log_2()); - let v2 = random_tape.random_vector(b"blinds_vec_2", 2 * n.log_2()); - (0..v1.len()) - .map(|i| (v1[i], v2[i])) - .collect::>() - }; - S::append_field_vector_to_transcript(b"a", transcript, a_vec); - - // sample a random base and scale the generator used for - // the output of the inner product - let r: S = transcript.challenge_scalar(b"r"); - - let blind_Gamma: S = *blind_x + r * *blind_y; - let (x_hat, a_hat, rhat_Gamma) = - BulletReductionProof::prove(transcript, x_vec, a_vec, &blind_Gamma, &blinds_vec); - - let y_hat = x_hat * a_hat; - - let c: S = transcript.challenge_scalar(b"c"); - - let z1 = d + c * y_hat; - let z2 = a_hat * (c * rhat_Gamma + r_beta) + r_delta; - - DotProductProofLog { z1, z2 } - } - - pub fn verify( - &self, - n: usize, - transcript: &mut Transcript, - a: &[S], - ) -> Result<(), ProofVerifyError> { - assert_eq!(a.len(), n); - - // Transcript operations to preserve consistency for the verify function - { - >::append_protocol_name( - transcript, - DotProductProofLog::::protocol_name(), - ); - - S::append_field_vector_to_transcript(b"a", transcript, a); - - // sample a random base and scale the generator used for - // the output of the inner product - let _r: S = transcript.challenge_scalar(b"r"); - - // BulletReductionProof - verification_scalars - let mut m = a.len(); - while m != 1 { - m /= 2; - - let _u: S = transcript.challenge_scalar(b"u"); - } - - let _c: S = transcript.challenge_scalar(b"c"); - } - - // TODO: Alternative PCS Verification - Ok(()) - } -} diff --git a/spartan_parallel/src/r1csproof.rs b/spartan_parallel/src/r1csproof.rs index 1188c0c9..05a52d94 100644 --- a/spartan_parallel/src/r1csproof.rs +++ b/spartan_parallel/src/r1csproof.rs @@ -1,12 +1,11 @@ #![allow(clippy::too_many_arguments)] use super::custom_dense_mlpoly::DensePolynomialPqx; -use super::dense_mlpoly::{DensePolynomial, EqPolynomial, PolyEvalProof}; +use super::dense_mlpoly::{DensePolynomial, EqPolynomial}; use super::errors::ProofVerifyError; use super::math::Math; -use super::nizk::{EqualityProof, KnowledgeProof, ProductProof}; use super::r1csinstance::R1CSInstance; use super::random::RandomTape; -use super::sumcheck::ZKSumcheckInstanceProof; +use super::sumcheck::SumcheckInstanceProof; use super::timer::Timer; use super::transcript::ProofTranscript; use crate::scalar::SpartanExtensionField; @@ -17,12 +16,10 @@ use std::cmp::min; #[derive(Serialize, Deserialize, Debug)] pub struct R1CSProof { - sc_proof_phase1: ZKSumcheckInstanceProof, - sc_proof_phase2: ZKSumcheckInstanceProof, - pok_claims_phase2: (KnowledgeProof, ProductProof), - proof_eq_sc_phase1: EqualityProof, - proof_eq_sc_phase2: EqualityProof, - proof_eval_vars_at_ry_list: Vec>, + sc_proof_phase1: SumcheckInstanceProof, + sc_proof_phase2: SumcheckInstanceProof, + claims_phase2: (S, S, S), + // proof_eval_vars_at_ry_list: Vec>, } impl R1CSProof { @@ -40,16 +37,14 @@ impl R1CSProof { evals_Bz: &mut DensePolynomialPqx, evals_Cz: &mut DensePolynomialPqx, transcript: &mut Transcript, - random_tape: &mut RandomTape, - ) -> (ZKSumcheckInstanceProof, Vec, Vec, S) { + ) -> (SumcheckInstanceProof, Vec, Vec) { let comb_func = |poly_A_comp: &S, poly_B_comp: &S, poly_C_comp: &S, poly_D_comp: &S| -> S { *poly_A_comp * (*poly_B_comp * *poly_C_comp - *poly_D_comp) }; - let (sc_proof_phase_one, r, claims, blind_claim_postsc) = - ZKSumcheckInstanceProof::::prove_cubic_with_additive_term_disjoint_rounds( + let (sc_proof_phase_one, r, claims) = + SumcheckInstanceProof::::prove_cubic_with_additive_term_disjoint_rounds( &S::field_zero(), // claim is zero - &S::field_zero(), // blind for claim is also zero num_rounds, num_rounds_x_max, num_rounds_q_max, @@ -64,10 +59,9 @@ impl R1CSProof { evals_Cz, comb_func, transcript, - random_tape, ); - (sc_proof_phase_one, r, claims, blind_claim_postsc) + (sc_proof_phase_one, r, claims) } fn prove_phase_two( @@ -79,36 +73,31 @@ impl R1CSProof { num_witness_secs: usize, num_inputs: Vec, claim: &S, - blind_claim: &S, evals_eq: &mut DensePolynomial, evals_ABC: &mut DensePolynomialPqx, evals_z: &mut DensePolynomialPqx, transcript: &mut Transcript, - random_tape: &mut RandomTape, - ) -> (ZKSumcheckInstanceProof, Vec, Vec, S) { + ) -> (SumcheckInstanceProof, Vec, Vec) { let comb_func = |poly_A_comp: &S, poly_B_comp: &S, poly_C_comp: &S| -> S { *poly_A_comp * *poly_B_comp * *poly_C_comp }; - let (sc_proof_phase_two, r, claims, blind_claim_postsc) = - ZKSumcheckInstanceProof::::prove_cubic_disjoint_rounds( - claim, - blind_claim, - num_rounds, - num_rounds_y_max, - num_rounds_w, - num_rounds_p, - single_inst, - num_witness_secs, - num_inputs, - evals_eq, - evals_ABC, - evals_z, - comb_func, - transcript, - random_tape, - ); + let (sc_proof_phase_two, r, claims) = SumcheckInstanceProof::::prove_cubic_disjoint_rounds( + claim, + num_rounds, + num_rounds_y_max, + num_rounds_w, + num_rounds_p, + single_inst, + num_witness_secs, + num_inputs, + evals_eq, + evals_ABC, + evals_z, + comb_func, + transcript, + ); - (sc_proof_phase_two, r, claims, blind_claim_postsc) + (sc_proof_phase_two, r, claims) } fn protocol_name() -> &'static [u8] { @@ -137,7 +126,6 @@ impl R1CSProof { // INSTANCES inst: &R1CSInstance, transcript: &mut Transcript, - random_tape: &mut RandomTape, ) -> (R1CSProof, [Vec; 4]) { let timer_prove = Timer::new("R1CSProof::prove"); >::append_protocol_name( @@ -235,7 +223,7 @@ impl R1CSProof { // Sumcheck 1: (Az * Bz - Cz) * eq(x, q, p) = 0 let timer_tmp = Timer::new("prove_sum_check"); - let (sc_proof_phase1, rx, _claims_phase1, blind_claim_postsc1) = R1CSProof::prove_phase_one( + let (sc_proof_phase1, rx, _claims_phase1) = R1CSProof::prove_phase_one( num_rounds_x + num_rounds_q + num_rounds_p, num_rounds_x, num_rounds_q, @@ -249,7 +237,6 @@ impl R1CSProof { &mut poly_Bz, &mut poly_Cz, transcript, - random_tape, ); assert_eq!(poly_tau_p.len(), 1); @@ -268,43 +255,8 @@ impl R1CSProof { &poly_Cz.index(0, 0, 0, 0), ); - let (Az_blind, Bz_blind, Cz_blind, prod_Az_Bz_blind) = ( - random_tape.random_scalar(b"Az_blind"), - random_tape.random_scalar(b"Bz_blind"), - random_tape.random_scalar(b"Cz_blind"), - random_tape.random_scalar(b"prod_Az_Bz_blind"), - ); - - let pok_Cz_claim = { KnowledgeProof::prove(transcript, random_tape, Cz_claim, &Cz_blind) }; - - let proof_prod = { - let prod = *Az_claim * *Bz_claim; - ProductProof::prove( - transcript, - random_tape, - Az_claim, - &Az_blind, - Bz_claim, - &Bz_blind, - &prod, - &prod_Az_Bz_blind, - ) - }; - // prove the final step of sum-check #1 - let taus_bound_rx = tau_claim; - - let blind_expected_claim_postsc1 = *taus_bound_rx * (prod_Az_Bz_blind - Cz_blind); - let claim_post_phase1 = (*Az_claim * *Bz_claim - *Cz_claim) * *taus_bound_rx; - - let proof_eq_sc_phase1 = EqualityProof::prove( - transcript, - random_tape, - &claim_post_phase1, - &blind_expected_claim_postsc1, - &claim_post_phase1, - &blind_claim_postsc1, - ); + let _taus_bound_rx = tau_claim; // Separate the result rx into rp, rq, and rx let (rx_rev, rq_rev) = rx.split_at(num_rounds_x); @@ -324,7 +276,6 @@ impl R1CSProof { let r_C: S = transcript.challenge_scalar(b"challenge_Cz"); let claim_phase2 = r_A * *Az_claim + r_B * *Bz_claim + r_C * *Cz_claim; - let blind_claim_phase2 = r_A * Az_blind + r_B * Bz_blind + r_C * Cz_blind; let timer_tmp = Timer::new("prove_abc_gen"); let evals_ABC = { @@ -380,7 +331,7 @@ impl R1CSProof { let mut eq_p_rp_poly = DensePolynomial::new(EqPolynomial::new(rp).evals()); // Sumcheck 2: (rA + rB + rC) * Z * eq(p) = e - let (sc_proof_phase2, ry, claims_phase2, blind_claim_postsc2) = R1CSProof::prove_phase_two( + let (sc_proof_phase2, ry, _claims_phase2) = R1CSProof::prove_phase_two( num_rounds_y + num_rounds_w + num_rounds_p, num_rounds_y, num_rounds_w, @@ -389,12 +340,10 @@ impl R1CSProof { num_witness_secs, num_inputs.clone(), &claim_phase2, - &blind_claim_phase2, &mut eq_p_rp_poly, &mut ABC_poly, &mut Z_poly, transcript, - random_tape, ); timer_sc_proof_phase2.stop(); @@ -466,18 +415,18 @@ impl R1CSProof { } } + /* let proof_eval_vars_at_ry_list = PolyEvalProof::prove_batched_instances_disjoint_rounds( &poly_list, &num_proofs_list, &num_inputs_list, - None, &rq, &ry, &Zr_list, - None, transcript, random_tape, ); + */ // Bind the resulting witness list to rp // poly_vars stores the result of each witness matrix bounded to (rq_short ++ ry) @@ -543,31 +492,14 @@ impl R1CSProof { let poly_vars = DensePolynomial::new(eval_vars_comb_list); let _eval_vars_at_ry = poly_vars.evaluate(&rp); - // prove the final step of sum-check #2 - let blind_expected_claim_postsc2 = S::field_zero(); - let claim_post_phase2 = claims_phase2[0] * claims_phase2[1] * claims_phase2[2]; - - let proof_eq_sc_phase2 = EqualityProof::prove( - transcript, - random_tape, - &claim_post_phase2, - &blind_expected_claim_postsc2, - &claim_post_phase2, - &blind_claim_postsc2, - ); - timer_prove.stop(); - let pok_claims_phase2 = (pok_Cz_claim, proof_prod); - ( R1CSProof { sc_proof_phase1, sc_proof_phase2, - pok_claims_phase2, - proof_eq_sc_phase1, - proof_eq_sc_phase2, - proof_eval_vars_at_ry_list, + claims_phase2: (*Az_claim, *Bz_claim, *Cz_claim), + // proof_eval_vars_at_ry_list, }, [rp, rq_rev, rx, [rw, ry].concat()], ) @@ -619,23 +551,19 @@ impl R1CSProof { let tau_q = transcript.challenge_vector(b"challenge_tau_q", num_rounds_q); let tau_x = transcript.challenge_vector(b"challenge_tau_x", num_rounds_x); - let rx = - self - .sc_proof_phase1 - .verify(num_rounds_x + num_rounds_q + num_rounds_p, 3, transcript)?; - - // perform the intermediate sum-check test with claimed Az, Bz, and Cz - let (pok_Cz_claim, proof_prod) = &self.pok_claims_phase2; - - pok_Cz_claim.verify(transcript)?; - proof_prod.verify(transcript)?; + let (_, rx) = self.sc_proof_phase1.verify( + S::field_zero(), + num_rounds_x + num_rounds_q + num_rounds_p, + 3, + transcript, + )?; // Separate the result rx into rp_round1, rq, and rx let (rx_rev, rq_rev) = rx.split_at(num_rounds_x); let (rq_rev, rp_round1) = rq_rev.split_at(num_rounds_q); let rx: Vec = rx_rev.iter().copied().rev().collect(); let rq_rev = rq_rev.to_vec(); - let rq: Vec = rq_rev.iter().copied().rev().collect(); + let _rq: Vec = rq_rev.iter().copied().rev().collect(); let rp_round1 = rp_round1.to_vec(); // taus_bound_rx is really taus_bound_rx_rq_rp @@ -652,19 +580,21 @@ impl R1CSProof { .product(); let _taus_bound_rx = taus_bound_rp * taus_bound_rq * taus_bound_rx; - // verify proof that expected_claim_post_phase1 == claim_post_phase1 - self.proof_eq_sc_phase1.verify(transcript)?; - // derive three public challenges and then derive a joint claim - let _r_A: S = transcript.challenge_scalar(b"challenge_Az"); - let _r_B: S = transcript.challenge_scalar(b"challenge_Bz"); - let _r_C: S = transcript.challenge_scalar(b"challenge_Cz"); + let r_A: S = transcript.challenge_scalar(b"challenge_Az"); + let r_B: S = transcript.challenge_scalar(b"challenge_Bz"); + let r_C: S = transcript.challenge_scalar(b"challenge_Cz"); + + let (Az_claim, Bz_claim, Cz_claim) = self.claims_phase2; + let claim_phase2 = r_A * Az_claim + r_B * Bz_claim + r_C * Cz_claim; // verify the joint claim with a sum-check protocol - let ry = - self - .sc_proof_phase2 - .verify(num_rounds_y + num_rounds_w + num_rounds_p, 3, transcript)?; + let (_, ry) = self.sc_proof_phase2.verify( + claim_phase2, + num_rounds_y + num_rounds_w + num_rounds_p, + 3, + transcript, + )?; // Separate ry into rp, rw, and ry let (ry_rev, rw) = ry.split_at(num_rounds_y); @@ -701,6 +631,7 @@ impl R1CSProof { } } + /* PolyEvalProof::verify_batched_instances_disjoint_rounds( &self.proof_eval_vars_at_ry_list, &num_proofs_list, @@ -709,6 +640,7 @@ impl R1CSProof { &rq, &ry, )?; + */ // Then on rp for p in 0..num_instances { @@ -754,9 +686,6 @@ impl R1CSProof { timer_commit_opening.stop(); - // verify proof that expected_claim_post_phase2 == claim_post_phase2 - self.proof_eq_sc_phase2.verify(transcript)?; - Ok([rp, rq_rev, rx, [rw, ry].concat()]) } } diff --git a/spartan_parallel/src/sparse_mlpoly.rs b/spartan_parallel/src/sparse_mlpoly.rs index cff1f6c6..830d2803 100644 --- a/spartan_parallel/src/sparse_mlpoly.rs +++ b/spartan_parallel/src/sparse_mlpoly.rs @@ -104,15 +104,8 @@ impl DerefsEvalProof { // decommit the joint polynomial at r_joint S::append_field_to_transcript(b"joint_claim_eval", transcript, eval_joint); - let proof_derefs = PolyEvalProof::prove( - joint_poly, - None, - &r_joint, - &eval_joint, - None, - transcript, - random_tape, - ); + let proof_derefs = + PolyEvalProof::prove(joint_poly, &r_joint, &eval_joint, transcript, random_tape); proof_derefs } @@ -764,10 +757,8 @@ impl HashLayerProof { let proof_ops = PolyEvalProof::prove( &dense.comb_ops, - None, &r_joint_ops, &joint_claim_eval_ops, - None, transcript, random_tape, ); @@ -791,10 +782,8 @@ impl HashLayerProof { let proof_mem = PolyEvalProof::prove( &dense.comb_mem, - None, &r_joint_mem, &joint_claim_eval_mem, - None, transcript, random_tape, ); diff --git a/spartan_parallel/src/sumcheck.rs b/spartan_parallel/src/sumcheck.rs index 249b1abd..57b11cf4 100644 --- a/spartan_parallel/src/sumcheck.rs +++ b/spartan_parallel/src/sumcheck.rs @@ -6,7 +6,6 @@ use crate::scalar::SpartanExtensionField; use super::dense_mlpoly::DensePolynomial; use super::errors::ProofVerifyError; -use super::nizk::DotProductProof; use super::random::RandomTape; use super::transcript::{AppendToTranscript, ProofTranscript}; use super::unipoly::{CompressedUniPoly, UniPoly}; @@ -70,67 +69,6 @@ impl SumcheckInstanceProof { } } -#[derive(Serialize, Deserialize, Debug)] -pub struct ZKSumcheckInstanceProof { - proofs: Vec>, -} - -impl ZKSumcheckInstanceProof { - pub fn new(proofs: Vec>) -> Self { - ZKSumcheckInstanceProof { proofs } - } - - pub fn verify( - &self, - num_rounds: usize, - degree_bound: usize, - transcript: &mut Transcript, - ) -> Result, ProofVerifyError> { - let mut r: Vec = Vec::new(); - - for i in 0..num_rounds { - // derive the verifier's challenge for the next round - let r_i = transcript.challenge_scalar(b"challenge_nextround"); - - // verify the proof of sum-check and evals - let _res = { - // produce two weights - let w: Vec = transcript.challenge_vector(b"combine_two_claims_to_one", 2); - - let a = { - // the vector to use to decommit for sum-check test - let a_sc = { - let mut a = vec![S::field_one(); degree_bound + 1]; - a[0] = a[0] + S::field_one(); - a - }; - - // the vector to use to decommit for evaluation - let a_eval = { - let mut a = vec![S::field_one(); degree_bound + 1]; - for j in 1..a.len() { - a[j] = a[j - 1] * r_i; - } - a - }; - - // take weighted sum of the two vectors using w - assert_eq!(a_sc.len(), a_eval.len()); - (0..a_sc.len()) - .map(|i| w[0] * a_sc[i] + w[1] * a_eval[i]) - .collect::>() - }; - - self.proofs[i].verify(transcript, &a).is_ok() - }; - - r.push(r_i); - } - - Ok(r) - } -} - impl SumcheckInstanceProof { pub fn prove_cubic( claim: &S, @@ -379,12 +317,9 @@ impl SumcheckInstanceProof { claims_dotp, ) } -} -impl ZKSumcheckInstanceProof { pub fn prove_cubic_disjoint_rounds( claim: &S, - blind_claim: &S, num_rounds: usize, num_rounds_y_max: usize, num_rounds_w: usize, @@ -397,8 +332,7 @@ impl ZKSumcheckInstanceProof { poly_C: &mut DensePolynomialPqx, comb_func: F, transcript: &mut Transcript, - random_tape: &mut RandomTape, - ) -> (Self, Vec, Vec, S) + ) -> (Self, Vec, Vec) where F: Fn(&S, &S, &S) -> S, { @@ -408,15 +342,10 @@ impl ZKSumcheckInstanceProof { // poly_A is the EQ polynomial of size P * W * Y_max assert_eq!(num_rounds, num_rounds_y_max + num_rounds_w + num_rounds_p); - let (blinds_poly, blinds_evals) = ( - random_tape.random_vector(b"blinds_poly", num_rounds), - random_tape.random_vector(b"blinds_evals", num_rounds), - ); - let mut claim_per_round = *claim; let mut r: Vec = Vec::new(); - let mut proofs: Vec> = Vec::new(); + let mut polys: Vec> = Vec::new(); let mut inputs_len = num_rounds_y_max.pow2(); let mut witness_secs_len = num_rounds_w.pow2(); @@ -546,8 +475,12 @@ impl ZKSumcheckInstanceProof { poly }; + // append the prover's message to the transcript + poly.append_to_transcript(b"poly", transcript); + //derive the verifier's challenge for the next round let r_j = transcript.challenge_scalar(b"challenge_nextround"); + r.push(r_j); // bound all tables to the verifier's challenege if mode == MODE_P { @@ -557,95 +490,23 @@ impl ZKSumcheckInstanceProof { poly_B.bound_poly(&r_j, mode); } poly_C.bound_poly(&r_j, mode); - - // produce a proof of sum-check and of evaluation - let (proof, claim_next_round) = { - let eval = poly.evaluate(&r_j); - - // we need to prove the following under homomorphic commitments: - // (1) poly(0) + poly(1) = claim_per_round - // (2) poly(r_j) = eval - - // Our technique is to leverage dot product proofs: - // (1) we can prove: = claim_per_round - // (2) we can prove: = transcript.challenge_vector(b"combine_two_claims_to_one", 2); - - // compute a weighted sum of the RHS - let target = w[0] * claim_per_round + w[1] * eval; - - let blind = { - let blind_sc = if j == 0 { - blind_claim - } else { - &blinds_evals[j - 1] - }; - - let blind_eval = &blinds_evals[j]; - - w[0] * *blind_sc + w[1] * *blind_eval - }; - - let a = { - // the vector to use to decommit for sum-check test - let a_sc = { - let mut a = vec![S::field_one(); poly.degree() + 1]; - a[0] = a[0] + S::field_one(); - a - }; - - // the vector to use to decommit for evaluation - let a_eval = { - let mut a = vec![S::field_one(); poly.degree() + 1]; - for j in 1..a.len() { - a[j] = a[j - 1] * r_j; - } - a - }; - - // take weighted sum of the two vectors using w - assert_eq!(a_sc.len(), a_eval.len()); - (0..a_sc.len()) - .map(|i| w[0] * a_sc[i] + w[1] * a_eval[i]) - .collect::>() - }; - - let proof = DotProductProof::prove( - transcript, - random_tape, - &poly.as_vec(), - &blinds_poly[j], - &a, - &target, - &blind, - ); - - (proof, eval) - }; - - proofs.push(proof); - claim_per_round = claim_next_round; - r.push(r_j); + claim_per_round = poly.evaluate(&r_j); + polys.push(poly.compress()); } ( - ZKSumcheckInstanceProof::new(proofs), + SumcheckInstanceProof::new(polys), r, vec![ poly_A[0], poly_B.index(0, 0, 0, 0), poly_C.index(0, 0, 0, 0), ], - blinds_evals[num_rounds - 1], ) } pub fn prove_cubic_with_additive_term_disjoint_rounds( claim: &S, - blind_claim: &S, num_rounds: usize, num_rounds_x_max: usize, num_rounds_q_max: usize, @@ -660,8 +521,7 @@ impl ZKSumcheckInstanceProof { poly_D: &mut DensePolynomialPqx, comb_func: F, transcript: &mut Transcript, - random_tape: &mut RandomTape, - ) -> (Self, Vec, Vec, S) + ) -> (Self, Vec, Vec) where F: Fn(&S, &S, &S, &S) -> S, { @@ -678,15 +538,10 @@ impl ZKSumcheckInstanceProof { assert_eq!(poly_C.num_witness_secs, 1); assert_eq!(poly_D.num_witness_secs, 1); - let (blinds_poly, blinds_evals) = ( - random_tape.random_vector(b"blinds_poly", num_rounds), - random_tape.random_vector(b"blinds_evals", num_rounds), - ); - let mut claim_per_round = *claim; let mut r: Vec = Vec::new(); - let mut proofs: Vec> = Vec::new(); + let mut polys: Vec> = Vec::new(); let mut cons_len = num_rounds_x_max.pow2(); let mut proof_len = num_rounds_q_max.pow2(); @@ -831,8 +686,12 @@ impl ZKSumcheckInstanceProof { poly }; + // append the prover's message to the transcript + poly.append_to_transcript(b"poly", transcript); + //derive the verifier's challenge for the next round let r_j = transcript.challenge_scalar(b"challenge_nextround"); + r.push(r_j); // bound all tables to the verifier's challenege if mode == 1 { @@ -845,81 +704,12 @@ impl ZKSumcheckInstanceProof { poly_B.bound_poly(&r_j, mode); poly_C.bound_poly(&r_j, mode); poly_D.bound_poly(&r_j, mode); - - let (proof, claim_next_round) = { - let eval = poly.evaluate(&r_j); - - // we need to prove the following under homomorphic commitments: - // (1) poly(0) + poly(1) = claim_per_round - // (2) poly(r_j) = eval - - // Our technique is to leverage dot product proofs: - // (1) we can prove: = claim_per_round - // (2) we can prove: = transcript.challenge_vector(b"combine_two_claims_to_one", 2); - - // compute a weighted sum of the RHS - let target = w[0] * claim_per_round + w[1] * eval; - - let blind = { - let blind_sc = if j == 0 { - blind_claim - } else { - &blinds_evals[j - 1] - }; - - let blind_eval = &blinds_evals[j]; - - w[0] * *blind_sc + w[1] * *blind_eval - }; - - let a = { - // the vector to use to decommit for sum-check test - let a_sc = { - let mut a = vec![S::field_one(); poly.degree() + 1]; - a[0] = a[0] + S::field_one(); - a - }; - - // the vector to use to decommit for evaluation - let a_eval = { - let mut a = vec![S::field_one(); poly.degree() + 1]; - for j in 1..a.len() { - a[j] = a[j - 1] * r_j; - } - a - }; - - // take weighted sum of the two vectors using w - assert_eq!(a_sc.len(), a_eval.len()); - (0..a_sc.len()) - .map(|i| w[0] * a_sc[i] + w[1] * a_eval[i]) - .collect::>() - }; - - let proof = DotProductProof::prove( - transcript, - random_tape, - &poly.as_vec(), - &blinds_poly[j], - &a, - &target, - &blind, - ); - - (proof, eval) - }; - - proofs.push(proof); - claim_per_round = claim_next_round; - r.push(r_j); + claim_per_round = poly.evaluate(&r_j); + polys.push(poly.compress()); } ( - ZKSumcheckInstanceProof::new(proofs), + SumcheckInstanceProof::new(polys), r, vec![ poly_Ap[0] * poly_Aq[0] * poly_Ax[0], @@ -927,7 +717,6 @@ impl ZKSumcheckInstanceProof { poly_C.index(0, 0, 0, 0), poly_D.index(0, 0, 0, 0), ], - blinds_evals[num_rounds - 1], ) } }