arnaucube
arnaucube/nova-studyPublic Self-hosted repository
sumcheck use transcript, reorganize some files
arnaucube root@arnaucube.com
Sun, 23 Apr 2023 23:11:18 +0200
commit

590512de0c2546ffa5a7e142201fb3d6998037e2

parent

946fa1ce85bd367792bc5b12026eb5ee14a6f229

7 files changed, 78 insertions(+), 68 deletions(-)

jump to
M src/lib.rs → src/lib.rs

@@ -3,9 +3,9 @@ #![allow(non_camel_case_types)]

#![allow(non_upper_case_globals)] #![allow(unused)] // TMP +mod circuits; mod nifs; -mod novacircuit; mod pedersen; -mod r1cs; +mod sumcheck; mod transcript; mod utils;
M src/nifs.rs → src/nifs.rs

@@ -1,15 +1,21 @@

use ark_ec::AffineRepr; +use ark_ff::fields::PrimeField; +use ark_std::{ + rand::{Rng, RngCore}, + UniformRand, +}; use ark_std::{One, Zero}; use std::marker::PhantomData; use crate::pedersen::{Commitment, Params as PedersenParams, Pedersen, Proof as PedersenProof}; -use crate::r1cs::*; use crate::transcript::Transcript; use crate::utils::*; -use ark_std::{ - rand::{Rng, RngCore}, - UniformRand, -}; + +pub struct R1CS<F: PrimeField> { + pub A: Vec<Vec<F>>, + pub B: Vec<Vec<F>>, + pub C: Vec<Vec<F>>, +} // Phi: φ in the paper (later 𝖴), a folded instance pub struct Phi<C: AffineRepr> {
M src/novacircuit.rs → src/circuits.rs

@@ -1,4 +1,5 @@

use ark_crypto_primitives::snark::{FromFieldElementsGadget, SNARKGadget, SNARK}; +use ark_ec::AffineRepr; use ark_ec::CurveGroup; use ark_ff::{fields::Fp256, Field, PrimeField}; use ark_r1cs_std::{

@@ -42,8 +43,6 @@ ConstraintSynthesizer<Fq> for AugmentedFCircuit<Fq, Fr, C, GC, Cfg>

{ fn generate_constraints(self, cs: ConstraintSystemRef<Fq>) -> Result<(), SynthesisError> { unimplemented!(); - // nifscircuit::NIFSGadget::<Fq, C, GC<Fq, C>>::verify(); - // hash } }
M src/pedersen.rs → src/pedersen.rs

@@ -22,7 +22,7 @@

pub struct Params<C: AffineRepr> { g: C, h: C, - pub r_vec: Vec<C>, + pub generators: Vec<C>, } pub struct Pedersen<C: AffineRepr> {

@@ -33,11 +33,11 @@ impl<C: AffineRepr> Pedersen<C> {

pub fn new_params<R: Rng>(rng: &mut R, max: usize) -> Params<C> { let h_scalar = C::ScalarField::rand(rng); let g: C = C::generator(); - let r_vec: Vec<C> = vec![C::rand(rng); max]; + let generators: Vec<C> = vec![C::rand(rng); max]; let params: Params<C> = Params::<C> { g, h: g.mul(h_scalar).into(), - r_vec, // will need 2 r: rE, rW + generators, }; params }

@@ -56,7 +56,7 @@ params: &Params<C>,

v: &Vec<C::ScalarField>, r: &C::ScalarField, // random value is provided, in order to be choosen by other parts of the protocol ) -> Commitment<C> { - let cm = params.h.mul(r) + naive_msm(v, &params.r_vec); + let cm = params.h.mul(r) + naive_msm(v, &params.generators); Commitment::<C>(cm.into()) }

@@ -91,7 +91,7 @@ ) -> Proof<C> {

let r1 = transcript.get_challenge(b"r_1"); let d = transcript.get_challenge_vec(b"d", v.len()); - let R: C = (params.h.mul(r1) + naive_msm(&d, &params.r_vec)).into(); + let R: C = (params.h.mul(r1) + naive_msm(&d, &params.generators)).into(); transcript.add(b"cm", &cm.0); transcript.add(b"R", &R);

@@ -116,7 +116,7 @@ transcript.add(b"cm", &cm.0);

transcript.add(b"R", &proof.R); let e = transcript.get_challenge(b"e"); let lhs = proof.R + cm.0.mul(e); - let rhs = params.h.mul(proof.ru_) + naive_msm(&proof.u_, &params.r_vec); + let rhs = params.h.mul(proof.ru_) + naive_msm(&proof.u_, &params.generators); if lhs != rhs { return false; }
D src/r1cs.rs

@@ -1,34 +0,0 @@

-use crate::pedersen; - -use ark_ff::fields::PrimeField; -use core::ops::Add; - -// this file contains an abstraction of R1CS struct, to later be plugged from arkworks -// ConstraintSystem or something similar. - -pub struct R1CS<F: PrimeField> { - pub A: Vec<Vec<F>>, - pub B: Vec<Vec<F>>, - pub C: Vec<Vec<F>>, -} - -pub struct RelaxedR1CS<F: PrimeField> { - pub ABC: R1CS<F>, - pub u: F, - pub E: F, -} - -impl<F: PrimeField> R1CS<F> { - pub fn relax(self) -> RelaxedR1CS<F> { - RelaxedR1CS::<F> { - ABC: self, - u: F::one(), - E: F::zero(), - } - } -} -impl<F: PrimeField> RelaxedR1CS<F> { - pub fn fold(self, other: Self, r: F) -> Self { - unimplemented!(); - } -}
M src/sumcheck.rs → src/sumcheck.rs

@@ -1,5 +1,5 @@

// Sum-check protocol initial implementation, not used by the rest of the repo but implemented as -// an exercise and might be used in the future. +// an exercise and it will probably be used in the future. use ark_ff::{BigInteger, PrimeField}; use ark_poly::{

@@ -13,6 +13,8 @@ use ark_std::log2;

use ark_std::marker::PhantomData; use ark_std::ops::Mul; use ark_std::{rand::Rng, UniformRand}; + +use crate::transcript::Transcript; pub struct SumCheck< F: PrimeField,

@@ -81,10 +83,8 @@ }

fn point_complete(challenges: Vec<F>, n_elems: usize, iter_num: usize) -> Vec<F> { let p = Self::point(challenges, false, n_elems, iter_num); - // let mut r = Vec::new(); let mut r = vec![F::zero(); n_elems]; for i in 0..n_elems { - // r.push(p[i].unwrap()); r[i] = p[i].unwrap(); } r

@@ -96,7 +96,7 @@

if none { // WIP if n_vars == 0 { - panic!("err"); + panic!("err"); // or return directly challenges vector } n_vars -= 1; }

@@ -125,9 +125,10 @@ pub fn prove(g: MV) -> (F, Vec<UV>, F)

where <MV as Polynomial<F>>::Point: From<Vec<F>>, { - let v = g.num_vars(); + // init transcript + let mut transcript: Transcript<F> = Transcript::<F>::new(); - let r = vec![F::from(2_u32), F::from(3_u32), F::from(6_u32)]; // TMP will come from transcript + let v = g.num_vars(); // compute H let mut H = F::zero();

@@ -136,43 +137,56 @@ let p = Self::point_complete(vec![], v, i);

H = H + g.evaluate(&p.into()); } + transcript.add(b"H", &H); let mut ss: Vec<UV> = Vec::new(); + let mut r: Vec<F> = vec![]; for i in 0..v { + let r_i = transcript.get_challenge(b"r_i"); + r.push(r_i); + let var_slots = v - 1 - i; let n_points = 2_u64.pow(var_slots as u32) as usize; + let mut s_i = UV::zero(); - let r_round = r.as_slice()[..i].to_vec(); for j in 0..n_points { - let point = Self::point(r_round.clone(), true, v, j); + let point = Self::point(r[..i].to_vec(), true, v, j); s_i = s_i + Self::partial_evaluate(&g, &point); } + transcript.add(b"s_i", &s_i); ss.push(s_i); } - let point_last = r; - let last_g_eval = g.evaluate(&point_last.into()); + let last_g_eval = g.evaluate(&r.into()); (H, ss, last_g_eval) } pub fn verify(proof: (F, Vec<UV>, F)) -> bool { - // let c: F, ss: Vec<UV>; + // init transcript + let mut transcript: Transcript<F> = Transcript::<F>::new(); + transcript.add(b"H", &proof.0); + let (c, ss, last_g_eval) = proof; - let r = vec![F::from(2_u32), F::from(3_u32), F::from(6_u32)]; // TMP will come from transcript - + let mut r: Vec<F> = vec![]; for (i, s) in ss.iter().enumerate() { // TODO check degree if i == 0 { if c != s.evaluate(&F::zero()) + s.evaluate(&F::one()) { return false; } + let r_i = transcript.get_challenge(b"r_i"); + r.push(r_i); + transcript.add(b"s_i", s); continue; } + let r_i = transcript.get_challenge(b"r_i"); + r.push(r_i); if ss[i - 1].evaluate(&r[i - 1]) != s.evaluate(&F::zero()) + s.evaluate(&F::one()) { return false; } + transcript.add(b"s_i", s); } // last round if ss[ss.len() - 1].evaluate(&r[r.len() - 1]) != last_g_eval {

@@ -264,9 +278,6 @@

#[test] fn test_flow_hardcoded_values() { let mut rng = ark_std::test_rng(); - // let p = SparsePolynomial::<Fr, SparseTerm>::rand(deg, 3, &mut rng); - // let p = rand_poly(3, 3, &mut rng); - // g(X_0, X_1, X_2) = 2 X_0^3 + X_0 X_2 + X_1 X_2 let terms = vec![ (Fr::from(2u32), SparseTerm::new(vec![(0_usize, 3)])),

@@ -286,17 +297,43 @@ type SC = SumCheck<Fr, DensePolynomial<Fr>, SparsePolynomial<Fr, SparseTerm>>;

let proof = SC::prove(p); assert_eq!(proof.0, Fr::from(12_u32)); - println!("proof {:?}", proof); + // println!("proof {:?}", proof); let v = SC::verify(proof); assert!(v); } + fn rand_poly<R: Rng>(l: usize, d: usize, rng: &mut R) -> SparsePolynomial<Fr, SparseTerm> { + // This method is from the arkworks/algebra/poly/multivariate test: + // https://github.com/arkworks-rs/algebra/blob/bc991d44c5e579025b7ed56df3d30267a7b9acac/poly/src/polynomial/multivariate/sparse.rs#L303 + let mut random_terms = Vec::new(); + let num_terms = rng.gen_range(1..1000); + // For each term, randomly select up to `l` variables with degree + // in [1,d] and random coefficient + random_terms.push((Fr::rand(rng), SparseTerm::new(vec![]))); + for _ in 1..num_terms { + let term = (0..l) + .map(|i| { + if rng.gen_bool(0.5) { + Some((i, rng.gen_range(1..(d + 1)))) + } else { + None + } + }) + .flatten() + .collect(); + let coeff = Fr::rand(rng); + random_terms.push((coeff, SparseTerm::new(term))); + } + SparsePolynomial::from_coefficients_slice(l, &random_terms) + } + #[test] fn test_flow_rng() { let mut rng = ark_std::test_rng(); - let p = SparsePolynomial::<Fr, SparseTerm>::rand(3, 3, &mut rng); - println!("p {:?}", p); + // let p = SparsePolynomial::<Fr, SparseTerm>::rand(3, 3, &mut rng); + let p = rand_poly(3, 3, &mut rng); + // println!("p {:?}", p); type SC = SumCheck<Fr, DensePolynomial<Fr>, SparsePolynomial<Fr, SparseTerm>>;
M src/transcript.rs → src/transcript.rs

@@ -3,6 +3,8 @@ use ark_serialize::CanonicalSerialize;

use merlin::Transcript as MerlinTranscript; use std::marker::PhantomData; +// TODO poseidon transcript (not keccak) + // This Transcript approach is a modified version from https://github.com/arkworks-rs/gemini , // using Merlin transcript (https://merlin.cool). pub struct Transcript<F: PrimeField> {