Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Super IVC: based on a variant of SuperNova #2426

Draft
wants to merge 20 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
44cd41c
Starting superivc
dannywillems Jul 13, 2024
bac1b0f
Define environments
dannywillems Jul 13, 2024
a6abbb9
SuperIVC columns and constraints env
dannywillems Jul 13, 2024
4dfbb73
Adding columns for the block - will be public values
dannywillems Jul 13, 2024
e6ba88d
Adding a constructor for the public columns, used by Poseidon
dannywillems Jul 13, 2024
208ec03
SuperIVC: add some comments regarding the logic
dannywillems Jul 13, 2024
d8fffee
Split the witness environment into IVC and App accumulators
dannywillems Jul 13, 2024
dade17b
Add the current application instance in the environment
dannywillems Jul 13, 2024
256bc2f
Allow to modify the current app instance
dannywillems Jul 13, 2024
6248613
Add some FIXME regarding type cosntraints
dannywillems Jul 13, 2024
fd5652b
SuperIVC: comment about the block computing the hash commitments
dannywillems Jul 13, 2024
07e030e
Env: add some type constraints between folding configurations
dannywillems Jul 13, 2024
a47bc00
Add a helper to get the application output
dannywillems Jul 13, 2024
1266d38
Env: sponges must be parametrized with an ArithmeticSponge, not Spong…
dannywillems Jul 13, 2024
a9b869f
Define get_application_output
dannywillems Jul 13, 2024
e2ea7dd
SuperIVC: add fixme regarding the index type of the btreemap
dannywillems Jul 13, 2024
8cf2b0a
SuperIVC: remove useless import
dannywillems Jul 13, 2024
a89c72d
Implement InterpreterEnv for Witness and Constraints
dannywillems Jul 13, 2024
0526a50
SuperIVC: description and encoding of the function `phi`
dannywillems Jul 14, 2024
00b6f0e
Continue doc
dannywillems Jul 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ivc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,4 +215,5 @@ pub mod poseidon_8_56_5_3_2;
/// 3 elements
pub mod poseidon_params_55_0_7_3;
pub mod prover;
pub mod superivc;
pub mod verifier;
39 changes: 39 additions & 0 deletions ivc/src/superivc/columns.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#[derive(Debug, Clone, PartialEq)]
pub enum SuperIVCColumn {
/// Public selectors
/// Selector to compute the ECC addition
BlockAppECCAdd,
/// Selector to compute the hash of the commitments (APP + IVC)
/// The block will also be responsible to compute the "output" of the
/// selected application "f_j". The block will use the state of the sponge
/// for the specific app, and the final state of this sponge at the end of
/// the fold will be used as a public input for the next instance.
BlockAppHashCommitments,
/// Selector to split the foreign field elements into chunks of 150 bits and
/// 75 bits that can be used for the EC ADD
BlockAppSplit,
/// Public columns. Should be at least the number of round constants for
/// Poseidon
PublicColumn(usize),
/// Any variable
X(usize),
}

/// Compute the height of each block
/// The blocks are:
/// - foreign field elliptic curve additions
/// - computing the hash of the commitments
/// - splitting the commitments in chunks of 150 bits, 15 bits and 75 bits to be
/// used by FF EC addition and the hashes
// FIXME: the output is faked for now
pub fn compute_block_height(block_idx: usize) -> usize {
match block_idx {
// Block for EC ADD
0 => 42,
// Block for hashing the commitments
1 => 42,
// Block for splitting the app in different chunks
2 => 42,
_ => panic!("No block with index {block_idx}"),
}
}
16 changes: 16 additions & 0 deletions ivc/src/superivc/constraints.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use ark_ff::Field;

use kimchi::circuits::expr::{ConstantExpr, Expr};

use super::{columns::SuperIVCColumn, interpreter::InterpreterEnv};

pub struct Env<Fp: Field> {
pub current_idx: usize,
pub constraints: Vec<Expr<ConstantExpr<Fp>, SuperIVCColumn>>,
}

impl<Fp: Field> InterpreterEnv for Env<Fp> {
type Position = SuperIVCColumn;

type Variable = Expr<ConstantExpr<Fp>, SuperIVCColumn>;
}
13 changes: 13 additions & 0 deletions ivc/src/superivc/interpreter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use ark_ff::{One, Zero};

pub trait InterpreterEnv {
type Position;

type Variable: Clone
+ std::ops::Add<Self::Variable, Output = Self::Variable>
+ std::ops::Sub<Self::Variable, Output = Self::Variable>
+ std::ops::Mul<Self::Variable, Output = Self::Variable>
+ std::fmt::Debug
+ Zero
+ One;
}
87 changes: 87 additions & 0 deletions ivc/src/superivc/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//! This module contains an implementation of a variant of the non uniform IVC
//! circuit (NIVC) described in the paper
//! [SuperNova](https://eprint.iacr.org/2022/1758) to be used with the library
//! [folding](folding) of this monorepo. The curve will be supposed to be the
//! curve BN254. We will also suppose that the scalar multiplication can be
//! performed in two steps and that the NIVC circuit can simply perform a
//! foreign field elliptic curve addition.
//!
//! The circuit generalizes the IVC circuit described in the paper
//! [Nova](https://eprint.iacr.org/2021/370) to support non-uniform circuit by
//! adding a list of accumulators ("running instances") and by adding a
//! polynomial-time function φ that will be used to select the function to be
//! run in the circuit.
//!
//! The circuit can be used with the `o1vm` interpreter to run a
//! zero-knowledge virtual machine.
//! To encode the instructions of the virtual machine, the module will use the
//! encoding of the 32-bit instructions.
//! Suppose that there are N instructions, and their encodings is the 32bits
//! value `{x_1, x_1, ..., x_{N}}`.
//! The function φ will be the polynomial function that results of the
//! interpolation of the points `{(i, x_i)}` for `i = 1, ..., N`.
//! In the circuit, we will constrain the evaluation to be equal to zero to
//! encode the condition that `φ((z_i, w_i)) is in [1, ..., N]`, where `(z_i,,
//! w_i)` is the witness of the current instance.
//!
//! As the degree of this function is high (N - 1), we will encode the
//! evaluation of it to degree 2 constraints. The number of columns of the
//! circuit will restrict the number of instructions we can encode. However, as
//! described below, the number of columns will be significantly high to allow
//! the encoding of a large number of instructions, at least enough for a
//! reasonable virtual machine.
//!
//! The paper SuperNova encodes the instructions by polynomial-time function
//! `F_1`, ..., `F_N`. In this module, we want to allow a parallelisation of the
//! NIVC scheme. For that, we will first suppose that all the instructions of
//! the ISA the virtual machine encodes are given by the functions `F_1`, ...,
//! `F_M`.
//! We will suppose that the execution of the function `F_i` is simply given by
//! hashing the commitments to the columns generated by the execution of the
//! function `F_i`. It will give us the value `z_i`.
//!
//! We will also suppose that the polynomials representing the functions `F_i`
//! are over 435 variables. The number 435 is explained below.
// FIXME: maybe 435 will be different.
//!
//! The NIVC circuit described by the SuperNova paper needs to pass the public
//! IO to the next iteration. For that, we will use an instantiation of the
//! Poseidon hash function. For BN254, we decide to use the following parameters
//! to reach a security level of 128 bits: - The number of full rounds is 8.
//! - The number of partial rounds is 56.
//! - The number of state elements is 3.
//!
//! We decide to encode one full execution of the Poseidon hash function in one
//! row. It gives us a total of 435 columns and 192 public inputs to encode the
//! round constants.
//!
//! ## Layout of the circuit
//!
//! TODO
//! 1. Encode the polynomial φ.
//! 2. Check that the execution of the instruction is allowed by providing a
//! merkle path.
//! 3. Execute the function `F_(phi)`.
//! 4. Encode the verifier
//! a. Compute FF EC addition.
//! 5. Compute a merkle root.
//!
//! ## Encode parallelisation
//!
//! The NIVC circuit as described in the SuperNova paper only allow one
//! instruction to be executed at the next step `i + 1`, as at step `i`, the
//! prover must execute the function `phi` to select the next instruction, and
//! compute the hash of the public IO to pass it to the next step. At the next
//! step, the NIVC circuit will check that the hash of the public IO is correct,
//! by recomputing the instruction to be run, and by checking the hash.
//!
//! To allow parallelisation (i.e. at step i + 1, the prover can run any
//! instruction in a set of instructions), we will instead compute a merkle
//! root at step i. At step i + 1, the prover will provide the path in the
//! merkle tree. This will allow to run any instruction in the set of the predefined
//! instructions. The overhead for the prover is to compute the merkle root at
//! the end of the step i.
pub mod columns;
pub mod constraints;
pub mod interpreter;
pub mod witness;
89 changes: 89 additions & 0 deletions ivc/src/superivc/witness.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use std::collections::BTreeMap;

use ark_ec::AffineCurve;
use folding::{FoldingConfig, FoldingOutput};
use mina_poseidon::{constants::SpongeConstants, poseidon::ArithmeticSponge};
use poly_commitment::PolyComm;

use super::{columns::SuperIVCColumn, interpreter::InterpreterEnv};

/// An environment that can be shared between IVC instances
/// It contains all the accumulators that can be picked for a given fold
/// instance k, including the sponges.
/// For each fold instance k, the prover will pick one accumulator to merge with
/// the current instance.
/// We split the accumulators between the ones used by the applications and the one
/// for the IVC.
/// It is parametrized by:
/// - FCAPP: a folding configuration specific for the application
/// - FCIVC: a folding configuration specific for the IVC circuit only
/// - N_APP_COL: the number of columns used by the applications. It does suppose
/// all applications use the same number of columns
// FIXME: constrain the curve, field, etc to be the same
// FIXME: instead of indexing by usize, it would be nice to have a type
// "instruction" or "application" that can be later generalized. It could simply
// be an enum.
pub struct Env<
SpongeConfig: SpongeConstants,
FCApp: FoldingConfig,
FCIVC: FoldingConfig<Curve = FCApp::Curve, Srs = FCApp::Srs>,
const N_APP_COL: usize,
> {
/// IVC accumulators, indexed by natural numbers, but it should be an
/// instruction or an enum representing a list of accepting "functions".
pub ivc_accumulators: BTreeMap<usize, FoldingOutput<FCIVC>>,

/// Accumulators of the applications
pub app_accumulators: BTreeMap<usize, FoldingOutput<FCApp>>,

/// Sponges, index by natural numbers. The natural numbers should be the
/// instruction.
/// We keep one sponge state by isntruction and when we merge different
/// instructions, we can use the different sponges states to compute a new
/// global one.
pub sponges: BTreeMap<
usize,
ArithmeticSponge<
<<FCApp as FoldingConfig>::Curve as AffineCurve>::ScalarField,
SpongeConfig,
>,
>,

/// Contains the current application instance that will be folded with
pub current_app_instance: [PolyComm<FCApp::Curve>; N_APP_COL],
}

impl<
SpongeConfig: SpongeConstants,
FCApp: FoldingConfig,
FCIVC: FoldingConfig<Curve = FCApp::Curve, Srs = FCApp::Srs>,
const N_APP_COL: usize,
> Env<SpongeConfig, FCApp, FCIVC, N_APP_COL>
{
pub fn set_current_app_instance(&mut self, instance: [PolyComm<FCApp::Curve>; N_APP_COL]) {
self.current_app_instance = instance
}

/// Return the output of the application.
/// We define the output as the first element of the sponge specialised for
/// the application, after absorbing all the commitments of the current app
/// instance being processed
pub fn get_application_output(
&self,
instruction: usize,
) -> <<FCApp as FoldingConfig>::Curve as AffineCurve>::ScalarField {
self.sponges[&instruction].state[0]
}
}

impl<
SpongeConfig: SpongeConstants,
FCApp: FoldingConfig,
FCIVC: FoldingConfig<Curve = FCApp::Curve, Srs = FCApp::Srs>,
const N_APP_COL: usize,
> InterpreterEnv for Env<SpongeConfig, FCApp, FCIVC, N_APP_COL>
{
type Position = SuperIVCColumn;

type Variable = <<FCApp as FoldingConfig>::Curve as AffineCurve>::ScalarField;
}
Loading