Skip to content

Commit fd949ec

Browse files
authored
Merge pull request #3073 from o1-labs/dw/use-selectors-in-setup
Arrabbiata: move selectors into setup
2 parents 3614c62 + 48a1902 commit fd949ec

15 files changed

+210
-215
lines changed

arrabbiata/src/column.rs

+37-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::challenge::ChallengeTerm;
1+
use crate::{challenge::ChallengeTerm, interpreter::Instruction};
22
use kimchi::circuits::expr::{CacheId, ConstantExpr, Expr, FormattedOutput};
33
use std::collections::HashMap;
44
use strum_macros::{EnumCount as EnumCountMacro, EnumIter};
@@ -14,6 +14,16 @@ use crate::NUMBER_OF_COLUMNS;
1414
// depend on runtime values (e.g. in a zero-knowledge virtual machine).
1515
#[derive(Debug, Clone, Copy, PartialEq, EnumCountMacro, EnumIter, Eq, Hash)]
1616
pub enum Gadget {
17+
/// A dummy gadget, doing nothing. Use for padding.
18+
NoOp,
19+
20+
/// The gadget defining the app.
21+
///
22+
/// For now, the application is considered to be a one-line computation.
23+
/// However, we want to see the application as a collection of reusable
24+
/// gadgets.
25+
///
26+
/// See `<https://github.com/o1-labs/proof-systems/issues/3074>`
1727
App,
1828
// Elliptic curve related gadgets
1929
EllipticCurveAddition,
@@ -41,6 +51,21 @@ pub enum Gadget {
4151
PoseidonSpongeAbsorb,
4252
}
4353

54+
/// Convert an instruction into the corresponding gadget.
55+
impl From<Instruction> for Gadget {
56+
fn from(val: Instruction) -> Gadget {
57+
match val {
58+
Instruction::NoOp => Gadget::NoOp,
59+
Instruction::PoseidonFullRound(starting_round) => {
60+
Gadget::PoseidonFullRound(starting_round)
61+
}
62+
Instruction::PoseidonSpongeAbsorb => Gadget::PoseidonSpongeAbsorb,
63+
Instruction::EllipticCurveScaling(_i_comm, _s) => Gadget::EllipticCurveScaling,
64+
Instruction::EllipticCurveAddition(_i) => Gadget::EllipticCurveAddition,
65+
}
66+
}
67+
}
68+
4469
#[derive(Debug, Clone, Copy, PartialEq)]
4570
pub enum Column {
4671
Selector(Gadget),
@@ -74,11 +99,15 @@ pub type E<Fp> = Expr<ConstantExpr<Fp, ChallengeTerm>, Column>;
7499
impl From<Gadget> for usize {
75100
fn from(val: Gadget) -> usize {
76101
match val {
77-
Gadget::App => 0,
78-
Gadget::EllipticCurveAddition => 1,
79-
Gadget::EllipticCurveScaling => 2,
80-
Gadget::PoseidonSpongeAbsorb => 3,
81-
Gadget::PoseidonFullRound(starting_round) => 4 + starting_round / 5,
102+
Gadget::NoOp => 0,
103+
Gadget::App => 1,
104+
Gadget::EllipticCurveAddition => 2,
105+
Gadget::EllipticCurveScaling => 3,
106+
Gadget::PoseidonSpongeAbsorb => 4,
107+
Gadget::PoseidonFullRound(starting_round) => {
108+
assert_eq!(starting_round % 5, 0);
109+
5 + starting_round / 5
110+
}
82111
}
83112
}
84113
}
@@ -88,6 +117,7 @@ impl FormattedOutput for Column {
88117
fn latex(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
89118
match self {
90119
Column::Selector(sel) => match sel {
120+
Gadget::NoOp => "q_noop".to_string(),
91121
Gadget::App => "q_app".to_string(),
92122
Gadget::EllipticCurveAddition => "q_ec_add".to_string(),
93123
Gadget::EllipticCurveScaling => "q_ec_mul".to_string(),
@@ -104,6 +134,7 @@ impl FormattedOutput for Column {
104134
fn text(&self, _cache: &mut HashMap<CacheId, Self>) -> String {
105135
match self {
106136
Column::Selector(sel) => match sel {
137+
Gadget::NoOp => "q_noop".to_string(),
107138
Gadget::App => "q_app".to_string(),
108139
Gadget::EllipticCurveAddition => "q_ec_add".to_string(),
109140
Gadget::EllipticCurveScaling => "q_ec_mul".to_string(),

arrabbiata/src/constraint.rs

-7
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ where
2828
pub idx_var: usize,
2929
pub idx_var_next_row: usize,
3030
pub constraints: Vec<E<C::ScalarField>>,
31-
pub activated_gadget: Option<Gadget>,
3231
}
3332

3433
impl<C: ArrabbiataCurve> Env<C>
@@ -48,7 +47,6 @@ where
4847
idx_var: 0,
4948
idx_var_next_row: 0,
5049
constraints: Vec::new(),
51-
activated_gadget: None,
5250
}
5351
}
5452
}
@@ -100,10 +98,6 @@ where
10098
res
10199
}
102100

103-
fn activate_gadget(&mut self, gadget: Gadget) {
104-
self.activated_gadget = Some(gadget);
105-
}
106-
107101
fn add_constraint(&mut self, constraint: Self::Variable) {
108102
let degree = constraint.degree(1, 0);
109103
debug!("Adding constraint of degree {degree}: {:}", constraint);
@@ -151,7 +145,6 @@ where
151145
self.idx_var = 0;
152146
self.idx_var_next_row = 0;
153147
self.constraints.clear();
154-
self.activated_gadget = None;
155148
}
156149

157150
fn coin_folding_combiner(&mut self, pos: Self::Position) -> Self::Variable {
File renamed without changes.

arrabbiata/src/decider/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pub mod column_env;
2+
pub mod proof;
3+
pub mod prover;
4+
pub mod verifier;
File renamed without changes.

arrabbiata/src/prover.rs arrabbiata/src/decider/prover.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! A prover for the folding/accumulation scheme
22
3-
use crate::{curve::ArrabbiataCurve, proof::Proof};
3+
use crate::{curve::ArrabbiataCurve, decider::proof::Proof};
44
use ark_ff::PrimeField;
55

66
use crate::witness::Env;
File renamed without changes.

arrabbiata/src/interpreter.rs

+53-12
Original file line numberDiff line numberDiff line change
@@ -570,9 +570,7 @@
570570
//! +-----------------------------+
571571
//! ```
572572
573-
use crate::{
574-
column::Gadget, curve::PlonkSpongeConstants, MAXIMUM_FIELD_SIZE_IN_BITS, NUMBER_OF_COLUMNS,
575-
};
573+
use crate::{curve::PlonkSpongeConstants, MAXIMUM_FIELD_SIZE_IN_BITS, NUMBER_OF_COLUMNS};
576574
use ark_ff::{One, Zero};
577575
use log::debug;
578576
use mina_poseidon::constants::SpongeConstants;
@@ -621,6 +619,11 @@ pub enum Instruction {
621619
NoOp,
622620
}
623621

622+
/// The first instruction in the verifier circuit (often shortened in "IVC" in
623+
/// the crate) is the Poseidon permutation. It is used to start hashing the
624+
/// public input.
625+
pub const VERIFIER_STARTING_INSTRUCTION: Instruction = Instruction::PoseidonSpongeAbsorb;
626+
624627
/// Define the side of the temporary accumulator.
625628
/// When computing G1 + G2, the interpreter will load G1 and after that G2.
626629
/// This enum is used to decide which side fetching into the cells.
@@ -662,9 +665,6 @@ pub trait InterpreterEnv {
662665
/// Set the value of the variable at the given position for the current row
663666
fn write_column(&mut self, col: Self::Position, v: Self::Variable) -> Self::Variable;
664667

665-
/// Activate the gadget for the row.
666-
fn activate_gadget(&mut self, gadget: Gadget);
667-
668668
/// Build the constant zero
669669
fn zero(&self) -> Self::Variable;
670670

@@ -874,7 +874,6 @@ pub fn run_ivc<E: InterpreterEnv>(env: &mut E, instr: Instruction) {
874874
assert!(processing_bit < MAXIMUM_FIELD_SIZE_IN_BITS, "Invalid bit index. The fields are maximum on {MAXIMUM_FIELD_SIZE_IN_BITS} bits, therefore we cannot process the bit {processing_bit}");
875875
assert!(i_comm < NUMBER_OF_COLUMNS, "Invalid index. We do only support the scaling of the commitments to the columns, for now. We must additionally support the scaling of cross-terms and error terms");
876876
debug!("Processing scaling of commitment {i_comm}, bit {processing_bit}");
877-
env.activate_gadget(Gadget::EllipticCurveScaling);
878877
// When processing the first bit, we must load the scalar, and it
879878
// comes from previous computation.
880879
// The two first columns are supposed to be used for the output.
@@ -1018,7 +1017,6 @@ pub fn run_ivc<E: InterpreterEnv>(env: &mut E, instr: Instruction) {
10181017
};
10191018
}
10201019
Instruction::EllipticCurveAddition(i_comm) => {
1021-
env.activate_gadget(Gadget::EllipticCurveAddition);
10221020
assert!(i_comm < NUMBER_OF_COLUMNS, "Invalid index. We do only support the addition of the commitments to the columns, for now. We must additionally support the scaling of cross-terms and error terms");
10231021
let (x1, y1) = {
10241022
let x1 = env.allocate();
@@ -1075,8 +1073,6 @@ pub fn run_ivc<E: InterpreterEnv>(env: &mut E, instr: Instruction) {
10751073
starting_round + 5
10761074
);
10771075

1078-
env.activate_gadget(Gadget::PoseidonFullRound(starting_round));
1079-
10801076
let round_input_positions: Vec<E::Position> = (0..PlonkSpongeConstants::SPONGE_WIDTH)
10811077
.map(|_i| env.allocate())
10821078
.collect();
@@ -1146,8 +1142,6 @@ pub fn run_ivc<E: InterpreterEnv>(env: &mut E, instr: Instruction) {
11461142
});
11471143
}
11481144
Instruction::PoseidonSpongeAbsorb => {
1149-
env.activate_gadget(Gadget::PoseidonSpongeAbsorb);
1150-
11511145
let round_input_positions: Vec<E::Position> = (0..PlonkSpongeConstants::SPONGE_WIDTH
11521146
- 1)
11531147
.map(|_i| env.allocate())
@@ -1186,3 +1180,50 @@ pub fn run_ivc<E: InterpreterEnv>(env: &mut E, instr: Instruction) {
11861180
// Compute the hash of the public input
11871181
// FIXME: add the verification key. We should have a hash of it.
11881182
}
1183+
1184+
/// Describe the control-flow for the verifier circuit.
1185+
pub fn fetch_next_instruction(current_instruction: Instruction) -> Instruction {
1186+
match current_instruction {
1187+
Instruction::PoseidonFullRound(i) => {
1188+
if i < PlonkSpongeConstants::PERM_ROUNDS_FULL - 5 {
1189+
Instruction::PoseidonFullRound(i + 5)
1190+
} else {
1191+
// FIXME: for now, we continue absorbing because the current
1192+
// code, while fetching the values to absorb, raises an
1193+
// exception when we absorbed everythimg, and the main file
1194+
// handles the halt by filling as many rows as expected (see
1195+
// [VERIFIER_CIRCUIT_SIZE]).
1196+
Instruction::PoseidonSpongeAbsorb
1197+
}
1198+
}
1199+
Instruction::PoseidonSpongeAbsorb => {
1200+
// Whenever we absorbed a value, we run the permutation.
1201+
Instruction::PoseidonFullRound(0)
1202+
}
1203+
Instruction::EllipticCurveScaling(i_comm, bit) => {
1204+
// TODO: we still need to substract (or not?) the blinder.
1205+
// Maybe we can avoid this by aggregating them.
1206+
// TODO: we also need to aggregate the cross-terms.
1207+
// Therefore i_comm must also take into the account the number
1208+
// of cross-terms.
1209+
assert!(i_comm < NUMBER_OF_COLUMNS, "Maximum number of columns reached ({NUMBER_OF_COLUMNS}), increase the number of columns");
1210+
assert!(bit < MAXIMUM_FIELD_SIZE_IN_BITS, "Maximum number of bits reached ({MAXIMUM_FIELD_SIZE_IN_BITS}), increase the number of bits");
1211+
if bit < MAXIMUM_FIELD_SIZE_IN_BITS - 1 {
1212+
Instruction::EllipticCurveScaling(i_comm, bit + 1)
1213+
} else if i_comm < NUMBER_OF_COLUMNS - 1 {
1214+
Instruction::EllipticCurveScaling(i_comm + 1, 0)
1215+
} else {
1216+
// We have computed all the bits for all the columns
1217+
Instruction::NoOp
1218+
}
1219+
}
1220+
Instruction::EllipticCurveAddition(i_comm) => {
1221+
if i_comm < NUMBER_OF_COLUMNS - 1 {
1222+
Instruction::EllipticCurveAddition(i_comm + 1)
1223+
} else {
1224+
Instruction::NoOp
1225+
}
1226+
}
1227+
Instruction::NoOp => Instruction::NoOp,
1228+
}
1229+
}

arrabbiata/src/lib.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,25 @@ use strum::EnumCount as _;
55
pub mod challenge;
66
pub mod cli;
77
pub mod column;
8-
pub mod column_env;
98
pub mod constraint;
109
pub mod curve;
10+
11+
/// The final decider, i.e. the SNARK used on the accumulation scheme.
12+
pub mod decider;
13+
1114
pub mod interpreter;
1215
pub mod logup;
1316
pub mod poseidon_3_60_0_5_5_fp;
1417
pub mod poseidon_3_60_0_5_5_fq;
15-
pub mod proof;
16-
pub mod prover;
1718
pub mod setup;
18-
pub mod verifier;
1919
pub mod witness;
2020

2121
/// The maximum degree of the polynomial that can be represented by the
2222
/// polynomial-time function the library supports.
2323
pub const MAX_DEGREE: usize = 5;
2424

2525
/// The minimum SRS size required to use Nova, in base 2.
26-
/// Requiring at least 2^16 to perform 16bits range checks.
27-
pub const MIN_SRS_LOG2_SIZE: usize = 16;
26+
pub const MIN_SRS_LOG2_SIZE: usize = 8;
2827

2928
/// The maximum number of columns that can be used in the circuit.
3029
pub const NUMBER_OF_COLUMNS: usize = 15;
@@ -58,8 +57,8 @@ pub const MAXIMUM_FIELD_SIZE_IN_BITS: u64 = 255;
5857
/// verifier circuit.
5958
pub const NUMBER_OF_VALUES_TO_ABSORB_PUBLIC_IO: usize = NUMBER_OF_COLUMNS * 2;
6059

61-
/// The number of selectors used in the circuit.
62-
pub const NUMBER_OF_SELECTORS: usize =
60+
/// The number of gadgets supported by the program
61+
pub const NUMBER_OF_GADGETS: usize =
6362
column::Gadget::COUNT + (PlonkSpongeConstants::PERM_ROUNDS_FULL / 5);
6463

6564
/// The arity of the multivariate polynomials describing the constraints.

arrabbiata/src/main.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,19 @@ pub fn execute(args: cli::ExecuteArgs) {
3636
// FIXME: correctly setup
3737
let indexed_relation = IndexedRelation::new(srs_log2_size);
3838

39-
let domain_size = 1 << srs_log2_size;
40-
4139
let mut env = witness::Env::<Fp, Fq, Vesta, Pallas>::new(BigInt::from(1u64), indexed_relation);
4240

43-
let n_iteration_per_fold = domain_size - VERIFIER_CIRCUIT_SIZE;
44-
4541
while env.current_iteration < n_iteration {
4642
let start_iteration = Instant::now();
4743

4844
info!("Run iteration: {}/{}", env.current_iteration, n_iteration);
4945

5046
// Build the application circuit
51-
info!("Running {n_iteration_per_fold} iterations of the application circuit");
52-
for _i in 0..n_iteration_per_fold {
47+
info!(
48+
"Running {} iterations of the application circuit",
49+
env.indexed_relation.app_size
50+
);
51+
for _i in 0..env.indexed_relation.app_size {
5352
interpreter::run_app(&mut env);
5453
env.reset();
5554
}
@@ -63,13 +62,15 @@ pub fn execute(args: cli::ExecuteArgs) {
6362
// Poseidon hash, and we write on the next row. We don't want to execute
6463
// a new instruction for the verifier circuit here.
6564
for i in 0..VERIFIER_CIRCUIT_SIZE - 1 {
66-
let instr = env.fetch_instruction();
65+
let current_instr = env.fetch_instruction();
6766
debug!(
6867
"Running verifier row {} (instruction = {:?}, witness row = {})",
69-
i, instr, env.current_row
68+
i,
69+
current_instr.clone(),
70+
env.current_row
7071
);
71-
interpreter::run_ivc(&mut env, instr);
72-
env.current_instruction = env.fetch_next_instruction();
72+
interpreter::run_ivc(&mut env, current_instr);
73+
env.current_instruction = interpreter::fetch_next_instruction(current_instr);
7374
env.reset();
7475
}
7576
// FIXME: additional row for the Poseidon hash

0 commit comments

Comments
 (0)