Skip to content

Commit cbfa7d7

Browse files
committed
zf: production WHIR grind bits 20 -> 18 on the block (queries 112 -> 114; min proven bits unchanged at 130.393)
The default flip of LAMBDA_VM_ZF_WHIR_GRIND_BITS: the port of #1010's 5364aa2 and its pin follow-up 2687e48. PRODUCTION_WHIR_GRIND_BITS is 18; LEGACY_WHIR_GRIND_BITS = 20 keeps the legacy format and is the opt-out (LAMBDA_VM_ZF_WHIR_GRIND_BITS=20). It reaches #1014's WHIR proofs: the block's group chains and prepared openings, verify_block_whir, and the W3 leaves' in-guest verifier. The W3 tree's own STARK LFM proofs do not read it. The binding WHIR phase is unchanged (the unground fold at 27 variables, 130.393 bits); the query phases move 130.926 -> 130.907. Measured behind the knob on c55dec4: ULTRA 019 1x phase B -0.344 s (t -12.9), whole -0.270 s, recursion -0.010 s; BIG 628 median whole -3.42 s, both arms verified. The opt-out reproduces the previous 1x proof byte for byte (top digest 0da6fea9 under fixed hash keys and deterministic grind); the new default's is b9b4826d. The W-leg sizing pins follow the process's grind bits, as 2687e48 did on #1010.
1 parent 7863ab5 commit cbfa7d7

8 files changed

Lines changed: 287 additions & 113 deletions

‎prover/src/lfm/whir_chain_tests.rs‎

Lines changed: 98 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1939,59 +1939,100 @@ fn the_first_fold_production_chains_cost_what_the_design_derived() {
19391939
/// do not depend on the fold.
19401940
struct ChainPins {
19411941
grind_perms: usize,
1942+
opening_perms: usize,
19421943
perms: usize,
19431944
words: u32,
19441945
lean: (usize, usize),
19451946
classic: (usize, usize),
19461947
}
19471948

19481949
/// ★ THE PRODUCTION DEFAULT CHAIN — what `chain_config` builds with no knob
1949-
/// set — is `first6` under the `Auto` cap, at blowup 2^2 and Q = 112, grinding
1950-
/// before its queries alone: P2's `whir_grind=query`, one 20-bit grind and one
1950+
/// set — is `first6` under the `Auto` cap, at blowup 2^2 and Q = 114, grinding
1951+
/// before its queries alone: P2's `whir_grind=query`, one 18-bit grind and one
19511952
/// nonce word a round. The legacy chain keeps its own pins above
1952-
/// (`the_production_chain_costs…`, 185,509 / 22,828), and the opt-out
1953-
/// (`whir_grind=all`) keeps the pins this chain had before P2
1954-
/// ([`the_grind_opt_out_chain_keeps_the_pins_from_before_p2`]).
1953+
/// (`the_production_chain_costs…`, 185,509 / 22,828); the same chain at 20
1954+
/// bits (`LAMBDA_VM_ZF_WHIR_GRIND_BITS=20`, Q 112) keeps the pins the default
1955+
/// had before the bits moved ([`the_grind_bits_opt_out_chain_keeps_its_pins`]),
1956+
/// and the opt-out of both (`whir_grind=all` at 20 bits) the pins this chain
1957+
/// had before P2 ([`the_grind_opt_out_chain_keeps_the_pins_from_before_p2`]).
19551958
#[test]
19561959
fn the_production_default_chain_is_first6_under_the_auto_cap() {
19571960
let production = crate::multilinear_prove::chain_config_under(
19581961
&crate::zf_format::ZfFormat::DEFAULT,
19591962
&[(1, 25)],
19601963
);
19611964
let want = ChainConfig {
1962-
grind: GrindBits::query_only(20),
1965+
grind: GrindBits::query_only(18),
19631966
format: ChainFormat {
19641967
cap: CapPolicy::Auto,
19651968
folds: WhirFolds::First(FirstFold::new(6).expect("6")),
19661969
stack: multilinear::whir_chain::StackVars::new(27).expect("27"),
19671970
nonces: NonceLayout::Spent,
19681971
argue: multilinear::whir_chain::ArgueFormat::PerTable,
19691972
},
1970-
..config(112, 0)
1973+
..config(114, 0)
19711974
};
19721975
assert_eq!(production, want, "the production default's chain config");
19731976
let shape = ChainShape::new(&production, 25);
19741977
for r in 0..shape.rounds() {
19751978
assert_eq!(shape.carries(r), [false, false, true], "round {r}");
19761979
}
19771980
check_production_chain("DEFAULT", &shape, &DEFAULT_CHAIN_PINS);
1978-
// Both levers pay: fewer permutations than either alone, and fewer than
1979-
// the same chain grinding all three.
1981+
// The two queries the 18-bit grind buys back cost the verifier their
1982+
// openings (2 × 144 permutations, plus the extra queries' schedule terms):
1983+
// the in-circuit price of two fewer grind bits on the prover.
1984+
const {
1985+
assert!(DEFAULT_CHAIN_PINS.perms > GRIND_BITS_20_CHAIN_PINS.perms);
1986+
assert!(DEFAULT_CHAIN_PINS.grind_perms == GRIND_BITS_20_CHAIN_PINS.grind_perms);
1987+
};
1988+
}
1989+
1990+
/// ★ THE GRIND-BITS OPT-OUT'S CHAIN IS THE DEFAULT'S BEFORE THE BITS MOVED.
1991+
/// `LAMBDA_VM_ZF_WHIR_GRIND_BITS=20` builds P2's chain at 20 bits and Q 112,
1992+
/// with every cost it had then: these pins are the previous default's,
1993+
/// unmoved. P2 and first6 under the auto cap both pay at this Q: fewer
1994+
/// permutations than either alone, and fewer than the same chain grinding all
1995+
/// three.
1996+
#[test]
1997+
fn the_grind_bits_opt_out_chain_keeps_its_pins() {
1998+
let at20 = crate::multilinear_prove::chain_config_under(
1999+
&crate::zf_format::ZfFormat {
2000+
whir_grind_bits: crate::zf_format::LEGACY_WHIR_GRIND_BITS,
2001+
..crate::zf_format::ZfFormat::DEFAULT
2002+
},
2003+
&[(1, 25)],
2004+
);
2005+
let want = ChainConfig {
2006+
grind: GrindBits::query_only(20),
2007+
format: ChainFormat {
2008+
cap: CapPolicy::Auto,
2009+
folds: WhirFolds::First(FirstFold::new(6).expect("6")),
2010+
stack: multilinear::whir_chain::StackVars::new(27).expect("27"),
2011+
nonces: NonceLayout::Spent,
2012+
argue: multilinear::whir_chain::ArgueFormat::PerTable,
2013+
},
2014+
..config(112, 0)
2015+
};
2016+
assert_eq!(at20, want, "the 20-bit chain config");
2017+
let shape = ChainShape::new(&at20, 25);
2018+
check_production_chain("GRIND-BITS-20", &shape, &GRIND_BITS_20_CHAIN_PINS);
19802019
const {
1981-
assert!(DEFAULT_CHAIN_PINS.perms < 18_729 && DEFAULT_CHAIN_PINS.perms < 19_877);
1982-
assert!(DEFAULT_CHAIN_PINS.perms < GRIND_ALL_CHAIN_PINS.perms);
2020+
assert!(GRIND_BITS_20_CHAIN_PINS.perms < 18_729 && GRIND_BITS_20_CHAIN_PINS.perms < 19_877);
2021+
assert!(GRIND_BITS_20_CHAIN_PINS.perms < GRIND_ALL_CHAIN_PINS.perms);
19832022
};
19842023
}
19852024

1986-
/// ★ THE OPT-OUT'S CHAIN IS TODAY'S. `LAMBDA_VM_ZF_WHIR_GRIND=all` builds the
1987-
/// production default's chain exactly as it was before P2, 20-bit grinds before
1988-
/// all three challenges and three nonce words a round, and every cost it had
1989-
/// then: these pins are the pre-P2 default's, unmoved.
2025+
/// ★ THE OPT-OUT'S CHAIN IS TODAY'S. `LAMBDA_VM_ZF_WHIR_GRIND=all` with
2026+
/// `LAMBDA_VM_ZF_WHIR_GRIND_BITS=20` builds the production default's chain
2027+
/// exactly as it was before P2, 20-bit grinds before all three challenges and
2028+
/// three nonce words a round, and every cost it had then: these pins are the
2029+
/// pre-P2 default's, unmoved.
19902030
#[test]
19912031
fn the_grind_opt_out_chain_keeps_the_pins_from_before_p2() {
19922032
let opt_out = crate::multilinear_prove::chain_config_under(
19932033
&crate::zf_format::ZfFormat {
19942034
whir_grind: crate::zf_format::WhirGrind::All,
2035+
whir_grind_bits: crate::zf_format::LEGACY_WHIR_GRIND_BITS,
19952036
..crate::zf_format::ZfFormat::DEFAULT
19962037
},
19972038
&[(1, 25)],
@@ -2020,9 +2061,10 @@ fn check_production_chain(label: &str, shape: &ChainShape, pins: &ChainPins) {
20202061
);
20212062
let entry = SpongeEntry::fresh();
20222063
println!(
2023-
"production {label} chain S=25 first6 cap=auto Q=112 grind={:?}: caps {:?}, {} opening \
2064+
"production {label} chain S=25 first6 cap=auto Q={} grind={:?}: caps {:?}, {} opening \
20242065
permutations, {} cap permutations, {} grind permutations, {} permutations, {} words, \
20252066
{} rows ({} shape rows)",
2067+
shape.num_queries,
20262068
shape.grind,
20272069
shape.caps,
20282070
chain_opening_perms(shape),
@@ -2040,7 +2082,7 @@ fn check_production_chain(label: &str, shape: &ChainShape, pins: &ChainPins) {
20402082
);
20412083
assert_eq!(
20422084
chain_opening_perms(shape),
2043-
16_166,
2085+
pins.opening_perms,
20442086
"{label}: opening permutations"
20452087
);
20462088
assert_eq!(chain_cap_perms(shape), 38, "{label}: cap permutations");
@@ -2080,10 +2122,22 @@ fn check_production_chain(label: &str, shape: &ChainShape, pins: &ChainPins) {
20802122
/// The production default chain's pins, derived by the closed forms and
20812123
/// checked against the EMITTED program by
20822124
/// [`the_production_chains_emit_their_closed_forms`]. P2's: one grind a round
2083-
/// (6 × 2 permutations), one nonce word a round.
2125+
/// (6 × 2 permutations), one nonce word a round; Q 114 at 18 grind bits.
20842126
const DEFAULT_CHAIN_CAPS: &[usize] = &[3, 3, 3, 3, 3, 2];
20852127
const DEFAULT_CHAIN_PINS: ChainPins = ChainPins {
20862128
grind_perms: 12,
2129+
opening_perms: 16_454,
2130+
perms: 16_705,
2131+
words: 33_170,
2132+
lean: (152_175, 152_904),
2133+
classic: (205_730, 206_459),
2134+
};
2135+
2136+
/// The grind-bits opt-out's pins (20 bits, Q 112), which are the production
2137+
/// default's from before the bits moved.
2138+
const GRIND_BITS_20_CHAIN_PINS: ChainPins = ChainPins {
2139+
grind_perms: 12,
2140+
opening_perms: 16_166,
20872141
perms: 16_411,
20882142
words: 32_590,
20892143
lean: (149_547, 150_258),
@@ -2094,33 +2148,44 @@ const DEFAULT_CHAIN_PINS: ChainPins = ChainPins {
20942148
/// `3R − 1 = 17` grinds (34 permutations), three nonce words a round.
20952149
const GRIND_ALL_CHAIN_PINS: ChainPins = ChainPins {
20962150
grind_perms: 34,
2151+
opening_perms: 16_166,
20972152
perms: 16_443,
20982153
words: 32_602,
20992154
lean: (150_075, 150_811),
21002155
classic: (202_690, 203_426),
21012156
};
21022157

2103-
/// ★ The production chains, EMITTED (the F1 of the two tests above), the
2104-
/// default and the opt-out, under both fold emissions. `#[ignore]`d like its
2105-
/// siblings: production-shape programs; laptop-safe.
2158+
/// ★ The production chains, EMITTED (the F1 of the three tests above), the
2159+
/// default and the two opt-outs, under both fold emissions. `#[ignore]`d like
2160+
/// its siblings: production-shape programs; laptop-safe.
21062161
#[test]
21072162
#[ignore = "builds production-shape chain programs; run with -- --ignored"]
21082163
fn the_production_chains_emit_their_closed_forms() {
2109-
for (label, whir_grind, pins) in [
2164+
use crate::zf_format::{LEGACY_WHIR_GRIND_BITS, PRODUCTION_WHIR_GRIND_BITS, WhirGrind};
2165+
for (label, whir_grind, whir_grind_bits, pins) in [
21102166
(
21112167
"DEFAULT",
2112-
crate::zf_format::WhirGrind::Query,
2168+
WhirGrind::Query,
2169+
PRODUCTION_WHIR_GRIND_BITS,
21132170
&DEFAULT_CHAIN_PINS,
21142171
),
2172+
(
2173+
"GRIND-BITS-20",
2174+
WhirGrind::Query,
2175+
LEGACY_WHIR_GRIND_BITS,
2176+
&GRIND_BITS_20_CHAIN_PINS,
2177+
),
21152178
(
21162179
"GRIND-ALL",
2117-
crate::zf_format::WhirGrind::All,
2180+
WhirGrind::All,
2181+
LEGACY_WHIR_GRIND_BITS,
21182182
&GRIND_ALL_CHAIN_PINS,
21192183
),
21202184
] {
21212185
let production = crate::multilinear_prove::chain_config_under(
21222186
&crate::zf_format::ZfFormat {
21232187
whir_grind,
2188+
whir_grind_bits,
21242189
..crate::zf_format::ZfFormat::DEFAULT
21252190
},
21262191
&[(1, 25)],
@@ -2151,11 +2216,11 @@ fn the_production_chains_emit_their_closed_forms() {
21512216
"{label}, {fold:?}: every arena word hinted once"
21522217
);
21532218
println!(
2154-
"PRODUCTION {label} chain S=25 first6 cap=auto Q=112 grind={:?}, {fold:?} fold: \
2219+
"PRODUCTION {label} chain S=25 first6 cap=auto Q={} grind={:?}, {fold:?} fold: \
21552220
{measured} rows against {predicted} predicted; {perms} permutations against \
21562221
{predicted_perms} predicted; {consts} constants, {hints} hints, {instructions} \
21572222
instructions",
2158-
shape.grind
2223+
shape.num_queries, shape.grind
21592224
);
21602225
assert_eq!(measured, predicted, "{label}, {fold:?}: rows");
21612226
assert_eq!(perms, predicted_perms, "{label}, {fold:?}: permutations");
@@ -2422,7 +2487,7 @@ fn a_query_only_chain_checks_its_query_nonce_in_every_round_on_both_sides() {
24222487
}
24232488
}
24242489

2425-
/// ★ `LAMBDA_VM_ZF_WHIR_GRIND_BITS=18`'s trade, at a test width: the grind
2490+
/// ★ The default's 18-bit grind (against `LAMBDA_VM_ZF_WHIR_GRIND_BITS=20`), at a test width: the grind
24262491
/// bits and Q are verifier constants. A chain ground at fewer bits and opened
24272492
/// at more queries executes on the machine built for its own config, and both
24282493
/// the host and the machine refuse it under a stricter grind at the same Q; the
@@ -2628,8 +2693,9 @@ fn proof_digest(proof: &ChainProof<F, E>) -> (usize, String) {
26282693
/// programs (instructions, a digest of all of them, arena words), the arenas and
26292694
/// the host proofs' rkyv bytes at zero bits (the only width where two proves
26302695
/// agree: a search returns any valid nonce), under `Three` with uniform grinds.
2631-
/// Also the production chain under the opt-out, `whir_grind=all`, at the stacks
2632-
/// the block reaches (25 and 27): the program the pre-P2 default emitted.
2696+
/// Also the production chain under the opt-out, `whir_grind=all` at 20 bits, at
2697+
/// the stacks the block reaches (25 and 27): the program the pre-P2 default
2698+
/// emitted.
26332699
#[test]
26342700
fn the_legacy_nonce_layout_reproduces_the_bytes_from_before_p2() {
26352701
const PROGRAMS: [(usize, u8, usize, u32, &str); 4] = [
@@ -2711,6 +2777,7 @@ fn the_legacy_nonce_layout_reproduces_the_bytes_from_before_p2() {
27112777

27122778
let opt_out = crate::zf_format::ZfFormat {
27132779
whir_grind: crate::zf_format::WhirGrind::All,
2780+
whir_grind_bits: crate::zf_format::LEGACY_WHIR_GRIND_BITS,
27142781
..crate::zf_format::ZfFormat::DEFAULT
27152782
};
27162783
for (num_vars, instrs, words, digest) in [
@@ -2745,8 +2812,8 @@ fn the_legacy_nonce_layout_reproduces_the_bytes_from_before_p2() {
27452812

27462813
/// I-GRIND instrument (not a gate): the emitted chain verifier's real rows per
27472814
/// chip at every production height, under the production format at 20 grind
2748-
/// bits (Q 112) and at `LAMBDA_VM_ZF_WHIR_GRIND_BITS=18` (Q 114). The per-chain
2749-
/// deltas size the recursion's table heights under the arm.
2815+
/// bits (Q 112, the opt-out) and at the default's 18 (Q 114). The per-chain
2816+
/// deltas size the recursion's table heights under each.
27502817
///
27512818
/// cargo test -p lambda-vm-prover --lib grind_bits_chain_census -- --ignored --nocapture
27522819
#[test]

‎prover/src/lfm/whir_epoch_program_tests.rs‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,10 @@ fn the_production_epoch_recount() {
164164
production.format,
165165
crate::zf_format::ZfFormat::DEFAULT.chain_format()
166166
);
167-
assert_eq!(production.num_queries, 112, "the flip keeps Q");
167+
assert_eq!(
168+
production.num_queries, 114,
169+
"first6 keeps Q; the default's 18-bit grind buys two queries"
170+
);
168171
assert_eq!(ChainShape::new(&production, 25).rounds(), 6, "first6 at 25");
169172
}
170173
let (layouts, _domains) = stacks(&shapes, &sizes, &config).expect("the epoch's stacks build");

‎prover/src/lfm/whir_leg_tests.rs‎

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -562,8 +562,15 @@ fn the_leg_program_round_trips_as_a_w_lfm_proof() {
562562
///
563563
/// The child publishes a NODE schema (`SchemaLayout::node(0)`), the instrument's
564564
/// assumption, so the two are compared like for like.
565+
///
566+
/// The pins follow the process's grind bits, which set Q (a W-LFM plan refuses
567+
/// artifacts built under another config, so one process costs one setting):
568+
/// at the default's 18 (Q 114) the 18-bit pins; under
569+
/// `LAMBDA_VM_ZF_WHIR_GRIND_BITS=20` (Q 112, the default before the bits moved)
570+
/// the 20-bit pins and the design's instrument numbers, which were taken there.
565571
#[test]
566572
fn the_w_leg_costs_at_the_sizing_shapes() {
573+
use crate::zf_format::{LEGACY_WHIR_GRIND_BITS, PRODUCTION_WHIR_GRIND_BITS, ZfFormat};
567574
let opts = options();
568575
let publics = super::per_table_aggregator::SchemaLayout::node(0).total();
569576
let mut rows = Vec::new();
@@ -615,7 +622,54 @@ fn the_w_leg_costs_at_the_sizing_shapes() {
615622
);
616623
rows_b.push((*label, cost.perms, cost.operations(), cost.hints));
617624
}
618-
// ★ The policy-B pins, same format.
625+
let check =
626+
|rows: &[(&str, usize, usize, usize)], pins: &[(&str, usize, usize, usize)], what: &str| {
627+
for &(label, perms, ops, hints) in pins {
628+
let row = rows
629+
.iter()
630+
.find(|(l, ..)| *l == label)
631+
.expect("the profile is in the table");
632+
assert_eq!(
633+
(row.1, row.2, row.3),
634+
(perms, ops, hints),
635+
"{label} ({what}): (perms, ops, hints) moved off the pin"
636+
);
637+
}
638+
};
639+
let bits = ZfFormat::global().whir_grind_bits;
640+
if bits == PRODUCTION_WHIR_GRIND_BITS {
641+
// ★ THE PINS at the default's 18 bits (Q 114), both policies: two more
642+
// queries a chain, so every leg costs more to verify than at 20 bits
643+
// (wrap 0: +619 perms under policy A, +596 under B).
644+
check(
645+
&rows,
646+
&[
647+
("wrap 0", 40_342, 403_062, 76_608),
648+
("global wrap", 63_558, 601_451, 119_698),
649+
("L1N0", 63_603, 602_296, 119_755),
650+
("L2N0", 83_370, 777_006, 157_349),
651+
("node -1", 41_835, 413_171, 78_887),
652+
],
653+
"A, 18 bits",
654+
);
655+
check(
656+
&rows_b,
657+
&[
658+
("wrap 0", 38_970, 389_075, 75_113),
659+
("global wrap", 63_483, 598_273, 119_698),
660+
("L1N0", 63_528, 599_001, 119_755),
661+
("L2N0", 63_580, 599_687, 119_830),
662+
("node -1", 41_760, 409_686, 78_887),
663+
],
664+
"B, 18 bits",
665+
);
666+
return;
667+
}
668+
assert_eq!(
669+
bits, LEGACY_WHIR_GRIND_BITS,
670+
"the sizing pins exist at 18 and 20 grind bits only"
671+
);
672+
// ★ The policy-B pins at 20 bits, same format.
619673
//
620674
// Re-blessed under P2 (the chains grind before their queries only, with
621675
// one spent nonce a round): each chain round drops its folding and OOD
@@ -657,9 +711,9 @@ fn the_w_leg_costs_at_the_sizing_shapes() {
657711
);
658712
}
659713

660-
// ★ THE PINS, at the default format (stack 27, first6, cap auto, grind 20
661-
// before the queries only — P2): `(label, permutations, operations,
662-
// hints)`, the exact form's values. Re-blessed under P2 as the B pins
714+
// ★ THE PINS at 20 bits (stack 27, first6, cap auto, grind 20 before the
715+
// queries only — P2): `(label, permutations, operations, hints)`, the exact
716+
// form's values. Re-blessed under P2 as the B pins
663717
// above; before it: wrap 0 39,795 / 398,742 / 75,432 · global 62,651 /
664718
// 594,462 / 117,796 · L1N0 62,696 / 595,307 / 117,853 · L2N0 82,155 /
665719
// 767,664 / 154,805 · node −1 41,266 / 408,727 / 77,677.

‎prover/src/lfm/whir_proof.rs‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,9 +1155,10 @@ pub fn lfm_verify_whir(
11551155

11561156
/// A TEST-ONLY switch that proves W-LFM chains without grinding.
11571157
///
1158-
/// A W-LFM chain grinds 20 bits before each redrawable challenge, and on a
1159-
/// laptop's CPU that search is most of a small proof's time (≈ 24 grinds, ≈ 29 s
1160-
/// for `TrivialV0`). The refusals the tests check do not depend on it, so they
1158+
/// A W-LFM chain grinds before its redrawable challenges (by default 18 bits
1159+
/// before each round's queries), and on a laptop's CPU that search is most of a
1160+
/// small proof's time (≈ 24 grinds, ≈ 29 s for `TrivialV0` when it ground 20
1161+
/// bits before every challenge). The refusals the tests check do not depend on it, so they
11611162
/// run with it off; the round trip that anchors the production config keeps it
11621163
/// on. Thread-local, and applied inside [`whir_lfm_config`], so the prover, the
11631164
/// verifier and the emitter of one test all see the same config and a

‎prover/src/lfm/whir_proof_tests.rs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,10 @@ fn forge(
114114
fn the_trivial_program_round_trips_at_the_production_config() {
115115
let program = trivial_program();
116116
let build = build(&program, HasherKind::Rpx);
117-
// The production grind is P2's: 20 bits before each round's queries only.
117+
// The production grind is P2's: 18 bits before each round's queries only.
118118
assert_eq!(
119119
build.artifacts.config.grind,
120-
multilinear::whir_chain::GrindBits::query_only(20),
120+
multilinear::whir_chain::GrindBits::query_only(18),
121121
"the anchor must run the production grind"
122122
);
123123
let proved = lfm_prove_whir(&program, &build, &arenas(), &options())

0 commit comments

Comments
 (0)