diff --git a/circ_blocks/Cargo.lock b/circ_blocks/Cargo.lock index 3ac35621..cc080398 100644 --- a/circ_blocks/Cargo.lock +++ b/circ_blocks/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addchain" @@ -314,6 +314,7 @@ dependencies = [ "gmp-mpfr-sys", "good_lp", "group 0.12.1", + "halo2curves", "ieee754", "im", "itertools 0.10.5", @@ -1705,6 +1706,7 @@ dependencies = [ "ff 0.13.0", "flate2", "goldilocks", + "halo2curves", "itertools 0.13.0", "merlin", "rand 0.8.5", diff --git a/circ_blocks/Cargo.toml b/circ_blocks/Cargo.toml index 7a97c52a..92860d8e 100644 --- a/circ_blocks/Cargo.toml +++ b/circ_blocks/Cargo.toml @@ -29,6 +29,7 @@ thiserror = "1" bellman = { git = "https://github.com/alex-ozdemir/bellman.git", branch = "mirage", optional = true } rayon = { version = "1", optional = true } ff = { version = "0.12", optional = true } +halo2curves = "0.1.0" fxhash = "0.2" good_lp = { version = "1.10", features = [ "lp-solvers", diff --git a/circ_blocks/examples/zxc.rs b/circ_blocks/examples/zxc.rs index c2627f31..9baeaa19 100644 --- a/circ_blocks/examples/zxc.rs +++ b/circ_blocks/examples/zxc.rs @@ -12,6 +12,7 @@ use circ::target::r1cs::wit_comp::StagedWitCompEvaluator; use circ::target::r1cs::ProverData; use circ::target::r1cs::{Lc, VarType}; use core::cmp::min; +use halo2curves::serde::SerdeObject; use libspartan::scalar::{ScalarExt2, SpartanExtensionField}; use rug::Integer; @@ -33,7 +34,6 @@ use libspartan::{ use merlin::Transcript; use serde::{Deserialize, Serialize}; use std::time::*; -use std::time::*; // How many reserved variables (EXCLUDING V) are in front of the actual input / output? // %BN, %RET, %TS, %AS, %SP, %BP @@ -437,7 +437,10 @@ impl RunTimeKnowledge { for exec in block { writeln!(&mut f, "EXEC {}", exec_counter)?; for assg in &exec.assignment { - write!(&mut f, "{} ", bytes_to_integer(&assg.to_bytes()))?; + let mut padded = [0; 32]; + padded[..8].copy_from_slice(&assg.to_raw_bytes()); + + write!(&mut f, "{} ", bytes_to_integer(&padded))?; } writeln!(&mut f)?; exec_counter += 1; @@ -449,7 +452,10 @@ impl RunTimeKnowledge { for exec in &self.exec_inputs { writeln!(&mut f, "EXEC {}", exec_counter)?; for assg in &exec.assignment { - write!(&mut f, "{} ", bytes_to_integer(&assg.to_bytes()))?; + let mut padded = [0; 32]; + padded[..8].copy_from_slice(&assg.to_raw_bytes()); + + write!(&mut f, "{} ", bytes_to_integer(&padded))?; } writeln!(&mut f)?; exec_counter += 1; @@ -459,7 +465,10 @@ impl RunTimeKnowledge { for addr in &self.init_phy_mems_list { writeln!(&mut f, "ACCESS {}", addr_counter)?; for assg in &addr.assignment { - write!(&mut f, "{} ", bytes_to_integer(&assg.to_bytes()))?; + let mut padded = [0; 32]; + padded[..8].copy_from_slice(&assg.to_raw_bytes()); + + write!(&mut f, "{} ", bytes_to_integer(&padded))?; } writeln!(&mut f)?; addr_counter += 1; @@ -469,7 +478,10 @@ impl RunTimeKnowledge { for addr in &self.init_vir_mems_list { writeln!(&mut f, "ACCESS {}", addr_counter)?; for assg in &addr.assignment { - write!(&mut f, "{} ", bytes_to_integer(&assg.to_bytes()))?; + let mut padded = [0; 32]; + padded[..8].copy_from_slice(&assg.to_raw_bytes()); + + write!(&mut f, "{} ", bytes_to_integer(&padded))?; } writeln!(&mut f)?; addr_counter += 1; @@ -479,7 +491,10 @@ impl RunTimeKnowledge { for addr in &self.addr_phy_mems_list { writeln!(&mut f, "ACCESS {}", addr_counter)?; for assg in &addr.assignment { - write!(&mut f, "{} ", bytes_to_integer(&assg.to_bytes()))?; + let mut padded = [0; 32]; + padded[..8].copy_from_slice(&assg.to_raw_bytes()); + + write!(&mut f, "{} ", bytes_to_integer(&padded))?; } writeln!(&mut f)?; addr_counter += 1; @@ -489,7 +504,10 @@ impl RunTimeKnowledge { for addr in &self.addr_vir_mems_list { writeln!(&mut f, "ACCESS {}", addr_counter)?; for assg in &addr.assignment { - write!(&mut f, "{} ", bytes_to_integer(&assg.to_bytes()))?; + let mut padded = [0; 32]; + padded[..8].copy_from_slice(&assg.to_raw_bytes()); + + write!(&mut f, "{} ", bytes_to_integer(&padded))?; } writeln!(&mut f)?; addr_counter += 1; @@ -499,7 +517,10 @@ impl RunTimeKnowledge { for addr in &self.addr_ts_bits_list { writeln!(&mut f, "ACCESS {}", addr_counter)?; for assg in &addr.assignment { - write!(&mut f, "{} ", bytes_to_integer(&assg.to_bytes()))?; + let mut padded = [0; 32]; + padded[..8].copy_from_slice(&assg.to_raw_bytes()); + + write!(&mut f, "{} ", bytes_to_integer(&padded))?; } writeln!(&mut f)?; addr_counter += 1; diff --git a/spartan_parallel/Cargo.toml b/spartan_parallel/Cargo.toml index 2472d2d5..e61bc5d0 100644 --- a/spartan_parallel/Cargo.toml +++ b/spartan_parallel/Cargo.toml @@ -30,6 +30,7 @@ colored = { version = "2", default-features = false, optional = true } flate2 = { version = "1" } goldilocks = { git = "https://github.com/scroll-tech/ceno-Goldilocks" } ff = "0.13.0" +halo2curves = "0.1.0" [dev-dependencies] criterion = "0.5" diff --git a/spartan_parallel/src/custom_dense_mlpoly.rs b/spartan_parallel/src/custom_dense_mlpoly.rs index 18489e98..6c8c5b66 100644 --- a/spartan_parallel/src/custom_dense_mlpoly.rs +++ b/spartan_parallel/src/custom_dense_mlpoly.rs @@ -1,11 +1,11 @@ #![allow(clippy::too_many_arguments)] use std::cmp::min; +use super::math::Math; use crate::dense_mlpoly::DensePolynomial; +use crate::mle::Ext; use crate::scalar::SpartanExtensionField; -use super::math::Math; - const MODE_P: usize = 1; const MODE_Q: usize = 2; const MODE_W: usize = 3; @@ -328,7 +328,7 @@ impl DensePolynomialPqx { } // Convert to a (p, q_rev, x_rev) regular dense poly of form (p, q, x) - pub fn to_dense_poly(&self) -> DensePolynomial { + pub fn to_dense_poly(&self) -> DensePolynomial { let mut Z_poly = vec![ S::field_zero(); diff --git a/spartan_parallel/src/dense_mlpoly.rs b/spartan_parallel/src/dense_mlpoly.rs index 78a0886f..bf2e977c 100644 --- a/spartan_parallel/src/dense_mlpoly.rs +++ b/spartan_parallel/src/dense_mlpoly.rs @@ -1,23 +1,24 @@ #![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 crate::mle::{Base, Ext, MLEType, MLE}; +use crate::scalar::SpartanExtensionField; use core::ops::Index; +use ff::Field; use merlin::Transcript; use serde::{Deserialize, Serialize}; -use std::collections::HashMap; +use std::{collections::HashMap, process::Output}; #[cfg(feature = "multicore")] use rayon::prelude::*; #[derive(Debug, Clone)] -pub struct DensePolynomial { +pub struct DensePolynomial { num_vars: usize, // the number of variables in the multilinear polynomial len: usize, - Z: Vec, // evaluations of the polynomial in all the 2^num_vars Boolean inputs + Z: MLE, // evaluations of the polynomial in all the 2^num_vars Boolean inputs } pub struct EqPolynomial { @@ -114,7 +115,7 @@ impl IdentityPolynomial { } } -impl DensePolynomial { +impl DensePolynomial { pub fn new(mut Z: Vec) -> Self { // If length of Z is not a power of 2, append Z with 0 let zero = S::field_zero(); @@ -122,7 +123,7 @@ impl DensePolynomial { DensePolynomial { num_vars: Z.len().log_2(), len: Z.len(), - Z, + Z: MLE::::new(Z), } } @@ -134,11 +135,7 @@ impl DensePolynomial { self.len } - pub fn clone(&self) -> DensePolynomial { - DensePolynomial::new(self.Z[0..self.len].to_vec()) - } - - pub fn split(&self, idx: usize) -> (DensePolynomial, DensePolynomial) { + pub fn split(&self, idx: usize) -> (DensePolynomial, DensePolynomial) { assert!(idx < self.len()); ( DensePolynomial::new(self.Z[..idx].to_vec()), @@ -253,7 +250,7 @@ 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()); - Self::compute_dotproduct(&self.Z, &chis) + Self::compute_dotproduct(&self.Z[0..], &chis) } fn compute_dotproduct(a: &[S], b: &[S]) -> S { @@ -262,10 +259,10 @@ impl DensePolynomial { } fn vec(&self) -> &Vec { - &self.Z + &self.Z.inner_ref() } - pub fn extend(&mut self, other: &DensePolynomial) { + pub fn extend(&mut self, other: &DensePolynomial) { // TODO: allow extension even when some vars are bound assert_eq!(self.Z.len(), self.len); let other_vec = other.vec(); @@ -276,9 +273,9 @@ impl DensePolynomial { assert_eq!(self.Z.len(), self.len); } - pub fn merge<'a, I>(polys: I) -> DensePolynomial + pub fn merge<'a, I>(polys: I) -> DensePolynomial where - I: IntoIterator>, + I: IntoIterator>, { let mut Z: Vec = Vec::new(); for poly in polys.into_iter() { @@ -300,12 +297,34 @@ impl DensePolynomial { } } -impl Index for DensePolynomial { +impl DensePolynomial { + pub fn new_from_base(mut Z: Vec) -> Self { + // If length of Z is not a power of 2, append Z with 0 + let zero = S::BaseField::ZERO; + Z.extend(vec![zero; Z.len().next_power_of_two() - Z.len()]); + DensePolynomial { + num_vars: Z.len().log_2(), + len: Z.len(), + Z: MLE::::new(Z), + } + } +} + +impl Index for DensePolynomial { type Output = S; #[inline(always)] - fn index(&self, _index: usize) -> &S { - &(self.Z[_index]) + fn index(&self, index: usize) -> &Self::Output { + &(self.Z[index]) + } +} + +impl Index for DensePolynomial { + type Output = S::BaseField; + + #[inline(always)] + fn index(&self, index: usize) -> &Self::Output { + &(self.Z[index]) } } @@ -320,7 +339,7 @@ impl PolyEvalProof { } pub fn prove( - _poly: &DensePolynomial, + _poly: &DensePolynomial, _r: &[S], // point at which the polynomial is evaluated _Zr: &S, // evaluation of \widetilde{Z}(r) _transcript: &mut Transcript, @@ -352,7 +371,7 @@ impl PolyEvalProof { // Evaluation of multiple points on the same instance pub fn prove_batched_points( - _poly: &DensePolynomial, + _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, @@ -375,9 +394,9 @@ impl PolyEvalProof { // 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 - _r_list: Vec<&Vec>, // point at which the polynomial is evaluated - _Zr_list: &Vec, // evaluation of \widetilde{Z}(r) on each instance + _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> { @@ -399,7 +418,7 @@ impl PolyEvalProof { // 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>, + _poly_list: &Vec<&DensePolynomial>, _num_proofs_list: &Vec, _num_inputs_list: &Vec, _rq: &[S], @@ -426,7 +445,7 @@ impl PolyEvalProof { // Treat the polynomial(s) as univariate and open on a single point pub fn prove_uni_batched_instances( - _poly_list: &Vec<&DensePolynomial>, + _poly_list: &Vec<&DensePolynomial>, _r: &S, // point at which the polynomial is evaluated _Zr: &Vec, // evaluation of \widetilde{Z}(r) _transcript: &mut Transcript, diff --git a/spartan_parallel/src/lib.rs b/spartan_parallel/src/lib.rs index 3c41496b..95269de2 100644 --- a/spartan_parallel/src/lib.rs +++ b/spartan_parallel/src/lib.rs @@ -25,6 +25,7 @@ mod errors; /// R1CS instance used by libspartan pub mod instance; mod math; +mod mle; mod product_tree; mod r1csinstance; mod r1csproof; @@ -45,10 +46,13 @@ use std::{ use dense_mlpoly::{DensePolynomial, PolyEvalProof}; use errors::{ProofVerifyError, R1CSError}; +use goldilocks::SmallField; +use halo2curves::serde::SerdeObject; use instance::Instance; use itertools::Itertools; use math::Math; use merlin::Transcript; +use mle::Ext; use r1csinstance::{R1CSCommitment, R1CSDecommitment, R1CSEvalProof, R1CSInstance}; use r1csproof::R1CSProof; use random::RandomTape; @@ -78,40 +82,32 @@ pub struct ComputationDecommitment { #[derive(Clone, Serialize, Deserialize)] pub struct Assignment { /// Entries of an assignment - pub assignment: Vec, + pub assignment: Vec, } impl Assignment { /// Constructs a new `Assignment` from a vector pub fn new(assignment: &[[u8; 32]]) -> Result, R1CSError> { - let bytes_to_scalar = |vec: &[[u8; 32]]| -> Result, R1CSError> { - let mut vec_scalar: Vec = Vec::new(); - for v in vec { - let val = S::from_bytes(v); - if val.is_some().unwrap_u8() == 1 { - vec_scalar.push(val.unwrap()); - } else { - return Err(R1CSError::InvalidScalar); - } - } - Ok(vec_scalar) + let bytes_to_scalar = |vec: &[[u8; 32]]| -> Result, R1CSError> { + Ok( + vec + .into_iter() + .map(|v| S::BaseField::from_raw_bytes_unchecked(v)) + .collect::>(), + ) }; let assignment_scalar = bytes_to_scalar(assignment); - // check for any parsing errors - if assignment_scalar.is_err() { - return Err(R1CSError::InvalidScalar); - } - - Ok(Assignment { - assignment: assignment_scalar.unwrap(), - }) + assignment_scalar.map(|a| Assignment { assignment: a }) } /// Write the assignment into a file pub fn write(&self, f: &File) -> std::io::Result<()> { for assg in &self.assignment { - write_bytes(f, &assg.to_bytes())?; + let mut padded = [0; 32]; + padded[..8].copy_from_slice(&assg.to_raw_bytes()); + + write_bytes(f, &padded)?; } Ok(()) } @@ -153,7 +149,7 @@ struct IOProofs { impl IOProofs { // Given the polynomial in execution order, generate all proofs fn prove( - exec_poly_inputs: &DensePolynomial, + exec_poly_inputs: &DensePolynomial, num_ios: usize, num_inputs_unpadded: usize, @@ -325,8 +321,8 @@ struct ShiftProofs { impl ShiftProofs { fn prove( - orig_polys: Vec<&DensePolynomial>, - shifted_polys: Vec<&DensePolynomial>, + orig_polys: Vec<&DensePolynomial>, + shifted_polys: Vec<&DensePolynomial>, // For each orig_poly, how many entries at the front of proof 0 are non-zero? header_len_list: Vec, transcript: &mut Transcript, @@ -421,11 +417,11 @@ struct ProverWitnessSecInfo { // num_instances x num_proofs x num_inputs hypermatrix for all values w_mat: Vec>>, // One dense polynomial per instance - poly_w: Vec>, + poly_w: Vec>, } impl ProverWitnessSecInfo { - fn new(w_mat: Vec>>, poly_w: Vec>) -> ProverWitnessSecInfo { + fn new(w_mat: Vec>>, poly_w: Vec>) -> ProverWitnessSecInfo { ProverWitnessSecInfo { num_inputs: w_mat.iter().map(|i| i[0].len()).collect(), w_mat, @@ -854,31 +850,70 @@ impl SNARK { // unwrap the assignments let mut block_vars_mat = block_vars_mat .into_iter() - .map(|a| a.into_iter().map(|v| v.assignment).collect::>>()) + .map(|a| { + a.into_iter() + .map(|v| { + v.assignment + .into_iter() + .map(|a| S::from_base(&a)) + .collect::>() + }) + .collect::>>() + }) .collect::>>>(); let mut exec_inputs_list = exec_inputs_list .into_iter() - .map(|v| v.assignment) + .map(|v| { + v.assignment + .into_iter() + .map(|a| S::from_base(&a)) + .collect::>() + }) .collect::>>(); let mut init_phy_mems_list = init_phy_mems_list .into_iter() - .map(|v| v.assignment) + .map(|v| { + v.assignment + .into_iter() + .map(|a| S::from_base(&a)) + .collect::>() + }) .collect::>>(); let mut init_vir_mems_list = init_vir_mems_list .into_iter() - .map(|v| v.assignment) + .map(|v| { + v.assignment + .into_iter() + .map(|a| S::from_base(&a)) + .collect::>() + }) .collect::>>(); let mut addr_phy_mems_list = addr_phy_mems_list .into_iter() - .map(|v| v.assignment) + .map(|v| { + v.assignment + .into_iter() + .map(|a| S::from_base(&a)) + .collect::>() + }) .collect::>>(); let mut addr_vir_mems_list = addr_vir_mems_list .into_iter() - .map(|v| v.assignment) + .map(|v| { + v.assignment + .into_iter() + .map(|a| S::from_base(&a)) + .collect::>() + }) .collect::>>(); let mut addr_ts_bits_list = addr_ts_bits_list .into_iter() - .map(|v| v.assignment) + .map(|v| { + v.assignment + .into_iter() + .map(|a| S::from_base(&a)) + .collect::>() + }) .collect::>>(); // -- @@ -2166,7 +2201,7 @@ impl SNARK { // PHY_MEM_BLOCK takes r = 4, VIR_MEM_BLOCK takes r = 6, everything else takes r = 2 let perm_poly_poly_list: Vec = (0..inst_map.len()) .map(|i| { - let p: &DensePolynomial = &perm_poly_w3_prover.poly_w[i]; + let p: &DensePolynomial = &perm_poly_w3_prover.poly_w[i]; let i = inst_map[i]; if i == vm_bl_id { p[6] diff --git a/spartan_parallel/src/mle.rs b/spartan_parallel/src/mle.rs new file mode 100644 index 00000000..1bc349a8 --- /dev/null +++ b/spartan_parallel/src/mle.rs @@ -0,0 +1,142 @@ +use crate::scalar::SpartanExtensionField; +use std::cmp::max; +use std::ops::{Index, IndexMut, Range, RangeFrom, RangeTo}; + +pub trait MLEType {} + +#[derive(Debug, Clone)] +pub struct Base; +impl MLEType for Base {} + +#[derive(Debug, Clone)] +pub struct Ext; +impl MLEType for Ext {} + +#[derive(Debug, Clone)] +pub struct MLE { + t: T, + + // Depending on T, one of the following fields will be empty. + // For MLE, field elements can potentially be stored as elements + // in the base field (resource saving) or in the extended field. + ext_vec: Vec, + base_vec: Vec, +} + +// Define universal behavior of MLE +impl MLE { + pub fn len(&self) -> usize { + max(self.ext_vec.len(), self.base_vec.len()) + } +} + +// Define behavior of MLE when elements are in the base field +impl MLE { + pub fn new(vals: Vec) -> Self { + Self { + t: Base, + ext_vec: vec![], + base_vec: vals, + } + } + + pub fn inner_ref(&self) -> &Vec { + &self.base_vec + } +} + +impl Index for MLE { + type Output = S::BaseField; + + fn index(&self, index: usize) -> &Self::Output { + &self.base_vec[index] + } +} + +impl Index> for MLE { + type Output = [S::BaseField]; + + fn index(&self, index: Range) -> &Self::Output { + &self.base_vec[index] + } +} + +impl Index> for MLE { + type Output = [S::BaseField]; + + fn index(&self, range: RangeTo) -> &Self::Output { + &self.base_vec[range] + } +} + +impl Index> for MLE { + type Output = [S::BaseField]; + + fn index(&self, range: RangeFrom) -> &Self::Output { + &self.base_vec[range] + } +} + +impl IndexMut for MLE { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.base_vec[index] + } +} + +// Define behavior of MLE when elements are in the extended field +impl MLE { + pub fn new(vals: Vec) -> Self { + Self { + t: Ext, + ext_vec: vals, + base_vec: vec![], + } + } + + pub fn inner_ref(&self) -> &Vec { + &self.ext_vec + } + + pub fn extend(&mut self, other_vec: &Vec) -> &Vec { + self.ext_vec.extend(other_vec); + &self.ext_vec + } +} + +impl Index for MLE { + type Output = S; + + fn index(&self, index: usize) -> &Self::Output { + &self.ext_vec[index] + } +} + +impl Index> for MLE { + type Output = [S]; + + fn index(&self, index: Range) -> &Self::Output { + &self.ext_vec[index] + } +} + +impl Index> for MLE { + type Output = [S]; + + fn index(&self, range: RangeTo) -> &Self::Output { + &self.ext_vec[range] + } +} + +impl Index> for MLE { + type Output = [S]; + + fn index(&self, range: RangeFrom) -> &Self::Output { + &self.ext_vec[range] + } +} + +impl IndexMut for MLE { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.ext_vec[index] + } +} diff --git a/spartan_parallel/src/product_tree.rs b/spartan_parallel/src/product_tree.rs index c42d9a79..70f53a43 100644 --- a/spartan_parallel/src/product_tree.rs +++ b/spartan_parallel/src/product_tree.rs @@ -1,4 +1,5 @@ #![allow(dead_code)] +use crate::mle::Ext; use crate::scalar::SpartanExtensionField; use super::dense_mlpoly::DensePolynomial; @@ -11,15 +12,15 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone)] pub struct ProductCircuit { - left_vec: Vec>, - right_vec: Vec>, + left_vec: Vec>, + right_vec: Vec>, } impl ProductCircuit { fn compute_layer( - inp_left: &DensePolynomial, - inp_right: &DensePolynomial, - ) -> (DensePolynomial, DensePolynomial) { + inp_left: &DensePolynomial, + inp_right: &DensePolynomial, + ) -> (DensePolynomial, DensePolynomial) { let len = inp_left.len() + inp_right.len(); let outp_left = (0..len / 4) .map(|i| inp_left[i] * inp_right[i]) @@ -34,9 +35,9 @@ impl ProductCircuit { ) } - pub fn new(poly: &DensePolynomial) -> Self { - let mut left_vec: Vec> = Vec::new(); - let mut right_vec: Vec> = Vec::new(); + pub fn new(poly: &DensePolynomial) -> Self { + let mut left_vec: Vec> = Vec::new(); + let mut right_vec: Vec> = Vec::new(); let num_layers = poly.len().log_2(); let (outp_left, outp_right) = poly.split(poly.len() / 2); @@ -66,16 +67,16 @@ impl ProductCircuit { #[derive(Clone)] pub struct DotProductCircuit { - left: DensePolynomial, - right: DensePolynomial, - weight: DensePolynomial, + left: DensePolynomial, + right: DensePolynomial, + weight: DensePolynomial, } impl DotProductCircuit { pub fn new( - left: DensePolynomial, - right: DensePolynomial, - weight: DensePolynomial, + left: DensePolynomial, + right: DensePolynomial, + weight: DensePolynomial, ) -> Self { assert_eq!(left.len(), right.len()); assert_eq!(left.len(), weight.len()); @@ -281,8 +282,8 @@ impl ProductCircuitEvalProofBatched { *poly_A_comp * *poly_B_comp * *poly_C_comp }; - let mut poly_A_batched_par: Vec<&mut DensePolynomial> = Vec::new(); - let mut poly_B_batched_par: Vec<&mut DensePolynomial> = Vec::new(); + let mut poly_A_batched_par: Vec<&mut DensePolynomial> = Vec::new(); + let mut poly_B_batched_par: Vec<&mut DensePolynomial> = Vec::new(); for prod_circuit in prod_circuit_vec.iter_mut() { poly_A_batched_par.push(&mut prod_circuit.left_vec[layer_id]); poly_B_batched_par.push(&mut prod_circuit.right_vec[layer_id]) @@ -294,9 +295,9 @@ impl ProductCircuitEvalProofBatched { ); // prepare sequential instances that don't share poly_C - let mut poly_A_batched_seq: Vec<&mut DensePolynomial> = Vec::new(); - let mut poly_B_batched_seq: Vec<&mut DensePolynomial> = Vec::new(); - let mut poly_C_batched_seq: Vec<&mut DensePolynomial> = Vec::new(); + let mut poly_A_batched_seq: Vec<&mut DensePolynomial> = Vec::new(); + let mut poly_B_batched_seq: Vec<&mut DensePolynomial> = Vec::new(); + let mut poly_C_batched_seq: Vec<&mut DensePolynomial> = Vec::new(); if layer_id == 0 && !dotp_circuit_vec.is_empty() { // add additional claims for item in dotp_circuit_vec.iter() { diff --git a/spartan_parallel/src/r1csproof.rs b/spartan_parallel/src/r1csproof.rs index 05a52d94..2eb1b9e3 100644 --- a/spartan_parallel/src/r1csproof.rs +++ b/spartan_parallel/src/r1csproof.rs @@ -8,6 +8,7 @@ use super::random::RandomTape; use super::sumcheck::SumcheckInstanceProof; use super::timer::Timer; use super::transcript::ProofTranscript; +use crate::mle::Ext; use crate::scalar::SpartanExtensionField; use crate::{ProverWitnessSecInfo, VerifierWitnessSecInfo}; use merlin::Transcript; @@ -30,9 +31,9 @@ impl R1CSProof { num_rounds_p: usize, num_proofs: &Vec, num_cons: &Vec, - evals_tau_p: &mut DensePolynomial, - evals_tau_q: &mut DensePolynomial, - evals_tau_x: &mut DensePolynomial, + evals_tau_p: &mut DensePolynomial, + evals_tau_q: &mut DensePolynomial, + evals_tau_x: &mut DensePolynomial, evals_Az: &mut DensePolynomialPqx, evals_Bz: &mut DensePolynomialPqx, evals_Cz: &mut DensePolynomialPqx, @@ -73,7 +74,7 @@ impl R1CSProof { num_witness_secs: usize, num_inputs: Vec, claim: &S, - evals_eq: &mut DensePolynomial, + evals_eq: &mut DensePolynomial, evals_ABC: &mut DensePolynomialPqx, evals_z: &mut DensePolynomialPqx, transcript: &mut Transcript, diff --git a/spartan_parallel/src/scalar/mod.rs b/spartan_parallel/src/scalar/mod.rs index 138a2259..66d2d260 100644 --- a/spartan_parallel/src/scalar/mod.rs +++ b/spartan_parallel/src/scalar/mod.rs @@ -4,10 +4,10 @@ mod fp2; use ff::Field; pub use fp::Scalar; pub use fp2::ScalarExt2; -use goldilocks::ExtensionField; +use goldilocks::{ExtensionField, SmallField}; use merlin::Transcript; use rand::{CryptoRng, RngCore}; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use std::fmt; use std::{ cmp::Eq, @@ -52,7 +52,7 @@ pub trait SpartanExtensionField: type InnerType: ExtensionField + Field; /// Basefield for conserving computational resources - type BaseField: Field; + type BaseField: SmallField + Field + for<'a> Deserialize<'a>; /// Return inner Goldilocks field element fn inner(&self) -> &Self::InnerType; diff --git a/spartan_parallel/src/sparse_mlpoly.rs b/spartan_parallel/src/sparse_mlpoly.rs index 830d2803..4213f498 100644 --- a/spartan_parallel/src/sparse_mlpoly.rs +++ b/spartan_parallel/src/sparse_mlpoly.rs @@ -1,6 +1,7 @@ #![allow(clippy::type_complexity)] #![allow(clippy::too_many_arguments)] #![allow(clippy::needless_range_loop)] +use crate::mle::{Base, Ext}; use crate::scalar::SpartanExtensionField; use super::dense_mlpoly::DensePolynomial; @@ -12,6 +13,7 @@ use super::random::RandomTape; use super::timer::Timer; use super::transcript::{AppendToTranscript, ProofTranscript}; use core::cmp::Ordering; +use ff::Field; use merlin::Transcript; use serde::{Deserialize, Serialize}; @@ -19,11 +21,11 @@ use serde::{Deserialize, Serialize}; pub struct SparseMatEntry { row: usize, col: usize, - val: S, + val: S::BaseField, } impl SparseMatEntry { - pub fn new(row: usize, col: usize, val: S) -> Self { + pub fn new(row: usize, col: usize, val: S::BaseField) -> Self { SparseMatEntry { row, col, val } } } @@ -36,13 +38,16 @@ pub struct SparseMatPolynomial { } pub struct Derefs { - row_ops_val: Vec>, - col_ops_val: Vec>, - comb: DensePolynomial, + row_ops_val: Vec>, + col_ops_val: Vec>, + comb: DensePolynomial, } impl Derefs { - pub fn new(row_ops_val: Vec>, col_ops_val: Vec>) -> Self { + pub fn new( + row_ops_val: Vec>, + col_ops_val: Vec>, + ) -> Self { assert_eq!(row_ops_val.len(), col_ops_val.len()); let ret_row_ops_val = row_ops_val.clone(); @@ -74,7 +79,7 @@ impl DerefsEvalProof { } fn prove_single( - joint_poly: &DensePolynomial, + joint_poly: &DensePolynomial, r: &[S], evals: Vec, transcript: &mut Transcript, @@ -187,9 +192,9 @@ impl DerefsEvalProof { #[derive(Clone)] struct AddrTimestamps { ops_addr_usize: Vec>, - ops_addr: Vec>, - read_ts: Vec>, - audit_ts: DensePolynomial, + ops_addr: Vec>, + read_ts: Vec>, + audit_ts: DensePolynomial, } impl AddrTimestamps { @@ -199,8 +204,8 @@ impl AddrTimestamps { } let mut audit_ts = vec![0usize; num_cells]; - let mut ops_addr_vec: Vec> = Vec::new(); - let mut read_ts_vec: Vec> = Vec::new(); + let mut ops_addr_vec: Vec> = Vec::new(); + let mut read_ts_vec: Vec> = Vec::new(); for ops_addr_inst in ops_addr.iter() { let mut read_ts = vec![0usize; num_ops]; @@ -228,7 +233,7 @@ impl AddrTimestamps { } } - fn deref_mem(addr: &[usize], mem_val: &[S]) -> DensePolynomial { + fn deref_mem(addr: &[usize], mem_val: &[S]) -> DensePolynomial { DensePolynomial::new( (0..addr.len()) .map(|i| { @@ -239,20 +244,20 @@ impl AddrTimestamps { ) } - pub fn deref(&self, mem_val: &[S]) -> Vec> { + pub fn deref(&self, mem_val: &[S]) -> Vec> { (0..self.ops_addr.len()) .map(|i| AddrTimestamps::deref_mem(&self.ops_addr_usize[i], mem_val)) - .collect::>>() + .collect::>>() } } pub struct MultiSparseMatPolynomialAsDense { batch_size: usize, - val: Vec>, + val: Vec>, row: AddrTimestamps, col: AddrTimestamps, - comb_ops: DensePolynomial, - comb_mem: DensePolynomial, + comb_ops: DensePolynomial, + comb_mem: DensePolynomial, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -260,6 +265,7 @@ pub struct SparseMatPolyCommitment { batch_size: usize, num_ops: usize, num_mem_cells: usize, + // TODO: add mpcs commitment _phantom: S, } @@ -284,11 +290,11 @@ impl SparseMatPolynomial { self.M.len().next_power_of_two() } - fn sparse_to_dense_vecs(&self, N: usize) -> (Vec, Vec, Vec) { + fn sparse_to_dense_vecs(&self, N: usize) -> (Vec, Vec, Vec) { assert!(N >= self.get_num_nz_entries()); let mut ops_row: Vec = vec![0; N]; let mut ops_col: Vec = vec![0; N]; - let mut val: Vec = vec![S::field_zero(); N]; + let mut val: Vec = vec![S::BaseField::ZERO; N]; for i in 0..self.M.len() { ops_row[i] = self.M[i].row; @@ -314,7 +320,7 @@ impl SparseMatPolynomial { let mut ops_row_vec: Vec> = Vec::new(); let mut ops_col_vec: Vec> = Vec::new(); - let mut val_vec: Vec> = Vec::new(); + let mut val_vec: Vec> = Vec::new(); for poly in sparse_polys { let (ops_row, ops_col, val) = poly.sparse_to_dense_vecs(N); ops_row_vec.push(ops_row); @@ -502,16 +508,16 @@ struct Layers { impl Layers { fn build_hash_layer( eval_table: &[S], - addrs_vec: &[DensePolynomial], - derefs_vec: &[DensePolynomial], - read_ts_vec: &[DensePolynomial], - audit_ts: &DensePolynomial, + addrs_vec: &[DensePolynomial], + derefs_vec: &[DensePolynomial], + read_ts_vec: &[DensePolynomial], + audit_ts: &DensePolynomial, r_mem_check: &(S, S), ) -> ( - DensePolynomial, - Vec>, - Vec>, - DensePolynomial, + DensePolynomial, + Vec>, + Vec>, + DensePolynomial, ) { let (r_hash, r_multiset_check) = r_mem_check; @@ -539,8 +545,8 @@ impl Layers { ); // hash read and write that depends on #instances - let mut poly_read_hashed_vec: Vec> = Vec::new(); - let mut poly_write_hashed_vec: Vec> = Vec::new(); + let mut poly_read_hashed_vec: Vec> = Vec::new(); + let mut poly_write_hashed_vec: Vec> = Vec::new(); for i in 0..addrs_vec.len() { let (addrs, derefs, read_ts) = (&addrs_vec[i], &derefs_vec[i], &read_ts_vec[i]); assert_eq!(addrs.len(), derefs.len()); @@ -578,7 +584,7 @@ impl Layers { pub fn new( eval_table: &[S], addr_timestamps: &AddrTimestamps, - poly_ops_val: &[DensePolynomial], + poly_ops_val: &[DensePolynomial], r_mem_check: &(S, S), ) -> Self { let (poly_init_hashed, poly_read_hashed_vec, poly_write_hashed_vec, poly_audit_hashed) = diff --git a/spartan_parallel/src/sumcheck.rs b/spartan_parallel/src/sumcheck.rs index 57b11cf4..db549eb0 100644 --- a/spartan_parallel/src/sumcheck.rs +++ b/spartan_parallel/src/sumcheck.rs @@ -2,6 +2,7 @@ #![allow(clippy::type_complexity)] use crate::custom_dense_mlpoly::DensePolynomialPqx; use crate::math::Math; +use crate::mle::Ext; use crate::scalar::SpartanExtensionField; use super::dense_mlpoly::DensePolynomial; @@ -73,9 +74,9 @@ impl SumcheckInstanceProof { pub fn prove_cubic( claim: &S, num_rounds: usize, - poly_A: &mut DensePolynomial, - poly_B: &mut DensePolynomial, - poly_C: &mut DensePolynomial, + poly_A: &mut DensePolynomial, + poly_B: &mut DensePolynomial, + poly_C: &mut DensePolynomial, comb_func: F, transcript: &mut Transcript, ) -> (Self, Vec, Vec) @@ -147,14 +148,14 @@ impl SumcheckInstanceProof { claim: &S, num_rounds: usize, poly_vec_par: ( - &mut Vec<&mut DensePolynomial>, - &mut Vec<&mut DensePolynomial>, - &mut DensePolynomial, + &mut Vec<&mut DensePolynomial>, + &mut Vec<&mut DensePolynomial>, + &mut DensePolynomial, ), poly_vec_seq: ( - &mut Vec<&mut DensePolynomial>, - &mut Vec<&mut DensePolynomial>, - &mut Vec<&mut DensePolynomial>, + &mut Vec<&mut DensePolynomial>, + &mut Vec<&mut DensePolynomial>, + &mut Vec<&mut DensePolynomial>, ), coeffs: &[S], comb_func: F, @@ -327,7 +328,7 @@ impl SumcheckInstanceProof { single_inst: bool, // indicates whether poly_B only has one instance num_witness_secs: usize, mut num_inputs: Vec, - poly_A: &mut DensePolynomial, + poly_A: &mut DensePolynomial, poly_B: &mut DensePolynomialPqx, poly_C: &mut DensePolynomialPqx, comb_func: F, @@ -513,9 +514,9 @@ impl SumcheckInstanceProof { num_rounds_p: usize, mut num_proofs: Vec, mut num_cons: Vec, - poly_Ap: &mut DensePolynomial, - poly_Aq: &mut DensePolynomial, - poly_Ax: &mut DensePolynomial, + poly_Ap: &mut DensePolynomial, + poly_Aq: &mut DensePolynomial, + poly_Ax: &mut DensePolynomial, poly_B: &mut DensePolynomialPqx, poly_C: &mut DensePolynomialPqx, poly_D: &mut DensePolynomialPqx,