Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
669a694
Change Circuit Interaction PoW Bits (#339)
Gali-StarkWare Mar 12, 2026
56c9f27
Store 1 Variable Value in Eq Gate AIR (#340)
Gali-StarkWare Mar 12, 2026
be4422a
Modify FriCommit validation. (#335)
leo-starkware Mar 15, 2026
490b5e2
Bump stwo, stwo-cairo, and use fri jumps in test. (#336)
leo-starkware Mar 15, 2026
a033b05
small changes (#341)
anatgstarkware Mar 15, 2026
ffd4234
Add packing logic in FRI decommit. (#320)
leo-starkware Mar 15, 2026
f58d877
Change FRI proof deduction. (#321)
leo-starkware Mar 15, 2026
23debfe
Update preprocessed root for lifting_log_size 21 and add root for siz…
ilyalesokhin-starkware Mar 16, 2026
e1b1c8d
Add Debug and PartialEq to configs (#345)
anatgstarkware Mar 16, 2026
0374399
Derive lifting_log_size from log_blowup_factor in privacy config (#348)
ilyalesokhin-starkware Mar 16, 2026
2fe71e9
Parameterize privacy_cairo_verifier_config by log_blowup_factor (#349)
ilyalesokhin-starkware Mar 16, 2026
f91de19
Add decomposed Blake gates (BlakeG, TripleXor, M31ToU32) with packed-…
alon-f Mar 10, 2026
b3ac5a1
Address PR review: cleanup, dedup, and readability improvements
alon-f Mar 15, 2026
8859b92
Document 0x01010020 parameter block fields
alon-f Mar 15, 2026
ed06e36
Rename current_permutation to permutation
alon-f Mar 15, 2026
27e54a4
Add preprocessed column generation for decomposed Blake gates
alon-f Mar 15, 2026
5c43900
Original m31_to_u32 gate files.
alon-f Mar 18, 2026
8ff8377
Add M31ToU32 AIR component with full prove+verify
alon-f Mar 18, 2026
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
338 changes: 170 additions & 168 deletions Cargo.lock

Large diffs are not rendered by default.

36 changes: 21 additions & 15 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,42 @@ edition = "2024"
[workspace.dependencies]
blake2 = { version = "0.10.6", default-features = false }
hashbrown = ">=0.15.2"
indexmap = { version = "2.10.0", default-features = false }
indexmap = { version = "2.10.0", default-features = false, features = ["std"] }
indoc = "2.0.6"
itertools = { version = "0.12", default-features = false, features = [
"use_alloc",
] }
num-traits = { version = "0.2.19", default-features = false }
stwo = { git = "https://github.com/starkware-libs/stwo", rev = "3428a95e", features = [
rstest = "0.26.1"
expect-test = "1.5.1"
rayon = "1.10.0"
serde = "1.0.219"
serde_json = "1.0"

# stwo
stwo = { git = "https://github.com/starkware-libs/stwo", rev = "e584a309", features = [
"parallel",
], default-features = false }
stwo-constraint-framework = { git = "https://github.com/starkware-libs/stwo", rev = "3428a95e", features = [
stwo-constraint-framework = { git = "https://github.com/starkware-libs/stwo", rev = "e584a309", features = [
"parallel",
] }
stwo-air-utils-derive = { git = "https://github.com/starkware-libs/stwo", rev = "3428a95e" }
stwo-air-utils = { git = "https://github.com/starkware-libs/stwo", rev = "3428a95e" }
cairo-air = { git = "https://github.com/starkware-libs/stwo-cairo", rev = "333ba16d" }
stwo_cairo_prover = { package = "stwo-cairo-prover", git = "https://github.com/starkware-libs/stwo-cairo", rev = "333ba16d" }
stwo_cairo_common = { package = "stwo-cairo-common", git = "https://github.com/starkware-libs/stwo-cairo", rev = "333ba16d" }
stwo_cairo_dev_utils = { package = "stwo-cairo-dev-utils", git = "https://github.com/starkware-libs/stwo-cairo", rev = "333ba16d" }
stwo_cairo_utils = { package = "stwo-cairo-utils", git = "https://github.com/starkware-libs/stwo-cairo", rev = "333ba16d" }
stwo-air-utils-derive = { git = "https://github.com/starkware-libs/stwo", rev = "e584a309" }
stwo-air-utils = { git = "https://github.com/starkware-libs/stwo", rev = "e584a309" }

# stwo-cairo
cairo-air = { git = "https://github.com/starkware-libs/stwo-cairo", rev = "0fe22c1f" }
stwo_cairo_prover = { package = "stwo-cairo-prover", git = "https://github.com/starkware-libs/stwo-cairo", rev = "0fe22c1f" }
stwo_cairo_common = { package = "stwo-cairo-common", git = "https://github.com/starkware-libs/stwo-cairo", rev = "0fe22c1f" }
stwo_cairo_dev_utils = { package = "stwo-cairo-dev-utils", git = "https://github.com/starkware-libs/stwo-cairo", rev = "0fe22c1f" }
stwo_cairo_utils = { package = "stwo-cairo-utils", git = "https://github.com/starkware-libs/stwo-cairo", rev = "0fe22c1f" }

# local crates
circuits = { path = "crates/circuits"}
circuit-air = { path = "crates/circuit_air"}
circuit-common = { path = "crates/circuit_common" }
circuit-prover = { path = "crates/circuit_prover"}
circuits-stark-verifier = { path = "crates/stark_verifier"}
circuits-stark-verifier-examples = { path = "crates/stark_verifier_examples"}
rstest = "0.26.1"
expect-test = "1.5.1"
rayon = "1.10.0"
serde = "1.0.219"
serde_json = "1.0"

# Compile the circuit-prover and stwo crates with optimization level 3 to speed up the blake related tests.
[profile.test.package.circuit-prover]
Expand Down
28 changes: 20 additions & 8 deletions crates/cairo_air/src/privacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ pub const PRIVACY_CAIRO_VERIFIER_CONSTS_HASH: [u32; 8] =
[1283865202, 2009681603, 1266623912, 534797207, 1489758000, 741307218, 1414461714, 1643656987];

pub const PRIVACY_RECURSION_CIRCUIT_CONSTS_HASH: [u32; 8] =
[1918909779, 1959776519, 1259409979, 1114474154, 106626018, 731417550, 96744222, 1513056460];
[265232987, 822253498, 1042354533, 1199589796, 811253900, 1354313564, 985444759, 349528097];

pub const PRIVACY_RECURSION_CIRCUIT_PREPROCESSED_ROOT: [u32; 8] =
[263240521, 1367152939, 1051535423, 332158340, 51922189, 1390263238, 1273523373, 1503851977];
[736666193, 671587538, 1100540541, 1401951855, 202000446, 1284259076, 1586213897, 825089717];

/// Returns a fixed [CairoVerifierConfig] for the privacy proof setup.
pub fn privacy_cairo_verifier_config() -> CairoVerifierConfig {
/// Returns a [CairoVerifierConfig] for the privacy proof setup with the given log blowup factor.
pub fn privacy_cairo_verifier_config(log_blowup_factor: u32) -> CairoVerifierConfig {
let privacy_set = privacy_components();
let components: Vec<Box<dyn CircuitEval<NoValue>>> = all_components::<NoValue>()
.into_iter()
Expand All @@ -36,10 +36,22 @@ pub fn privacy_cairo_verifier_config() -> CairoVerifierConfig {
})
.collect_vec();

// Derive proof config parameters from the log blowup factor, targeting 96-bit security.
let (pow_bits, n_queries) = match log_blowup_factor {
1 => (26, 70),
2 => (26, 35),
3 => (27, 23),
_ => panic!("Unsupported log blowup factor: {log_blowup_factor}"),
};
assert!(
pow_bits + n_queries as u32 * log_blowup_factor >= 96_u32,
"The config is not secure enough."
);
let lifting_log_size = 20 + log_blowup_factor;
let pcs_config = PcsConfig {
pow_bits: 26,
fri_config: FriConfig::new(0, 2, 35, 1),
lifting_log_size: Some(22),
pow_bits,
fri_config: FriConfig::new(0, log_blowup_factor, n_queries, 1),
lifting_log_size: Some(lifting_log_size),
};

let proof_config = ProofConfig::from_components(
Expand All @@ -53,7 +65,7 @@ pub fn privacy_cairo_verifier_config() -> CairoVerifierConfig {
let program = load_program(&program_path);

CairoVerifierConfig {
preprocessed_root: get_preprocessed_root(22),
preprocessed_root: get_preprocessed_root(lifting_log_size),
proof_config,
program,
n_outputs: 1,
Expand Down
11 changes: 7 additions & 4 deletions crates/cairo_air/src/privacy_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ fn verify_circuit_proof(
preprocessed_root: HashValue(QM31::zero(), QM31::zero()),
};
let (proof, public_data) =
preprare_circuit_proof_for_circuit_verifier(circuit_proof, proof_config);
preprare_circuit_proof_for_circuit_verifier(circuit_proof, &proof_config);
circuit_config.preprocessed_root = preprocessed_root.unwrap_or(proof.preprocessed_root);
verify_circuit(circuit_config, proof, public_data).unwrap()
}
Expand Down Expand Up @@ -88,7 +88,8 @@ fn test_verify_privacy() {
let context = verify_cairo_with_component_set(&cairo_proof, privacy_components()).unwrap();

// Build the verifier circuit via NoValue.
let const_config = privacy_cairo_verifier_config();
let log_blowup_factor = 2;
let const_config = privacy_cairo_verifier_config(log_blowup_factor);
let novalue_context = build_cairo_verifier_circuit(&const_config);

// Check that building the verifier circuit via NoValue produces the same topology.
Expand Down Expand Up @@ -116,7 +117,8 @@ fn test_verify_privacy_with_recursion() {
#[test]
fn test_privacy_recursion_with_preprocessed_context() {
// Build the verifier circuit via NoValue and preprocess it.
let const_config = privacy_cairo_verifier_config();
let cairo_proof_log_blowup_factor = 2;
let const_config = privacy_cairo_verifier_config(cairo_proof_log_blowup_factor);
let mut novalue_context = build_cairo_verifier_circuit(&const_config);
let preprocessed = PreprocessedCircuit::preprocess_circuit(&mut novalue_context);

Expand Down Expand Up @@ -160,7 +162,8 @@ fn test_privacy_recursion_with_preprocessed_context() {

#[test]
fn test_privacy_consts() {
let const_config = privacy_cairo_verifier_config();
let cairo_proof_log_blowup_factor = 2;
let const_config = privacy_cairo_verifier_config(cairo_proof_log_blowup_factor);
let mut novalue_context = build_cairo_verifier_circuit(&const_config);
let constants = novalue_context.constants().keys().cloned().collect_vec();
let blake_value = QM31::blake(constants.as_slice(), constants.len() * 16);
Expand Down
3 changes: 2 additions & 1 deletion crates/cairo_air/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,8 @@ fn test_verify_all_opcodes() {
channel_hash: ChannelHash::Blake2sM31,
pcs_config: PcsConfig {
pow_bits: 26,
fri_config: FriConfig::new(0, low_blowup_factor, 70, 1),
// Fold step = 3.
fri_config: FriConfig::new(0, low_blowup_factor, 70, 3),
lifting_log_size: Some(20 + low_blowup_factor),
},
preprocessed_trace: PreProcessedTraceVariant::CanonicalSmall,
Expand Down
8 changes: 6 additions & 2 deletions crates/cairo_air/src/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,17 @@ pub const INTERACTION_POW_BITS: u32 = 24;
pub fn get_preprocessed_root(lifting_log_size: u32) -> HashValue<QM31> {
let root = match lifting_log_size {
21 => [
564120632, 1595734162, 1550883364, 1605077950, 129976625, 906430422, 812575238,
606882670,
1318760383, 1968650180, 1092022781, 246736179, 768637788, 1782650371, 1631388100,
1492376542,
],
22 => [
2019947850, 1578675143, 1485624323, 207118193, 636087281, 1354843492, 2101876892,
721181021,
],
23 => [
403551725, 1198969136, 1544105195, 2074510234, 916191583, 1646435042, 649872328,
1026506463,
],
_ => panic!("Unsupported lifting_log_size: {lifting_log_size}"),
};
root.into()
Expand Down
207 changes: 207 additions & 0 deletions crates/circuit_air/src/circuit_eval_components/m_31_to_u_32.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
use super::prelude::*;

pub const N_TRACE_COLUMNS: usize = 4;
pub const N_INTERACTION_COLUMNS: usize = 12;

pub const RELATION_USES_PER_ROW: [RelationUse; 2] = [
RelationUse {
relation_id: "Gate",
uses: 1,
},
RelationUse {
relation_id: "RangeCheck_16",
uses: 3,
},
];

#[allow(unused_variables)]
pub fn accumulate_constraints<Value: IValue>(
input: &[Var],
context: &mut Context<Value>,
component_data: &dyn ComponentDataTrait<Value>,
acc: &mut CompositionConstraintAccumulator,
) {
let [input_m31_col0, input_u32_limb_0_col1, input_u32_limb_1_col2, inv_or_one_col3] =
input.try_into().unwrap();
let m31_to_u32_input_addr = acc.get_preprocessed_column(&PreProcessedColumnId {
id: "m31_to_u32_input_addr".to_owned(),
});
let m31_to_u32_multiplicity = acc.get_preprocessed_column(&PreProcessedColumnId {
id: "m31_to_u32_multiplicity".to_owned(),
});
let m31_to_u32_output_addr = acc.get_preprocessed_column(&PreProcessedColumnId {
id: "m31_to_u32_output_addr".to_owned(),
});
// Use RangeCheck_16.
let tuple_0 = &[
eval!(context, 1008385708),
eval!(context, input_u32_limb_0_col1),
];
let numerator_0 = eval!(context, 1);
acc.add_to_relation(context, numerator_0, tuple_0);

// Use RangeCheck_16.
let tuple_1 = &[
eval!(context, 1008385708),
eval!(context, input_u32_limb_1_col2),
];
let numerator_1 = eval!(context, 1);
acc.add_to_relation(context, numerator_1, tuple_1);

// Use RangeCheck_16.
let tuple_2 = &[
eval!(context, 1008385708),
eval!(context, (32767) - (input_u32_limb_1_col2)),
];
let numerator_2 = eval!(context, 1);
acc.add_to_relation(context, numerator_2, tuple_2);

//input is zero then limb_low is zero.
let constraint_3_value = eval!(
context,
(((input_m31_col0) * (inv_or_one_col3)) - (1)) * (input_u32_limb_0_col1)
);
acc.add_constraint(context, constraint_3_value);

//input reconstruction.
let constraint_4_value = eval!(
context,
(input_m31_col0) - ((input_u32_limb_0_col1) + ((input_u32_limb_1_col2) * (65536)))
);
acc.add_constraint(context, constraint_4_value);

// Use Gate.
let tuple_5 = &[
eval!(context, 378353459),
eval!(context, m31_to_u32_input_addr),
eval!(context, input_m31_col0),
];
let numerator_5 = eval!(context, 1);
acc.add_to_relation(context, numerator_5, tuple_5);

// Yield Gate.
let tuple_6 = &[
eval!(context, 378353459),
eval!(context, m31_to_u32_output_addr),
eval!(context, input_u32_limb_0_col1),
eval!(context, input_u32_limb_1_col2),
];
let numerator_6 = eval!(context, -(m31_to_u32_multiplicity));
acc.add_to_relation(context, numerator_6, tuple_6);
}

pub struct Component {}
impl<Value: IValue> CircuitEval<Value> for Component {
fn name(&self) -> String {
"m_31_to_u_32".to_string()
}

fn evaluate(
&self,
context: &mut Context<Value>,
component_data: &dyn ComponentDataTrait<Value>,
acc: &mut CompositionConstraintAccumulator,
) {
accumulate_constraints(component_data.trace_columns(), context, component_data, acc);
}

fn trace_columns(&self) -> usize {
N_TRACE_COLUMNS
}

fn interaction_columns(&self) -> usize {
N_INTERACTION_COLUMNS
}

fn relation_uses_per_row(&self) -> &[RelationUse] {
&RELATION_USES_PER_ROW
}
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use stwo::core::fields::qm31::QM31;

#[allow(unused_imports)]
use crate::components::prelude::PreProcessedColumnId;
use crate::sample_evaluations::*;
use circuits::context::Context;
use circuits::ivalue::qm31_from_u32s;
use circuits_stark_verifier::constraint_eval::*;
use circuits_stark_verifier::test_utils::TestComponentData;

use super::Component;

#[test]
fn test_evaluation_result() {
let component = Component {};
let mut context: Context<QM31> = Default::default();
context.enable_assert_eq_on_eval();
let trace_columns = [
qm31_from_u32s(1659099300, 905558730, 651199673, 1375009625),
qm31_from_u32s(1591990121, 771341002, 584090809, 1375009625),
qm31_from_u32s(1793317658, 1173994186, 785417401, 1375009625),
qm31_from_u32s(1726208479, 1039776458, 718308537, 1375009625),
];
let interaction_columns = [
qm31_from_u32s(1005168032, 79980996, 1847888101, 1941984119),
qm31_from_u32s(1072277211, 214198724, 1914996965, 1941984119),
qm31_from_u32s(1139386390, 348416452, 1982105829, 1941984119),
];
let component_data = TestComponentData::from_values(
&mut context,
&trace_columns,
&interaction_columns,
qm31_from_u32s(1115374022, 1127856551, 489657863, 643630026),
qm31_from_u32s(1398335417, 314974026, 1722107152, 821933968),
32768,
);
let random_coeff =
context.new_var(qm31_from_u32s(474642921, 876336632, 1911695779, 974600512));
let interaction_elements = [
context.new_var(qm31_from_u32s(445623802, 202571636, 1360224996, 131355117)),
context.new_var(qm31_from_u32s(476823935, 939223384, 62486082, 122423602)),
];
let preprocessed_columns = HashMap::from([
(
PreProcessedColumnId {
id: "m31_to_u32_input_addr".to_owned(),
},
context.constant(qm31_from_u32s(15668215, 1851966168, 874056991, 2075313468)),
),
(
PreProcessedColumnId {
id: "m31_to_u32_output_addr".to_owned(),
},
context.constant(qm31_from_u32s(701904311, 1125291129, 1904795215, 38357025)),
),
(
PreProcessedColumnId {
id: "m31_to_u32_multiplicity".to_owned(),
},
context.constant(qm31_from_u32s(
1979029033, 1524573277, 1930122227, 1490762084,
)),
),
]);
let public_params = HashMap::from([]);
let mut accumulator = CompositionConstraintAccumulator::new(
&mut context,
preprocessed_columns,
public_params,
random_coeff,
interaction_elements,
);
accumulator.set_enable_bit(context.one());
component.evaluate(&mut context, &component_data, &mut accumulator);
accumulator.finalize_logup_in_pairs(
&mut context,
<TestComponentData as ComponentDataTrait<QM31>>::interaction_columns(&component_data),
&component_data,
);

let result = accumulator.finalize();
let result_value = context.get(result);
assert_eq!(result_value, M_31_TO_U_32_SAMPLE_EVAL_RESULT)
}
}
1 change: 1 addition & 0 deletions crates/circuit_air/src/circuit_eval_components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub mod range_check_15;
pub mod range_check_16;
pub mod subroutines;
pub mod triple_xor_32;
pub mod m_31_to_u_32;
pub mod verify_bitwise_xor_12;
pub mod verify_bitwise_xor_4;
pub mod verify_bitwise_xor_7;
Expand Down
Loading