arkworks migration to bls12377
jump to
@@ -32,6 +32,8 @@ ark-std = { version = "^0.3.0"}
ark-bls12-377 = { version = "^0.3.0", features = ["r1cs","curve"] } ark-serialize = { version = "^0.3.0", features = ["derive"] } lazy_static = "1.4.0" +rand = { version = "0.8", features = [ "std", "std_rng" ] } +num-bigint = { version = "0.4" } [dev-dependencies] criterion = "0.3.1"@@ -58,4 +60,4 @@ harness = false
[features] multicore = ["rayon"] -profile = [] +profile = []
@@ -109,13 +109,15 @@ Finally, we provide an example that specifies a custom R1CS instance instead of using a synthetic instance
```rust #![allow(non_snake_case)] -# extern crate curve25519_dalek; +# extern crate ark_std; # extern crate libspartan; # extern crate merlin; -# use curve25519_dalek::scalar::Scalar; +# mod scalar; +# use scalar::Scalar; # use libspartan::{InputsAssignment, Instance, SNARKGens, VarsAssignment, SNARK}; # use merlin::Transcript; -# use rand::rngs::OsRng; +# use ark_ff::{PrimeField, Field, BigInteger}; +# use ark_std::{One, Zero, UniformRand}; # fn main() { // produce a tiny instance let (@@ -177,16 +179,16 @@ let num_non_zero_entries = 5;
// We will encode the above constraints into three matrices, where // the coefficients in the matrix are in the little-endian byte order - let mut A: Vec<(usize, usize, [u8; 32])> = Vec::new(); - let mut B: Vec<(usize, usize, [u8; 32])> = Vec::new(); - let mut C: Vec<(usize, usize, [u8; 32])> = Vec::new(); + let mut A: Vec<(usize, usize, Vec<u8>)> = Vec::new(); + let mut B: Vec<(usize, usize, Vec<u8>)> = Vec::new(); + let mut C: Vec<(usize, usize, Vec<u8>)> = Vec::new(); // The constraint system is defined over a finite field, which in our case is // the scalar field of ristreeto255/curve25519 i.e., p = 2^{252}+27742317777372353535851937790883648493 // To construct these matrices, we will use `curve25519-dalek` but one can use any other method. // a variable that holds a byte representation of 1 - let one = Scalar::one().to_bytes(); + let one = Scalar::one().into_repr().to_bytes_le(); // R1CS is a set of three sparse matrices A B C, where is a row for every // constraint and a column for every entry in z = (vars, 1, inputs)@@ -198,20 +200,20 @@ // constraint 0 is (Z0 + Z1) * I0 - Z2 = 0.
// We set 1 in matrix A for columns that correspond to Z0 and Z1 // We set 1 in matrix B for column that corresponds to I0 // We set 1 in matrix C for column that corresponds to Z2 - A.push((0, 0, one)); - A.push((0, 1, one)); - B.push((0, num_vars + 1, one)); - C.push((0, 2, one)); + A.push((0, 0, one.clone())); + A.push((0, 1, one.clone())); + B.push((0, num_vars + 1, one.clone())); + C.push((0, 2, one.clone())); // constraint 1 entries in (A,B,C) - A.push((1, 0, one)); - A.push((1, num_vars + 2, one)); - B.push((1, 2, one)); - C.push((1, 3, one)); + A.push((1, 0, one.clone())); + A.push((1, num_vars + 2, one.clone())); + B.push((1, 2, one.clone())); + C.push((1, 3, one.clone())); // constraint 3 entries in (A,B,C) - A.push((2, 4, one)); - B.push((2, num_vars, one)); + A.push((2, 4, one.clone())); + B.push((2, num_vars, one.clone())); let inst = Instance::new(num_cons, num_vars, num_inputs, &A, &B, &C).unwrap();@@ -226,18 +228,18 @@ let z3 = (z0 + i1) * z2; // constraint 1
let z4 = Scalar::zero(); //constraint 2 // create a VarsAssignment - let mut vars = vec![Scalar::zero().to_bytes(); num_vars]; - vars[0] = z0.to_bytes(); - vars[1] = z1.to_bytes(); - vars[2] = z2.to_bytes(); - vars[3] = z3.to_bytes(); - vars[4] = z4.to_bytes(); + let mut vars = vec![Scalar::zero().into_repr().to_bytes_le(); num_vars]; + vars[0] = z0.into_repr().to_bytes_le(); + vars[1] = z1.into_repr().to_bytes_le(); + vars[2] = z2.into_repr().to_bytes_le(); + vars[3] = z3.into_repr().to_bytes_le(); + vars[4] = z4.into_repr().to_bytes_le(); let assignment_vars = VarsAssignment::new(&vars).unwrap(); // create an InputsAssignment - let mut inputs = vec![Scalar::zero().to_bytes(); num_inputs]; - inputs[0] = i0.to_bytes(); - inputs[1] = i1.to_bytes(); + let mut inputs = vec![Scalar::zero().into_repr().to_bytes_le(); num_inputs]; + inputs[0] = i0.into_repr().to_bytes_le(); + inputs[1] = i1.into_repr().to_bytes_le(); let assignment_inputs = InputsAssignment::new(&inputs).unwrap(); // check if the instance we created is satisfiable
@@ -9,9 +9,10 @@ //! `(Z3 + 5) * 1 - I0 = 0`
//! //! [here]: https://medium.com/@VitalikButerin/quadratic-arithmetic-programs-from-zero-to-hero-f6d558cea649 use ark_bls12_377::Fr as Scalar; +use ark_ff::{PrimeField, BigInteger}; use libspartan::{InputsAssignment, Instance, SNARKGens, VarsAssignment, SNARK}; use merlin::Transcript; -use rand::rngs::OsRng; +use ark_std::{UniformRand, One, Zero}; #[allow(non_snake_case)] fn produce_r1cs() -> (@@ -31,11 +32,11 @@ let num_non_zero_entries = 8;
// We will encode the above constraints into three matrices, where // the coefficients in the matrix are in the little-endian byte order - let mut A: Vec<(usize, usize, [u8; 32])> = Vec::new(); - let mut B: Vec<(usize, usize, [u8; 32])> = Vec::new(); - let mut C: Vec<(usize, usize, [u8; 32])> = Vec::new(); + let mut A: Vec<(usize, usize, Vec<u8>)> = Vec::new(); + let mut B: Vec<(usize, usize, Vec<u8>)> = Vec::new(); + let mut C: Vec<(usize, usize, Vec<u8>)> = Vec::new(); - let one = Scalar::one().to_bytes(); + let one = Scalar::one().into_repr().to_bytes_le(); // R1CS is a set of three sparse matrices A B C, where is a row for every // constraint and a column for every entry in z = (vars, 1, inputs)@@ -44,29 +45,29 @@ // Az \circ Bz = Cz, where z = (vars, 1, inputs)
// constraint 0 entries in (A,B,C) // constraint 0 is Z0 * Z0 - Z1 = 0. - A.push((0, 0, one)); - B.push((0, 0, one)); - C.push((0, 1, one)); + A.push((0, 0, one.clone())); + B.push((0, 0, one.clone())); + C.push((0, 1, one.clone())); // constraint 1 entries in (A,B,C) // constraint 1 is Z1 * Z0 - Z2 = 0. - A.push((1, 1, one)); - B.push((1, 0, one)); - C.push((1, 2, one)); + A.push((1, 1, one.clone())); + B.push((1, 0, one.clone())); + C.push((1, 2, one.clone())); // constraint 2 entries in (A,B,C) // constraint 2 is (Z2 + Z0) * 1 - Z3 = 0. - A.push((2, 2, one)); - A.push((2, 0, one)); - B.push((2, num_vars, one)); - C.push((2, 3, one)); + A.push((2, 2, one.clone())); + A.push((2, 0, one.clone())); + B.push((2, num_vars, one.clone())); + C.push((2, 3, one.clone())); // constraint 3 entries in (A,B,C) // constraint 3 is (Z3 + 5) * 1 - I0 = 0. - A.push((3, 3, one)); - A.push((3, num_vars, Scalar::from(5u32).to_bytes())); - B.push((3, num_vars, one)); - C.push((3, num_vars + 1, one)); + A.push((3, 3, one.clone())); + A.push((3, num_vars, Scalar::from(5u32).into_repr().to_bytes_le())); + B.push((3, num_vars, one.clone())); + C.push((3, num_vars + 1, one.clone())); let inst = Instance::new(num_cons, num_vars, num_inputs, &A, &B, &C).unwrap();@@ -79,16 +80,16 @@ let z3 = z2 + z0; // constraint 2
let i0 = z3 + Scalar::from(5u32); // constraint 3 // create a VarsAssignment - let mut vars = vec![Scalar::zero().to_bytes(); num_vars]; - vars[0] = z0.to_bytes(); - vars[1] = z1.to_bytes(); - vars[2] = z2.to_bytes(); - vars[3] = z3.to_bytes(); + let mut vars = vec![Scalar::zero().into_repr().to_bytes_le(); num_vars]; + vars[0] = z0.into_repr().to_bytes_le(); + vars[1] = z1.into_repr().to_bytes_le(); + vars[2] = z2.into_repr().to_bytes_le(); + vars[3] = z3.into_repr().to_bytes_le(); let assignment_vars = VarsAssignment::new(&vars).unwrap(); // create an InputsAssignment - let mut inputs = vec![Scalar::zero().to_bytes(); num_inputs]; - inputs[0] = i0.to_bytes(); + let mut inputs = vec![Scalar::zero().into_repr().to_bytes_le(); num_inputs]; + inputs[0] = i0.into_repr().to_bytes_le(); let assignment_inputs = InputsAssignment::new(&inputs).unwrap(); // check if the instance we created is satisfiable
@@ -4,9 +4,9 @@ extern crate libspartan;
extern crate merlin; extern crate rand; -use flate2::{write::ZlibEncoder, Compression}; use libspartan::{Instance, NIZKGens, NIZK}; use merlin::Transcript; +use ark_serialize::*; fn print(msg: &str) { let star = "* ";@@ -33,9 +33,8 @@ // produce a proof of satisfiability
let mut prover_transcript = Transcript::new(b"nizk_example"); let proof = NIZK::prove(&inst, vars, &inputs, &gens, &mut prover_transcript); - let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default()); - bincode::serialize_into(&mut encoder, &proof).unwrap(); - let proof_encoded = encoder.finish().unwrap(); + let mut proof_encoded = Vec::new(); + proof.serialize(&mut proof_encoded).unwrap(); let msg_proof_len = format!("NIZK::proof_compressed_len {:?}", proof_encoded.len()); print(&msg_proof_len);
@@ -3,9 +3,9 @@ extern crate flate2;
extern crate libspartan; extern crate merlin; -use flate2::{write::ZlibEncoder, Compression}; use libspartan::{Instance, SNARKGens, SNARK}; use merlin::Transcript; +use ark_serialize::*; fn print(msg: &str) { let star = "* ";@@ -43,9 +43,8 @@ &gens,
&mut prover_transcript, ); - let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default()); - bincode::serialize_into(&mut encoder, &proof).unwrap(); - let proof_encoded = encoder.finish().unwrap(); + let mut proof_encoded = Vec::new(); + proof.serialize(&mut proof_encoded).unwrap(); let msg_proof_len = format!("SNARK::proof_compressed_len {:?}", proof_encoded.len()); print(&msg_proof_len);
@@ -1,10 +1,13 @@
-use super::group::{GroupElement, VartimeMultiscalarMul, GROUP_BASEPOINT}; +use crate::group::{CompressGroupElement, DecompressGroupElement}; + +use super::group::{GroupElement, VartimeMultiscalarMul, GROUP_BASEPOINT, GroupElementAffine}; use super::scalar::Scalar; +use ark_ff::PrimeField; use digest::{ExtendableOutput, Input}; use sha3::Shake256; use std::io::Read; -use ark_ff::fields::{Field}; -use ark_ec::{ProjectiveCurve}; +use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use ark_ec::{ProjectiveCurve, AffineCurve}; #[derive(Debug)] pub struct MultiCommitGens {@@ -17,14 +20,21 @@ impl MultiCommitGens {
pub fn new(n: usize, label: &[u8]) -> Self { let mut shake = Shake256::default(); shake.input(label); - shake.input(GROUP_BASEPOINT.as_bytes()); + let mut generator_encoded = Vec::new(); + GROUP_BASEPOINT.serialize(&mut generator_encoded).unwrap(); + shake.input(generator_encoded); let mut reader = shake.xof_result(); let mut gens: Vec<GroupElement> = Vec::new(); let mut uniform_bytes = [0u8; 64]; for _ in 0..n + 1 { + let mut el_aff: Option<GroupElementAffine> = None; + while el_aff.is_some() != true { reader.read_exact(&mut uniform_bytes).unwrap(); - gens.push(GroupElement::from_random_bytes(&uniform_bytes)); + el_aff = GroupElementAffine::from_random_bytes(&uniform_bytes); + } + let el = el_aff.unwrap().mul_by_cofactor_to_projective(); + gens.push(el); } MultiCommitGens {@@ -74,13 +84,15 @@
impl Commitments for Vec<Scalar> { fn commit(&self, blind: &Scalar, gens_n: &MultiCommitGens) -> GroupElement { assert_eq!(gens_n.n, self.len()); - GroupElement::vartime_multiscalar_mul(self, &gens_n.G) + blind * gens_n.h + GroupElement::vartime_multiscalar_mul(self, &gens_n.G) + gens_n.h.mul(blind.into_repr()) + } } impl Commitments for [Scalar] { fn commit(&self, blind: &Scalar, gens_n: &MultiCommitGens) -> GroupElement { assert_eq!(gens_n.n, self.len()); - GroupElement::vartime_multiscalar_mul(self, &gens_n.G) + blind * gens_n.h + GroupElement::vartime_multiscalar_mul(self, &gens_n.G) + gens_n.h.mul(blind.into_repr()) + } }
@@ -1,7 +1,7 @@
#![allow(clippy::too_many_arguments)] use super::commitments::{Commitments, MultiCommitGens}; use super::errors::ProofVerifyError; -use super::group::{CompressedGroup, GroupElement, VartimeMultiscalarMul}; +use super::group::{GroupElement, CompressedGroup, VartimeMultiscalarMul, CompressGroupElement, DecompressGroupElement}; use super::math::Math; use super::nizk::{DotProductProofGens, DotProductProofLog}; use super::random::RandomTape;@@ -217,7 +217,7 @@
pub fn bound_poly_var_top(&mut self, r: &Scalar) { let n = self.len() / 2; for i in 0..n { - self.Z[i] = self.Z[i] + r * (self.Z[i + n] - self.Z[i]); + self.Z[i] = self.Z[i] + (self.Z[i + n] - self.Z[i]) * r; } self.num_vars -= 1; self.len = n;@@ -226,7 +226,7 @@
pub fn bound_poly_var_bot(&mut self, r: &Scalar) { let n = self.len() / 2; for i in 0..n { - self.Z[i] = self.Z[2 * i] + r * (self.Z[2 * i + 1] - self.Z[2 * i]); + self.Z[i] = self.Z[2 * i] + (self.Z[2 * i + 1] - self.Z[2 * i]) * r; } self.num_vars -= 1; self.len = n;@@ -379,9 +379,9 @@ let eq = EqPolynomial::new(r.to_vec());
let (L, R) = eq.compute_factored_evals(); // compute a weighted sum of commitments and L - let C_decompressed = comm.C.iter().map(|pt| pt.decompress().unwrap()); + let C_decompressed = comm.C.iter().map(|pt| GroupElement::decompress(pt).unwrap()).collect::<Vec<GroupElement>>(); - let C_LZ = GroupElement::vartime_multiscalar_mul(&L, C_decompressed).compress(); + let C_LZ = GroupElement::vartime_multiscalar_mul(&L, C_decompressed.as_slice()).compress(); self .proof
@@ -6,13 +6,13 @@ pub enum ProofVerifyError {
#[error("Proof verification failed")] InternalError, #[error("Compressed group element failed to decompress: {0:?}")] - DecompressionError([u8; 32]), + DecompressionError(Vec<u8>), } impl Default for ProofVerifyError { fn default() -> Self { ProofVerifyError::InternalError - } + } } #[derive(Clone, Debug, Eq, PartialEq)]
@@ -1,131 +1,84 @@
+use ark_bls12_377::FrParameters; +use ark_ec::group::Group; +use ark_ec::{ + msm::VariableBaseMSM, +}; +use ark_ff::{PrimeField, Fp256, Zero}; +use digest::DynDigest; use lazy_static::lazy_static; +use num_bigint::BigInt; +use crate::errors::ProofVerifyError; + use super::scalar::{Scalar}; use core::borrow::Borrow; use core::ops::{Mul, MulAssign}; use ark_ec::{ProjectiveCurve, AffineCurve}; - -pub use ark_bls12_377::G1Projective as GroupElement; -pub use ark_bls12_377::G1Affine as AffineGroupElement; - - - -// pub type CompressedGroup = curve25519_dalek::ristretto::CompressedRistretto; - -// pub trait CompressedGroupExt { -// type Group; -// fn unpack(&self) -> Result<Self::Group, ProofVerifyError>; -// } - +use ark_serialize::*; -// what I should prolly do is implement compression and decompression operation on the GroupAffine +pub type GroupElement = ark_bls12_377::G1Projective; +pub type GroupElementAffine = ark_bls12_377::G1Affine; -// impl CompressedGroupExt for CompressedGroup { -// type Group = curve25519_dalek::ristretto::RistrettoPoint; -// fn unpack(&self) -> Result<Self::Group, ProofVerifyError> { -// self -// .decompress() -// .ok_or_else(|| ProofVerifyError::DecompressionError(self.to_bytes())) -// } -// } +#[derive(Clone, Eq, PartialEq, Hash, Debug, CanonicalSerialize, CanonicalDeserialize)] +pub struct CompressedGroup(pub Vec<u8>); -// ???? lazy_static! { pub static ref GROUP_BASEPOINT: GroupElement = GroupElement::prime_subgroup_generator(); } +pub trait CompressGroupElement { + fn compress(&self) -> CompressedGroup; +} -// impl<'b> MulAssign<&'b Scalar> for GroupElement { -// fn mul_assign(&mut self, scalar: &'b Scalar) { -// let result = (self as &GroupElement).mul( scalar.into_repr()); -// *self = result; -// } -// } +pub trait DecompressGroupElement { + fn decompress(encoded: &CompressedGroup) -> Option<GroupElement>; +} -// // This game happens because dalek works with scalars as bytes representation but we want people to have an easy life and not care about this -// impl<'a, 'b> Mul<&'b Scalar> for &'a GroupElement { -// type Output = GroupElement; -// fn mul(self, scalar: &'b Scalar) -> GroupElement { -// self * Scalar::into_repr(scalar) -// } -// } +pub trait UnpackGroupElement { + fn unpack(&self) -> Result<GroupElement, ProofVerifyError>; +} -// impl<'a, 'b> Mul<&'b GroupElement> for &'a Scalar { -// type Output = GroupElement; +impl CompressGroupElement for GroupElement { + fn compress(&self) -> CompressedGroup { + let mut point_encoding = Vec::new(); + self.serialize(&mut point_encoding).unwrap(); + // println!("in compress {:?}", point_encoding);; + CompressedGroup(point_encoding) + } +} -// fn mul(self, point: &'b GroupElement) -> GroupElement { -// Scalar::into_repr(self) * point -// } -// } +impl DecompressGroupElement for GroupElement { + fn decompress(encoded: &CompressedGroup) -> Option<Self> + { -// macro_rules! define_mul_variants { -// (LHS = $lhs:ty, RHS = $rhs:ty, Output = $out:ty) => { -// impl<'b> Mul<&'b $rhs> for $lhs { -// type Output = $out; -// fn mul(self, rhs: &'b $rhs) -> $out { -// &self * rhs -// } -// } + let res = GroupElement::deserialize(&*encoded.0); + if res.is_err() { + println!("{:?}", res); + None + } else { + Some(res.unwrap()) + } + } +} -// impl<'a> Mul<$rhs> for &'a $lhs { -// type Output = $out; -// fn mul(self, rhs: $rhs) -> $out { -// self * &rhs -// } -// } +impl UnpackGroupElement for CompressedGroup { + fn unpack(&self) -> Result<GroupElement, ProofVerifyError> { + let encoded = self.0.clone(); + GroupElement::decompress(self).ok_or_else(|| ProofVerifyError::DecompressionError(encoded)) + } +} -// impl Mul<$rhs> for $lhs { -// type Output = $out; -// fn mul(self, rhs: $rhs) -> $out { -// &self * &rhs -// } -// } -// }; -// } - -// macro_rules! define_mul_assign_variants { -// (LHS = $lhs:ty, RHS = $rhs:ty) => { -// impl MulAssign<$rhs> for $lhs { -// fn mul_assign(&mut self, rhs: $rhs) { -// *self *= &rhs; -// } -// } -// }; -// } - -// define_mul_assign_variants!(LHS = GroupElement, RHS = Scalar); -// define_mul_variants!(LHS = GroupElement, RHS = Scalar, Output = GroupElement); -// define_mul_variants!(LHS = Scalar, RHS = GroupElement, Output = GroupElement); - +pub trait VartimeMultiscalarMul { + fn vartime_multiscalar_mul(scalars: &[Scalar], points: &[GroupElement]) -> GroupElement; +} -// TODO -// pub trait VartimeMultiscalarMul { -// type Scalar; -// fn vartime_multiscalar_mul<I, J>(scalars: I, points: J) -> Self -// where -// I: IntoIterator, -// I::Item: Borrow<Self::Scalar>, -// J: IntoIterator, -// J::Item: Borrow<Self>, -// Self: Clone; -// } +impl VartimeMultiscalarMul for GroupElement { + fn vartime_multiscalar_mul( + scalars: &[Scalar], + points: &[GroupElement], +) -> GroupElement{ + let repr_scalars= scalars.into_iter().map(|S| S.borrow().into_repr()).collect::<Vec<<Scalar as PrimeField>::BigInt>>(); + let aff_points = points.into_iter().map(|P| P.borrow().into_affine()).collect::<Vec<GroupElementAffine>>(); + VariableBaseMSM::multi_scalar_mul(aff_points.as_slice(), repr_scalars.as_slice()) +} +} -// impl VartimeMultiscalarMul for GroupElement { -// type Scalar = super::scalar::Scalar; -// fn vartime_multiscalar_mul<I, J>(scalars: I, points: J) -> Self -// where -// I: IntoIterator, -// I::Item: Borrow<Self::Scalar>, -// J: IntoIterator, -// J::Item: Borrow<Self>, -// Self: Clone, -// { -// // use curve25519_dalek::traits::VartimeMultiscalarMul; -// <Self as VartimeMultiscalarMul>::vartime_multiscalar_mul( -// scalars -// .into_iter() -// .map(|s| Scalar::into_repr(s.borrow())) -// .collect::<Vec<Scalar>>(), -// points, -// ) -// } -// }
@@ -6,11 +6,11 @@ #![deny(missing_docs)]
extern crate byteorder; extern crate core; -extern crate curve25519_dalek; extern crate digest; extern crate merlin; extern crate sha3; extern crate test; +extern crate rand; extern crate lazy_static; extern crate ark_std;@@ -34,7 +34,8 @@ mod timer;
mod transcript; mod unipoly; -use core::cmp::max; +use core::{cmp::max}; +use std::borrow::Borrow; use errors::{ProofVerifyError, R1CSError}; use merlin::Transcript; use r1csinstance::{@@ -44,6 +45,8 @@ use r1csproof::{R1CSGens, R1CSProof};
use random::RandomTape; use scalar::Scalar; use ark_serialize::*; +use ark_ff::{PrimeField, Field, BigInteger}; +use ark_std::{One, Zero, UniformRand}; use timer::Timer; use transcript::{AppendToTranscript, ProofTranscript};@@ -65,12 +68,12 @@ }
impl Assignment { /// Constructs a new `Assignment` from a vector - pub fn new(assignment: &[[u8; 32]]) -> Result<Assignment, R1CSError> { - let bytes_to_scalar = |vec: &[[u8; 32]]| -> Result<Vec<Scalar>, R1CSError> { + pub fn new(assignment: &Vec<Vec<u8>>) -> Result<Assignment, R1CSError> { + let bytes_to_scalar = |vec: &Vec<Vec<u8>>| -> Result<Vec<Scalar>, R1CSError> { let mut vec_scalar: Vec<Scalar> = Vec::new(); for v in vec { - let val = Scalar::from_bytes(v); - if val.is_some().unwrap_u8() == 1 { + let val = Scalar::from_random_bytes(v.as_slice()); + if val.is_some() == true { vec_scalar.push(val.unwrap()); } else { return Err(R1CSError::InvalidScalar);@@ -115,6 +118,7 @@ /// `VarsAssignment` holds an assignment of values to variables in an `Instance`
pub type InputsAssignment = Assignment; /// `Instance` holds the description of R1CS matrices +#[derive(Debug)] pub struct Instance { inst: R1CSInstance, }@@ -125,9 +129,9 @@ pub fn new(
num_cons: usize, num_vars: usize, num_inputs: usize, - A: &[(usize, usize, [u8; 32])], - B: &[(usize, usize, [u8; 32])], - C: &[(usize, usize, [u8; 32])], + A: &[(usize, usize, Vec<u8>)], + B: &[(usize, usize, Vec<u8>)], + C: &[(usize, usize, Vec<u8>)], ) -> Result<Instance, R1CSError> { let (num_vars_padded, num_cons_padded) = { let num_vars_padded = {@@ -162,27 +166,27 @@ (num_vars_padded, num_cons_padded)
}; let bytes_to_scalar = - |tups: &[(usize, usize, [u8; 32])]| -> Result<Vec<(usize, usize, Scalar)>, R1CSError> { + |tups: & [(usize, usize, Vec<u8>)]| -> Result<Vec<(usize, usize, Scalar)>, R1CSError> { let mut mat: Vec<(usize, usize, Scalar)> = Vec::new(); - for &(row, col, val_bytes) in tups { + for (row, col, val_bytes) in tups { // row must be smaller than num_cons - if row >= num_cons { + if *row >= num_cons { return Err(R1CSError::InvalidIndex); } // col must be smaller than num_vars + 1 + num_inputs - if col >= num_vars + 1 + num_inputs { + if *col >= num_vars + 1 + num_inputs { return Err(R1CSError::InvalidIndex); } - let val = Scalar::from_bytes(&val_bytes); - if val.is_some().unwrap_u8() == 1 { + let val = Scalar::from_random_bytes(&val_bytes.as_slice()); + if val.is_some() == true { // if col >= num_vars, it means that it is referencing a 1 or input in the satisfying // assignment - if col >= num_vars { - mat.push((row, col + num_vars_padded - num_vars, val.unwrap())); + if *col >= num_vars { + mat.push((*row, *col + num_vars_padded - num_vars, val.unwrap())); } else { - mat.push((row, col, val.unwrap())); + mat.push((*row, *col, val.unwrap())); } } else { return Err(R1CSError::InvalidScalar);@@ -376,7 +380,8 @@ &mut random_tape,
) }; - let proof_encoded: Vec<u8> = bincode::serialize(&proof).unwrap(); + let mut proof_encoded: Vec<u8> = Vec::new(); + proof.serialize(&mut proof_encoded).unwrap(); Timer::print(&format!("len_r1cs_sat_proof {:?}", proof_encoded.len())); (proof, rx, ry)@@ -405,7 +410,8 @@ transcript,
&mut random_tape, ); - let proof_encoded: Vec<u8> = bincode::serialize(&proof).unwrap(); + let mut proof_encoded: Vec<u8> = Vec::new(); + proof.serialize(&mut proof_encoded).unwrap(); Timer::print(&format!("len_r1cs_eval_proof {:?}", proof_encoded.len())); proof };@@ -532,7 +538,8 @@ &gens.gens_r1cs_sat,
transcript, &mut random_tape, ); - let proof_encoded: Vec<u8> = bincode::serialize(&proof).unwrap(); + let mut proof_encoded = Vec::new(); + proof.serialize(&mut proof_encoded).unwrap(); Timer::print(&format!("len_r1cs_sat_proof {:?}", proof_encoded.len())); (proof, rx, ry) };@@ -588,6 +595,7 @@
#[cfg(test)] mod tests { use super::*; + use ark_ff::{PrimeField}; #[test] pub fn check_snark() {@@ -634,9 +642,9 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, ]; - let A = vec![(0, 0, zero)]; - let B = vec![(100, 1, zero)]; - let C = vec![(1, 1, zero)]; + let A = vec![(0, 0, zero.to_vec())]; + let B = vec![(100, 1, zero.to_vec())]; + let C = vec![(1, 1, zero.to_vec())]; let inst = Instance::new(num_cons, num_vars, num_inputs, &A, &B, &C); assert!(inst.is_err());@@ -659,9 +667,9 @@ 3, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, 216,
57, 51, 72, 125, 157, 41, 83, 167, 237, 115, ]; - let A = vec![(0, 0, zero)]; - let B = vec![(1, 1, larger_than_mod)]; - let C = vec![(1, 1, zero)]; + let A = vec![(0, 0, zero.to_vec())]; + let B = vec![(1, 1, larger_than_mod.to_vec())]; + let C = vec![(1, 1, zero.to_vec())]; let inst = Instance::new(num_cons, num_vars, num_inputs, &A, &B, &C); assert!(inst.is_err());@@ -678,25 +686,25 @@ let num_non_zero_entries = 3;
// We will encode the above constraints into three matrices, where // the coefficients in the matrix are in the little-endian byte order - let mut A: Vec<(usize, usize, [u8; 32])> = Vec::new(); - let mut B: Vec<(usize, usize, [u8; 32])> = Vec::new(); - let mut C: Vec<(usize, usize, [u8; 32])> = Vec::new(); + let mut A: Vec<(usize, usize, Vec<u8>)> = Vec::new(); + let mut B: Vec<(usize, usize, Vec<u8>)> = Vec::new(); + let mut C: Vec<(usize, usize, Vec<u8>)> = Vec::new(); // Create a^2 + b + 13 - A.push((0, num_vars + 2, Scalar::one().to_bytes())); // 1*a - B.push((0, num_vars + 2, Scalar::one().to_bytes())); // 1*a - C.push((0, num_vars + 1, Scalar::one().to_bytes())); // 1*z - C.push((0, num_vars, (-Scalar::from(13u64)).to_bytes())); // -13*1 - C.push((0, num_vars + 3, (-Scalar::one()).to_bytes())); // -1*b + A.push((0, num_vars + 2, (Scalar::one().into_repr().to_bytes_le()))); // 1*a + B.push((0, num_vars + 2, Scalar::one().into_repr().to_bytes_le())); // 1*a + C.push((0, num_vars + 1, Scalar::one().into_repr().to_bytes_le())); // 1*z + C.push((0, num_vars, (-Scalar::from(13u64)).into_repr().to_bytes_le())); // -13*1 + C.push((0, num_vars + 3, (-Scalar::one()).into_repr().to_bytes_le())); // -1*b // Var Assignments (Z_0 = 16 is the only output) - let vars = vec![Scalar::zero().to_bytes(); num_vars]; + let vars = vec![Scalar::zero().into_repr().to_bytes_le(); num_vars]; // create an InputsAssignment (a = 1, b = 2) - let mut inputs = vec![Scalar::zero().to_bytes(); num_inputs]; - inputs[0] = Scalar::from(16u64).to_bytes(); - inputs[1] = Scalar::from(1u64).to_bytes(); - inputs[2] = Scalar::from(2u64).to_bytes(); + let mut inputs = vec![Scalar::zero().into_repr().to_bytes_le(); num_inputs]; + inputs[0] = Scalar::from(16u64).into_repr().to_bytes_le(); + inputs[1] = Scalar::from(1u64).into_repr().to_bytes_le(); + inputs[2] = Scalar::from(2u64).into_repr().to_bytes_le(); let assignment_inputs = InputsAssignment::new(&inputs).unwrap(); let assignment_vars = VarsAssignment::new(&vars).unwrap();
@@ -4,10 +4,11 @@ #![allow(non_snake_case)]
#![allow(clippy::type_complexity)] #![allow(clippy::too_many_arguments)] use super::super::errors::ProofVerifyError; -use super::super::group::{CompressedGroup, GroupElement, VartimeMultiscalarMul}; +use super::super::group::{CompressedGroup, GroupElement, VartimeMultiscalarMul, CompressGroupElement, DecompressGroupElement}; use super::super::scalar::Scalar; use super::super::transcript::ProofTranscript; use core::iter; +use std::ops::MulAssign; use merlin::Transcript; use ark_serialize::*; use ark_ff::{Field, fields};@@ -85,16 +86,16 @@ let L = GroupElement::vartime_multiscalar_mul(
a_L .iter() .chain(iter::once(&c_L)) - .chain(iter::once(blind_L)), - G_R.iter().chain(iter::once(Q)).chain(iter::once(H)), + .chain(iter::once(blind_L)).map(|s| *s).collect::<Vec<Scalar>>().as_slice(), + G_R.iter().chain(iter::once(Q)).chain(iter::once(H)).map(|p| *p).collect::<Vec<GroupElement>>().as_slice(), ); let R = GroupElement::vartime_multiscalar_mul( a_R .iter() .chain(iter::once(&c_R)) - .chain(iter::once(blind_R)), - G_L.iter().chain(iter::once(Q)).chain(iter::once(H)), + .chain(iter::once(blind_R)).map(|s| *s).collect::<Vec<Scalar>>().as_slice(), + G_L.iter().chain(iter::once(Q)).chain(iter::once(H)).map(|p| *p).collect::<Vec<GroupElement>>().as_slice(), ); transcript.append_point(b"L", &L.compress());@@ -109,7 +110,7 @@ b_L[i] = b_L[i] * u_inv + u * b_R[i];
G_L[i] = GroupElement::vartime_multiscalar_mul(&[u_inv, u], &[G_L[i], G_R[i]]); } - blind_fin = blind_fin + blind_L * u * u + blind_R * u_inv * u_inv; + blind_fin = blind_fin + u * u * blind_L + u_inv * u_inv * blind_R; L_vec.push(L.compress()); R_vec.push(R.compress());@@ -159,8 +160,14 @@ 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 = ark_ff::fields::batch_inversion(&mut challenges_inv); + let mut challenges_inv: Vec<Scalar> = challenges.clone(); + + ark_ff::fields::batch_inversion(&mut challenges_inv); + let mut allinv: Scalar = Scalar::one(); + for c in challenges.iter().filter(|s| !s.is_zero()) { + allinv.mul_assign(c); + } + allinv = allinv.inverse().unwrap(); // 3. Compute u_i^2 and (1/u_i)^2 for i in 0..lg_n {@@ -202,24 +209,24 @@
let Ls = self .L_vec .iter() - .map(|p| p.decompress().ok_or(ProofVerifyError::InternalError)) + .map(|p| GroupElement::decompress(p).ok_or(ProofVerifyError::InternalError)) .collect::<Result<Vec<_>, _>>()?; let Rs = self .R_vec .iter() - .map(|p| p.decompress().ok_or(ProofVerifyError::InternalError)) + .map(|p| GroupElement::decompress(p).ok_or(ProofVerifyError::InternalError)) .collect::<Result<Vec<_>, _>>()?; - let G_hat = GroupElement::vartime_multiscalar_mul(s.iter(), G.iter()); + let G_hat = GroupElement::vartime_multiscalar_mul(s.as_slice(), G); let a_hat = inner_product(a, &s); let Gamma_hat = GroupElement::vartime_multiscalar_mul( u_sq .iter() .chain(u_inv_sq.iter()) - .chain(iter::once(&Scalar::one())), - Ls.iter().chain(Rs.iter()).chain(iter::once(Gamma)), + .chain(iter::once(&Scalar::one())).map(|s| *s).collect::<Vec<Scalar>>().as_slice(), + Ls.iter().chain(Rs.iter()).chain(iter::once(Gamma)).map(|p| *p).collect::<Vec<GroupElement>>().as_slice(), ); Ok((G_hat, Gamma_hat, a_hat))
@@ -1,12 +1,16 @@
#![allow(clippy::too_many_arguments)] use super::commitments::{Commitments, MultiCommitGens}; use super::errors::ProofVerifyError; -use super::group::{CompressedGroup, CompressedGroupExt}; +use super::group::{ + CompressedGroup, CompressGroupElement, UnpackGroupElement, GroupElement, DecompressGroupElement, GroupElementAffine}; use super::random::RandomTape; use super::scalar::Scalar; use super::transcript::{AppendToTranscript, ProofTranscript}; +use ark_ec::group::Group; use merlin::Transcript; use ark_serialize::*; +use ark_ec::ProjectiveCurve; +use ark_ff::PrimeField; mod bullet; use bullet::BulletReductionProof;@@ -44,8 +48,8 @@ alpha.append_to_transcript(b"alpha", transcript);
let c = transcript.challenge_scalar(b"c"); - let z1 = x * c + t1; - let z2 = r * c + t2; + let z1 = c * x + t1; + let z2 = c * r + t2; (KnowledgeProof { alpha, z1, z2 }, C) }@@ -54,7 +58,8 @@ pub fn verify(
&self, gens_n: &MultiCommitGens, transcript: &mut Transcript, - C: &CompressedGroup, + C: & + CompressedGroup, ) -> Result<(), ProofVerifyError> { transcript.append_protocol_name(KnowledgeProof::protocol_name()); C.append_to_transcript(b"C", transcript);@@ -63,7 +68,7 @@
let c = transcript.challenge_scalar(b"c"); let lhs = self.z1.commit(&self.z2, gens_n).compress(); - let rhs = (c * C.unpack()? + self.alpha.unpack()?).compress(); + let rhs = ( C.unpack()?.mul(c.into_repr()) + self.alpha.unpack()?).compress(); if lhs == rhs { Ok(())@@ -75,7 +80,8 @@ }
#[derive(CanonicalSerialize, CanonicalDeserialize, Debug)] pub struct EqualityProof { - alpha: CompressedGroup, + alpha: + CompressedGroup, z: Scalar, }@@ -92,7 +98,9 @@ v1: &Scalar,
s1: &Scalar, v2: &Scalar, s2: &Scalar, - ) -> (EqualityProof, CompressedGroup, CompressedGroup) { + ) -> (EqualityProof, + CompressedGroup, + CompressedGroup) { transcript.append_protocol_name(EqualityProof::protocol_name()); // produce a random Scalar@@ -104,12 +112,12 @@
let C2 = v2.commit(s2, gens_n).compress(); C2.append_to_transcript(b"C2", transcript); - let alpha = (r * gens_n.h).compress(); + let alpha = gens_n.h.mul(r.into_repr()).compress(); alpha.append_to_transcript(b"alpha", transcript); let c = transcript.challenge_scalar(b"c"); - let z = c * (s1 - s2) + r; + let z = c * ((*s1) - s2) + r; (EqualityProof { alpha, z }, C1, C2) }@@ -118,8 +126,10 @@ pub fn verify(
&self, gens_n: &MultiCommitGens, transcript: &mut Transcript, - C1: &CompressedGroup, - C2: &CompressedGroup, + C1: & + CompressedGroup, + C2: & + CompressedGroup, ) -> Result<(), ProofVerifyError> { transcript.append_protocol_name(EqualityProof::protocol_name()); C1.append_to_transcript(b"C1", transcript);@@ -129,11 +139,12 @@
let c = transcript.challenge_scalar(b"c"); let rhs = { let C = C1.unpack()? - C2.unpack()?; - (c * C + self.alpha.unpack()?).compress() + (C.mul(c.into_repr()) + self.alpha.unpack()?).compress() }; - - let lhs = (self.z * gens_n.h).compress(); + println!("rhs {:?}", rhs); + let lhs = gens_n.h.mul(self.z.into_repr()).compress(); + println!("lhs {:?}", lhs); if lhs == rhs { Ok(()) } else {@@ -144,10 +155,13 @@ }
#[derive(CanonicalSerialize, CanonicalDeserialize, Debug)] pub struct ProductProof { - alpha: CompressedGroup, - beta: CompressedGroup, - delta: CompressedGroup, - z: [Scalar; 5], + alpha: + CompressedGroup, + beta: + CompressedGroup, + delta: + CompressedGroup, + z: Vec<Scalar>, } impl ProductProof {@@ -167,8 +181,11 @@ z: &Scalar,
rZ: &Scalar, ) -> ( ProductProof, + CompressedGroup, + CompressedGroup, + CompressedGroup, ) { transcript.append_protocol_name(ProductProof::protocol_name());@@ -180,8 +197,16 @@ 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 X = x.commit(rX, gens_n).compress(); + let X_unc = x.commit(rX, gens_n); + + + let X = X_unc.compress(); X.append_to_transcript(b"X", transcript); + + let X_new = GroupElement::decompress(&X); + + assert_eq!(X_unc, X_new.unwrap()); + let Y = y.commit(rY, gens_n).compress(); Y.append_to_transcript(b"Y", transcript);@@ -198,7 +223,7 @@
let delta = { let gens_X = &MultiCommitGens { n: 1, - G: vec![X.decompress().unwrap()], + G: vec![GroupElement::decompress(&X).unwrap()], h: gens_n.h, }; b3.commit(&b5, gens_X).compress()@@ -211,8 +236,8 @@ 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]; + let z5 = b5 + c * ((*rZ) - (*rX) * y); + let z = [z1, z2, z3, z4, z5].to_vec(); ( ProductProof {@@ -228,14 +253,17 @@ )
} fn check_equality( - P: &CompressedGroup, - X: &CompressedGroup, + P: & + CompressedGroup, + X: & + CompressedGroup, c: &Scalar, gens_n: &MultiCommitGens, z1: &Scalar, z2: &Scalar, ) -> bool { - let lhs = (P.decompress().unwrap() + c * X.decompress().unwrap()).compress(); + println!("{:?}", X); + let lhs = (GroupElement::decompress(P).unwrap() + GroupElement::decompress(X).unwrap().mul(c.into_repr())).compress(); let rhs = z1.commit(z2, gens_n).compress(); lhs == rhs@@ -245,9 +273,12 @@ pub fn verify(
&self, gens_n: &MultiCommitGens, transcript: &mut Transcript, - X: &CompressedGroup, - Y: &CompressedGroup, - Z: &CompressedGroup, + X: & + CompressedGroup, + Y: & + CompressedGroup, + Z: & + CompressedGroup, ) -> Result<(), ProofVerifyError> { transcript.append_protocol_name(ProductProof::protocol_name());@@ -290,8 +321,10 @@ }
#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)] pub struct DotProductProof { - delta: CompressedGroup, - beta: CompressedGroup, + delta: + CompressedGroup, + beta: + CompressedGroup, z: Vec<Scalar>, z_delta: Scalar, z_beta: Scalar,@@ -317,7 +350,9 @@ blind_x: &Scalar,
a_vec: &[Scalar], y: &Scalar, blind_y: &Scalar, - ) -> (DotProductProof, CompressedGroup, CompressedGroup) { + ) -> (DotProductProof, + CompressedGroup, + CompressedGroup) { transcript.append_protocol_name(DotProductProof::protocol_name()); let n = x_vec.len();@@ -374,8 +409,10 @@ gens_1: &MultiCommitGens,
gens_n: &MultiCommitGens, transcript: &mut Transcript, a: &[Scalar], - Cx: &CompressedGroup, - Cy: &CompressedGroup, + Cx: & + CompressedGroup, + Cy: & + CompressedGroup, ) -> Result<(), ProofVerifyError> { assert_eq!(gens_n.n, a.len()); assert_eq!(gens_1.n, 1);@@ -390,11 +427,10 @@
let c = transcript.challenge_scalar(b"c"); let mut result = - c * Cx.unpack()? + self.delta.unpack()? == self.z.commit(&self.z_delta, gens_n); + Cx.unpack()?.mul(c.into_repr()) + self.delta.unpack()? == self.z.commit(&self.z_delta, gens_n); let dotproduct_z_a = DotProductProof::compute_dotproduct(&self.z, a); - result &= c * Cy.unpack()? + self.beta.unpack()? == dotproduct_z_a.commit(&self.z_beta, gens_1); - + result &= Cy.unpack()?.mul(c.into_repr()) + self.beta.unpack()? == dotproduct_z_a.commit(&self.z_beta, gens_1); if result { Ok(()) } else {@@ -419,8 +455,10 @@
#[derive(Debug, CanonicalSerialize, CanonicalDeserialize)] pub struct DotProductProofLog { bullet_reduction_proof: BulletReductionProof, - delta: CompressedGroup, - beta: CompressedGroup, + delta: + CompressedGroup, + beta: + CompressedGroup, z1: Scalar, z2: Scalar, }@@ -444,7 +482,9 @@ blind_x: &Scalar,
a_vec: &[Scalar], y: &Scalar, blind_y: &Scalar, - ) -> (DotProductProofLog, CompressedGroup, CompressedGroup) { + ) -> (DotProductProofLog, + CompressedGroup, + CompressedGroup) { transcript.append_protocol_name(DotProductProofLog::protocol_name()); let n = x_vec.len();@@ -471,7 +511,7 @@ Cy.append_to_transcript(b"Cy", transcript);
a_vec.append_to_transcript(b"a", transcript); - let blind_Gamma = blind_x + blind_y; + let blind_Gamma = (*blind_x) + blind_y; let (bullet_reduction_proof, _Gamma_hat, x_hat, a_hat, g_hat, rhat_Gamma) = BulletReductionProof::prove( transcript,@@ -522,8 +562,10 @@ n: usize,
gens: &DotProductProofGens, transcript: &mut Transcript, a: &[Scalar], - Cx: &CompressedGroup, - Cy: &CompressedGroup, + Cx: & + CompressedGroup, + Cy: & + CompressedGroup, ) -> Result<(), ProofVerifyError> { assert_eq!(gens.n, n); assert_eq!(a.len(), n);@@ -551,8 +593,8 @@ let delta_s = self.delta.unpack()?;
let z1_s = &self.z1; let z2_s = &self.z2; - let lhs = ((Gamma_hat * c_s + beta_s) * a_hat_s + delta_s).compress(); - let rhs = ((g_hat + gens.gens_1.G[0] * a_hat_s) * z1_s + gens.gens_1.h * z2_s).compress(); + let lhs = ((Gamma_hat.mul(c_s.into_repr()) + beta_s).mul(a_hat_s.into_repr()) + delta_s).compress(); + let rhs = ((g_hat + gens.gens_1.G[0].mul(a_hat_s.into_repr())).mul(z1_s.into_repr()) + gens.gens_1.h.mul(z2_s.into_repr())).compress(); assert_eq!(lhs, rhs);@@ -566,7 +608,13 @@ }
#[cfg(test)] mod tests { - use super::*; + use std::marker::PhantomData; + +use crate::group::VartimeMultiscalarMul; + +use super::*; +use ark_bls12_377::{G1Affine, Fq, FqParameters}; +use ark_ff::{Fp384, BigInteger384}; use ark_std::{UniformRand}; #[test] fn check_knowledgeproof() {@@ -615,10 +663,14 @@ assert!(proof
.verify(&gens_1, &mut verifier_transcript, &C1, &C2) .is_ok()); } - + #[test] fn check_productproof() { let mut rng = ark_std::rand::thread_rng(); + let pt = GroupElement::rand(&mut rng); + let pt_c = pt.compress(); + let pt2 = GroupElement::decompress(&pt_c).unwrap(); + assert_eq!(pt, pt2); let gens_1 = MultiCommitGens::new(1, b"test-productproof"); let x = Scalar::rand(&mut rng);
@@ -186,7 +186,7 @@ let num_rounds_prod = poly_C.len().log2() as usize;
let comb_func_prod = |poly_A_comp: &Scalar, poly_B_comp: &Scalar, poly_C_comp: &Scalar| - -> Scalar { poly_A_comp * poly_B_comp * poly_C_comp }; + -> Scalar { (*poly_A_comp) * poly_B_comp * poly_C_comp }; let (proof_prod, rand_prod, claims_prod) = SumcheckInstanceProof::prove_cubic( &claim, num_rounds_prod,@@ -283,7 +283,7 @@ let num_rounds_prod = poly_C_par.len().log2() as usize;
let comb_func_prod = |poly_A_comp: &Scalar, poly_B_comp: &Scalar, poly_C_comp: &Scalar| - -> Scalar { poly_A_comp * poly_B_comp * poly_C_comp }; + -> Scalar { (*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();@@ -455,7 +455,7 @@ let r_layer = transcript.challenge_scalar(b"challenge_r_layer");
claims_to_verify = (0..claims_prod_left.len()) .map(|i| claims_prod_left[i] + r_layer * (claims_prod_right[i] - claims_prod_left[i])) - .collect::<Vec<Scalar>>(); + .collect(); // add claims to verify for dotp circuit if i == num_layers - 1 {
@@ -10,7 +10,6 @@ MultiSparseMatPolynomialAsDense, SparseMatEntry, SparseMatPolyCommitment,
SparseMatPolyCommitmentGens, SparseMatPolyEvalProof, SparseMatPolynomial, }; use super::timer::Timer; -use flate2::{write::ZlibEncoder, Compression}; use merlin::Transcript; use ark_serialize::*; use ark_std::{One, Zero, UniformRand};@@ -28,9 +27,8 @@ }
impl AppendToTranscript for R1CSInstance { fn append_to_transcript(&self, _label: &'static [u8], transcript: &mut Transcript) { - let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default()); - bincode::serialize_into(&mut encoder, &self).unwrap(); - let bytes = encoder.finish().unwrap(); + let mut bytes = Vec::new(); + self.serialize(&mut bytes).unwrap(); transcript.append_message(b"R1CSInstance", &bytes); } }
@@ -1,10 +1,12 @@
#![allow(clippy::too_many_arguments)] +use crate::group::CompressedGroup; + use super::commitments::{Commitments, MultiCommitGens}; use super::dense_mlpoly::{ DensePolynomial, EqPolynomial, PolyCommitment, PolyCommitmentGens, PolyEvalProof, }; use super::errors::ProofVerifyError; -use super::group::{CompressedGroup, GroupElement, VartimeMultiscalarMul}; +use super::group::{GroupElement, VartimeMultiscalarMul, CompressGroupElement, DecompressGroupElement}; use super::nizk::{EqualityProof, KnowledgeProof, ProductProof}; use super::r1csinstance::R1CSInstance; use super::random::RandomTape;@@ -14,19 +16,21 @@ use super::sumcheck::ZKSumcheckInstanceProof;
use super::timer::Timer; use super::transcript::{AppendToTranscript, ProofTranscript}; use core::iter; +use ark_ff::PrimeField; use merlin::Transcript; use ark_serialize::*; use ark_std::{Zero, One}; +use ark_ec::{ProjectiveCurve}; #[derive(CanonicalSerialize, CanonicalDeserialize, Debug)] pub struct R1CSProof { comm_vars: PolyCommitment, sc_proof_phase1: ZKSumcheckInstanceProof, claims_phase2: ( - CompressedGroup, - CompressedGroup, - CompressedGroup, - CompressedGroup, + CompressedGroup, + CompressedGroup, + CompressedGroup, + CompressedGroup, ), pok_claims_phase2: (KnowledgeProof, ProductProof), proof_eq_sc_phase1: EqualityProof,@@ -86,7 +90,7 @@ let comb_func = |poly_A_comp: &Scalar,
poly_B_comp: &Scalar, poly_C_comp: &Scalar, poly_D_comp: &Scalar| - -> Scalar { poly_A_comp * (poly_B_comp * poly_C_comp - poly_D_comp) }; + -> Scalar { (*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(@@ -118,7 +122,7 @@ transcript: &mut Transcript,
random_tape: &mut RandomTape, ) -> (ZKSumcheckInstanceProof, Vec<Scalar>, Vec<Scalar>, Scalar) { let comb_func = - |poly_A_comp: &Scalar, poly_B_comp: &Scalar| -> Scalar { poly_A_comp * poly_B_comp }; + |poly_A_comp: &Scalar, poly_B_comp: &Scalar| -> Scalar { (*poly_A_comp) * poly_B_comp }; let (sc_proof_phase_two, r, claims, blind_claim_postsc) = ZKSumcheckInstanceProof::prove_quad( claim, blind_claim,@@ -227,7 +231,7 @@ )
}; let (proof_prod, comm_Az_claim, comm_Bz_claim, comm_prod_Az_Bz_claims) = { - let prod = Az_claim * Bz_claim; + let prod = (*Az_claim) * Bz_claim; ProductProof::prove( &gens.gens_sc.gens_1, transcript,@@ -248,8 +252,8 @@ comm_prod_Az_Bz_claims.append_to_transcript(b"comm_prod_Az_Bz_claims", transcript);
// 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 blind_expected_claim_postsc1 = (prod_Az_Bz_blind - Cz_blind) * taus_bound_rx; + let claim_post_phase1 = ((*Az_claim) * Bz_claim - Cz_claim) * taus_bound_rx; let (proof_eq_sc_phase1, _C1, _C2) = EqualityProof::prove( &gens.gens_sc.gens_1, transcript,@@ -404,8 +408,7 @@
let taus_bound_rx: Scalar = (0..rx.len()) .map(|i| rx[i] * tau[i] + (Scalar::one() - rx[i]) * (Scalar::one() - tau[i])) .product(); - let expected_claim_post_phase1 = (taus_bound_rx - * (comm_prod_Az_Bz_claims.decompress().unwrap() - comm_Cz_claim.decompress().unwrap())) + let expected_claim_post_phase1 = (GroupElement::decompress(comm_prod_Az_Bz_claims).unwrap() - GroupElement::decompress(comm_Cz_claim).unwrap()).mul(taus_bound_rx.into_repr()) .compress(); // verify proof that expected_claim_post_phase1 == claim_post_phase1@@ -425,12 +428,12 @@ // r_A * comm_Az_claim + r_B * comm_Bz_claim + r_C * comm_Cz_claim;
let comm_claim_phase2 = GroupElement::vartime_multiscalar_mul( iter::once(&r_A) .chain(iter::once(&r_B)) - .chain(iter::once(&r_C)), + .chain(iter::once(&r_C)).map(|s| (*s)).collect::<Vec<Scalar>>().as_slice(), iter::once(&comm_Az_claim) .chain(iter::once(&comm_Bz_claim)) .chain(iter::once(&comm_Cz_claim)) - .map(|pt| pt.decompress().unwrap()) - .collect::<Vec<GroupElement>>(), + .map(|pt| GroupElement::decompress(pt).unwrap()) + .collect::<Vec<GroupElement>>().as_slice(), ) .compress();@@ -468,16 +471,17 @@ };
// compute commitment to eval_Z_at_ry = (Scalar::one() - ry[0]) * self.eval_vars_at_ry + ry[0] * poly_input_eval let comm_eval_Z_at_ry = GroupElement::vartime_multiscalar_mul( - iter::once(Scalar::one() - ry[0]).chain(iter::once(ry[0])), - iter::once(&self.comm_vars_at_ry.decompress().unwrap()).chain(iter::once( - &poly_input_eval.commit(&Scalar::zero(), &gens.gens_pc.gens.gens_1), - )), + iter::once(Scalar::one() - ry[0]).chain(iter::once(ry[0])).collect::<Vec<Scalar>>().as_slice(), + iter::once(GroupElement::decompress(&self.comm_vars_at_ry).unwrap()).chain(iter::once( + poly_input_eval.commit(&Scalar::zero(), &gens.gens_pc.gens.gens_1), + )).collect::<Vec<GroupElement>>().as_slice(), ); // perform the final check in the second sum-check protocol let (eval_A_r, eval_B_r, eval_C_r) = evals; + let scalar = r_A * eval_A_r + r_B * eval_B_r + r_C * eval_C_r; let expected_claim_post_phase2 = - ((r_A * eval_A_r + r_B * eval_B_r + r_C * eval_C_r) * comm_eval_Z_at_ry).compress(); + comm_eval_Z_at_ry.mul(scalar.into_repr()).compress(); // verify proof that expected_claim_post_phase1 == claim_post_phase1 self.proof_eq_sc_phase2.verify( &gens.gens_sc.gens_1,
@@ -15,7 +15,7 @@ use super::transcript::{AppendToTranscript, ProofTranscript};
use core::cmp::Ordering; use merlin::Transcript; use ark_serialize::*; -use ark_ff::{One, Zero}; +use ark_ff::{One, Zero, Field}; #[derive(Debug, CanonicalSerialize, CanonicalDeserialize)] pub struct SparseMatEntry {@@ -466,9 +466,9 @@ .map(|i| {
let row = self.M[i].row; let col = self.M[i].col; let val = &self.M[i].val; - (row, val * z[col]) + (row, z[col] * val) }) - .fold(vec![Scalar::zero(); num_rows], |mut Mz, (r, v)| { + .fold(vec![Scalar::zero(); num_rows], |mut Mz, (r, v)| { Mz[r] += v; Mz })@@ -553,9 +553,9 @@ ) {
let (r_hash, r_multiset_check) = r_mem_check; //hash(addr, val, ts) = ts * r_hash_sqr + val * r_hash + addr - let r_hash_sqr = r_hash * r_hash; + let r_hash_sqr = r_hash.square(); let hash_func = |addr: &Scalar, val: &Scalar, ts: &Scalar| -> Scalar { - ts * r_hash_sqr + val * r_hash + addr + r_hash_sqr * ts + (*val) * r_hash + addr }; // hash init and audit that does not depend on #instances@@ -856,9 +856,9 @@ r: &[Scalar],
r_hash: &Scalar, r_multiset_check: &Scalar, ) -> Result<(), ProofVerifyError> { - let r_hash_sqr = r_hash * r_hash; + let r_hash_sqr = r_hash.square(); let hash_func = |addr: &Scalar, val: &Scalar, ts: &Scalar| -> Scalar { - ts * r_hash_sqr + val * r_hash + addr + r_hash_sqr * ts + (*val) * r_hash + addr }; let (rand_mem, _rand_ops) = rand;@@ -1220,7 +1220,8 @@ proof_mem,
proof_ops, }; - let product_layer_proof_encoded: Vec<u8> = bincode::serialize(&product_layer_proof).unwrap(); + let mut product_layer_proof_encoded: Vec<u8> = Vec::new(); + product_layer_proof.serialize(&mut product_layer_proof_encoded).unwrap(); let msg = format!( "len_product_layer_proof {:?}", product_layer_proof_encoded.len()@@ -1259,7 +1260,7 @@ let ws: Scalar = (0..row_eval_write.len())
.map(|i| row_eval_write[i]) .product(); let rs: Scalar = (0..row_eval_read.len()).map(|i| row_eval_read[i]).product(); - assert_eq!(row_eval_init * ws, rs * row_eval_audit); + assert_eq!( ws * row_eval_init , rs * row_eval_audit); row_eval_init.append_to_transcript(b"claim_row_eval_init", transcript); row_eval_read.append_to_transcript(b"claim_row_eval_read", transcript);@@ -1274,7 +1275,7 @@ let ws: Scalar = (0..col_eval_write.len())
.map(|i| col_eval_write[i]) .product(); let rs: Scalar = (0..col_eval_read.len()).map(|i| col_eval_read[i]).product(); - assert_eq!(col_eval_init * ws, rs * col_eval_audit); + assert_eq!(ws * col_eval_init, rs * col_eval_audit); col_eval_init.append_to_transcript(b"claim_col_eval_init", transcript); col_eval_read.append_to_transcript(b"claim_col_eval_read", transcript);@@ -1628,7 +1629,8 @@ #[cfg(test)]
mod tests { use super::*; use ark_std::{UniformRand}; - use rand::RngCore; +use rand::RngCore; + #[test] fn check_sparse_polyeval_proof() { let mut rng = ark_std::rand::thread_rng();@@ -1643,8 +1645,8 @@ let mut M: Vec<SparseMatEntry> = Vec::new();
for _i in 0..num_nz_entries { M.push(SparseMatEntry::new( - (csprng.next_u64() % (num_rows as u64)) as usize, - (csprng.next_u64() % (num_cols as u64)) as usize, + (rng.next_u64()% (num_rows as u64)) as usize, + (rng.next_u64() % (num_cols as u64)) as usize, Scalar::rand(&mut rng), )); }
@@ -3,7 +3,7 @@ #![allow(clippy::type_complexity)]
use super::commitments::{Commitments, MultiCommitGens}; use super::dense_mlpoly::DensePolynomial; use super::errors::ProofVerifyError; -use super::group::{CompressedGroup, GroupElement, VartimeMultiscalarMul}; +use super::group::{CompressedGroup, GroupElement, VartimeMultiscalarMul, CompressGroupElement, DecompressGroupElement}; use super::nizk::DotProductProof; use super::random::RandomTape; use super::scalar::Scalar;@@ -115,7 +115,7 @@ comm_claim
} else { &self.comm_evals[i - 1] }; - let comm_eval = &self.comm_evals[i]; + let mut comm_eval = &self.comm_evals[i]; // add two claims to transcript comm_claim_per_round.append_to_transcript(b"comm_claim_per_round", transcript);@@ -126,11 +126,11 @@ let w = transcript.challenge_vector(b"combine_two_claims_to_one", 2);
// compute a weighted sum of the RHS let comm_target = GroupElement::vartime_multiscalar_mul( - w.iter(), + w.as_slice(), iter::once(&comm_claim_per_round) .chain(iter::once(&comm_eval)) - .map(|pt| pt.decompress().unwrap()) - .collect::<Vec<GroupElement>>(), + .map(|pt| GroupElement::decompress(pt).unwrap()) + .collect::<Vec<GroupElement>>().as_slice(), ) .compress();@@ -176,7 +176,7 @@
r.push(r_i); } - Ok((self.comm_evals[self.comm_evals.len() - 1], r)) + Ok((self.comm_evals[&self.comm_evals.len() - 1].clone(), r)) } }@@ -510,11 +510,11 @@
// compute a weighted sum of the RHS let target = w[0] * claim_per_round + w[1] * eval; let comm_target = GroupElement::vartime_multiscalar_mul( - w.iter(), + w.as_slice(), iter::once(&comm_claim_per_round) .chain(iter::once(&comm_eval)) - .map(|pt| pt.decompress().unwrap()) - .collect::<Vec<GroupElement>>(), + .map(|pt| GroupElement::decompress(pt).unwrap()) + .collect::<Vec<GroupElement>>().as_slice(), ) .compress();@@ -575,7 +575,7 @@ comm_claim_per_round = comm_claim_next_round;
proofs.push(proof); r.push(r_j); - comm_evals.push(comm_claim_per_round); + comm_evals.push(comm_claim_per_round.clone()); } (@@ -693,20 +693,21 @@
// add two claims to transcript comm_claim_per_round.append_to_transcript(b"comm_claim_per_round", transcript); comm_eval.append_to_transcript(b"comm_eval", transcript); + // produce two weights let w = 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 comm_target = GroupElement::vartime_multiscalar_mul( - w.iter(), + w.as_slice(), iter::once(&comm_claim_per_round) .chain(iter::once(&comm_eval)) - .map(|pt| pt.decompress().unwrap()) - .collect::<Vec<GroupElement>>(), - ) - .compress(); + .map(|pt|GroupElement::decompress(&pt).unwrap()) + .collect::<Vec<GroupElement>>().as_slice(), + ).compress(); let blind = { let blind_sc = if j == 0 {@@ -720,7 +721,10 @@
w[0] * blind_sc + w[1] * blind_eval }; - assert_eq!(target.commit(&blind, gens_1).compress(), comm_target); + + let res = target.commit(&blind, gens_1); + + assert_eq!(res.compress(), comm_target); let a = { // the vector to use to decommit for sum-check test@@ -765,7 +769,7 @@ proofs.push(proof);
claim_per_round = claim_next_round; comm_claim_per_round = comm_claim_next_round; r.push(r_j); - comm_evals.push(comm_claim_per_round); + comm_evals.push(comm_claim_per_round.clone()); } (
@@ -1,6 +1,8 @@
-use super::group::CompressedGroup; +use crate::group::CompressedGroup; use super::scalar::Scalar; use merlin::Transcript; +use ark_ff::{PrimeField, BigInteger}; +use ark_serialize::{CanonicalSerialize}; pub trait ProofTranscript { fn append_protocol_name(&mut self, protocol_name: &'static [u8]);@@ -16,17 +18,19 @@ self.append_message(b"protocol-name", protocol_name);
} fn append_scalar(&mut self, label: &'static [u8], scalar: &Scalar) { - self.append_message(label, &scalar.to_bytes()); + self.append_message(label, &scalar.into_repr().to_bytes_le().as_slice()); } fn append_point(&mut self, label: &'static [u8], point: &CompressedGroup) { - self.append_message(label, point.as_bytes()); + let mut point_encoded = Vec::new(); + point.serialize(&mut point_encoded).unwrap(); + self.append_message(label, point_encoded.as_slice()); } fn challenge_scalar(&mut self, label: &'static [u8]) -> Scalar { let mut buf = [0u8; 64]; self.challenge_bytes(label, &mut buf); - Scalar::from_bytes_wide(&buf) + Scalar::from_le_bytes_mod_order(&buf) } fn challenge_vector(&mut self, label: &'static [u8], len: usize) -> Vec<Scalar> {
@@ -97,7 +97,7 @@ // we require eval(0) + eval(1) = hint, so we can solve for the linear term as:
// linear_term = hint - 2 * constant_term - deg2 term - deg3 term pub fn decompress(&self, hint: &Scalar) -> UniPoly { let mut linear_term = - hint - self.coeffs_except_linear_term[0] - self.coeffs_except_linear_term[0]; + (*hint) - self.coeffs_except_linear_term[0] - self.coeffs_except_linear_term[0]; for i in 1..self.coeffs_except_linear_term.len() { linear_term -= self.coeffs_except_linear_term[i]; }