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