Skip to content

Commit 4fc4b7b

Browse files
committed
prover: LogUp k4 is the default on the STARK base tables
`LAMBDA_VM_ZF_LOGUP` unset now selects k4 (up to four LogUp interactions per aux column where the arity rule admits it); `=pair` keeps the previous bytes and is the rollback. The setting reaches the block's base tables only (block_base_options); the LFM chips keep pairs. Measured as the opt-in: median phase B -9.56 s (BIG 600, t -27), 1x base -0.97 s (FAST 861). Every consumer derives the layout from the options, not from the proof: the base AIRs pick the arity in AirWithBuses::new from options.format.logup, the host verifier and the block verifier build those AIRs from block_base_options, and the tree's leaf programs size each base sub-proof (aux width, composition parts, constraint program) from the same AIRs. Tests: the default base options build exactly the k4 programs and the pair spelling builds the golden pair list; a pair proof is refused under the k4 layout (the reverse of N3); the production-sites test expects the base format's arity; the pinned tree ids derive under pair, the format they were recorded under.
1 parent 035aef5 commit 4fc4b7b

5 files changed

Lines changed: 93 additions & 26 deletions

File tree

‎crypto/stark/src/tests/bus_tests/logup_arity_tests.rs‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,19 @@ fn a_k4_proof_is_refused_under_the_pair_layout() {
352352
assert!(!verifies(&pair, &proof));
353353
}
354354

355+
/// N3 reversed, now that k4 is the production default: a pair-layout proof
356+
/// (the rollback) checked against the k4 AIR is refused on shape too, so a
357+
/// verifier at the default never accepts a proof made at the rollback.
358+
#[test]
359+
fn a_pair_proof_is_refused_under_the_k4_layout() {
360+
let pair = air(6, 1, &options(4, LogUpPolicy::Pair));
361+
let proof = prove(&pair, trace(6, 1, 13));
362+
assert!(verifies(&pair, &proof), "the pair control proof verifies");
363+
let k4 = air(6, 1, &options(4, LogUpPolicy::K4));
364+
assert_eq!(k4.trace_layout().1, 4);
365+
assert!(!verifies(&k4, &proof));
366+
}
367+
355368
/// N4: a proof carrying 3 or 5 part OODs for a 4-part AIR.
356369
#[test]
357370
fn a_wrong_composition_part_count_is_refused() {

‎prover/src/lfm/block_tree_tests.rs‎

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -777,11 +777,30 @@ fn production_height_plan() -> BlockTreePlan {
777777

778778
/// [`spread_fixture_shape`]'s plan under the block base's options.
779779
fn spread_plan(chunks: usize, cpus: usize) -> BlockTreePlan {
780-
let opts = super::proof::block_base_options();
780+
spread_plan_under(chunks, cpus, &super::proof::block_base_options())
781+
}
782+
783+
/// [`spread_plan`] at the default format with the LogUp pair layout — the
784+
/// format the pinned tree ids were recorded under, before k4 became the
785+
/// default. The pins guard the program form, which no format choice changes,
786+
/// so they keep holding at the rollback format.
787+
fn pinned_spread_plan(chunks: usize, cpus: usize) -> BlockTreePlan {
788+
let pair = crate::zf_format::ZfFormat {
789+
logup: stark::proof::options::LogUpPolicy::Pair,
790+
..crate::zf_format::ZfFormat::DEFAULT
791+
};
792+
spread_plan_under(
793+
chunks,
794+
cpus,
795+
&pair.base_options(crate::recursion::Preset::Blowup4.options()),
796+
)
797+
}
798+
799+
fn spread_plan_under(chunks: usize, cpus: usize, opts: &crate::ProofOptions) -> BlockTreePlan {
781800
let elf_bytes = crate::test_utils::asm_elf_bytes("poc_rodata_commit");
782801
let elf = executor::elf::Elf::load(&elf_bytes).expect("load the ELF");
783802
let shape = spread_fixture_shape(&elf, chunks, cpus);
784-
BlockTreePlan::derive(&elf_bytes, &opts, &shape).expect("the plan derives")
803+
BlockTreePlan::derive(&elf_bytes, opts, &shape).expect("the plan derives")
785804
}
786805

787806
/// ★ D-ANYBLOCK S5 §4.13 instrument (laptop): a block leaf program's host bytes
@@ -1123,7 +1142,7 @@ fn check_pinned_tree_ids(label: &str, plan: &BlockTreePlan, pins: &[(&str, &[&st
11231142
#[test]
11241143
#[should_panic(expected = "no pinned ids for the fixture ELF's digest")]
11251144
fn pinned_tree_ids_refuse_an_elf_they_do_not_know() {
1126-
check_pinned_tree_ids("NONE", &spread_plan(2, 4), &[("00", &[])]);
1145+
check_pinned_tree_ids("NONE", &pinned_spread_plan(2, 4), &[("00", &[])]);
11271146
}
11281147

11291148
/// The fixture ELF's digest on the laptop (macOS clang) and on FAST.
@@ -1137,7 +1156,7 @@ const FAST_ELF_DIGEST: &str = "f5e120d0eaa369d7ebdec2767b8d0c0559ceeac138edf0970
11371156
#[test]
11381157
#[ignore = "laptop or box: run with --exact"]
11391158
fn the_compact_program_form_keeps_a_small_trees_ids() {
1140-
check_pinned_tree_ids("SMALL TREE IDS", &spread_plan(2, 4), &SMALL_TREE_IDS);
1159+
check_pinned_tree_ids("SMALL TREE IDS", &pinned_spread_plan(2, 4), &SMALL_TREE_IDS);
11411160
}
11421161

11431162
/// The same at production heights ([`production_height_plan`]: 7 leaves, 2
@@ -1148,7 +1167,7 @@ fn the_compact_program_form_keeps_a_small_trees_ids() {
11481167
fn the_compact_program_form_keeps_every_production_height_tree_id() {
11491168
check_pinned_tree_ids(
11501169
"TREE IDS",
1151-
&production_height_plan(),
1170+
&pinned_spread_plan(13, 40),
11521171
&PRODUCTION_HEIGHT_TREE_IDS,
11531172
);
11541173
}

‎prover/src/tests/compiled_constraints.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ pub(crate) fn production_programs(
116116

117117
/// The option sets the compiled kernels cover: the legacy format at blowup 2
118118
/// and 4 (every program the pair layout builds), and the VM tables under
119-
/// `LAMBDA_VM_ZF_LOGUP=k4` at the block's blowup 4 (the tables the rule moves
119+
/// k4, the block's default, at its blowup 4 (the tables the rule moves
120120
/// to four interactions per column get their own programs; the LFM chips keep
121121
/// pairs under every policy and the local-to-global tables are too narrow to
122122
/// move, so neither is rebuilt).

‎prover/src/tests/logup_arity_tests.rs‎

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,13 +140,9 @@ fn options(blowup: u8, logup: LogUpPolicy) -> ProofOptions {
140140
opts
141141
}
142142

143-
/// ★ T0a: under the pair policy, every production VM table and every LFM chip
144-
/// has today's widths, part count and constraint program, byte for byte —
145-
/// the default format moves no compiled-kernel key and no proof. The same
146-
/// holds for a wide policy at a blowup that cannot hold wider groups.
147-
#[test]
148-
fn the_pair_policy_keeps_every_production_program() {
149-
let golden: Vec<Program> = PAIR_GOLDEN
143+
/// [`PAIR_GOLDEN`] as programs.
144+
fn pair_golden() -> Vec<Program> {
145+
PAIR_GOLDEN
150146
.iter()
151147
.map(|&(label, main, aux, parts, digest)| Program {
152148
label: label.to_string(),
@@ -155,7 +151,17 @@ fn the_pair_policy_keeps_every_production_program() {
155151
parts,
156152
digest,
157153
})
158-
.collect();
154+
.collect()
155+
}
156+
157+
/// ★ T0a: under the pair policy, every production VM table and every LFM chip
158+
/// has the widths, part count and constraint program it had before arities
159+
/// existed, byte for byte — the rollback (`LAMBDA_VM_ZF_LOGUP=pair`) moves no
160+
/// compiled-kernel key and no proof. The same holds for a wide policy at a
161+
/// blowup that cannot hold wider groups.
162+
#[test]
163+
fn the_pair_policy_keeps_every_production_program() {
164+
let golden = pair_golden();
159165
assert!(!golden.is_empty(), "the golden list is pinned");
160166
assert_eq!(programs(&options(4, LogUpPolicy::Pair)), golden);
161167
let legacy = GoldilocksCubicProofOptions::with_blowup(4).expect("blowup 4");
@@ -171,6 +177,27 @@ fn the_pair_policy_keeps_every_production_program() {
171177
}
172178
}
173179

180+
/// ★ k4 is the production default: the block's base options with no knob set
181+
/// ([`crate::zf_format::ZfFormat::DEFAULT`]) build exactly the k4 programs, and
182+
/// the rollback spelling `LAMBDA_VM_ZF_LOGUP=pair` builds the golden pair list,
183+
/// byte for byte.
184+
#[test]
185+
fn the_default_base_format_is_k4_and_pair_rolls_back() {
186+
use crate::zf_format::{ENV_LOGUP, ZfFormat};
187+
let base = GoldilocksCubicProofOptions::with_blowup(4).expect("blowup 4");
188+
let default = ZfFormat::DEFAULT.base_options(base.clone());
189+
assert_eq!(default.format.logup, LogUpPolicy::K4);
190+
assert_eq!(programs(&default), programs(&options(4, LogUpPolicy::K4)));
191+
assert_ne!(
192+
programs(&default),
193+
pair_golden(),
194+
"k4 moves the switched tables"
195+
);
196+
let rollback = ZfFormat::from_lookup(|name| (name == ENV_LOGUP).then(|| "pair".to_string()))
197+
.expect("the rollback spelling parses");
198+
assert_eq!(programs(&rollback.base_options(base)), pair_golden());
199+
}
200+
174201
/// ★ T0f on the production tables: under `k4` at blowup 4 each table commits
175202
/// `⌈N/k⌉` aux columns and `max(3, k + 1) − 1` parts for the arity the rule
176203
/// picks (D-LOGUP §2.2), the LFM chips keep pairs under the production

‎prover/src/zf_format.rs‎

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
//!
1414
//! ★ Every unset knob is [`ZfFormat::DEFAULT`], the MEASURED configuration:
1515
//! `cap=auto whir_cap=auto fri=dp one_row=auto whir_folds=first6 whir_stack=27 whir_grind=query
16-
//! logup=pair`.
16+
//! logup=k4`.
1717
//! Each lever was measured net positive on block runs before it became the
1818
//! default (`one_row=auto` on the STARK pipeline: see [`ZfFormat::DEFAULT`]).
1919
//! Every knob keeps its OFF spelling (`cap=off`, `whir_cap=off`,
@@ -52,7 +52,7 @@
5252
//! `*_IMPLEMENTED` constant is flipped when its lever is real.
5353
//!
5454
//! **The banner prints on every setting, including the default**:
55-
//! `ZF FORMAT: cap=auto whir_cap=auto fri=dp one_row=auto whir_folds=first6 whir_stack=27 whir_grind=query logup=pair`.
55+
//! `ZF FORMAT: cap=auto whir_cap=auto fri=dp one_row=auto whir_folds=first6 whir_stack=27 whir_grind=query logup=k4`.
5656
//! Its absence in a log is then a fact about the run, not an ambiguity.
5757
5858
use std::sync::OnceLock;
@@ -210,6 +210,12 @@ impl ZfFormat {
210210
/// query grinds and the blowups are the legacy ones. It changes no STARK
211211
/// proof. `LAMBDA_VM_ZF_WHIR_STACK=25` is the stack's rollback and
212212
/// `LAMBDA_VM_ZF_WHIR_GRIND=all` the grind's.
213+
/// `logup=k4` commits up to four LogUp interactions per aux column on the
214+
/// STARK base tables where the rule admits it (degree ≤ blowup + 1): the
215+
/// median block's phase B −9.56 s (BIG 600, t −27) and the 1× base −0.97 s
216+
/// (FAST 861), most of it from smaller per-table device sets packing under
217+
/// the VRAM gate. It reaches the base tables only ([`Self::base_proof_format`]);
218+
/// the LFM chips keep pairs. `LAMBDA_VM_ZF_LOGUP=pair` is its rollback.
213219
pub const DEFAULT: Self = Self {
214220
cap: CapPolicy::Auto,
215221
whir_cap: CapPolicy::Auto,
@@ -218,7 +224,7 @@ impl ZfFormat {
218224
whir_folds: WhirFolds::First(DEFAULT_WHIR_FIRST_FOLD),
219225
whir_stack: DEFAULT_WHIR_STACK,
220226
whir_grind: WhirGrind::Query,
221-
logup: LogUpPolicy::Pair,
227+
logup: LogUpPolicy::K4,
222228
};
223229

224230
/// The legacy format: every lever off. What all eight knobs at their
@@ -565,13 +571,13 @@ mod tests {
565571
whir_folds: WhirFolds::First(FirstFold::new(6).unwrap()),
566572
whir_stack: StackVars::new(27).unwrap(),
567573
whir_grind: WhirGrind::Query,
568-
logup: LogUpPolicy::Pair,
574+
logup: LogUpPolicy::K4,
569575
}
570576
);
571577
assert_eq!(
572578
f.banner(),
573579
"ZF FORMAT: cap=auto whir_cap=auto fri=dp one_row=auto whir_folds=first6 whir_stack=27 \
574-
whir_grind=query logup=pair"
580+
whir_grind=query logup=k4"
575581
);
576582
assert!(!f.is_legacy());
577583
assert!(f.unimplemented_levers().is_empty());
@@ -865,7 +871,7 @@ mod tests {
865871
.unwrap()
866872
.banner(),
867873
"ZF FORMAT: cap=auto whir_cap=auto fri=dp one_row=auto whir_folds=first6 whir_stack=27 \
868-
whir_grind=query logup=pair"
874+
whir_grind=query logup=k4"
869875
);
870876
}
871877

@@ -1150,15 +1156,17 @@ mod tests {
11501156
// No test sets a ZF knob, so the process format is the default and the
11511157
// production constructors must stamp the MEASURED configuration.
11521158
assert_eq!(*ZfFormat::global(), ZfFormat::DEFAULT);
1153-
let want = ZfFormat::DEFAULT.proof_format();
1154-
for (site, o) in [
1159+
// The LFM proofs carry the chips' pair layout; the base, the default arity.
1160+
for (site, o, want) in [
11551161
(
11561162
"aggregation_wrap_options",
11571163
crate::lfm::proof::aggregation_wrap_options(),
1164+
ZfFormat::DEFAULT.proof_format(),
11581165
),
11591166
(
11601167
"block_base_options",
11611168
crate::lfm::proof::block_base_options(),
1169+
ZfFormat::DEFAULT.base_proof_format(),
11621170
),
11631171
] {
11641172
assert_eq!(o.format, want, "{site}");
@@ -1384,12 +1392,12 @@ mod tests {
13841392
}
13851393

13861394
/// `LAMBDA_VM_ZF_LOGUP`: every spelling parses to its policy and moves no
1387-
/// other field; `pair` is the default and the legacy value. A policy whose
1395+
/// other field; `k4` is the default, `pair` the legacy value and the rollback. A policy whose
13881396
/// device path this build lacks is reported (and so aborts at
13891397
/// [`ZfFormat::global`]), never proved as another format.
13901398
#[test]
13911399
fn the_logup_knob_parses_and_unbuilt_policies_are_refused() {
1392-
assert_eq!(ZfFormat::DEFAULT.logup, LogUpPolicy::Pair);
1400+
assert_eq!(ZfFormat::DEFAULT.logup, LogUpPolicy::K4);
13931401
assert_eq!(ZfFormat::LEGACY.logup, LogUpPolicy::Pair);
13941402
for (v, want) in [
13951403
("pair", LogUpPolicy::Pair),
@@ -1474,10 +1482,10 @@ mod tests {
14741482
);
14751483
assert_eq!(f.proof_format(), ZfFormat::DEFAULT.proof_format());
14761484
}
1477-
// No knob set: the production base options are the pair layout.
1485+
// No knob set: the production base options carry k4; the chips, pairs.
14781486
assert_eq!(
14791487
crate::lfm::proof::block_base_options().format.logup,
1480-
LogUpPolicy::Pair
1488+
LogUpPolicy::K4
14811489
);
14821490
assert_eq!(
14831491
crate::lfm::proof::aggregation_wrap_options().format.logup,

0 commit comments

Comments
 (0)