mirror of
https://github.com/arnaucube/Nova.git
synced 2026-01-11 08:31:29 +01:00
traits for a vector commitment engine and a polynomial evaluation engine (#136)
make spartan generic over the evaluation engine update version disable Wasm CI check
This commit is contained in:
4
.github/workflows/rust.yml
vendored
4
.github/workflows/rust.yml
vendored
@@ -17,12 +17,8 @@ jobs:
|
||||
run: rustup component add rustfmt
|
||||
- name: Install clippy
|
||||
run: rustup component add clippy
|
||||
- name: Install Wasm target
|
||||
run: rustup target add wasm32-unknown-unknown
|
||||
- name: Build
|
||||
run: cargo build --verbose
|
||||
- name: Wasm build
|
||||
run: cargo build --target wasm32-unknown-unknown
|
||||
- name: Build examples
|
||||
run: cargo build --examples --verbose
|
||||
- name: Run tests
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "nova-snark"
|
||||
version = "0.12.0"
|
||||
version = "0.13.0"
|
||||
authors = ["Srinath Setty <srinath@microsoft.com>"]
|
||||
edition = "2021"
|
||||
description = "Recursive zkSNARKs without trusted setup"
|
||||
@@ -13,7 +13,7 @@ keywords = ["zkSNARKs", "cryptography", "proofs"]
|
||||
[dependencies]
|
||||
bellperson = { version = "0.24", default-features = false }
|
||||
ff = { version = "0.12.0", features = ["derive"] }
|
||||
merlin = "2.0.0"
|
||||
merlin = "3.0.0"
|
||||
digest = "0.8.1"
|
||||
sha3 = "0.8.2"
|
||||
rayon = "1.3.0"
|
||||
|
||||
@@ -15,8 +15,10 @@ use std::time::Duration;
|
||||
|
||||
type G1 = pasta_curves::pallas::Point;
|
||||
type G2 = pasta_curves::vesta::Point;
|
||||
type S1 = nova_snark::spartan_with_ipa_pc::RelaxedR1CSSNARK<G1>;
|
||||
type S2 = nova_snark::spartan_with_ipa_pc::RelaxedR1CSSNARK<G2>;
|
||||
type EE1 = nova_snark::provider::ipa_pc::EvaluationEngine<G1>;
|
||||
type EE2 = nova_snark::provider::ipa_pc::EvaluationEngine<G2>;
|
||||
type S1 = nova_snark::spartan::RelaxedR1CSSNARK<G1, EE1>;
|
||||
type S2 = nova_snark::spartan::RelaxedR1CSSNARK<G2, EE2>;
|
||||
type C1 = NonTrivialTestCircuit<<G1 as Group>::Scalar>;
|
||||
type C2 = TrivialTestCircuit<<G2 as Group>::Scalar>;
|
||||
|
||||
|
||||
@@ -257,8 +257,11 @@ fn main() {
|
||||
// produce a compressed SNARK
|
||||
println!("Generating a CompressedSNARK using Spartan with IPA-PC...");
|
||||
let start = Instant::now();
|
||||
type S1 = nova_snark::spartan_with_ipa_pc::RelaxedR1CSSNARK<G1>;
|
||||
type S2 = nova_snark::spartan_with_ipa_pc::RelaxedR1CSSNARK<G2>;
|
||||
type EE1 = nova_snark::provider::ipa_pc::EvaluationEngine<G1>;
|
||||
type EE2 = nova_snark::provider::ipa_pc::EvaluationEngine<G2>;
|
||||
type S1 = nova_snark::spartan::RelaxedR1CSSNARK<G1, EE1>;
|
||||
type S2 = nova_snark::spartan::RelaxedR1CSSNARK<G2, EE2>;
|
||||
|
||||
let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &recursive_snark);
|
||||
println!(
|
||||
"CompressedSNARK::prove: {:?}, took {:?}",
|
||||
|
||||
@@ -182,7 +182,6 @@ pub fn synthesize_bits<F: PrimeField, CS: ConstraintSystem<F>>(
|
||||
bits: Option<Vec<bool>>,
|
||||
) -> Result<Vec<AllocatedBit>, SynthesisError> {
|
||||
(0..F::NUM_BITS)
|
||||
.into_iter()
|
||||
.map(|i| {
|
||||
AllocatedBit::alloc(
|
||||
cs.namespace(|| format!("bit {i}")),
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
//! H(params = H(shape, gens), i, z0, zi, U). Each circuit folds the last invocation of
|
||||
//! the other into the running instance
|
||||
|
||||
use super::{
|
||||
commitments::Commitment,
|
||||
use crate::{
|
||||
constants::{NUM_FE_WITHOUT_IO_FOR_CRHF, NUM_HASH_BITS},
|
||||
gadgets::{
|
||||
ecc::AllocatedPoint,
|
||||
@@ -17,7 +16,10 @@ use super::{
|
||||
},
|
||||
},
|
||||
r1cs::{R1CSInstance, RelaxedR1CSInstance},
|
||||
traits::{circuit::StepCircuit, Group, ROCircuitTrait, ROConstantsCircuit},
|
||||
traits::{
|
||||
circuit::StepCircuit, commitment::CommitmentTrait, Group, ROCircuitTrait, ROConstantsCircuit,
|
||||
},
|
||||
Commitment,
|
||||
};
|
||||
use bellperson::{
|
||||
gadgets::{
|
||||
@@ -59,10 +61,7 @@ pub struct NovaAugmentedCircuitInputs<G: Group> {
|
||||
T: Option<Commitment<G>>,
|
||||
}
|
||||
|
||||
impl<G> NovaAugmentedCircuitInputs<G>
|
||||
where
|
||||
G: Group,
|
||||
{
|
||||
impl<G: Group> NovaAugmentedCircuitInputs<G> {
|
||||
/// Create new inputs/witness for the verification circuit
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
@@ -88,22 +87,14 @@ where
|
||||
|
||||
/// The augmented circuit F' in Nova that includes a step circuit F
|
||||
/// and the circuit for the verifier in Nova's non-interactive folding scheme
|
||||
pub struct NovaAugmentedCircuit<G, SC>
|
||||
where
|
||||
G: Group,
|
||||
SC: StepCircuit<G::Base>,
|
||||
{
|
||||
pub struct NovaAugmentedCircuit<G: Group, SC: StepCircuit<G::Base>> {
|
||||
params: NovaAugmentedCircuitParams,
|
||||
ro_consts: ROConstantsCircuit<G>,
|
||||
inputs: Option<NovaAugmentedCircuitInputs<G>>,
|
||||
step_circuit: SC, // The function that is applied for each step
|
||||
}
|
||||
|
||||
impl<G, SC> NovaAugmentedCircuit<G, SC>
|
||||
where
|
||||
G: Group,
|
||||
SC: StepCircuit<G::Base>,
|
||||
{
|
||||
impl<G: Group, SC: StepCircuit<G::Base>> NovaAugmentedCircuit<G, SC> {
|
||||
/// Create a new verification circuit for the input relaxed r1cs instances
|
||||
pub fn new(
|
||||
params: NovaAugmentedCircuitParams,
|
||||
@@ -186,10 +177,7 @@ where
|
||||
let T = AllocatedPoint::alloc(
|
||||
cs.namespace(|| "allocate T"),
|
||||
self.inputs.get().map_or(None, |inputs| {
|
||||
inputs
|
||||
.T
|
||||
.get()
|
||||
.map_or(None, |T| Some(T.comm.to_coordinates()))
|
||||
inputs.T.get().map_or(None, |T| Some(T.to_coordinates()))
|
||||
}),
|
||||
)?;
|
||||
|
||||
@@ -274,10 +262,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<G, SC> Circuit<<G as Group>::Base> for NovaAugmentedCircuit<G, SC>
|
||||
where
|
||||
G: Group,
|
||||
SC: StepCircuit<G::Base>,
|
||||
impl<G: Group, SC: StepCircuit<G::Base>> Circuit<<G as Group>::Base>
|
||||
for NovaAugmentedCircuit<G, SC>
|
||||
{
|
||||
fn synthesize<CS: ConstraintSystem<<G as Group>::Base>>(
|
||||
self,
|
||||
@@ -388,10 +374,11 @@ mod tests {
|
||||
use crate::bellperson::{shape_cs::ShapeCS, solver::SatisfyingAssignment};
|
||||
type G1 = pasta_curves::pallas::Point;
|
||||
type G2 = pasta_curves::vesta::Point;
|
||||
|
||||
use crate::constants::{BN_LIMB_WIDTH, BN_N_LIMBS};
|
||||
use crate::{
|
||||
bellperson::r1cs::{NovaShape, NovaWitness},
|
||||
poseidon::PoseidonConstantsCircuit,
|
||||
provider::poseidon::PoseidonConstantsCircuit,
|
||||
traits::{circuit::TrivialTestCircuit, ROConstantsTrait},
|
||||
};
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ use crate::{
|
||||
},
|
||||
},
|
||||
r1cs::{R1CSInstance, RelaxedR1CSInstance},
|
||||
traits::{Group, ROCircuitTrait, ROConstantsCircuit},
|
||||
traits::{commitment::CommitmentTrait, Group, ROCircuitTrait, ROConstantsCircuit},
|
||||
};
|
||||
use bellperson::{
|
||||
gadgets::{boolean::Boolean, num::AllocatedNum, Assignment},
|
||||
@@ -23,19 +23,13 @@ use ff::Field;
|
||||
|
||||
/// An Allocated R1CS Instance
|
||||
#[derive(Clone)]
|
||||
pub struct AllocatedR1CSInstance<G>
|
||||
where
|
||||
G: Group,
|
||||
{
|
||||
pub struct AllocatedR1CSInstance<G: Group> {
|
||||
pub(crate) W: AllocatedPoint<G>,
|
||||
pub(crate) X0: AllocatedNum<G::Base>,
|
||||
pub(crate) X1: AllocatedNum<G::Base>,
|
||||
}
|
||||
|
||||
impl<G> AllocatedR1CSInstance<G>
|
||||
where
|
||||
G: Group,
|
||||
{
|
||||
impl<G: Group> AllocatedR1CSInstance<G> {
|
||||
/// Takes the r1cs instance and creates a new allocated r1cs instance
|
||||
pub fn alloc<CS: ConstraintSystem<<G as Group>::Base>>(
|
||||
mut cs: CS,
|
||||
@@ -44,8 +38,7 @@ where
|
||||
// Check that the incoming instance has exactly 2 io
|
||||
let W = AllocatedPoint::alloc(
|
||||
cs.namespace(|| "allocate W"),
|
||||
u.get()
|
||||
.map_or(None, |u| Some(u.comm_W.comm.to_coordinates())),
|
||||
u.get().map_or(None, |u| Some(u.comm_W.to_coordinates())),
|
||||
)?;
|
||||
|
||||
let X0 = alloc_scalar_as_base::<G, _>(
|
||||
@@ -71,10 +64,7 @@ where
|
||||
}
|
||||
|
||||
/// An Allocated Relaxed R1CS Instance
|
||||
pub struct AllocatedRelaxedR1CSInstance<G>
|
||||
where
|
||||
G: Group,
|
||||
{
|
||||
pub struct AllocatedRelaxedR1CSInstance<G: Group> {
|
||||
pub(crate) W: AllocatedPoint<G>,
|
||||
pub(crate) E: AllocatedPoint<G>,
|
||||
pub(crate) u: AllocatedNum<G::Base>,
|
||||
@@ -82,10 +72,7 @@ where
|
||||
pub(crate) X1: BigNat<G::Base>,
|
||||
}
|
||||
|
||||
impl<G> AllocatedRelaxedR1CSInstance<G>
|
||||
where
|
||||
G: Group,
|
||||
{
|
||||
impl<G: Group> AllocatedRelaxedR1CSInstance<G> {
|
||||
/// Allocates the given RelaxedR1CSInstance as a witness of the circuit
|
||||
pub fn alloc<CS: ConstraintSystem<<G as Group>::Base>>(
|
||||
mut cs: CS,
|
||||
@@ -97,14 +84,14 @@ where
|
||||
cs.namespace(|| "allocate W"),
|
||||
inst
|
||||
.get()
|
||||
.map_or(None, |inst| Some(inst.comm_W.comm.to_coordinates())),
|
||||
.map_or(None, |inst| Some(inst.comm_W.to_coordinates())),
|
||||
)?;
|
||||
|
||||
let E = AllocatedPoint::alloc(
|
||||
cs.namespace(|| "allocate E"),
|
||||
inst
|
||||
.get()
|
||||
.map_or(None, |inst| Some(inst.comm_E.comm.to_coordinates())),
|
||||
.map_or(None, |inst| Some(inst.comm_E.to_coordinates())),
|
||||
)?;
|
||||
|
||||
// u << |G::Base| despite the fact that u is a scalar.
|
||||
|
||||
23
src/lib.rs
23
src/lib.rs
@@ -6,17 +6,15 @@
|
||||
// private modules
|
||||
mod bellperson;
|
||||
mod circuit;
|
||||
mod commitments;
|
||||
mod constants;
|
||||
mod nifs;
|
||||
mod poseidon;
|
||||
mod r1cs;
|
||||
|
||||
// public modules
|
||||
pub mod errors;
|
||||
pub mod gadgets;
|
||||
pub mod pasta;
|
||||
pub mod spartan_with_ipa_pc;
|
||||
pub mod provider;
|
||||
pub mod spartan;
|
||||
pub mod traits;
|
||||
|
||||
use crate::bellperson::{
|
||||
@@ -37,8 +35,10 @@ use r1cs::{
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use traits::{
|
||||
circuit::StepCircuit, snark::RelaxedR1CSSNARKTrait, AbsorbInROTrait, Group, ROConstants,
|
||||
ROConstantsCircuit, ROConstantsTrait, ROTrait,
|
||||
circuit::StepCircuit,
|
||||
commitment::{CommitmentEngineTrait, CompressedCommitmentTrait},
|
||||
snark::RelaxedR1CSSNARKTrait,
|
||||
AbsorbInROTrait, Group, ROConstants, ROConstantsCircuit, ROConstantsTrait, ROTrait,
|
||||
};
|
||||
|
||||
/// A type that holds public parameters of Nova
|
||||
@@ -717,13 +717,20 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
type CommitmentGens<G> = <<G as traits::Group>::CE as CommitmentEngineTrait<G>>::CommitmentGens;
|
||||
type Commitment<G> = <<G as Group>::CE as CommitmentEngineTrait<G>>::Commitment;
|
||||
type CompressedCommitment<G> = <<G as Group>::CE as CommitmentEngineTrait<G>>::CompressedCommitment;
|
||||
type CE<G> = <G as Group>::CE;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
type G1 = pasta_curves::pallas::Point;
|
||||
type G2 = pasta_curves::vesta::Point;
|
||||
type S1 = spartan_with_ipa_pc::RelaxedR1CSSNARK<G1>;
|
||||
type S2 = spartan_with_ipa_pc::RelaxedR1CSSNARK<G2>;
|
||||
type EE1 = provider::ipa_pc::EvaluationEngine<G1>;
|
||||
type EE2 = provider::ipa_pc::EvaluationEngine<G2>;
|
||||
type S1 = spartan::RelaxedR1CSSNARK<G1, EE1>;
|
||||
type S2 = spartan::RelaxedR1CSSNARK<G2, EE2>;
|
||||
use ::bellperson::{gadgets::num::AllocatedNum, ConstraintSystem, SynthesisError};
|
||||
use core::marker::PhantomData;
|
||||
use ff::PrimeField;
|
||||
|
||||
12
src/nifs.rs
12
src/nifs.rs
@@ -2,12 +2,15 @@
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(clippy::type_complexity)]
|
||||
|
||||
use super::{
|
||||
commitments::CompressedCommitment,
|
||||
use crate::{
|
||||
constants::{NUM_CHALLENGE_BITS, NUM_FE_FOR_RO},
|
||||
errors::NovaError,
|
||||
r1cs::{R1CSGens, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness},
|
||||
traits::{AbsorbInROTrait, Group, ROTrait},
|
||||
traits::{
|
||||
commitment::{CommitmentTrait, CompressedCommitmentTrait},
|
||||
AbsorbInROTrait, Group, ROTrait,
|
||||
},
|
||||
CompressedCommitment,
|
||||
};
|
||||
use core::marker::PhantomData;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -15,8 +18,9 @@ use serde::{Deserialize, Serialize};
|
||||
/// A SNARK that holds the proof of a step of an incremental computation
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(bound = "")]
|
||||
pub struct NIFS<G: Group> {
|
||||
pub(crate) comm_T: CompressedCommitment<G::CompressedGroupElement>,
|
||||
pub(crate) comm_T: CompressedCommitment<G>,
|
||||
_p: PhantomData<G>,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
//! This module implements `EvaluationEngine` using an IPA-based polynomial commitment scheme
|
||||
#![allow(clippy::too_many_arguments)]
|
||||
use crate::commitments::{CommitGens, CommitTrait, Commitment, CompressedCommitment};
|
||||
use crate::errors::NovaError;
|
||||
use crate::traits::{AppendToTranscriptTrait, ChallengeTrait, Group};
|
||||
use crate::{
|
||||
errors::NovaError,
|
||||
spartan::polynomial::EqPolynomial,
|
||||
traits::{
|
||||
commitment::{CommitmentEngineTrait, CommitmentGensTrait, CommitmentTrait},
|
||||
evaluation::EvaluationEngineTrait,
|
||||
AppendToTranscriptTrait, ChallengeTrait, Group,
|
||||
},
|
||||
Commitment, CommitmentGens, CompressedCommitment, CE,
|
||||
};
|
||||
use core::{cmp::max, iter};
|
||||
use ff::Field;
|
||||
use merlin::Transcript;
|
||||
@@ -9,7 +17,131 @@ use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub fn inner_product<T>(a: &[T], b: &[T]) -> T
|
||||
/// Provides an implementation of generators for proving evaluations
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(bound = "")]
|
||||
pub struct EvaluationGens<G: Group> {
|
||||
gens_v: CommitmentGens<G>,
|
||||
gens_s: CommitmentGens<G>,
|
||||
}
|
||||
|
||||
/// Provides an implementation of a polynomial evaluation argument
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(bound = "")]
|
||||
pub struct EvaluationArgument<G: Group> {
|
||||
nifs: Vec<NIFSForInnerProduct<G>>,
|
||||
ipa: InnerProductArgument<G>,
|
||||
}
|
||||
|
||||
/// Provides an implementation of a polynomial evaluation engine using IPA
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct EvaluationEngine<G: Group> {
|
||||
_p: PhantomData<G>,
|
||||
}
|
||||
|
||||
impl<G: Group> EvaluationEngineTrait<G> for EvaluationEngine<G> {
|
||||
type CE = G::CE;
|
||||
type EvaluationGens = EvaluationGens<G>;
|
||||
type EvaluationArgument = EvaluationArgument<G>;
|
||||
|
||||
fn setup(gens: &<Self::CE as CommitmentEngineTrait<G>>::CommitmentGens) -> Self::EvaluationGens {
|
||||
EvaluationGens {
|
||||
gens_v: gens.clone(),
|
||||
gens_s: CommitmentGens::<G>::new(b"ipa", 1),
|
||||
}
|
||||
}
|
||||
|
||||
fn prove_batch(
|
||||
gens: &Self::EvaluationGens,
|
||||
transcript: &mut Transcript,
|
||||
comms: &[Commitment<G>],
|
||||
polys: &[Vec<G::Scalar>],
|
||||
points: &[Vec<G::Scalar>],
|
||||
evals: &[G::Scalar],
|
||||
) -> Result<Self::EvaluationArgument, NovaError> {
|
||||
// sanity checks (these should never fail)
|
||||
assert!(polys.len() >= 2);
|
||||
assert_eq!(comms.len(), polys.len());
|
||||
assert_eq!(comms.len(), points.len());
|
||||
assert_eq!(comms.len(), evals.len());
|
||||
|
||||
let mut r_U = InnerProductInstance::new(
|
||||
&comms[0],
|
||||
&EqPolynomial::new(points[0].clone()).evals(),
|
||||
&evals[0],
|
||||
);
|
||||
let mut r_W = InnerProductWitness::new(&polys[0]);
|
||||
let mut nifs = Vec::new();
|
||||
|
||||
for i in 1..polys.len() {
|
||||
let (n, u, w) = NIFSForInnerProduct::prove(
|
||||
&r_U,
|
||||
&r_W,
|
||||
&InnerProductInstance::new(
|
||||
&comms[i],
|
||||
&EqPolynomial::new(points[i].clone()).evals(),
|
||||
&evals[i],
|
||||
),
|
||||
&InnerProductWitness::new(&polys[i]),
|
||||
transcript,
|
||||
);
|
||||
nifs.push(n);
|
||||
r_U = u;
|
||||
r_W = w;
|
||||
}
|
||||
|
||||
let ipa = InnerProductArgument::prove(&gens.gens_v, &gens.gens_s, &r_U, &r_W, transcript)?;
|
||||
|
||||
Ok(EvaluationArgument { nifs, ipa })
|
||||
}
|
||||
|
||||
/// A method to verify purported evaluations of a batch of polynomials
|
||||
fn verify_batch(
|
||||
gens: &Self::EvaluationGens,
|
||||
transcript: &mut Transcript,
|
||||
comms: &[<Self::CE as CommitmentEngineTrait<G>>::Commitment],
|
||||
points: &[Vec<G::Scalar>],
|
||||
evals: &[G::Scalar],
|
||||
arg: &Self::EvaluationArgument,
|
||||
) -> Result<(), NovaError> {
|
||||
// sanity checks (these should never fail)
|
||||
assert!(comms.len() >= 2);
|
||||
assert_eq!(comms.len(), points.len());
|
||||
assert_eq!(comms.len(), evals.len());
|
||||
|
||||
let mut r_U = InnerProductInstance::new(
|
||||
&comms[0],
|
||||
&EqPolynomial::new(points[0].clone()).evals(),
|
||||
&evals[0],
|
||||
);
|
||||
let mut num_vars = points[0].len();
|
||||
for i in 1..comms.len() {
|
||||
let u = arg.nifs[i - 1].verify(
|
||||
&r_U,
|
||||
&InnerProductInstance::new(
|
||||
&comms[i],
|
||||
&EqPolynomial::new(points[i].clone()).evals(),
|
||||
&evals[i],
|
||||
),
|
||||
transcript,
|
||||
);
|
||||
r_U = u;
|
||||
num_vars = max(num_vars, points[i].len());
|
||||
}
|
||||
|
||||
arg.ipa.verify(
|
||||
&gens.gens_v,
|
||||
&gens.gens_s,
|
||||
(2_usize).pow(num_vars as u32),
|
||||
&r_U,
|
||||
transcript,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn inner_product<T>(a: &[T], b: &[T]) -> T
|
||||
where
|
||||
T: Field + Send + Sync,
|
||||
{
|
||||
@@ -29,7 +161,7 @@ pub struct InnerProductInstance<G: Group> {
|
||||
}
|
||||
|
||||
impl<G: Group> InnerProductInstance<G> {
|
||||
pub fn new(comm_a_vec: &Commitment<G>, b_vec: &[G::Scalar], c: &G::Scalar) -> Self {
|
||||
fn new(comm_a_vec: &Commitment<G>, b_vec: &[G::Scalar], c: &G::Scalar) -> Self {
|
||||
InnerProductInstance {
|
||||
comm_a_vec: *comm_a_vec,
|
||||
b_vec: b_vec.to_vec(),
|
||||
@@ -37,7 +169,7 @@ impl<G: Group> InnerProductInstance<G> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pad(&self, n: usize) -> InnerProductInstance<G> {
|
||||
fn pad(&self, n: usize) -> InnerProductInstance<G> {
|
||||
let mut b_vec = self.b_vec.clone();
|
||||
b_vec.resize(n, G::Scalar::zero());
|
||||
InnerProductInstance {
|
||||
@@ -48,18 +180,18 @@ impl<G: Group> InnerProductInstance<G> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InnerProductWitness<G: Group> {
|
||||
struct InnerProductWitness<G: Group> {
|
||||
a_vec: Vec<G::Scalar>,
|
||||
}
|
||||
|
||||
impl<G: Group> InnerProductWitness<G> {
|
||||
pub fn new(a_vec: &[G::Scalar]) -> Self {
|
||||
fn new(a_vec: &[G::Scalar]) -> Self {
|
||||
InnerProductWitness {
|
||||
a_vec: a_vec.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pad(&self, n: usize) -> InnerProductWitness<G> {
|
||||
fn pad(&self, n: usize) -> InnerProductWitness<G> {
|
||||
let mut a_vec = self.a_vec.clone();
|
||||
a_vec.resize(n, G::Scalar::zero());
|
||||
InnerProductWitness { a_vec }
|
||||
@@ -67,17 +199,17 @@ impl<G: Group> InnerProductWitness<G> {
|
||||
}
|
||||
|
||||
/// A non-interactive folding scheme (NIFS) for inner product relations
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct NIFSForInnerProduct<G: Group> {
|
||||
cross_term: G::Scalar,
|
||||
}
|
||||
|
||||
impl<G: Group> NIFSForInnerProduct<G> {
|
||||
pub fn protocol_name() -> &'static [u8] {
|
||||
fn protocol_name() -> &'static [u8] {
|
||||
b"NIFSForInnerProduct"
|
||||
}
|
||||
|
||||
pub fn prove(
|
||||
fn prove(
|
||||
U1: &InnerProductInstance<G>,
|
||||
W1: &InnerProductWitness<G>,
|
||||
U2: &InnerProductInstance<G>,
|
||||
@@ -136,7 +268,7 @@ impl<G: Group> NIFSForInnerProduct<G> {
|
||||
(NIFSForInnerProduct { cross_term }, U, W)
|
||||
}
|
||||
|
||||
pub fn verify(
|
||||
fn verify(
|
||||
&self,
|
||||
U1: &InnerProductInstance<G>,
|
||||
U2: &InnerProductInstance<G>,
|
||||
@@ -183,10 +315,11 @@ impl<G: Group> NIFSForInnerProduct<G> {
|
||||
}
|
||||
|
||||
/// An inner product argument
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct InnerProductArgument<G: Group> {
|
||||
L_vec: Vec<CompressedCommitment<G::CompressedGroupElement>>,
|
||||
R_vec: Vec<CompressedCommitment<G::CompressedGroupElement>>,
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(bound = "")]
|
||||
struct InnerProductArgument<G: Group> {
|
||||
L_vec: Vec<CompressedCommitment<G>>,
|
||||
R_vec: Vec<CompressedCommitment<G>>,
|
||||
a_hat: G::Scalar,
|
||||
_p: PhantomData<G>,
|
||||
}
|
||||
@@ -196,9 +329,9 @@ impl<G: Group> InnerProductArgument<G> {
|
||||
b"inner product argument"
|
||||
}
|
||||
|
||||
pub fn prove(
|
||||
gens: &CommitGens<G>,
|
||||
gens_c: &CommitGens<G>,
|
||||
fn prove(
|
||||
gens: &CommitmentGens<G>,
|
||||
gens_c: &CommitmentGens<G>,
|
||||
U: &InnerProductInstance<G>,
|
||||
W: &InnerProductWitness<G>,
|
||||
transcript: &mut Transcript,
|
||||
@@ -220,15 +353,15 @@ impl<G: Group> InnerProductArgument<G> {
|
||||
// a closure that executes a step of the recursive inner product argument
|
||||
let prove_inner = |a_vec: &[G::Scalar],
|
||||
b_vec: &[G::Scalar],
|
||||
gens: &CommitGens<G>,
|
||||
gens: &CommitmentGens<G>,
|
||||
transcript: &mut Transcript|
|
||||
-> Result<
|
||||
(
|
||||
CompressedCommitment<G::CompressedGroupElement>,
|
||||
CompressedCommitment<G::CompressedGroupElement>,
|
||||
CompressedCommitment<G>,
|
||||
CompressedCommitment<G>,
|
||||
Vec<G::Scalar>,
|
||||
Vec<G::Scalar>,
|
||||
CommitGens<G>,
|
||||
CommitmentGens<G>,
|
||||
),
|
||||
NovaError,
|
||||
> {
|
||||
@@ -238,20 +371,24 @@ impl<G: Group> InnerProductArgument<G> {
|
||||
let c_L = inner_product(&a_vec[0..n / 2], &b_vec[n / 2..n]);
|
||||
let c_R = inner_product(&a_vec[n / 2..n], &b_vec[0..n / 2]);
|
||||
|
||||
let L = a_vec[0..n / 2]
|
||||
.iter()
|
||||
.chain(iter::once(&c_L))
|
||||
.copied()
|
||||
.collect::<Vec<G::Scalar>>()
|
||||
.commit(&gens_R.combine(&gens_c))
|
||||
.compress();
|
||||
let R = a_vec[n / 2..n]
|
||||
.iter()
|
||||
.chain(iter::once(&c_R))
|
||||
.copied()
|
||||
.collect::<Vec<G::Scalar>>()
|
||||
.commit(&gens_L.combine(&gens_c))
|
||||
.compress();
|
||||
let L = CE::<G>::commit(
|
||||
&gens_R.combine(&gens_c),
|
||||
&a_vec[0..n / 2]
|
||||
.iter()
|
||||
.chain(iter::once(&c_L))
|
||||
.copied()
|
||||
.collect::<Vec<G::Scalar>>(),
|
||||
)
|
||||
.compress();
|
||||
let R = CE::<G>::commit(
|
||||
&gens_L.combine(&gens_c),
|
||||
&a_vec[n / 2..n]
|
||||
.iter()
|
||||
.chain(iter::once(&c_R))
|
||||
.copied()
|
||||
.collect::<Vec<G::Scalar>>(),
|
||||
)
|
||||
.compress();
|
||||
|
||||
L.append_to_transcript(b"L", transcript);
|
||||
R.append_to_transcript(b"R", transcript);
|
||||
@@ -278,8 +415,8 @@ impl<G: Group> InnerProductArgument<G> {
|
||||
};
|
||||
|
||||
// two vectors to hold the logarithmic number of group elements
|
||||
let mut L_vec: Vec<CompressedCommitment<G::CompressedGroupElement>> = Vec::new();
|
||||
let mut R_vec: Vec<CompressedCommitment<G::CompressedGroupElement>> = Vec::new();
|
||||
let mut L_vec: Vec<CompressedCommitment<G>> = Vec::new();
|
||||
let mut R_vec: Vec<CompressedCommitment<G>> = Vec::new();
|
||||
|
||||
// we create mutable copies of vectors and generators
|
||||
let mut a_vec = W.a_vec.to_vec();
|
||||
@@ -304,10 +441,10 @@ impl<G: Group> InnerProductArgument<G> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn verify(
|
||||
fn verify(
|
||||
&self,
|
||||
gens: &CommitGens<G>,
|
||||
gens_c: &CommitGens<G>,
|
||||
gens: &CommitmentGens<G>,
|
||||
gens_c: &CommitmentGens<G>,
|
||||
n: usize,
|
||||
U: &InnerProductInstance<G>,
|
||||
transcript: &mut Transcript,
|
||||
@@ -329,7 +466,7 @@ impl<G: Group> InnerProductArgument<G> {
|
||||
let r = G::Scalar::challenge(b"r", transcript);
|
||||
let gens_c = gens_c.scale(&r);
|
||||
|
||||
let P = U.comm_a_vec + [U.c].commit(&gens_c);
|
||||
let P = U.comm_a_vec + CE::<G>::commit(&gens_c, &[U.c]);
|
||||
|
||||
let batch_invert = |v: &[G::Scalar]| -> Result<Vec<G::Scalar>, NovaError> {
|
||||
let mut products = vec![G::Scalar::zero(); v.len()];
|
||||
@@ -396,29 +533,37 @@ impl<G: Group> InnerProductArgument<G> {
|
||||
};
|
||||
|
||||
let gens_hat = {
|
||||
let c = s.commit(gens).compress();
|
||||
CommitGens::reinterpret_commitments_as_gens(&[c])?
|
||||
let c = CE::<G>::commit(gens, &s).compress();
|
||||
CommitmentGens::<G>::reinterpret_commitments_as_gens(&[c])?
|
||||
};
|
||||
|
||||
let b_hat = inner_product(&U.b_vec, &s);
|
||||
|
||||
let P_hat = {
|
||||
let gens_folded = {
|
||||
let gens_L = CommitGens::reinterpret_commitments_as_gens(&self.L_vec)?;
|
||||
let gens_R = CommitGens::reinterpret_commitments_as_gens(&self.R_vec)?;
|
||||
let gens_P = CommitGens::reinterpret_commitments_as_gens(&[P.compress()])?;
|
||||
let gens_L = CommitmentGens::<G>::reinterpret_commitments_as_gens(&self.L_vec)?;
|
||||
let gens_R = CommitmentGens::<G>::reinterpret_commitments_as_gens(&self.R_vec)?;
|
||||
let gens_P = CommitmentGens::<G>::reinterpret_commitments_as_gens(&[P.compress()])?;
|
||||
gens_L.combine(&gens_R).combine(&gens_P)
|
||||
};
|
||||
r_square
|
||||
.iter()
|
||||
.chain(r_inverse_square.iter())
|
||||
.chain(iter::once(&G::Scalar::one()))
|
||||
.copied()
|
||||
.collect::<Vec<G::Scalar>>()
|
||||
.commit(&gens_folded)
|
||||
|
||||
CE::<G>::commit(
|
||||
&gens_folded,
|
||||
&r_square
|
||||
.iter()
|
||||
.chain(r_inverse_square.iter())
|
||||
.chain(iter::once(&G::Scalar::one()))
|
||||
.copied()
|
||||
.collect::<Vec<G::Scalar>>(),
|
||||
)
|
||||
};
|
||||
|
||||
if P_hat == [self.a_hat, self.a_hat * b_hat].commit(&gens_hat.combine(&gens_c)) {
|
||||
if P_hat
|
||||
== CE::<G>::commit(
|
||||
&gens_hat.combine(&gens_c),
|
||||
&[self.a_hat, self.a_hat * b_hat],
|
||||
)
|
||||
{
|
||||
Ok(())
|
||||
} else {
|
||||
Err(NovaError::InvalidIPA)
|
||||
10
src/provider/mod.rs
Normal file
10
src/provider/mod.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
//! This module implements Nova's traits using the following configuration:
|
||||
//! `CommitmentEngine` with Pedersen's commitments
|
||||
//! `Group` with pasta curves
|
||||
//! `RO` traits with Poseidon
|
||||
//! `EvaluationEngine` with an IPA-based polynomial evaluation argument
|
||||
|
||||
pub mod ipa_pc;
|
||||
pub mod pasta;
|
||||
pub mod pedersen;
|
||||
pub mod poseidon;
|
||||
@@ -1,6 +1,9 @@
|
||||
//! This module implements the Nova traits for pallas::Point, pallas::Scalar, vesta::Point, vesta::Scalar.
|
||||
use crate::{
|
||||
poseidon::{PoseidonRO, PoseidonROCircuit},
|
||||
provider::{
|
||||
pedersen::CommitmentEngine,
|
||||
poseidon::{PoseidonRO, PoseidonROCircuit},
|
||||
},
|
||||
traits::{ChallengeTrait, CompressedGroup, Group},
|
||||
};
|
||||
use digest::{ExtendableOutput, Input};
|
||||
@@ -61,6 +64,7 @@ macro_rules! impl_traits {
|
||||
type PreprocessedGroupElement = $name::Affine;
|
||||
type RO = PoseidonRO<Self::Base, Self::Scalar>;
|
||||
type ROCircuit = PoseidonROCircuit<Self::Base>;
|
||||
type CE = CommitmentEngine<Self>;
|
||||
|
||||
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
|
||||
fn vartime_multiscalar_mul(
|
||||
@@ -1,6 +1,12 @@
|
||||
use super::{
|
||||
//! This module provides an implementation of a commitment engine
|
||||
use crate::{
|
||||
errors::NovaError,
|
||||
traits::{AbsorbInROTrait, AppendToTranscriptTrait, CompressedGroup, Group, ROTrait},
|
||||
traits::{
|
||||
commitment::{
|
||||
CommitmentEngineTrait, CommitmentGensTrait, CommitmentTrait, CompressedCommitmentTrait,
|
||||
},
|
||||
AbsorbInROTrait, AppendToTranscriptTrait, CompressedGroup, Group, ROTrait,
|
||||
},
|
||||
};
|
||||
use core::{
|
||||
fmt::Debug,
|
||||
@@ -12,27 +18,33 @@ use merlin::Transcript;
|
||||
use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct CommitGens<G: Group> {
|
||||
/// A type that holds commitment generators
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CommitmentGens<G: Group> {
|
||||
gens: Vec<G::PreprocessedGroupElement>,
|
||||
_p: PhantomData<G>,
|
||||
}
|
||||
|
||||
/// A type that holds a commitment
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(bound = "")]
|
||||
pub struct Commitment<G: Group> {
|
||||
pub(crate) comm: G,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
/// A type that holds a compressed commitment
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(bound = "")]
|
||||
pub struct CompressedCommitment<C: CompressedGroup> {
|
||||
comm: C,
|
||||
}
|
||||
|
||||
impl<G: Group> CommitGens<G> {
|
||||
pub fn new(label: &'static [u8], n: usize) -> Self {
|
||||
CommitGens {
|
||||
impl<G: Group> CommitmentGensTrait<G> for CommitmentGens<G> {
|
||||
type Commitment = Commitment<G>;
|
||||
type CompressedCommitment = CompressedCommitment<G::CompressedGroupElement>;
|
||||
|
||||
fn new(label: &'static [u8], n: usize) -> Self {
|
||||
CommitmentGens {
|
||||
gens: G::from_label(label, n.next_power_of_two()),
|
||||
_p: Default::default(),
|
||||
}
|
||||
@@ -42,76 +54,83 @@ impl<G: Group> CommitGens<G> {
|
||||
self.gens.len()
|
||||
}
|
||||
|
||||
pub fn split_at(&self, n: usize) -> (CommitGens<G>, CommitGens<G>) {
|
||||
fn commit(&self, v: &[G::Scalar]) -> Self::Commitment {
|
||||
assert!(self.gens.len() >= v.len());
|
||||
Commitment {
|
||||
comm: G::vartime_multiscalar_mul(v, &self.gens[..v.len()]),
|
||||
}
|
||||
}
|
||||
|
||||
fn split_at(&self, n: usize) -> (CommitmentGens<G>, CommitmentGens<G>) {
|
||||
(
|
||||
CommitGens {
|
||||
CommitmentGens {
|
||||
gens: self.gens[0..n].to_vec(),
|
||||
_p: Default::default(),
|
||||
},
|
||||
CommitGens {
|
||||
CommitmentGens {
|
||||
gens: self.gens[n..].to_vec(),
|
||||
_p: Default::default(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn combine(&self, other: &CommitGens<G>) -> CommitGens<G> {
|
||||
fn combine(&self, other: &CommitmentGens<G>) -> CommitmentGens<G> {
|
||||
let gens = {
|
||||
let mut c = self.gens.clone();
|
||||
c.extend(other.gens.clone());
|
||||
c
|
||||
};
|
||||
CommitGens {
|
||||
CommitmentGens {
|
||||
gens,
|
||||
_p: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
// combines the left and right halves of `self` using `w1` and `w2` as the weights
|
||||
pub fn fold(&self, w1: &G::Scalar, w2: &G::Scalar) -> CommitGens<G> {
|
||||
fn fold(&self, w1: &G::Scalar, w2: &G::Scalar) -> CommitmentGens<G> {
|
||||
let w = vec![*w1, *w2];
|
||||
let (L, R) = self.split_at(self.len() / 2);
|
||||
|
||||
let gens = (0..self.len() / 2)
|
||||
.into_par_iter()
|
||||
.map(|i| {
|
||||
let gens = CommitGens::<G> {
|
||||
let gens = CommitmentGens::<G> {
|
||||
gens: [L.gens[i].clone(), R.gens[i].clone()].to_vec(),
|
||||
_p: Default::default(),
|
||||
};
|
||||
w.commit(&gens).comm.preprocessed()
|
||||
gens.commit(&w).comm.preprocessed()
|
||||
})
|
||||
.collect();
|
||||
|
||||
CommitGens {
|
||||
CommitmentGens {
|
||||
gens,
|
||||
_p: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Scales each element in `self` by `r`
|
||||
pub fn scale(&self, r: &G::Scalar) -> Self {
|
||||
fn scale(&self, r: &G::Scalar) -> Self {
|
||||
let gens_scaled = self
|
||||
.gens
|
||||
.clone()
|
||||
.into_par_iter()
|
||||
.map(|g| {
|
||||
let gens = CommitGens::<G> {
|
||||
let gens = CommitmentGens::<G> {
|
||||
gens: vec![g],
|
||||
_p: Default::default(),
|
||||
};
|
||||
[*r].commit(&gens).comm.preprocessed()
|
||||
gens.commit(&[*r]).comm.preprocessed()
|
||||
})
|
||||
.collect();
|
||||
|
||||
CommitGens {
|
||||
CommitmentGens {
|
||||
gens: gens_scaled,
|
||||
_p: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// reinterprets a vector of commitments as a set of generators
|
||||
pub fn reinterpret_commitments_as_gens(
|
||||
fn reinterpret_commitments_as_gens(
|
||||
c: &[CompressedCommitment<G::CompressedGroupElement>],
|
||||
) -> Result<Self, NovaError> {
|
||||
let d = (0..c.len())
|
||||
@@ -122,19 +141,25 @@ impl<G: Group> CommitGens<G> {
|
||||
.into_par_iter()
|
||||
.map(|i| d[i].comm.preprocessed())
|
||||
.collect();
|
||||
Ok(CommitGens {
|
||||
Ok(CommitmentGens {
|
||||
gens,
|
||||
_p: Default::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> Commitment<G> {
|
||||
pub fn compress(&self) -> CompressedCommitment<G::CompressedGroupElement> {
|
||||
impl<G: Group> CommitmentTrait<G> for Commitment<G> {
|
||||
type CompressedCommitment = CompressedCommitment<G::CompressedGroupElement>;
|
||||
|
||||
fn compress(&self) -> CompressedCommitment<G::CompressedGroupElement> {
|
||||
CompressedCommitment {
|
||||
comm: self.comm.compress(),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_coordinates(&self) -> (G::Base, G::Base, bool) {
|
||||
self.comm.to_coordinates()
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> Default for Commitment<G> {
|
||||
@@ -143,8 +168,10 @@ impl<G: Group> Default for Commitment<G> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: CompressedGroup> CompressedCommitment<C> {
|
||||
pub fn decompress(&self) -> Result<Commitment<C::GroupElement>, NovaError> {
|
||||
impl<C: CompressedGroup> CompressedCommitmentTrait<C> for CompressedCommitment<C> {
|
||||
type Commitment = Commitment<C::GroupElement>;
|
||||
|
||||
fn decompress(&self) -> Result<Self::Commitment, NovaError> {
|
||||
let comm = self.comm.decompress();
|
||||
if comm.is_none() {
|
||||
return Err(NovaError::DecompressionError);
|
||||
@@ -155,19 +182,6 @@ impl<C: CompressedGroup> CompressedCommitment<C> {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CommitTrait<G: Group> {
|
||||
fn commit(&self, gens: &CommitGens<G>) -> Commitment<G>;
|
||||
}
|
||||
|
||||
impl<G: Group> CommitTrait<G> for [G::Scalar] {
|
||||
fn commit(&self, gens: &CommitGens<G>) -> Commitment<G> {
|
||||
assert!(gens.gens.len() >= self.len());
|
||||
Commitment {
|
||||
comm: G::vartime_multiscalar_mul(self, &gens.gens[..self.len()]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
@@ -193,8 +207,8 @@ impl<C: CompressedGroup> AppendToTranscriptTrait for CompressedCommitment<C> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, G: Group> MulAssign<&'b G::Scalar> for Commitment<G> {
|
||||
fn mul_assign(&mut self, scalar: &'b G::Scalar) {
|
||||
impl<G: Group> MulAssign<G::Scalar> for Commitment<G> {
|
||||
fn mul_assign(&mut self, scalar: G::Scalar) {
|
||||
let result = (self as &Commitment<G>).comm * scalar;
|
||||
*self = Commitment { comm: result };
|
||||
}
|
||||
@@ -272,3 +286,19 @@ macro_rules! define_add_assign_variants {
|
||||
|
||||
define_add_assign_variants!(G = Group, LHS = Commitment<G>, RHS = Commitment<G>);
|
||||
define_add_variants!(G = Group, LHS = Commitment<G>, RHS = Commitment<G>, Output = Commitment<G>);
|
||||
|
||||
/// Provides a commitment engine
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CommitmentEngine<G: Group> {
|
||||
_p: PhantomData<G>,
|
||||
}
|
||||
|
||||
impl<G: Group> CommitmentEngineTrait<G> for CommitmentEngine<G> {
|
||||
type CommitmentGens = CommitmentGens<G>;
|
||||
type Commitment = Commitment<G>;
|
||||
type CompressedCommitment = CompressedCommitment<G::CompressedGroupElement>;
|
||||
|
||||
fn commit(gens: &Self::CommitmentGens, v: &[G::Scalar]) -> Self::Commitment {
|
||||
gens.commit(v)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//! Poseidon Constants and Poseidon-based RO used in Nova
|
||||
use super::traits::{ROCircuitTrait, ROConstantsTrait, ROTrait};
|
||||
use crate::traits::{ROCircuitTrait, ROConstantsTrait, ROTrait};
|
||||
use bellperson::{
|
||||
gadgets::{
|
||||
boolean::{AllocatedBit, Boolean},
|
||||
39
src/r1cs.rs
39
src/r1cs.rs
@@ -1,12 +1,17 @@
|
||||
//! This module defines R1CS related types and a folding scheme for Relaxed R1CS
|
||||
#![allow(clippy::type_complexity)]
|
||||
use super::gadgets::nonnative::{bignat::nat_to_limbs, util::f_to_nat};
|
||||
use super::{
|
||||
commitments::{CommitGens, CommitTrait, Commitment},
|
||||
use crate::{
|
||||
constants::{BN_LIMB_WIDTH, BN_N_LIMBS, NUM_HASH_BITS},
|
||||
errors::NovaError,
|
||||
gadgets::utils::scalar_as_base,
|
||||
traits::{AbsorbInROTrait, AppendToTranscriptTrait, Group, ROTrait},
|
||||
gadgets::{
|
||||
nonnative::{bignat::nat_to_limbs, util::f_to_nat},
|
||||
utils::scalar_as_base,
|
||||
},
|
||||
traits::{
|
||||
commitment::{CommitmentEngineTrait, CommitmentGensTrait},
|
||||
AbsorbInROTrait, AppendToTranscriptTrait, Group, ROTrait,
|
||||
},
|
||||
Commitment, CommitmentGens, CE,
|
||||
};
|
||||
use core::cmp::max;
|
||||
use ff::Field;
|
||||
@@ -21,7 +26,7 @@ use sha3::{Digest, Sha3_256};
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[serde(bound = "")]
|
||||
pub struct R1CSGens<G: Group> {
|
||||
pub(crate) gens: CommitGens<G>,
|
||||
pub(crate) gens: CommitmentGens<G>,
|
||||
}
|
||||
|
||||
/// A type that holds the shape of the R1CS matrices
|
||||
@@ -71,7 +76,7 @@ impl<G: Group> R1CSGens<G> {
|
||||
/// Samples public parameters for the specified number of constraints and variables in an R1CS
|
||||
pub fn new(num_cons: usize, num_vars: usize) -> R1CSGens<G> {
|
||||
R1CSGens {
|
||||
gens: CommitGens::new(b"gens", max(num_vars, num_cons)),
|
||||
gens: CommitmentGens::<G>::new(b"gens", max(num_vars, num_cons)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -202,7 +207,10 @@ impl<G: Group> R1CSShape<G> {
|
||||
|
||||
// verify if comm_E and comm_W are commitments to E and W
|
||||
let res_comm: bool = {
|
||||
let (comm_W, comm_E) = rayon::join(|| W.W.commit(&gens.gens), || W.E.commit(&gens.gens));
|
||||
let (comm_W, comm_E) = rayon::join(
|
||||
|| CE::<G>::commit(&gens.gens, &W.W),
|
||||
|| CE::<G>::commit(&gens.gens, &W.E),
|
||||
);
|
||||
U.comm_W == comm_W && U.comm_E == comm_E
|
||||
};
|
||||
|
||||
@@ -239,7 +247,7 @@ impl<G: Group> R1CSShape<G> {
|
||||
};
|
||||
|
||||
// verify if comm_W is a commitment to W
|
||||
let res_comm: bool = U.comm_W == W.W.commit(&gens.gens);
|
||||
let res_comm: bool = U.comm_W == gens.gens.commit(&W.W);
|
||||
|
||||
if res_eq && res_comm {
|
||||
Ok(())
|
||||
@@ -293,7 +301,7 @@ impl<G: Group> R1CSShape<G> {
|
||||
.map(|(((a, b), c), d)| *a + *b - *c - *d)
|
||||
.collect::<Vec<G::Scalar>>();
|
||||
|
||||
let comm_T = T.commit(&gens.gens);
|
||||
let comm_T = gens.gens.commit(&T);
|
||||
|
||||
Ok((T, comm_T))
|
||||
}
|
||||
@@ -458,7 +466,7 @@ impl<G: Group> R1CSWitness<G> {
|
||||
|
||||
/// Commits to the witness using the supplied generators
|
||||
pub fn commit(&self, gens: &R1CSGens<G>) -> Commitment<G> {
|
||||
self.W.commit(&gens.gens)
|
||||
gens.gens.commit(&self.W)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,7 +523,10 @@ impl<G: Group> RelaxedR1CSWitness<G> {
|
||||
|
||||
/// Commits to the witness using the supplied generators
|
||||
pub fn commit(&self, gens: &R1CSGens<G>) -> (Commitment<G>, Commitment<G>) {
|
||||
(self.W.commit(&gens.gens), self.E.commit(&gens.gens))
|
||||
(
|
||||
CE::<G>::commit(&gens.gens, &self.W),
|
||||
CE::<G>::commit(&gens.gens, &self.E),
|
||||
)
|
||||
}
|
||||
|
||||
/// Folds an incoming R1CSWitness into the current one
|
||||
@@ -566,7 +577,7 @@ impl<G: Group> RelaxedR1CSWitness<G> {
|
||||
impl<G: Group> RelaxedR1CSInstance<G> {
|
||||
/// Produces a default RelaxedR1CSInstance given R1CSGens and R1CSShape
|
||||
pub fn default(_gens: &R1CSGens<G>, S: &R1CSShape<G>) -> RelaxedR1CSInstance<G> {
|
||||
let (comm_W, comm_E) = (Commitment::default(), Commitment::default());
|
||||
let (comm_W, comm_E) = (Commitment::<G>::default(), Commitment::<G>::default());
|
||||
RelaxedR1CSInstance {
|
||||
comm_W,
|
||||
comm_E,
|
||||
@@ -605,7 +616,7 @@ impl<G: Group> RelaxedR1CSInstance<G> {
|
||||
.zip(X2)
|
||||
.map(|(a, b)| *a + *r * *b)
|
||||
.collect::<Vec<G::Scalar>>();
|
||||
let comm_W = comm_W_1 + comm_W_2 * r;
|
||||
let comm_W = *comm_W_1 + *comm_W_2 * *r;
|
||||
let comm_E = *comm_E_1 + *comm_T * *r;
|
||||
let u = *u1 + *r;
|
||||
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
//! This module implements RelaxedR1CSSNARKTrait using a Spartan variant
|
||||
//! instantiated with an IPA-based polynomial commitment scheme
|
||||
mod ipa;
|
||||
mod polynomial;
|
||||
//! This module implements RelaxedR1CSSNARKTrait using Spartan that is generic
|
||||
//! over the polynomial commitment and evaluation argument (i.e., a PCS)
|
||||
pub mod polynomial;
|
||||
mod sumcheck;
|
||||
|
||||
use super::{
|
||||
commitments::CommitGens,
|
||||
use crate::{
|
||||
errors::NovaError,
|
||||
r1cs::{R1CSGens, R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness},
|
||||
traits::{
|
||||
evaluation::EvaluationEngineTrait,
|
||||
snark::{ProverKeyTrait, RelaxedR1CSSNARKTrait, VerifierKeyTrait},
|
||||
AppendToTranscriptTrait, ChallengeTrait, Group,
|
||||
},
|
||||
};
|
||||
use core::cmp::max;
|
||||
use ff::Field;
|
||||
use ipa::{InnerProductArgument, InnerProductInstance, InnerProductWitness, NIFSForInnerProduct};
|
||||
use itertools::concat;
|
||||
use merlin::Transcript;
|
||||
use polynomial::{EqPolynomial, MultilinearPolynomial, SparsePolynomial};
|
||||
@@ -26,17 +23,15 @@ use sumcheck::SumcheckProof;
|
||||
/// A type that represents the prover's key
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(bound = "")]
|
||||
pub struct ProverKey<G: Group> {
|
||||
gens_r1cs: R1CSGens<G>,
|
||||
gens_ipa: CommitGens<G>,
|
||||
pub struct ProverKey<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> {
|
||||
gens: EE::EvaluationGens,
|
||||
S: R1CSShape<G>,
|
||||
}
|
||||
|
||||
impl<G: Group> ProverKeyTrait<G> for ProverKey<G> {
|
||||
impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> ProverKeyTrait<G> for ProverKey<G, EE> {
|
||||
fn new(gens: &R1CSGens<G>, S: &R1CSShape<G>) -> Self {
|
||||
ProverKey {
|
||||
gens_r1cs: gens.clone(),
|
||||
gens_ipa: CommitGens::new(b"ipa", 1),
|
||||
gens: EE::setup(&gens.gens),
|
||||
S: S.clone(),
|
||||
}
|
||||
}
|
||||
@@ -45,17 +40,17 @@ impl<G: Group> ProverKeyTrait<G> for ProverKey<G> {
|
||||
/// A type that represents the verifier's key
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(bound = "")]
|
||||
pub struct VerifierKey<G: Group> {
|
||||
gens_r1cs: R1CSGens<G>,
|
||||
gens_ipa: CommitGens<G>,
|
||||
pub struct VerifierKey<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> {
|
||||
gens: EE::EvaluationGens,
|
||||
S: R1CSShape<G>,
|
||||
}
|
||||
|
||||
impl<G: Group> VerifierKeyTrait<G> for VerifierKey<G> {
|
||||
impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> VerifierKeyTrait<G>
|
||||
for VerifierKey<G, EE>
|
||||
{
|
||||
fn new(gens: &R1CSGens<G>, S: &R1CSShape<G>) -> Self {
|
||||
VerifierKey {
|
||||
gens_r1cs: gens.clone(),
|
||||
gens_ipa: CommitGens::new(b"ipa", 1),
|
||||
gens: EE::setup(&gens.gens),
|
||||
S: S.clone(),
|
||||
}
|
||||
}
|
||||
@@ -66,19 +61,20 @@ impl<G: Group> VerifierKeyTrait<G> for VerifierKey<G> {
|
||||
/// the commitment to a vector viewed as a polynomial commitment
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(bound = "")]
|
||||
pub struct RelaxedR1CSSNARK<G: Group> {
|
||||
pub struct RelaxedR1CSSNARK<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> {
|
||||
sc_proof_outer: SumcheckProof<G>,
|
||||
claims_outer: (G::Scalar, G::Scalar, G::Scalar),
|
||||
sc_proof_inner: SumcheckProof<G>,
|
||||
eval_E: G::Scalar,
|
||||
eval_W: G::Scalar,
|
||||
nifs_ip: NIFSForInnerProduct<G>,
|
||||
ipa: InnerProductArgument<G>,
|
||||
eval_arg: EE::EvaluationArgument,
|
||||
}
|
||||
|
||||
impl<G: Group> RelaxedR1CSSNARKTrait<G> for RelaxedR1CSSNARK<G> {
|
||||
type ProverKey = ProverKey<G>;
|
||||
type VerifierKey = VerifierKey<G>;
|
||||
impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G>
|
||||
for RelaxedR1CSSNARK<G, EE>
|
||||
{
|
||||
type ProverKey = ProverKey<G, EE>;
|
||||
type VerifierKey = VerifierKey<G, EE>;
|
||||
|
||||
/// produces a succinct proof of satisfiability of a RelaxedR1CS instance
|
||||
fn prove(
|
||||
@@ -88,8 +84,6 @@ impl<G: Group> RelaxedR1CSSNARKTrait<G> for RelaxedR1CSSNARK<G> {
|
||||
) -> Result<Self, NovaError> {
|
||||
let mut transcript = Transcript::new(b"RelaxedR1CSSNARK");
|
||||
|
||||
debug_assert!(pk.S.is_sat_relaxed(&pk.gens_r1cs, U, W).is_ok());
|
||||
|
||||
// sanity check that R1CSShape has certain size characteristics
|
||||
assert_eq!(pk.S.num_cons.next_power_of_two(), pk.S.num_cons);
|
||||
assert_eq!(pk.S.num_vars.next_power_of_two(), pk.S.num_vars);
|
||||
@@ -230,24 +224,13 @@ impl<G: Group> RelaxedR1CSSNARKTrait<G> for RelaxedR1CSSNARK<G> {
|
||||
let eval_W = MultilinearPolynomial::new(W.W.clone()).evaluate(&r_y[1..]);
|
||||
eval_W.append_to_transcript(b"eval_W", &mut transcript);
|
||||
|
||||
let (nifs_ip, r_U, r_W) = NIFSForInnerProduct::prove(
|
||||
&InnerProductInstance::new(&U.comm_E, &EqPolynomial::new(r_x).evals(), &eval_E),
|
||||
&InnerProductWitness::new(&W.E),
|
||||
&InnerProductInstance::new(
|
||||
&U.comm_W,
|
||||
&EqPolynomial::new(r_y[1..].to_vec()).evals(),
|
||||
&eval_W,
|
||||
),
|
||||
&InnerProductWitness::new(&W.W),
|
||||
&mut transcript,
|
||||
);
|
||||
|
||||
let ipa = InnerProductArgument::prove(
|
||||
&pk.gens_r1cs.gens,
|
||||
&pk.gens_ipa,
|
||||
&r_U,
|
||||
&r_W,
|
||||
let eval_arg = EE::prove_batch(
|
||||
&pk.gens,
|
||||
&mut transcript,
|
||||
&[U.comm_E, U.comm_W],
|
||||
&[W.E.clone(), W.W.clone()],
|
||||
&[r_x, r_y[1..].to_vec()],
|
||||
&[eval_E, eval_W],
|
||||
)?;
|
||||
|
||||
Ok(RelaxedR1CSSNARK {
|
||||
@@ -256,8 +239,7 @@ impl<G: Group> RelaxedR1CSSNARKTrait<G> for RelaxedR1CSSNARK<G> {
|
||||
sc_proof_inner,
|
||||
eval_W,
|
||||
eval_E,
|
||||
nifs_ip,
|
||||
ipa,
|
||||
eval_arg,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -366,22 +348,13 @@ impl<G: Group> RelaxedR1CSSNARKTrait<G> for RelaxedR1CSSNARK<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
|
||||
|
||||
let r_U = self.nifs_ip.verify(
|
||||
&InnerProductInstance::new(&U.comm_E, &EqPolynomial::new(r_x).evals(), &self.eval_E),
|
||||
&InnerProductInstance::new(
|
||||
&U.comm_W,
|
||||
&EqPolynomial::new(r_y[1..].to_vec()).evals(),
|
||||
&self.eval_W,
|
||||
),
|
||||
&mut transcript,
|
||||
);
|
||||
|
||||
self.ipa.verify(
|
||||
&vk.gens_r1cs.gens,
|
||||
&vk.gens_ipa,
|
||||
max(vk.S.num_vars, vk.S.num_cons),
|
||||
&r_U,
|
||||
EE::verify_batch(
|
||||
&vk.gens,
|
||||
&mut transcript,
|
||||
&[U.comm_E, U.comm_W],
|
||||
&[r_x, r_y[1..].to_vec()],
|
||||
&[self.eval_E, self.eval_W],
|
||||
&self.eval_arg,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
@@ -1,16 +1,19 @@
|
||||
//! This module defines basic types related to polynomials
|
||||
use core::ops::Index;
|
||||
use ff::PrimeField;
|
||||
use rayon::prelude::*;
|
||||
|
||||
pub struct EqPolynomial<Scalar: PrimeField> {
|
||||
pub(crate) struct EqPolynomial<Scalar: PrimeField> {
|
||||
r: Vec<Scalar>,
|
||||
}
|
||||
|
||||
impl<Scalar: PrimeField> EqPolynomial<Scalar> {
|
||||
/// Creates a new polynomial from its succinct specification
|
||||
pub fn new(r: Vec<Scalar>) -> Self {
|
||||
EqPolynomial { r }
|
||||
}
|
||||
|
||||
/// Evaluates the polynomial at the specified point
|
||||
pub fn evaluate(&self, rx: &[Scalar]) -> Scalar {
|
||||
assert_eq!(self.r.len(), rx.len());
|
||||
(0..rx.len())
|
||||
@@ -43,7 +46,7 @@ impl<Scalar: PrimeField> EqPolynomial<Scalar> {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MultilinearPolynomial<Scalar: PrimeField> {
|
||||
pub(crate) struct MultilinearPolynomial<Scalar: PrimeField> {
|
||||
num_vars: usize, // the number of variables in the multilinear polynomial
|
||||
Z: Vec<Scalar>, // evaluations of the polynomial in all the 2^num_vars Boolean inputs
|
||||
}
|
||||
@@ -105,7 +108,7 @@ impl<Scalar: PrimeField> Index<usize> for MultilinearPolynomial<Scalar> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SparsePolynomial<Scalar: PrimeField> {
|
||||
pub(crate) struct SparsePolynomial<Scalar: PrimeField> {
|
||||
num_vars: usize,
|
||||
Z: Vec<(usize, Scalar)>,
|
||||
}
|
||||
@@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(bound = "")]
|
||||
pub struct SumcheckProof<G: Group> {
|
||||
pub(crate) struct SumcheckProof<G: Group> {
|
||||
compressed_polys: Vec<CompressedUniPoly<G>>,
|
||||
}
|
||||
|
||||
149
src/traits/commitment.rs
Normal file
149
src/traits/commitment.rs
Normal file
@@ -0,0 +1,149 @@
|
||||
//! This module defines a collection of traits that define the behavior of a commitment engine
|
||||
//! We require the commitment engine to provide a commitment to vectors with a single group element
|
||||
use crate::{
|
||||
errors::NovaError,
|
||||
traits::{AbsorbInROTrait, AppendToTranscriptTrait, CompressedGroup, Group},
|
||||
};
|
||||
use core::{
|
||||
fmt::Debug,
|
||||
ops::{Add, AddAssign, Mul, MulAssign},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// This trait defines the behavior of commitment key
|
||||
#[allow(clippy::len_without_is_empty)]
|
||||
pub trait CommitmentGensTrait<G: Group>:
|
||||
Clone + Debug + Send + Sync + Serialize + for<'de> Deserialize<'de>
|
||||
{
|
||||
/// Holds the type of the commitment that can be produced
|
||||
type Commitment;
|
||||
|
||||
/// Holds the type of the compressed commitment
|
||||
type CompressedCommitment;
|
||||
|
||||
/// Samples a new commitment key of a specified size
|
||||
fn new(label: &'static [u8], n: usize) -> Self;
|
||||
|
||||
/// Returns the vector length that can be committed
|
||||
fn len(&self) -> usize;
|
||||
|
||||
/// Commits to a vector using the commitment key
|
||||
fn commit(&self, v: &[G::Scalar]) -> Self::Commitment;
|
||||
|
||||
/// Splits the commitment key into two pieces at a specified point
|
||||
fn split_at(&self, n: usize) -> (Self, Self)
|
||||
where
|
||||
Self: Sized;
|
||||
|
||||
/// Combines two commitment keys into one
|
||||
fn combine(&self, other: &Self) -> Self;
|
||||
|
||||
/// Folds the two commitment keys into one using the provided weights
|
||||
fn fold(&self, w1: &G::Scalar, w2: &G::Scalar) -> Self;
|
||||
|
||||
/// Scales the commitment key using the provided scalar
|
||||
fn scale(&self, r: &G::Scalar) -> Self;
|
||||
|
||||
/// Reinterprets commitments as commitment keys
|
||||
fn reinterpret_commitments_as_gens(c: &[Self::CompressedCommitment]) -> Result<Self, NovaError>
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
/// Defines basic operations on commitments
|
||||
pub trait CommitmentOps<Rhs = Self, Output = Self>:
|
||||
Add<Rhs, Output = Output> + AddAssign<Rhs>
|
||||
{
|
||||
}
|
||||
|
||||
impl<T, Rhs, Output> CommitmentOps<Rhs, Output> for T where
|
||||
T: Add<Rhs, Output = Output> + AddAssign<Rhs>
|
||||
{
|
||||
}
|
||||
|
||||
/// A helper trait for references with a commitment operation
|
||||
pub trait CommitmentOpsOwned<Rhs = Self, Output = Self>:
|
||||
for<'r> CommitmentOps<&'r Rhs, Output>
|
||||
{
|
||||
}
|
||||
impl<T, Rhs, Output> CommitmentOpsOwned<Rhs, Output> for T where
|
||||
T: for<'r> CommitmentOps<&'r Rhs, Output>
|
||||
{
|
||||
}
|
||||
|
||||
/// A helper trait for types implementing a multiplication of a commitment with a scalar
|
||||
pub trait ScalarMul<Rhs, Output = Self>: Mul<Rhs, Output = Output> + MulAssign<Rhs> {}
|
||||
|
||||
impl<T, Rhs, Output> ScalarMul<Rhs, Output> for T where T: Mul<Rhs, Output = Output> + MulAssign<Rhs>
|
||||
{}
|
||||
|
||||
/// This trait defines the behavior of the commitment
|
||||
pub trait CommitmentTrait<G: Group>:
|
||||
Clone
|
||||
+ Copy
|
||||
+ Debug
|
||||
+ Default
|
||||
+ PartialEq
|
||||
+ Eq
|
||||
+ Send
|
||||
+ Sync
|
||||
+ Serialize
|
||||
+ for<'de> Deserialize<'de>
|
||||
+ AbsorbInROTrait<G>
|
||||
+ AppendToTranscriptTrait
|
||||
+ CommitmentOps
|
||||
+ CommitmentOpsOwned
|
||||
+ ScalarMul<G::Scalar>
|
||||
{
|
||||
/// Holds the type of the compressed commitment
|
||||
type CompressedCommitment;
|
||||
|
||||
/// Compresses self into a compressed commitment
|
||||
fn compress(&self) -> Self::CompressedCommitment;
|
||||
|
||||
/// Returns the coordinate representation of the commitment
|
||||
fn to_coordinates(&self) -> (G::Base, G::Base, bool);
|
||||
}
|
||||
|
||||
/// This trait defines the behavior of a compressed commitment
|
||||
pub trait CompressedCommitmentTrait<C: CompressedGroup>:
|
||||
Clone
|
||||
+ Debug
|
||||
+ PartialEq
|
||||
+ Eq
|
||||
+ Send
|
||||
+ Sync
|
||||
+ Serialize
|
||||
+ for<'de> Deserialize<'de>
|
||||
+ AppendToTranscriptTrait
|
||||
{
|
||||
/// Holds the type of the commitment that can be decompressed into
|
||||
type Commitment;
|
||||
|
||||
/// Decompresses self into a commitment
|
||||
fn decompress(&self) -> Result<Self::Commitment, NovaError>;
|
||||
}
|
||||
|
||||
/// A trait that ties different pieces of the commitment generation together
|
||||
pub trait CommitmentEngineTrait<G: Group>:
|
||||
Clone + Send + Sync + Serialize + for<'de> Deserialize<'de>
|
||||
{
|
||||
/// Holds the type of the commitment key
|
||||
type CommitmentGens: CommitmentGensTrait<
|
||||
G,
|
||||
Commitment = Self::Commitment,
|
||||
CompressedCommitment = Self::CompressedCommitment,
|
||||
>;
|
||||
|
||||
/// Holds the type of the commitment
|
||||
type Commitment: CommitmentTrait<G, CompressedCommitment = Self::CompressedCommitment>;
|
||||
|
||||
/// Holds the type of the compressed commitment
|
||||
type CompressedCommitment: CompressedCommitmentTrait<
|
||||
G::CompressedGroupElement,
|
||||
Commitment = Self::Commitment,
|
||||
>;
|
||||
|
||||
/// Commits to the provided vector using the provided generators
|
||||
fn commit(gens: &Self::CommitmentGens, v: &[G::Scalar]) -> Self::Commitment;
|
||||
}
|
||||
46
src/traits/evaluation.rs
Normal file
46
src/traits/evaluation.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
//! This module defines a collection of traits that define the behavior of a polynomial evaluation engine
|
||||
//! A vector of size N is treated as a multilinear polynomial in \log{N} variables,
|
||||
//! and a commitment provided by the commitment engine is treated as a multilinear polynomial commitment
|
||||
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
|
||||
pub trait EvaluationEngineTrait<G: Group>:
|
||||
Clone + Send + Sync + Serialize + for<'de> Deserialize<'de>
|
||||
{
|
||||
/// A type that holds the associated commitment engine
|
||||
type CE: CommitmentEngineTrait<G>;
|
||||
|
||||
/// A type that holds generators
|
||||
type EvaluationGens: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de>;
|
||||
|
||||
/// A type that holds the evaluation argument
|
||||
type EvaluationArgument: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de>;
|
||||
|
||||
/// A method to perform any additional setup needed to produce proofs of evaluations
|
||||
fn setup(gens: &<Self::CE as CommitmentEngineTrait<G>>::CommitmentGens) -> Self::EvaluationGens;
|
||||
|
||||
/// A method to prove evaluations of a batch of polynomials
|
||||
fn prove_batch(
|
||||
gens: &Self::EvaluationGens,
|
||||
transcript: &mut Transcript,
|
||||
comm: &[<Self::CE as CommitmentEngineTrait<G>>::Commitment],
|
||||
polys: &[Vec<G::Scalar>],
|
||||
points: &[Vec<G::Scalar>],
|
||||
evals: &[G::Scalar],
|
||||
) -> Result<Self::EvaluationArgument, NovaError>;
|
||||
|
||||
/// A method to verify purported evaluations of a batch of polynomials
|
||||
fn verify_batch(
|
||||
gens: &Self::EvaluationGens,
|
||||
transcript: &mut Transcript,
|
||||
comm: &[<Self::CE as CommitmentEngineTrait<G>>::Commitment],
|
||||
points: &[Vec<G::Scalar>],
|
||||
evals: &[G::Scalar],
|
||||
arg: &Self::EvaluationArgument,
|
||||
) -> Result<(), NovaError>;
|
||||
}
|
||||
@@ -12,6 +12,10 @@ use merlin::Transcript;
|
||||
use num_bigint::BigInt;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub mod commitment;
|
||||
|
||||
use commitment::CommitmentEngineTrait;
|
||||
|
||||
/// Represents an element of a group
|
||||
/// This is currently tailored for an elliptic curve group
|
||||
pub trait Group:
|
||||
@@ -47,7 +51,7 @@ pub trait Group:
|
||||
+ for<'de> Deserialize<'de>;
|
||||
|
||||
/// A type representing preprocessed group element
|
||||
type PreprocessedGroupElement: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de>;
|
||||
type PreprocessedGroupElement: Clone + Debug + Send + Sync + Serialize + for<'de> Deserialize<'de>;
|
||||
|
||||
/// A type that represents a hash function that consumes elements
|
||||
/// from the base field and squeezes out elements of the scalar field
|
||||
@@ -56,6 +60,9 @@ pub trait Group:
|
||||
/// An alternate implementation of Self::RO in the circuit model
|
||||
type ROCircuit: ROCircuitTrait<Self::Base> + Serialize + for<'de> Deserialize<'de>;
|
||||
|
||||
/// A type that defines a commitment engine over scalars in the group
|
||||
type CE: CommitmentEngineTrait<Self> + Serialize + for<'de> Deserialize<'de>;
|
||||
|
||||
/// A method to compute a multiexponentation
|
||||
fn vartime_multiscalar_mul(
|
||||
scalars: &[Self::Scalar],
|
||||
@@ -212,4 +219,5 @@ impl<F: PrimeField> AppendToTranscriptTrait for [F] {
|
||||
}
|
||||
|
||||
pub mod circuit;
|
||||
pub mod evaluation;
|
||||
pub mod snark;
|
||||
|
||||
Reference in New Issue
Block a user