mirror of
https://github.com/arnaucube/Nova.git
synced 2026-01-11 08:31:29 +01:00
Make code generic over a TranscriptEngine (#139)
This commit is contained in:
@@ -13,7 +13,6 @@ keywords = ["zkSNARKs", "cryptography", "proofs"]
|
||||
[dependencies]
|
||||
bellperson = { version = "0.24", default-features = false }
|
||||
ff = { version = "0.12.0", features = ["derive"] }
|
||||
merlin = {version = "3.0.0", default-features = false }
|
||||
digest = "0.8.1"
|
||||
sha3 = "0.8.2"
|
||||
rayon = "1.3.0"
|
||||
@@ -40,6 +39,7 @@ pasta-msm = { version = "0.1.0", package = "lurk-pasta-msm" }
|
||||
[dev-dependencies]
|
||||
criterion = "0.3.1"
|
||||
rand = "0.8.4"
|
||||
hex = "0.4.3"
|
||||
|
||||
[[bench]]
|
||||
name = "recursive-snark"
|
||||
|
||||
@@ -41,4 +41,7 @@ pub enum NovaError {
|
||||
/// returned when the step execution produces an output whose length differs from a previously declared arity
|
||||
#[error("InvalidStepOutputLength")]
|
||||
InvalidStepOutputLength,
|
||||
/// returned when the transcript engine encounters an overflow of the round number
|
||||
#[error("InternalTranscriptError")]
|
||||
InternalTranscriptError,
|
||||
}
|
||||
|
||||
@@ -7,13 +7,12 @@ use crate::{
|
||||
traits::{
|
||||
commitment::{CommitmentEngineTrait, CommitmentGensTrait, CommitmentTrait},
|
||||
evaluation::EvaluationEngineTrait,
|
||||
AppendToTranscriptTrait, ChallengeTrait, Group,
|
||||
AppendToTranscriptTrait, ChallengeTrait, Group, TranscriptEngineTrait,
|
||||
},
|
||||
Commitment, CommitmentGens, CompressedCommitment, CE,
|
||||
};
|
||||
use core::{cmp::max, iter};
|
||||
use ff::Field;
|
||||
use merlin::Transcript;
|
||||
use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::marker::PhantomData;
|
||||
@@ -58,7 +57,7 @@ where
|
||||
|
||||
fn prove_batch(
|
||||
gens: &Self::EvaluationGens,
|
||||
transcript: &mut Transcript,
|
||||
transcript: &mut G::TE,
|
||||
comms: &[Commitment<G>],
|
||||
polys: &[Vec<G::Scalar>],
|
||||
points: &[Vec<G::Scalar>],
|
||||
@@ -89,7 +88,7 @@ where
|
||||
),
|
||||
&InnerProductWitness::new(&polys[i]),
|
||||
transcript,
|
||||
);
|
||||
)?;
|
||||
nifs.push(n);
|
||||
r_U = u;
|
||||
r_W = w;
|
||||
@@ -103,7 +102,7 @@ where
|
||||
/// A method to verify purported evaluations of a batch of polynomials
|
||||
fn verify_batch(
|
||||
gens: &Self::EvaluationGens,
|
||||
transcript: &mut Transcript,
|
||||
transcript: &mut G::TE,
|
||||
comms: &[Commitment<G>],
|
||||
points: &[Vec<G::Scalar>],
|
||||
evals: &[G::Scalar],
|
||||
@@ -129,7 +128,7 @@ where
|
||||
&evals[i],
|
||||
),
|
||||
transcript,
|
||||
);
|
||||
)?;
|
||||
r_U = u;
|
||||
num_vars = max(num_vars, points[i].len());
|
||||
}
|
||||
@@ -219,9 +218,9 @@ impl<G: Group> NIFSForInnerProduct<G> {
|
||||
W1: &InnerProductWitness<G>,
|
||||
U2: &InnerProductInstance<G>,
|
||||
W2: &InnerProductWitness<G>,
|
||||
transcript: &mut Transcript,
|
||||
) -> (Self, InnerProductInstance<G>, InnerProductWitness<G>) {
|
||||
transcript.append_message(b"protocol-name", Self::protocol_name());
|
||||
transcript: &mut G::TE,
|
||||
) -> Result<(Self, InnerProductInstance<G>, InnerProductWitness<G>), NovaError> {
|
||||
transcript.absorb_bytes(b"protocol-name", Self::protocol_name());
|
||||
|
||||
// pad the instances and witness so they are of the same length
|
||||
let U1 = U1.pad(max(U1.b_vec.len(), U2.b_vec.len()));
|
||||
@@ -230,21 +229,25 @@ impl<G: Group> NIFSForInnerProduct<G> {
|
||||
let W2 = W2.pad(max(U1.b_vec.len(), U2.b_vec.len()));
|
||||
|
||||
// add the two commitments and two public vectors to the transcript
|
||||
// we do not need to add public vectors as their compressed versions were
|
||||
// read from the transcript
|
||||
U1.comm_a_vec
|
||||
.append_to_transcript(b"U1_comm_a_vec", transcript);
|
||||
U1.b_vec.append_to_transcript(b"U1_b_vec", transcript);
|
||||
U2.comm_a_vec
|
||||
.append_to_transcript(b"U2_comm_a_vec", transcript);
|
||||
U2.b_vec.append_to_transcript(b"U2_b_vec", transcript);
|
||||
|
||||
// compute the cross-term
|
||||
let cross_term = inner_product(&W1.a_vec, &U2.b_vec) + inner_product(&W2.a_vec, &U1.b_vec);
|
||||
|
||||
// add the cross-term to the transcript
|
||||
cross_term.append_to_transcript(b"cross_term", transcript);
|
||||
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&cross_term,
|
||||
b"cross_term",
|
||||
transcript,
|
||||
);
|
||||
|
||||
// obtain a random challenge
|
||||
let r = G::Scalar::challenge(b"r", transcript);
|
||||
let r = G::Scalar::challenge(b"r", transcript)?;
|
||||
|
||||
// fold the vectors and their inner product
|
||||
let a_vec = W1
|
||||
@@ -270,36 +273,38 @@ impl<G: Group> NIFSForInnerProduct<G> {
|
||||
c,
|
||||
};
|
||||
|
||||
(NIFSForInnerProduct { cross_term }, U, W)
|
||||
Ok((NIFSForInnerProduct { cross_term }, U, W))
|
||||
}
|
||||
|
||||
fn verify(
|
||||
&self,
|
||||
U1: &InnerProductInstance<G>,
|
||||
U2: &InnerProductInstance<G>,
|
||||
transcript: &mut Transcript,
|
||||
) -> InnerProductInstance<G> {
|
||||
transcript.append_message(b"protocol-name", Self::protocol_name());
|
||||
transcript: &mut G::TE,
|
||||
) -> Result<InnerProductInstance<G>, NovaError> {
|
||||
transcript.absorb_bytes(b"protocol-name", Self::protocol_name());
|
||||
|
||||
// pad the instances so they are of the same length
|
||||
let U1 = U1.pad(max(U1.b_vec.len(), U2.b_vec.len()));
|
||||
let U2 = U2.pad(max(U1.b_vec.len(), U2.b_vec.len()));
|
||||
|
||||
// add the two commitments and two public vectors to the transcript
|
||||
// we do not need to add public vectors as their compressed representation
|
||||
// were derived from the transcript
|
||||
U1.comm_a_vec
|
||||
.append_to_transcript(b"U1_comm_a_vec", transcript);
|
||||
U1.b_vec.append_to_transcript(b"U1_b_vec", transcript);
|
||||
U2.comm_a_vec
|
||||
.append_to_transcript(b"U2_comm_a_vec", transcript);
|
||||
U2.b_vec.append_to_transcript(b"U2_b_vec", transcript);
|
||||
|
||||
// add the cross-term to the transcript
|
||||
self
|
||||
.cross_term
|
||||
.append_to_transcript(b"cross_term", transcript);
|
||||
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&self.cross_term,
|
||||
b"cross_term",
|
||||
transcript,
|
||||
);
|
||||
|
||||
// obtain a random challenge
|
||||
let r = G::Scalar::challenge(b"r", transcript);
|
||||
let r = G::Scalar::challenge(b"r", transcript)?;
|
||||
|
||||
// fold the vectors and their inner product
|
||||
let b_vec = U1
|
||||
@@ -311,11 +316,11 @@ impl<G: Group> NIFSForInnerProduct<G> {
|
||||
let c = U1.c + r * r * U2.c + r * self.cross_term;
|
||||
let comm_a_vec = U1.comm_a_vec + U2.comm_a_vec * r;
|
||||
|
||||
InnerProductInstance {
|
||||
Ok(InnerProductInstance {
|
||||
comm_a_vec,
|
||||
b_vec,
|
||||
c,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,27 +348,26 @@ where
|
||||
gens_c: &CommitmentGens<G>,
|
||||
U: &InnerProductInstance<G>,
|
||||
W: &InnerProductWitness<G>,
|
||||
transcript: &mut Transcript,
|
||||
transcript: &mut G::TE,
|
||||
) -> Result<Self, NovaError> {
|
||||
transcript.append_message(b"protocol-name", Self::protocol_name());
|
||||
transcript.absorb_bytes(b"protocol-name", 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);
|
||||
U.b_vec.append_to_transcript(b"b_vec", transcript);
|
||||
U.c.append_to_transcript(b"c", transcript);
|
||||
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(&U.c, b"c", transcript);
|
||||
|
||||
// sample a random base for commiting to the inner product
|
||||
let r = G::Scalar::challenge(b"r", transcript);
|
||||
let r = G::Scalar::challenge(b"r", transcript)?;
|
||||
let gens_c = gens_c.scale(&r);
|
||||
|
||||
// a closure that executes a step of the recursive inner product argument
|
||||
let prove_inner = |a_vec: &[G::Scalar],
|
||||
b_vec: &[G::Scalar],
|
||||
gens: &CommitmentGens<G>,
|
||||
transcript: &mut Transcript|
|
||||
transcript: &mut G::TE|
|
||||
-> Result<
|
||||
(
|
||||
CompressedCommitment<G>,
|
||||
@@ -402,7 +406,7 @@ where
|
||||
L.append_to_transcript(b"L", transcript);
|
||||
R.append_to_transcript(b"R", transcript);
|
||||
|
||||
let r = G::Scalar::challenge(b"challenge_r", transcript);
|
||||
let r = G::Scalar::challenge(b"challenge_r", transcript)?;
|
||||
let r_inverse = r.invert().unwrap();
|
||||
|
||||
// fold the left half and the right half
|
||||
@@ -456,9 +460,9 @@ where
|
||||
gens_c: &CommitmentGens<G>,
|
||||
n: usize,
|
||||
U: &InnerProductInstance<G>,
|
||||
transcript: &mut Transcript,
|
||||
transcript: &mut G::TE,
|
||||
) -> Result<(), NovaError> {
|
||||
transcript.append_message(b"protocol-name", Self::protocol_name());
|
||||
transcript.absorb_bytes(b"protocol-name", Self::protocol_name());
|
||||
if U.b_vec.len() != n
|
||||
|| n != (1 << self.L_vec.len())
|
||||
|| self.L_vec.len() != self.R_vec.len()
|
||||
@@ -468,11 +472,10 @@ where
|
||||
}
|
||||
|
||||
U.comm_a_vec.append_to_transcript(b"comm_a_vec", transcript);
|
||||
U.b_vec.append_to_transcript(b"b_vec", transcript);
|
||||
U.c.append_to_transcript(b"c", transcript);
|
||||
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(&U.c, b"c", transcript);
|
||||
|
||||
// sample a random base for commiting to the inner product
|
||||
let r = G::Scalar::challenge(b"r", transcript);
|
||||
let r = G::Scalar::challenge(b"r", transcript)?;
|
||||
let gens_c = gens_c.scale(&r);
|
||||
|
||||
let P = U.comm_a_vec + CE::<G>::commit(&gens_c, &[U.c]);
|
||||
@@ -511,7 +514,7 @@ where
|
||||
self.R_vec[i].append_to_transcript(b"R", transcript);
|
||||
G::Scalar::challenge(b"challenge_r", transcript)
|
||||
})
|
||||
.collect::<Vec<G::Scalar>>();
|
||||
.collect::<Result<Vec<G::Scalar>, NovaError>>()?;
|
||||
|
||||
// precompute scalars necessary for verification
|
||||
let r_square: Vec<G::Scalar> = (0..self.L_vec.len())
|
||||
|
||||
160
src/provider/keccak.rs
Normal file
160
src/provider/keccak.rs
Normal file
@@ -0,0 +1,160 @@
|
||||
//! This module provides an implementation of TranscriptEngineTrait using keccak256
|
||||
use crate::traits::PrimeFieldExt;
|
||||
use crate::{
|
||||
errors::NovaError,
|
||||
traits::{Group, TranscriptEngineTrait},
|
||||
};
|
||||
use core::marker::PhantomData;
|
||||
use sha3::{Digest, Keccak256};
|
||||
|
||||
const PERSONA_TAG: &[u8] = b"NovaTranscript";
|
||||
const DOM_SEP_TAG: &[u8] = b"NovaRound";
|
||||
const KECCAK256_STATE_SIZE: usize = 64;
|
||||
const KECCAK256_PREFIX_CHALLENGE_LO: u8 = 0;
|
||||
const KECCAK256_PREFIX_CHALLENGE_HI: u8 = 1;
|
||||
|
||||
/// Provides an implementation of TranscriptEngine
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Keccak256Transcript<G: Group> {
|
||||
round: u16,
|
||||
state: [u8; KECCAK256_STATE_SIZE],
|
||||
transcript: Vec<u8>,
|
||||
_p: PhantomData<G>,
|
||||
}
|
||||
|
||||
fn compute_updated_state(input: &[u8]) -> [u8; KECCAK256_STATE_SIZE] {
|
||||
let input_lo = [input, &[KECCAK256_PREFIX_CHALLENGE_LO]].concat();
|
||||
let input_hi = [input, &[KECCAK256_PREFIX_CHALLENGE_HI]].concat();
|
||||
|
||||
let mut hasher_lo = Keccak256::new();
|
||||
let mut hasher_hi = Keccak256::new();
|
||||
|
||||
hasher_lo.input(&input_lo);
|
||||
hasher_hi.input(&input_hi);
|
||||
|
||||
let output_lo = hasher_lo.result();
|
||||
let output_hi = hasher_hi.result();
|
||||
|
||||
[output_lo, output_hi]
|
||||
.concat()
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
impl<G: Group> TranscriptEngineTrait<G> for Keccak256Transcript<G> {
|
||||
fn new(label: &'static [u8]) -> Self {
|
||||
let input = [PERSONA_TAG, label].concat();
|
||||
let output = compute_updated_state(&input);
|
||||
|
||||
Self {
|
||||
round: 0u16,
|
||||
state: output,
|
||||
transcript: vec![],
|
||||
_p: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn squeeze_scalar(&mut self, label: &'static [u8]) -> Result<G::Scalar, NovaError> {
|
||||
let input = [
|
||||
DOM_SEP_TAG,
|
||||
self.round.to_le_bytes().as_ref(),
|
||||
self.state.as_ref(),
|
||||
self.transcript.as_ref(),
|
||||
label,
|
||||
]
|
||||
.concat();
|
||||
let output = compute_updated_state(&input);
|
||||
|
||||
// update state
|
||||
self.round = {
|
||||
if let Some(v) = self.round.checked_add(1) {
|
||||
v
|
||||
} else {
|
||||
return Err(NovaError::InternalTranscriptError);
|
||||
}
|
||||
};
|
||||
self.state.copy_from_slice(&output);
|
||||
self.transcript = vec![];
|
||||
|
||||
// squeeze out a challenge
|
||||
Ok(G::Scalar::from_uniform(&output))
|
||||
}
|
||||
|
||||
fn absorb_bytes(&mut self, label: &'static [u8], bytes: &[u8]) {
|
||||
self.transcript.extend_from_slice(label);
|
||||
self.transcript.extend_from_slice(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
provider::keccak::Keccak256Transcript,
|
||||
traits::{AppendToTranscriptTrait, ChallengeTrait, Group, TranscriptEngineTrait},
|
||||
};
|
||||
use ff::PrimeField;
|
||||
use sha3::{Digest, Keccak256};
|
||||
|
||||
type G = pasta_curves::pallas::Point;
|
||||
|
||||
#[test]
|
||||
fn test_keccak_transcript() {
|
||||
let mut transcript = 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,
|
||||
);
|
||||
|
||||
// make a challenge
|
||||
let c1 =
|
||||
<<G as Group>::Scalar as ChallengeTrait<G>>::challenge(b"challenge_c1", &mut transcript)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
hex::encode(c1.to_repr().as_ref()),
|
||||
"51648083af5387a04a7aa2aec789ee78fdabe45dc1391d270a38fcb576447c01"
|
||||
);
|
||||
|
||||
// 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,
|
||||
);
|
||||
|
||||
// make a challenge
|
||||
let c2 =
|
||||
<<G as Group>::Scalar as ChallengeTrait<G>>::challenge(b"challenge_c2", &mut transcript)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
hex::encode(c2.to_repr().as_ref()),
|
||||
"9773f3349f7308153f6012e72b97fc304e48372bbd28bd122b37a8e46855d50f"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_keccak_example() {
|
||||
let mut hasher = Keccak256::new();
|
||||
hasher.input(0xffffffff_u32.to_le_bytes());
|
||||
let output: [u8; 32] = hasher.result().try_into().unwrap();
|
||||
assert_eq!(
|
||||
hex::encode(output),
|
||||
"29045a592007d0c246ef02c2223570da9522d0cf0f73282c79a1bc8f0bb2c238"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
//! `EvaluationEngine` with an IPA-based polynomial evaluation argument
|
||||
|
||||
pub mod ipa_pc;
|
||||
pub mod keccak;
|
||||
pub mod pasta;
|
||||
pub mod pedersen;
|
||||
pub mod poseidon;
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
//! This module implements the Nova traits for pallas::Point, pallas::Scalar, vesta::Point, vesta::Scalar.
|
||||
use crate::{
|
||||
provider::{
|
||||
keccak::Keccak256Transcript,
|
||||
pedersen::CommitmentEngine,
|
||||
poseidon::{PoseidonRO, PoseidonROCircuit},
|
||||
},
|
||||
traits::{ChallengeTrait, CompressedGroup, Group},
|
||||
traits::{CompressedGroup, Group, PrimeFieldExt},
|
||||
};
|
||||
use digest::{ExtendableOutput, Input};
|
||||
use ff::Field;
|
||||
use merlin::Transcript;
|
||||
use num_bigint::BigInt;
|
||||
use num_traits::Num;
|
||||
use pasta_curves::{
|
||||
self,
|
||||
arithmetic::{CurveAffine, CurveExt, Group as OtherGroup},
|
||||
arithmetic::{CurveAffine, CurveExt, FieldExt, Group as OtherGroup},
|
||||
group::{cofactor::CofactorCurveAffine, Curve, Group as AnotherGroup, GroupEncoding},
|
||||
pallas, vesta, Ep, EpAffine, Eq, EqAffine,
|
||||
};
|
||||
use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng};
|
||||
use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha3::Shake256;
|
||||
@@ -64,6 +62,7 @@ macro_rules! impl_traits {
|
||||
type PreprocessedGroupElement = $name::Affine;
|
||||
type RO = PoseidonRO<Self::Base, Self::Scalar>;
|
||||
type ROCircuit = PoseidonROCircuit<Self::Base>;
|
||||
type TE = Keccak256Transcript<Self>;
|
||||
type CE = CommitmentEngine<Self>;
|
||||
|
||||
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
|
||||
@@ -171,12 +170,10 @@ macro_rules! impl_traits {
|
||||
}
|
||||
}
|
||||
|
||||
impl ChallengeTrait for $name::Scalar {
|
||||
fn challenge(label: &'static [u8], transcript: &mut Transcript) -> Self {
|
||||
let mut key: <ChaCha20Rng as SeedableRng>::Seed = Default::default();
|
||||
transcript.challenge_bytes(label, &mut key);
|
||||
let mut rng = ChaCha20Rng::from_seed(key);
|
||||
$name::Scalar::random(&mut rng)
|
||||
impl PrimeFieldExt for $name::Scalar {
|
||||
fn from_uniform(bytes: &[u8]) -> Self {
|
||||
let bytes_arr: [u8; 64] = bytes.try_into().unwrap();
|
||||
$name::Scalar::from_bytes_wide(&bytes_arr)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::{
|
||||
CommitmentEngineTrait, CommitmentGensTrait, CommitmentTrait, CompressedCommitmentTrait,
|
||||
},
|
||||
AbsorbInROTrait, AppendToTranscriptTrait, CompressedGroup, Group, ROTrait,
|
||||
TranscriptEngineTrait,
|
||||
},
|
||||
};
|
||||
use core::{
|
||||
@@ -13,8 +14,7 @@ use core::{
|
||||
marker::PhantomData,
|
||||
ops::{Add, AddAssign, Mul, MulAssign},
|
||||
};
|
||||
use ff::Field;
|
||||
use merlin::Transcript;
|
||||
use ff::{Field, PrimeField};
|
||||
use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -96,9 +96,17 @@ impl<C: CompressedGroup> CompressedCommitmentTrait<C> for CompressedCommitment<C
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> AppendToTranscriptTrait for Commitment<G> {
|
||||
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut Transcript) {
|
||||
transcript.append_message(label, self.comm.compress().as_bytes());
|
||||
impl<G: Group> AppendToTranscriptTrait<G> for Commitment<G> {
|
||||
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut G::TE) {
|
||||
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],
|
||||
]
|
||||
.concat();
|
||||
transcript.absorb_bytes(label, &bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,9 +123,16 @@ impl<G: Group> AbsorbInROTrait<G> for Commitment<G> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: CompressedGroup> AppendToTranscriptTrait for CompressedCommitment<C> {
|
||||
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut Transcript) {
|
||||
transcript.append_message(label, self.comm.as_bytes());
|
||||
impl<C: CompressedGroup> AppendToTranscriptTrait<C::GroupElement> for CompressedCommitment<C> {
|
||||
fn append_to_transcript(
|
||||
&self,
|
||||
label: &'static [u8],
|
||||
transcript: &mut <C::GroupElement as Group>::TE,
|
||||
) {
|
||||
let comm = self.decompress().unwrap();
|
||||
<Commitment<C::GroupElement> as AppendToTranscriptTrait<C::GroupElement>>::append_to_transcript(
|
||||
&comm, label, transcript,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
27
src/r1cs.rs
27
src/r1cs.rs
@@ -17,7 +17,6 @@ use core::cmp::max;
|
||||
use ff::Field;
|
||||
use flate2::{write::ZlibEncoder, Compression};
|
||||
use itertools::concat;
|
||||
use merlin::Transcript;
|
||||
use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha3::{Digest, Sha3_256};
|
||||
@@ -440,11 +439,13 @@ impl<G: Group> R1CSShape<G> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> AppendToTranscriptTrait for R1CSShape<G> {
|
||||
fn append_to_transcript(&self, _label: &'static [u8], transcript: &mut Transcript) {
|
||||
self
|
||||
.get_digest()
|
||||
.append_to_transcript(b"R1CSShape", transcript);
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,10 +489,10 @@ impl<G: Group> R1CSInstance<G> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> AppendToTranscriptTrait for R1CSInstance<G> {
|
||||
fn append_to_transcript(&self, _label: &'static [u8], transcript: &mut Transcript) {
|
||||
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);
|
||||
self.X.append_to_transcript(b"X", transcript);
|
||||
<[G::Scalar] as AppendToTranscriptTrait<G>>::append_to_transcript(&self.X, b"X", transcript);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -629,12 +630,12 @@ impl<G: Group> RelaxedR1CSInstance<G> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> AppendToTranscriptTrait for RelaxedR1CSInstance<G> {
|
||||
fn append_to_transcript(&self, _label: &'static [u8], transcript: &mut Transcript) {
|
||||
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);
|
||||
self.u.append_to_transcript(b"u", transcript);
|
||||
self.X.append_to_transcript(b"X", 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,12 +9,11 @@ use crate::{
|
||||
traits::{
|
||||
evaluation::EvaluationEngineTrait,
|
||||
snark::{ProverKeyTrait, RelaxedR1CSSNARKTrait, VerifierKeyTrait},
|
||||
AppendToTranscriptTrait, ChallengeTrait, Group,
|
||||
AppendToTranscriptTrait, ChallengeTrait, Group, TranscriptEngineTrait,
|
||||
},
|
||||
};
|
||||
use ff::Field;
|
||||
use itertools::concat;
|
||||
use merlin::Transcript;
|
||||
use polynomial::{EqPolynomial, MultilinearPolynomial, SparsePolynomial};
|
||||
use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -82,7 +81,7 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
U: &RelaxedR1CSInstance<G>,
|
||||
W: &RelaxedR1CSWitness<G>,
|
||||
) -> Result<Self, NovaError> {
|
||||
let mut transcript = Transcript::new(b"RelaxedR1CSSNARK");
|
||||
let mut transcript = G::TE::new(b"RelaxedR1CSSNARK");
|
||||
|
||||
// sanity check that R1CSShape has certain size characteristics
|
||||
assert_eq!(pk.S.num_cons.next_power_of_two(), pk.S.num_cons);
|
||||
@@ -105,7 +104,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"challenge_tau", &mut transcript))
|
||||
.collect();
|
||||
.collect::<Result<Vec<G::Scalar>, NovaError>>()?;
|
||||
|
||||
let mut poly_tau = MultilinearPolynomial::new(EqPolynomial::new(tau).evals());
|
||||
let (mut poly_Az, mut poly_Bz, poly_Cz, mut poly_uCz_E) = {
|
||||
@@ -136,22 +135,39 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
&mut poly_uCz_E,
|
||||
comb_func_outer,
|
||||
&mut transcript,
|
||||
);
|
||||
)?;
|
||||
|
||||
// claims from the end of sum-check
|
||||
let (claim_Az, claim_Bz): (G::Scalar, G::Scalar) = (claims_outer[1], claims_outer[2]);
|
||||
|
||||
claim_Az.append_to_transcript(b"claim_Az", &mut transcript);
|
||||
claim_Bz.append_to_transcript(b"claim_Bz", &mut transcript);
|
||||
let claim_Cz = poly_Cz.evaluate(&r_x);
|
||||
|
||||
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&claim_Az,
|
||||
b"claim_Az",
|
||||
&mut transcript,
|
||||
);
|
||||
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&claim_Bz,
|
||||
b"claim_Bz",
|
||||
&mut transcript,
|
||||
);
|
||||
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&claim_Cz,
|
||||
b"claim_Cz",
|
||||
&mut transcript,
|
||||
);
|
||||
|
||||
let eval_E = MultilinearPolynomial::new(W.E.clone()).evaluate(&r_x);
|
||||
claim_Cz.append_to_transcript(b"claim_Cz", &mut transcript);
|
||||
eval_E.append_to_transcript(b"eval_E", &mut transcript);
|
||||
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&eval_E,
|
||||
b"eval_E",
|
||||
&mut transcript,
|
||||
);
|
||||
|
||||
// inner sum-check
|
||||
let r_A = G::Scalar::challenge(b"challenge_rA", &mut transcript);
|
||||
let r_B = G::Scalar::challenge(b"challenge_rB", &mut transcript);
|
||||
let r_C = G::Scalar::challenge(b"challenge_rC", &mut transcript);
|
||||
let r_A = G::Scalar::challenge(b"challenge_rA", &mut transcript)?;
|
||||
let r_B = G::Scalar::challenge(b"challenge_rB", &mut transcript)?;
|
||||
let r_C = G::Scalar::challenge(b"challenge_rC", &mut transcript)?;
|
||||
let claim_inner_joint = r_A * claim_Az + r_B * claim_Bz + r_C * claim_Cz;
|
||||
|
||||
let poly_ABC = {
|
||||
@@ -219,10 +235,14 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
&mut MultilinearPolynomial::new(poly_z),
|
||||
comb_func,
|
||||
&mut transcript,
|
||||
);
|
||||
)?;
|
||||
|
||||
let eval_W = MultilinearPolynomial::new(W.W.clone()).evaluate(&r_y[1..]);
|
||||
eval_W.append_to_transcript(b"eval_W", &mut transcript);
|
||||
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&eval_W,
|
||||
b"eval_W",
|
||||
&mut transcript,
|
||||
);
|
||||
|
||||
let eval_arg = EE::prove_batch(
|
||||
&pk.gens,
|
||||
@@ -245,7 +265,7 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
|
||||
/// verifies a proof of satisfiability of a RelaxedR1CS instance
|
||||
fn verify(&self, vk: &Self::VerifierKey, U: &RelaxedR1CSInstance<G>) -> Result<(), NovaError> {
|
||||
let mut transcript = Transcript::new(b"RelaxedR1CSSNARK");
|
||||
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);
|
||||
@@ -259,7 +279,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"challenge_tau", &mut transcript))
|
||||
.collect::<Vec<G::Scalar>>();
|
||||
.collect::<Result<Vec<G::Scalar>, NovaError>>()?;
|
||||
|
||||
let (claim_outer_final, r_x) =
|
||||
self
|
||||
@@ -275,24 +295,31 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
return Err(NovaError::InvalidSumcheckProof);
|
||||
}
|
||||
|
||||
self
|
||||
.claims_outer
|
||||
.0
|
||||
.append_to_transcript(b"claim_Az", &mut transcript);
|
||||
self
|
||||
.claims_outer
|
||||
.1
|
||||
.append_to_transcript(b"claim_Bz", &mut transcript);
|
||||
self
|
||||
.claims_outer
|
||||
.2
|
||||
.append_to_transcript(b"claim_Cz", &mut transcript);
|
||||
self.eval_E.append_to_transcript(b"eval_E", &mut transcript);
|
||||
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&self.claims_outer.0,
|
||||
b"claim_Az",
|
||||
&mut transcript,
|
||||
);
|
||||
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&self.claims_outer.1,
|
||||
b"claim_Bz",
|
||||
&mut transcript,
|
||||
);
|
||||
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&self.claims_outer.2,
|
||||
b"claim_Cz",
|
||||
&mut transcript,
|
||||
);
|
||||
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&self.eval_E,
|
||||
b"eval_E",
|
||||
&mut transcript,
|
||||
);
|
||||
|
||||
// inner sum-check
|
||||
let r_A = G::Scalar::challenge(b"challenge_rA", &mut transcript);
|
||||
let r_B = G::Scalar::challenge(b"challenge_rB", &mut transcript);
|
||||
let r_C = G::Scalar::challenge(b"challenge_rC", &mut transcript);
|
||||
let r_A = G::Scalar::challenge(b"challenge_rA", &mut transcript)?;
|
||||
let r_B = G::Scalar::challenge(b"challenge_rB", &mut transcript)?;
|
||||
let r_C = G::Scalar::challenge(b"challenge_rC", &mut transcript)?;
|
||||
let claim_inner_joint =
|
||||
r_A * self.claims_outer.0 + r_B * self.claims_outer.1 + r_C * self.claims_outer.2;
|
||||
|
||||
@@ -346,7 +373,11 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
}
|
||||
|
||||
// verify eval_W and eval_E
|
||||
self.eval_W.append_to_transcript(b"eval_W", &mut transcript); //eval_E is already in the transcript
|
||||
<G::Scalar as AppendToTranscriptTrait<G>>::append_to_transcript(
|
||||
&self.eval_W,
|
||||
b"eval_W",
|
||||
&mut transcript,
|
||||
); //eval_E is already in the transcript
|
||||
|
||||
EE::verify_batch(
|
||||
&vk.gens,
|
||||
|
||||
@@ -5,7 +5,6 @@ use crate::errors::NovaError;
|
||||
use crate::traits::{AppendToTranscriptTrait, ChallengeTrait, Group};
|
||||
use core::marker::PhantomData;
|
||||
use ff::Field;
|
||||
use merlin::Transcript;
|
||||
use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -21,7 +20,7 @@ impl<G: Group> SumcheckProof<G> {
|
||||
claim: G::Scalar,
|
||||
num_rounds: usize,
|
||||
degree_bound: usize,
|
||||
transcript: &mut Transcript,
|
||||
transcript: &mut G::TE,
|
||||
) -> Result<(G::Scalar, Vec<G::Scalar>), NovaError> {
|
||||
let mut e = claim;
|
||||
let mut r: Vec<G::Scalar> = Vec::new();
|
||||
@@ -48,7 +47,7 @@ impl<G: Group> SumcheckProof<G> {
|
||||
poly.append_to_transcript(b"poly", transcript);
|
||||
|
||||
//derive the verifier's challenge for the next round
|
||||
let r_i = G::Scalar::challenge(b"challenge_nextround", transcript);
|
||||
let r_i = G::Scalar::challenge(b"challenge_nextround", transcript)?;
|
||||
|
||||
r.push(r_i);
|
||||
|
||||
@@ -65,8 +64,8 @@ impl<G: Group> SumcheckProof<G> {
|
||||
poly_A: &mut MultilinearPolynomial<G::Scalar>,
|
||||
poly_B: &mut MultilinearPolynomial<G::Scalar>,
|
||||
comb_func: F,
|
||||
transcript: &mut Transcript,
|
||||
) -> (Self, Vec<G::Scalar>, Vec<G::Scalar>)
|
||||
transcript: &mut G::TE,
|
||||
) -> Result<(Self, Vec<G::Scalar>, Vec<G::Scalar>), NovaError>
|
||||
where
|
||||
F: Fn(&G::Scalar, &G::Scalar) -> G::Scalar + Sync,
|
||||
{
|
||||
@@ -103,7 +102,7 @@ impl<G: Group> SumcheckProof<G> {
|
||||
poly.append_to_transcript(b"poly", transcript);
|
||||
|
||||
//derive the verifier's challenge for the next round
|
||||
let r_i = G::Scalar::challenge(b"challenge_nextround", transcript);
|
||||
let r_i = G::Scalar::challenge(b"challenge_nextround", transcript)?;
|
||||
r.push(r_i);
|
||||
polys.push(poly.compress());
|
||||
|
||||
@@ -115,13 +114,13 @@ impl<G: Group> SumcheckProof<G> {
|
||||
poly_B.bound_poly_var_top(&r_i);
|
||||
}
|
||||
|
||||
(
|
||||
Ok((
|
||||
SumcheckProof {
|
||||
compressed_polys: polys,
|
||||
},
|
||||
r,
|
||||
vec![poly_A[0], poly_B[0]],
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
pub fn prove_cubic_with_additive_term<F>(
|
||||
@@ -132,8 +131,8 @@ impl<G: Group> SumcheckProof<G> {
|
||||
poly_C: &mut MultilinearPolynomial<G::Scalar>,
|
||||
poly_D: &mut MultilinearPolynomial<G::Scalar>,
|
||||
comb_func: F,
|
||||
transcript: &mut Transcript,
|
||||
) -> (Self, Vec<G::Scalar>, Vec<G::Scalar>)
|
||||
transcript: &mut G::TE,
|
||||
) -> Result<(Self, Vec<G::Scalar>, Vec<G::Scalar>), NovaError>
|
||||
where
|
||||
F: Fn(&G::Scalar, &G::Scalar, &G::Scalar, &G::Scalar) -> G::Scalar + Sync,
|
||||
{
|
||||
@@ -195,7 +194,7 @@ impl<G: Group> SumcheckProof<G> {
|
||||
poly.append_to_transcript(b"poly", transcript);
|
||||
|
||||
//derive the verifier's challenge for the next round
|
||||
let r_i = G::Scalar::challenge(b"challenge_nextround", transcript);
|
||||
let r_i = G::Scalar::challenge(b"challenge_nextround", transcript)?;
|
||||
r.push(r_i);
|
||||
polys.push(poly.compress());
|
||||
|
||||
@@ -209,13 +208,13 @@ impl<G: Group> SumcheckProof<G> {
|
||||
poly_D.bound_poly_var_top(&r_i);
|
||||
}
|
||||
|
||||
(
|
||||
Ok((
|
||||
SumcheckProof {
|
||||
compressed_polys: polys,
|
||||
},
|
||||
r,
|
||||
vec![poly_A[0], poly_B[0], poly_C[0], poly_D[0]],
|
||||
)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,12 +321,12 @@ impl<G: Group> CompressedUniPoly<G> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> AppendToTranscriptTrait for UniPoly<G> {
|
||||
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut Transcript) {
|
||||
transcript.append_message(label, b"UniPoly_begin");
|
||||
for i in 0..self.coeffs.len() {
|
||||
self.coeffs[i].append_to_transcript(b"coeff", transcript);
|
||||
}
|
||||
transcript.append_message(label, b"UniPoly_end");
|
||||
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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ pub trait CommitmentTrait<G: Group>:
|
||||
+ Serialize
|
||||
+ for<'de> Deserialize<'de>
|
||||
+ AbsorbInROTrait<G>
|
||||
+ AppendToTranscriptTrait
|
||||
+ AppendToTranscriptTrait<G>
|
||||
+ CommitmentOps
|
||||
+ CommitmentOpsOwned
|
||||
+ ScalarMul<G::Scalar>
|
||||
@@ -96,7 +96,7 @@ pub trait CompressedCommitmentTrait<C: CompressedGroup>:
|
||||
+ Sync
|
||||
+ Serialize
|
||||
+ for<'de> Deserialize<'de>
|
||||
+ AppendToTranscriptTrait
|
||||
+ AppendToTranscriptTrait<C::GroupElement>
|
||||
{
|
||||
/// Holds the type of the commitment that can be decompressed into
|
||||
type Commitment;
|
||||
|
||||
@@ -5,7 +5,6 @@ use crate::{
|
||||
errors::NovaError,
|
||||
traits::{commitment::CommitmentEngineTrait, Group},
|
||||
};
|
||||
use merlin::Transcript;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// A trait that ties different pieces of the commitment evaluation together
|
||||
@@ -27,7 +26,7 @@ pub trait EvaluationEngineTrait<G: Group>:
|
||||
/// A method to prove evaluations of a batch of polynomials
|
||||
fn prove_batch(
|
||||
gens: &Self::EvaluationGens,
|
||||
transcript: &mut Transcript,
|
||||
transcript: &mut G::TE,
|
||||
comm: &[<Self::CE as CommitmentEngineTrait<G>>::Commitment],
|
||||
polys: &[Vec<G::Scalar>],
|
||||
points: &[Vec<G::Scalar>],
|
||||
@@ -37,7 +36,7 @@ pub trait EvaluationEngineTrait<G: Group>:
|
||||
/// A method to verify purported evaluations of a batch of polynomials
|
||||
fn verify_batch(
|
||||
gens: &Self::EvaluationGens,
|
||||
transcript: &mut Transcript,
|
||||
transcript: &mut G::TE,
|
||||
comm: &[<Self::CE as CommitmentEngineTrait<G>>::Commitment],
|
||||
points: &[Vec<G::Scalar>],
|
||||
evals: &[G::Scalar],
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//! This module defines various traits required by the users of the library to implement.
|
||||
use crate::errors::NovaError;
|
||||
use bellperson::{
|
||||
gadgets::{boolean::AllocatedBit, num::AllocatedNum},
|
||||
ConstraintSystem, SynthesisError,
|
||||
@@ -8,7 +9,6 @@ use core::{
|
||||
ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign},
|
||||
};
|
||||
use ff::{PrimeField, PrimeFieldBits};
|
||||
use merlin::Transcript;
|
||||
use num_bigint::BigInt;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -39,7 +39,8 @@ pub trait Group:
|
||||
/// A type representing an element of the scalar field of the group
|
||||
type Scalar: PrimeField
|
||||
+ PrimeFieldBits
|
||||
+ ChallengeTrait
|
||||
+ PrimeFieldExt
|
||||
+ ChallengeTrait<Self>
|
||||
+ Send
|
||||
+ Sync
|
||||
+ Serialize
|
||||
@@ -53,13 +54,16 @@ pub trait Group:
|
||||
/// A type representing preprocessed group element
|
||||
type PreprocessedGroupElement: Clone + Debug + Send + Sync + Serialize + for<'de> Deserialize<'de>;
|
||||
|
||||
/// A type that represents a hash function that consumes elements
|
||||
/// A type that represents a circuit-friendly sponge that consumes elements
|
||||
/// from the base field and squeezes out elements of the scalar field
|
||||
type RO: ROTrait<Self::Base, Self::Scalar> + Serialize + for<'de> Deserialize<'de>;
|
||||
|
||||
/// An alternate implementation of Self::RO in the circuit model
|
||||
type ROCircuit: ROCircuitTrait<Self::Base> + Serialize + for<'de> Deserialize<'de>;
|
||||
|
||||
/// A type that provides a generic Fiat-Shamir transcript to be used when externalizing proofs
|
||||
type TE: TranscriptEngineTrait<Self>;
|
||||
|
||||
/// A type that defines a commitment engine over scalars in the group
|
||||
type CE: CommitmentEngineTrait<Self> + Serialize + for<'de> Deserialize<'de>;
|
||||
|
||||
@@ -105,24 +109,12 @@ pub trait CompressedGroup:
|
||||
fn as_bytes(&self) -> &[u8];
|
||||
}
|
||||
|
||||
/// A helper trait to append different types to the transcript
|
||||
pub trait AppendToTranscriptTrait {
|
||||
/// appends the value to the transcript under the provided label
|
||||
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut Transcript);
|
||||
}
|
||||
|
||||
/// A helper trait to absorb different objects in RO
|
||||
pub trait AbsorbInROTrait<G: Group> {
|
||||
/// Absorbs the value in the provided RO
|
||||
fn absorb_in_ro(&self, ro: &mut G::RO);
|
||||
}
|
||||
|
||||
/// A helper trait to generate challenges using a transcript object
|
||||
pub trait ChallengeTrait {
|
||||
/// Returns a Scalar representing the challenge using the transcript
|
||||
fn challenge(label: &'static [u8], transcript: &mut Transcript) -> Self;
|
||||
}
|
||||
|
||||
/// A helper trait that defines the behavior of a hash function that we use as an RO
|
||||
pub trait ROTrait<Base, Scalar> {
|
||||
/// A type representing constants/parameters associated with the hash function
|
||||
@@ -204,17 +196,63 @@ 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> {}
|
||||
|
||||
impl<F: PrimeField> AppendToTranscriptTrait for F {
|
||||
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut Transcript) {
|
||||
transcript.append_message(label, self.to_repr().as_ref());
|
||||
/// 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>;
|
||||
|
||||
/// absorbs a label and a sequence of bytes
|
||||
fn absorb_bytes(&mut self, label: &'static [u8], bytes: &[u8]);
|
||||
}
|
||||
|
||||
/// 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;
|
||||
}
|
||||
|
||||
/// Defines additional methods on PrimeField objects
|
||||
pub trait PrimeFieldExt: PrimeField {
|
||||
/// Returns a Scalar representing the bytes
|
||||
fn from_uniform(bytes: &[u8]) -> Self;
|
||||
|
||||
/// Returns a byte representation
|
||||
fn to_bytes(v: &[Self]) -> Vec<u8> {
|
||||
(0..v.len())
|
||||
.map(|i| v[i].to_repr().as_ref().to_vec())
|
||||
.collect::<Vec<Vec<u8>>>()
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<u8>>()
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: PrimeField> AppendToTranscriptTrait for [F] {
|
||||
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut Transcript) {
|
||||
for s in self {
|
||||
s.append_to_transcript(label, transcript);
|
||||
}
|
||||
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<Scalar = F>, F: PrimeField> AppendToTranscriptTrait<G> for F {
|
||||
fn append_to_transcript(&self, label: &'static [u8], transcript: &mut G::TE) {
|
||||
transcript.absorb_bytes(label, self.to_repr().as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
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, &<F as PrimeFieldExt>::to_bytes(self));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user