mirror of
https://github.com/arnaucube/Nova.git
synced 2026-01-11 16:41:28 +01:00
Simplify TranscriptEngine usage (#148)
* simplify transcript engine usage * update version
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nova-snark"
|
||||
version = "0.17.0"
|
||||
version = "0.18.0"
|
||||
authors = ["Srinath Setty <srinath@microsoft.com>"]
|
||||
edition = "2021"
|
||||
description = "Recursive zkSNARKs without trusted setup"
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::{
|
||||
traits::{
|
||||
commitment::{CommitmentEngineTrait, CommitmentKeyTrait, CommitmentTrait},
|
||||
evaluation::EvaluationEngineTrait,
|
||||
AppendToTranscriptTrait, ChallengeTrait, Group, TranscriptEngineTrait,
|
||||
Group, TranscriptEngineTrait, TranscriptReprTrait,
|
||||
},
|
||||
Commitment, CommitmentKey, CompressedCommitment, CE,
|
||||
};
|
||||
@@ -139,6 +139,17 @@ impl<G: Group> InnerProductInstance<G> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> TranscriptReprTrait<G> for InnerProductInstance<G> {
|
||||
fn to_transcript_bytes(&self) -> Vec<u8> {
|
||||
// we do not need to include self.b_vec as in our context it is produced from the transcript
|
||||
[
|
||||
self.comm_a_vec.to_transcript_bytes(),
|
||||
self.c.to_transcript_bytes(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
|
||||
struct InnerProductWitness<G: Group> {
|
||||
a_vec: Vec<G::Scalar>,
|
||||
}
|
||||
@@ -167,7 +178,7 @@ where
|
||||
CommitmentKey<G>: CommitmentKeyExtTrait<G, CE = G::CE>,
|
||||
{
|
||||
fn protocol_name() -> &'static [u8] {
|
||||
b"inner product argument"
|
||||
b"IPA"
|
||||
}
|
||||
|
||||
fn prove(
|
||||
@@ -177,17 +188,17 @@ where
|
||||
W: &InnerProductWitness<G>,
|
||||
transcript: &mut G::TE,
|
||||
) -> Result<Self, NovaError> {
|
||||
transcript.absorb_bytes(b"protocol-name", Self::protocol_name());
|
||||
transcript.dom_sep(Self::protocol_name());
|
||||
|
||||
if U.b_vec.len() != W.a_vec.len() {
|
||||
return Err(NovaError::InvalidInputLength);
|
||||
}
|
||||
|
||||
U.comm_a_vec.append_to_transcript(b"comm_a_vec", transcript);
|
||||
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(&U.c, b"c", transcript);
|
||||
// absorb the instance in the transcript
|
||||
transcript.absorb(b"U", U);
|
||||
|
||||
// sample a random base for commiting to the inner product
|
||||
let r = G::Scalar::challenge(b"r", transcript)?;
|
||||
let r = transcript.squeeze(b"r")?;
|
||||
let ck_c = ck_c.scale(&r);
|
||||
|
||||
// a closure that executes a step of the recursive inner product argument
|
||||
@@ -230,10 +241,10 @@ where
|
||||
)
|
||||
.compress();
|
||||
|
||||
L.append_to_transcript(b"L", transcript);
|
||||
R.append_to_transcript(b"R", transcript);
|
||||
transcript.absorb(b"L", &L);
|
||||
transcript.absorb(b"R", &R);
|
||||
|
||||
let r = G::Scalar::challenge(b"challenge_r", transcript)?;
|
||||
let r = transcript.squeeze(b"r")?;
|
||||
let r_inverse = r.invert().unwrap();
|
||||
|
||||
// fold the left half and the right half
|
||||
@@ -289,7 +300,7 @@ where
|
||||
U: &InnerProductInstance<G>,
|
||||
transcript: &mut G::TE,
|
||||
) -> Result<(), NovaError> {
|
||||
transcript.absorb_bytes(b"protocol-name", Self::protocol_name());
|
||||
transcript.dom_sep(Self::protocol_name());
|
||||
if U.b_vec.len() != n
|
||||
|| n != (1 << self.L_vec.len())
|
||||
|| self.L_vec.len() != self.R_vec.len()
|
||||
@@ -298,11 +309,11 @@ where
|
||||
return Err(NovaError::InvalidInputLength);
|
||||
}
|
||||
|
||||
U.comm_a_vec.append_to_transcript(b"comm_a_vec", transcript);
|
||||
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(&U.c, b"c", transcript);
|
||||
// absorb the instance in the transcript
|
||||
transcript.absorb(b"U", U);
|
||||
|
||||
// sample a random base for commiting to the inner product
|
||||
let r = G::Scalar::challenge(b"r", transcript)?;
|
||||
let r = transcript.squeeze(b"r")?;
|
||||
let ck_c = ck_c.scale(&r);
|
||||
|
||||
let P = U.comm_a_vec + CE::<G>::commit(&ck_c, &[U.c]);
|
||||
@@ -337,9 +348,9 @@ where
|
||||
// compute a vector of public coins using self.L_vec and self.R_vec
|
||||
let r = (0..self.L_vec.len())
|
||||
.map(|i| {
|
||||
self.L_vec[i].append_to_transcript(b"L", transcript);
|
||||
self.R_vec[i].append_to_transcript(b"R", transcript);
|
||||
G::Scalar::challenge(b"challenge_r", transcript)
|
||||
transcript.absorb(b"L", &self.L_vec[i]);
|
||||
transcript.absorb(b"R", &self.R_vec[i]);
|
||||
transcript.squeeze(b"r")
|
||||
})
|
||||
.collect::<Result<Vec<G::Scalar>, NovaError>>()?;
|
||||
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
use crate::traits::PrimeFieldExt;
|
||||
use crate::{
|
||||
errors::NovaError,
|
||||
traits::{Group, TranscriptEngineTrait},
|
||||
traits::{Group, TranscriptEngineTrait, TranscriptReprTrait},
|
||||
};
|
||||
use core::marker::PhantomData;
|
||||
use sha3::{Digest, Keccak256};
|
||||
|
||||
const PERSONA_TAG: &[u8] = b"NovaTranscript";
|
||||
const DOM_SEP_TAG: &[u8] = b"NovaRound";
|
||||
const PERSONA_TAG: &[u8] = b"NoTR";
|
||||
const DOM_SEP_TAG: &[u8] = b"NoDS";
|
||||
const KECCAK256_STATE_SIZE: usize = 64;
|
||||
const KECCAK256_PREFIX_CHALLENGE_LO: u8 = 0;
|
||||
const KECCAK256_PREFIX_CHALLENGE_HI: u8 = 1;
|
||||
@@ -55,7 +55,7 @@ impl<G: Group> TranscriptEngineTrait<G> for Keccak256Transcript<G> {
|
||||
}
|
||||
}
|
||||
|
||||
fn squeeze_scalar(&mut self, label: &'static [u8]) -> Result<G::Scalar, NovaError> {
|
||||
fn squeeze(&mut self, label: &'static [u8]) -> Result<G::Scalar, NovaError> {
|
||||
let input = [
|
||||
DOM_SEP_TAG,
|
||||
self.round.to_le_bytes().as_ref(),
|
||||
@@ -81,8 +81,13 @@ impl<G: Group> TranscriptEngineTrait<G> for Keccak256Transcript<G> {
|
||||
Ok(G::Scalar::from_uniform(&output))
|
||||
}
|
||||
|
||||
fn absorb_bytes(&mut self, label: &'static [u8], bytes: &[u8]) {
|
||||
fn absorb<T: TranscriptReprTrait<G>>(&mut self, label: &'static [u8], o: &T) {
|
||||
self.transcript.extend_from_slice(label);
|
||||
self.transcript.extend_from_slice(&o.to_transcript_bytes());
|
||||
}
|
||||
|
||||
fn dom_sep(&mut self, bytes: &'static [u8]) {
|
||||
self.transcript.extend_from_slice(DOM_SEP_TAG);
|
||||
self.transcript.extend_from_slice(bytes);
|
||||
}
|
||||
}
|
||||
@@ -91,7 +96,7 @@ impl<G: Group> TranscriptEngineTrait<G> for Keccak256Transcript<G> {
|
||||
mod tests {
|
||||
use crate::{
|
||||
provider::keccak::Keccak256Transcript,
|
||||
traits::{AppendToTranscriptTrait, ChallengeTrait, Group, TranscriptEngineTrait},
|
||||
traits::{Group, TranscriptEngineTrait},
|
||||
};
|
||||
use ff::PrimeField;
|
||||
use sha3::{Digest, Keccak256};
|
||||
@@ -100,50 +105,34 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_keccak_transcript() {
|
||||
let mut transcript = Keccak256Transcript::new(b"test");
|
||||
let mut transcript: Keccak256Transcript<G> = Keccak256Transcript::new(b"test");
|
||||
|
||||
// two scalars
|
||||
let s1 = <G as Group>::Scalar::from(2u64);
|
||||
let s2 = <G as Group>::Scalar::from(5u64);
|
||||
|
||||
// add the scalars to the transcript
|
||||
<<G as Group>::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&s1,
|
||||
b"s1",
|
||||
&mut transcript,
|
||||
);
|
||||
<<G as Group>::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&s2,
|
||||
b"s2",
|
||||
&mut transcript,
|
||||
);
|
||||
transcript.absorb(b"s1", &s1);
|
||||
transcript.absorb(b"s2", &s2);
|
||||
|
||||
// make a challenge
|
||||
let c1 =
|
||||
<<G as Group>::Scalar as ChallengeTrait<G>>::challenge(b"challenge_c1", &mut transcript)
|
||||
.unwrap();
|
||||
let c1: <G as Group>::Scalar = transcript.squeeze(b"c1").unwrap();
|
||||
assert_eq!(
|
||||
hex::encode(c1.to_repr().as_ref()),
|
||||
"51648083af5387a04a7aa2aec789ee78fdabe45dc1391d270a38fcb576447c01"
|
||||
"432d5811c8be3d44d47f52108a8749ae18482efd1a37b830f966456b5d75340c"
|
||||
);
|
||||
|
||||
// a scalar
|
||||
let s3 = <G as Group>::Scalar::from(128u64);
|
||||
|
||||
// add the scalar to the transcript
|
||||
<<G as Group>::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&s3,
|
||||
b"s3",
|
||||
&mut transcript,
|
||||
);
|
||||
transcript.absorb(b"s3", &s3);
|
||||
|
||||
// make a challenge
|
||||
let c2 =
|
||||
<<G as Group>::Scalar as ChallengeTrait<G>>::challenge(b"challenge_c2", &mut transcript)
|
||||
.unwrap();
|
||||
let c2: <G as Group>::Scalar = transcript.squeeze(b"c2").unwrap();
|
||||
assert_eq!(
|
||||
hex::encode(c2.to_repr().as_ref()),
|
||||
"9773f3349f7308153f6012e72b97fc304e48372bbd28bd122b37a8e46855d50f"
|
||||
"65f7908d53abcd18f3b1d767456ef9009b91c7566a635e9ca7be26e21d4d7a10"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
//! This module implements the Nova traits for pallas::Point, pallas::Scalar, vesta::Point, vesta::Scalar.
|
||||
use crate::{
|
||||
errors::NovaError,
|
||||
provider::{
|
||||
keccak::Keccak256Transcript,
|
||||
pedersen::CommitmentEngine,
|
||||
poseidon::{PoseidonRO, PoseidonROCircuit},
|
||||
},
|
||||
traits::{ChallengeTrait, CompressedGroup, Group, PrimeFieldExt, TranscriptEngineTrait},
|
||||
traits::{CompressedGroup, Group, PrimeFieldExt, TranscriptReprTrait},
|
||||
};
|
||||
use digest::{ExtendableOutput, Input};
|
||||
use ff::PrimeField;
|
||||
@@ -177,9 +176,11 @@ macro_rules! impl_traits {
|
||||
let bytes_arr: [u8; 64] = bytes.try_into().unwrap();
|
||||
$name::Scalar::from_bytes_wide(&bytes_arr)
|
||||
}
|
||||
}
|
||||
|
||||
fn to_bytes(&self) -> Vec<u8> {
|
||||
self.to_repr().as_ref().to_vec()
|
||||
impl<G: Group> TranscriptReprTrait<G> for $name_compressed {
|
||||
fn to_transcript_bytes(&self) -> Vec<u8> {
|
||||
self.repr.to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,17 +190,19 @@ macro_rules! impl_traits {
|
||||
fn decompress(&self) -> Option<$name::Point> {
|
||||
Some($name_curve::from_bytes(&self.repr).unwrap())
|
||||
}
|
||||
|
||||
fn as_bytes(&self) -> Vec<u8> {
|
||||
self.repr.to_vec()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl<G: Group<Scalar = F>, F: PrimeField> ChallengeTrait<G> for F {
|
||||
fn challenge(label: &'static [u8], transcript: &mut G::TE) -> Result<F, NovaError> {
|
||||
transcript.squeeze_scalar(label)
|
||||
impl<G: Group> TranscriptReprTrait<G> for pallas::Base {
|
||||
fn to_transcript_bytes(&self) -> Vec<u8> {
|
||||
self.to_repr().to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> TranscriptReprTrait<G> for pallas::Scalar {
|
||||
fn to_transcript_bytes(&self) -> Vec<u8> {
|
||||
self.to_repr().to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ use crate::{
|
||||
errors::NovaError,
|
||||
traits::{
|
||||
commitment::{CommitmentEngineTrait, CommitmentKeyTrait, CommitmentTrait},
|
||||
AbsorbInROTrait, AppendToTranscriptTrait, CompressedGroup, Group, ROTrait,
|
||||
TranscriptEngineTrait,
|
||||
AbsorbInROTrait, CompressedGroup, Group, ROTrait, TranscriptReprTrait,
|
||||
},
|
||||
};
|
||||
use core::{
|
||||
@@ -12,7 +11,7 @@ use core::{
|
||||
marker::PhantomData,
|
||||
ops::{Add, AddAssign, Mul, MulAssign},
|
||||
};
|
||||
use ff::{Field, PrimeField};
|
||||
use ff::Field;
|
||||
use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -89,17 +88,16 @@ impl<G: Group> Default for Commitment<G> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> AppendToTranscriptTrait<G> for Commitment<G> {
|
||||
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut G::TE) {
|
||||
impl<G: Group> TranscriptReprTrait<G> for Commitment<G> {
|
||||
fn to_transcript_bytes(&self) -> Vec<u8> {
|
||||
let (x, y, is_infinity) = self.comm.to_coordinates();
|
||||
let is_infinity_byte = if is_infinity { 0u8 } else { 1u8 };
|
||||
let bytes = [
|
||||
x.to_repr().as_ref(),
|
||||
y.to_repr().as_ref(),
|
||||
&[is_infinity_byte],
|
||||
[
|
||||
x.to_transcript_bytes(),
|
||||
y.to_transcript_bytes(),
|
||||
[is_infinity_byte].to_vec(),
|
||||
]
|
||||
.concat();
|
||||
transcript.absorb_bytes(label, &bytes);
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,9 +114,9 @@ impl<G: Group> AbsorbInROTrait<G> for Commitment<G> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> AppendToTranscriptTrait<G> for CompressedCommitment<G> {
|
||||
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut G::TE) {
|
||||
transcript.absorb_bytes(label, &self.comm.as_bytes());
|
||||
impl<G: Group> TranscriptReprTrait<G> for CompressedCommitment<G> {
|
||||
fn to_transcript_bytes(&self) -> Vec<u8> {
|
||||
self.comm.to_transcript_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
34
src/r1cs.rs
34
src/r1cs.rs
@@ -9,7 +9,7 @@ use crate::{
|
||||
},
|
||||
traits::{
|
||||
commitment::{CommitmentEngineTrait, CommitmentKeyTrait},
|
||||
AbsorbInROTrait, AppendToTranscriptTrait, Group, ROTrait,
|
||||
AbsorbInROTrait, Group, ROTrait, TranscriptReprTrait,
|
||||
},
|
||||
Commitment, CommitmentKey, CE,
|
||||
};
|
||||
@@ -435,13 +435,9 @@ impl<G: Group> R1CSShape<G> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> AppendToTranscriptTrait<G> for R1CSShape<G> {
|
||||
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut G::TE) {
|
||||
<<G as Group>::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&self.get_digest(),
|
||||
label,
|
||||
transcript,
|
||||
);
|
||||
impl<G: Group> TranscriptReprTrait<G> for R1CSShape<G> {
|
||||
fn to_transcript_bytes(&self) -> Vec<u8> {
|
||||
self.get_digest().to_transcript_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -485,13 +481,6 @@ impl<G: Group> R1CSInstance<G> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> AppendToTranscriptTrait<G> for R1CSInstance<G> {
|
||||
fn append_to_transcript(&self, _label: &'static [u8], transcript: &mut G::TE) {
|
||||
self.comm_W.append_to_transcript(b"comm_W", transcript);
|
||||
<[G::Scalar] as AppendToTranscriptTrait<G>>::append_to_transcript(&self.X, b"X", transcript);
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> AbsorbInROTrait<G> for R1CSInstance<G> {
|
||||
fn absorb_in_ro(&self, ro: &mut G::RO) {
|
||||
self.comm_W.absorb_in_ro(ro);
|
||||
@@ -623,12 +612,15 @@ impl<G: Group> RelaxedR1CSInstance<G> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> AppendToTranscriptTrait<G> for RelaxedR1CSInstance<G> {
|
||||
fn append_to_transcript(&self, _label: &'static [u8], transcript: &mut G::TE) {
|
||||
self.comm_W.append_to_transcript(b"comm_W", transcript);
|
||||
self.comm_E.append_to_transcript(b"comm_E", transcript);
|
||||
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(&self.u, b"u", transcript);
|
||||
<[G::Scalar] as AppendToTranscriptTrait<G>>::append_to_transcript(&self.X, b"X", transcript);
|
||||
impl<G: Group> TranscriptReprTrait<G> for RelaxedR1CSInstance<G> {
|
||||
fn to_transcript_bytes(&self) -> Vec<u8> {
|
||||
[
|
||||
self.comm_W.to_transcript_bytes(),
|
||||
self.comm_E.to_transcript_bytes(),
|
||||
self.u.to_transcript_bytes(),
|
||||
self.X.as_slice().to_transcript_bytes(),
|
||||
]
|
||||
.concat()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,7 @@ use crate::{
|
||||
errors::NovaError,
|
||||
r1cs::{R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness},
|
||||
traits::{
|
||||
evaluation::EvaluationEngineTrait, snark::RelaxedR1CSSNARKTrait, AppendToTranscriptTrait,
|
||||
ChallengeTrait, Group, TranscriptEngineTrait,
|
||||
evaluation::EvaluationEngineTrait, snark::RelaxedR1CSSNARKTrait, Group, TranscriptEngineTrait,
|
||||
},
|
||||
CommitmentKey,
|
||||
};
|
||||
@@ -83,8 +82,8 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
assert!(pk.S.num_io < pk.S.num_vars);
|
||||
|
||||
// append the R1CSShape and RelaxedR1CSInstance to the transcript
|
||||
pk.S.append_to_transcript(b"S", &mut transcript);
|
||||
U.append_to_transcript(b"U", &mut transcript);
|
||||
transcript.absorb(b"S", &pk.S);
|
||||
transcript.absorb(b"U", U);
|
||||
|
||||
// compute the full satisfying assignment by concatenating W.W, U.u, and U.X
|
||||
let mut z = concat(vec![W.W.clone(), vec![U.u], U.X.clone()]);
|
||||
@@ -96,7 +95,7 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
|
||||
// outer sum-check
|
||||
let tau = (0..num_rounds_x)
|
||||
.map(|_i| G::Scalar::challenge(b"tau", &mut transcript))
|
||||
.map(|_i| transcript.squeeze(b"t"))
|
||||
.collect::<Result<Vec<G::Scalar>, NovaError>>()?;
|
||||
|
||||
let mut poly_tau = MultilinearPolynomial::new(EqPolynomial::new(tau).evals());
|
||||
@@ -134,15 +133,13 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
let (claim_Az, claim_Bz): (G::Scalar, G::Scalar) = (claims_outer[1], claims_outer[2]);
|
||||
let claim_Cz = poly_Cz.evaluate(&r_x);
|
||||
let eval_E = MultilinearPolynomial::new(W.E.clone()).evaluate(&r_x);
|
||||
|
||||
<[G::Scalar] as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&[claim_Az, claim_Bz, claim_Cz, eval_E],
|
||||
transcript.absorb(
|
||||
b"claims_outer",
|
||||
&mut transcript,
|
||||
&[claim_Az, claim_Bz, claim_Cz, eval_E].as_slice(),
|
||||
);
|
||||
|
||||
// inner sum-check
|
||||
let r = G::Scalar::challenge(b"r", &mut transcript)?;
|
||||
let r = transcript.squeeze(b"r")?;
|
||||
let claim_inner_joint = claim_Az + r * claim_Bz + r * r * claim_Cz;
|
||||
|
||||
let poly_ABC = {
|
||||
@@ -213,11 +210,7 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
)?;
|
||||
|
||||
let eval_W = MultilinearPolynomial::new(W.W.clone()).evaluate(&r_y[1..]);
|
||||
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&eval_W,
|
||||
b"eval_W",
|
||||
&mut transcript,
|
||||
);
|
||||
transcript.absorb(b"eval_W", &eval_W);
|
||||
|
||||
// We will now reduce eval_W =? W(r_y[1..]) and eval_W =? E(r_x) into
|
||||
// two claims: eval_W_prime =? W(rz) and eval_E_prime =? E(rz)
|
||||
@@ -225,7 +218,7 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
// where gamma is a public challenge
|
||||
// Since commitments to W and E are homomorphic, the verifier can compute a commitment
|
||||
// to the batched polynomial.
|
||||
let rho = G::Scalar::challenge(b"rho", &mut transcript)?;
|
||||
let rho = transcript.squeeze(b"rho")?;
|
||||
|
||||
let claim_batch_joint = eval_E + rho * eval_W;
|
||||
let num_rounds_z = num_rounds_x;
|
||||
@@ -248,14 +241,10 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
|
||||
let eval_E_prime = claims_batch[1];
|
||||
let eval_W_prime = claims_batch[3];
|
||||
<[G::Scalar] as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&[eval_E_prime, eval_W_prime],
|
||||
b"claims_batch",
|
||||
&mut transcript,
|
||||
);
|
||||
transcript.absorb(b"claims_batch", &[eval_E_prime, eval_W_prime].as_slice());
|
||||
|
||||
// we now combine evaluation claims at the same point rz into one
|
||||
let gamma = G::Scalar::challenge(b"gamma", &mut transcript)?;
|
||||
let gamma = transcript.squeeze(b"gamma")?;
|
||||
let comm = U.comm_E + U.comm_W * gamma;
|
||||
let poly = W
|
||||
.E
|
||||
@@ -285,8 +274,8 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
let mut transcript = G::TE::new(b"RelaxedR1CSSNARK");
|
||||
|
||||
// append the R1CSShape and RelaxedR1CSInstance to the transcript
|
||||
vk.S.append_to_transcript(b"S", &mut transcript);
|
||||
U.append_to_transcript(b"U", &mut transcript);
|
||||
transcript.absorb(b"S", &vk.S);
|
||||
transcript.absorb(b"U", U);
|
||||
|
||||
let (num_rounds_x, num_rounds_y) = (
|
||||
(vk.S.num_cons as f64).log2() as usize,
|
||||
@@ -295,7 +284,7 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
|
||||
// outer sum-check
|
||||
let tau = (0..num_rounds_x)
|
||||
.map(|_i| G::Scalar::challenge(b"tau", &mut transcript))
|
||||
.map(|_i| transcript.squeeze(b"t"))
|
||||
.collect::<Result<Vec<G::Scalar>, NovaError>>()?;
|
||||
|
||||
let (claim_outer_final, r_x) =
|
||||
@@ -312,19 +301,19 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
return Err(NovaError::InvalidSumcheckProof);
|
||||
}
|
||||
|
||||
<[G::Scalar] as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
transcript.absorb(
|
||||
b"claims_outer",
|
||||
&[
|
||||
self.claims_outer.0,
|
||||
self.claims_outer.1,
|
||||
self.claims_outer.2,
|
||||
self.eval_E,
|
||||
],
|
||||
b"claims_outer",
|
||||
&mut transcript,
|
||||
]
|
||||
.as_slice(),
|
||||
);
|
||||
|
||||
// inner sum-check
|
||||
let r = G::Scalar::challenge(b"r", &mut transcript)?;
|
||||
let r = transcript.squeeze(b"r")?;
|
||||
let claim_inner_joint =
|
||||
self.claims_outer.0 + r * self.claims_outer.1 + r * r * self.claims_outer.2;
|
||||
|
||||
@@ -380,13 +369,9 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
}
|
||||
|
||||
// batch sum-check
|
||||
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&self.eval_W,
|
||||
b"eval_W",
|
||||
&mut transcript,
|
||||
);
|
||||
transcript.absorb(b"eval_W", &self.eval_W);
|
||||
|
||||
let rho = G::Scalar::challenge(b"rho", &mut transcript)?;
|
||||
let rho = transcript.squeeze(b"rho")?;
|
||||
let claim_batch_joint = self.eval_E + rho * self.eval_W;
|
||||
let num_rounds_z = num_rounds_x;
|
||||
let (claim_batch_final, r_z) =
|
||||
@@ -405,14 +390,13 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
return Err(NovaError::InvalidSumcheckProof);
|
||||
}
|
||||
|
||||
<[G::Scalar] as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&[self.eval_E_prime, self.eval_W_prime],
|
||||
transcript.absorb(
|
||||
b"claims_batch",
|
||||
&mut transcript,
|
||||
&[self.eval_E_prime, self.eval_W_prime].as_slice(),
|
||||
);
|
||||
|
||||
// we now combine evaluation claims at the same point rz into one
|
||||
let gamma = G::Scalar::challenge(b"gamma", &mut transcript)?;
|
||||
let gamma = transcript.squeeze(b"gamma")?;
|
||||
let comm = U.comm_E + U.comm_W * gamma;
|
||||
let eval = self.eval_E_prime + gamma * self.eval_W_prime;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#![allow(clippy::type_complexity)]
|
||||
use super::polynomial::MultilinearPolynomial;
|
||||
use crate::errors::NovaError;
|
||||
use crate::traits::{AppendToTranscriptTrait, ChallengeTrait, Group};
|
||||
use crate::traits::{Group, TranscriptEngineTrait, TranscriptReprTrait};
|
||||
use core::marker::PhantomData;
|
||||
use ff::Field;
|
||||
use rayon::prelude::*;
|
||||
@@ -43,10 +43,10 @@ impl<G: Group> SumcheckProof<G> {
|
||||
debug_assert_eq!(poly.eval_at_zero() + poly.eval_at_one(), e);
|
||||
|
||||
// append the prover's message to the transcript
|
||||
poly.append_to_transcript(b"poly", transcript);
|
||||
transcript.absorb(b"p", &poly);
|
||||
|
||||
//derive the verifier's challenge for the next round
|
||||
let r_i = G::Scalar::challenge(b"challenge", transcript)?;
|
||||
let r_i = transcript.squeeze(b"c")?;
|
||||
|
||||
r.push(r_i);
|
||||
|
||||
@@ -98,10 +98,10 @@ impl<G: Group> SumcheckProof<G> {
|
||||
};
|
||||
|
||||
// append the prover's message to the transcript
|
||||
poly.append_to_transcript(b"poly", transcript);
|
||||
transcript.absorb(b"p", &poly);
|
||||
|
||||
//derive the verifier's challenge for the next round
|
||||
let r_i = G::Scalar::challenge(b"challenge", transcript)?;
|
||||
let r_i = transcript.squeeze(b"c")?;
|
||||
r.push(r_i);
|
||||
polys.push(poly.compress());
|
||||
|
||||
@@ -172,10 +172,10 @@ impl<G: Group> SumcheckProof<G> {
|
||||
};
|
||||
|
||||
// append the prover's message to the transcript
|
||||
poly.append_to_transcript(b"poly", transcript);
|
||||
transcript.absorb(b"p", &poly);
|
||||
|
||||
//derive the verifier's challenge for the next round
|
||||
let r_i = G::Scalar::challenge(b"challenge", transcript)?;
|
||||
// derive the verifier's challenge for the next round
|
||||
let r_i = transcript.squeeze(b"c")?;
|
||||
r.push(r_i);
|
||||
polys.push(poly.compress());
|
||||
|
||||
@@ -266,10 +266,10 @@ impl<G: Group> SumcheckProof<G> {
|
||||
};
|
||||
|
||||
// append the prover's message to the transcript
|
||||
poly.append_to_transcript(b"poly", transcript);
|
||||
transcript.absorb(b"p", &poly);
|
||||
|
||||
//derive the verifier's challenge for the next round
|
||||
let r_i = G::Scalar::challenge(b"challenge", transcript)?;
|
||||
let r_i = transcript.squeeze(b"c")?;
|
||||
r.push(r_i);
|
||||
polys.push(poly.compress());
|
||||
|
||||
@@ -396,12 +396,9 @@ impl<G: Group> CompressedUniPoly<G> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> AppendToTranscriptTrait<G> for UniPoly<G> {
|
||||
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut G::TE) {
|
||||
<[G::Scalar] as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&self.coeffs,
|
||||
label,
|
||||
transcript,
|
||||
);
|
||||
impl<G: Group> TranscriptReprTrait<G> for UniPoly<G> {
|
||||
fn to_transcript_bytes(&self) -> Vec<u8> {
|
||||
let coeffs = self.compress().coeffs_except_linear_term;
|
||||
coeffs.as_slice().to_transcript_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//! We require the commitment engine to provide a commitment to vectors with a single group element
|
||||
use crate::{
|
||||
errors::NovaError,
|
||||
traits::{AbsorbInROTrait, AppendToTranscriptTrait, Group},
|
||||
traits::{AbsorbInROTrait, Group, TranscriptReprTrait},
|
||||
};
|
||||
use core::{
|
||||
fmt::Debug,
|
||||
@@ -65,10 +65,10 @@ pub trait CommitmentTrait<G: Group>:
|
||||
+ Eq
|
||||
+ Send
|
||||
+ Sync
|
||||
+ TranscriptReprTrait<G>
|
||||
+ Serialize
|
||||
+ for<'de> Deserialize<'de>
|
||||
+ AbsorbInROTrait<G>
|
||||
+ AppendToTranscriptTrait<G>
|
||||
+ CommitmentOps
|
||||
+ CommitmentOpsOwned
|
||||
+ ScalarMul<G::Scalar>
|
||||
@@ -80,9 +80,9 @@ pub trait CommitmentTrait<G: Group>:
|
||||
+ Eq
|
||||
+ Send
|
||||
+ Sync
|
||||
+ TranscriptReprTrait<G>
|
||||
+ Serialize
|
||||
+ for<'de> Deserialize<'de>
|
||||
+ AppendToTranscriptTrait<G>;
|
||||
+ for<'de> Deserialize<'de>;
|
||||
|
||||
/// Compresses self into a compressed commitment
|
||||
fn compress(&self) -> Self::CompressedCommitment;
|
||||
|
||||
@@ -34,15 +34,19 @@ pub trait Group:
|
||||
+ for<'de> Deserialize<'de>
|
||||
{
|
||||
/// A type representing an element of the base field of the group
|
||||
type Base: PrimeField + PrimeFieldBits + Serialize + for<'de> Deserialize<'de>;
|
||||
type Base: PrimeField
|
||||
+ PrimeFieldBits
|
||||
+ TranscriptReprTrait<Self>
|
||||
+ Serialize
|
||||
+ for<'de> Deserialize<'de>;
|
||||
|
||||
/// A type representing an element of the scalar field of the group
|
||||
type Scalar: PrimeField
|
||||
+ PrimeFieldBits
|
||||
+ PrimeFieldExt
|
||||
+ ChallengeTrait<Self>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ TranscriptReprTrait<Self>
|
||||
+ Serialize
|
||||
+ for<'de> Deserialize<'de>;
|
||||
|
||||
@@ -97,16 +101,23 @@ pub trait Group:
|
||||
|
||||
/// Represents a compressed version of a group element
|
||||
pub trait CompressedGroup:
|
||||
Clone + Copy + Debug + Eq + Sized + Send + Sync + Serialize + for<'de> Deserialize<'de> + 'static
|
||||
Clone
|
||||
+ Copy
|
||||
+ Debug
|
||||
+ Eq
|
||||
+ Sized
|
||||
+ Send
|
||||
+ Sync
|
||||
+ TranscriptReprTrait<Self::GroupElement>
|
||||
+ Serialize
|
||||
+ for<'de> Deserialize<'de>
|
||||
+ 'static
|
||||
{
|
||||
/// A type that holds the decompressed version of the compressed group element
|
||||
type GroupElement: Group + Serialize + for<'de> Deserialize<'de>;
|
||||
|
||||
/// Decompresses the compressed group element
|
||||
fn decompress(&self) -> Option<Self::GroupElement>;
|
||||
|
||||
/// Returns a byte array representing the compressed group element
|
||||
fn as_bytes(&self) -> Vec<u8>;
|
||||
}
|
||||
|
||||
/// A helper trait to absorb different objects in RO
|
||||
@@ -196,56 +207,43 @@ impl<T, Rhs, Output> ScalarMul<Rhs, Output> for T where T: Mul<Rhs, Output = Out
|
||||
pub trait ScalarMulOwned<Rhs, Output = Self>: for<'r> ScalarMul<&'r Rhs, Output> {}
|
||||
impl<T, Rhs, Output> ScalarMulOwned<Rhs, Output> for T where T: for<'r> ScalarMul<&'r Rhs, Output> {}
|
||||
|
||||
/// This trait allows types to implement how they want to be added to TranscriptEngine
|
||||
pub trait TranscriptReprTrait<G: Group>: Send + Sync {
|
||||
/// returns a byte representation of self to be added to the transcript
|
||||
fn to_transcript_bytes(&self) -> Vec<u8>;
|
||||
}
|
||||
|
||||
/// This trait defines the behavior of a transcript engine compatible with Spartan
|
||||
pub trait TranscriptEngineTrait<G: Group>: Send + Sync {
|
||||
/// initializes the transcript
|
||||
fn new(label: &'static [u8]) -> Self;
|
||||
|
||||
/// returns a scalar element of the group as a challenge
|
||||
fn squeeze_scalar(&mut self, label: &'static [u8]) -> Result<G::Scalar, NovaError>;
|
||||
fn squeeze(&mut self, label: &'static [u8]) -> Result<G::Scalar, NovaError>;
|
||||
|
||||
/// absorbs a label and a sequence of bytes
|
||||
fn absorb_bytes(&mut self, label: &'static [u8], bytes: &[u8]);
|
||||
}
|
||||
/// absorbs any type that implements TranscriptReprTrait under a label
|
||||
fn absorb<T: TranscriptReprTrait<G>>(&mut self, label: &'static [u8], o: &T);
|
||||
|
||||
/// A helper trait to append different types to the transcript
|
||||
pub trait AppendToTranscriptTrait<G: Group> {
|
||||
/// appends the value to the transcript under the provided label
|
||||
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut G::TE);
|
||||
}
|
||||
|
||||
/// A helper trait to generate challenges using a transcript object
|
||||
pub trait ChallengeTrait<G: Group> {
|
||||
/// Returns a challenge from the transcript
|
||||
fn challenge(label: &'static [u8], transcript: &mut G::TE) -> Result<Self, NovaError>
|
||||
where
|
||||
Self: Sized;
|
||||
/// adds a domain separator
|
||||
fn dom_sep(&mut self, bytes: &'static [u8]);
|
||||
}
|
||||
|
||||
/// Defines additional methods on PrimeField objects
|
||||
pub trait PrimeFieldExt: PrimeField {
|
||||
/// Returns a scalar representing the bytes
|
||||
fn from_uniform(bytes: &[u8]) -> Self;
|
||||
|
||||
/// Returns a vector of bytes representing the scalar
|
||||
fn to_bytes(&self) -> Vec<u8>;
|
||||
}
|
||||
|
||||
impl<G: Group<Scalar = F>, F: PrimeField + PrimeFieldExt> AppendToTranscriptTrait<G> for F {
|
||||
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut G::TE) {
|
||||
transcript.absorb_bytes(label, &<Self as PrimeFieldExt>::to_bytes(self));
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group<Scalar = F>, F: PrimeField + PrimeFieldExt> AppendToTranscriptTrait<G> for [F] {
|
||||
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut G::TE) {
|
||||
let bytes = (0..self.len())
|
||||
.map(|i| <F as PrimeFieldExt>::to_bytes(&self[i]))
|
||||
impl<G: Group<Scalar = F>, F: PrimeField + TranscriptReprTrait<G>> TranscriptReprTrait<G>
|
||||
for &[F]
|
||||
{
|
||||
fn to_transcript_bytes(&self) -> Vec<u8> {
|
||||
(0..self.len())
|
||||
.map(|i| <F as TranscriptReprTrait<G>>::to_transcript_bytes(&self[i]))
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<u8>>();
|
||||
transcript.absorb_bytes(label, &bytes);
|
||||
.collect::<Vec<u8>>()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user