Skip to content

Commit be5c4c2

Browse files
perf(stark): skip fixed 0/1 muls in LogUp fingerprint accumulation (#696)
* perf(stark): skip fixed 0/1 muls in LogUp fingerprint accumulation In the fingerprint hot loop (prover aux-build + constraint-eval + verifier): - Bus-id term: alpha_powers[0] = alpha^0 = 1, so embed the bus id into the extension field directly instead of multiplying by 1 (drops one F*E mul per interaction per row, hoisted out of the row loop on the aux path). - Fixed-zero bus elements (the ~235 constant(0) used for bus-width padding) contribute nothing: skip the F*E multiply + accumulate entirely. Variable elements that happen to be zero on a row also benefit. Value-identical (field addition is exactly associative): stark lib 128/128 (default + parallel), prover bus/logup tests pass, clippy clean. Net effect on prove time is what we want to measure on the 32-core bench. * docs(stark): align fingerprint comments with the α⁰=1 optimization - compute_fingerprint_from_step: drop the vestigial *α^0 from the doc formula so it mirrors the code (and matches docs/cryptography/lookup.md and spec/logup.typ). - accumulate_fingerprint{,_from_step}: the zero-skip also covers variable elements that are zero on a row, not just the constant(0) padding — reword the inline comments to say so. --------- Co-authored-by: Mauro Toscano <12560266+MauroToscano@users.noreply.github.com> Co-authored-by: MauroFab <maurotoscano2@gmail.com>
1 parent 3bb9107 commit be5c4c2

1 file changed

Lines changed: 18 additions & 10 deletions

File tree

crypto/stark/src/lookup.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,13 @@ impl BusValue {
668668
}
669669
}
670670
}
671-
*acc += &result * &alpha_powers[alpha_offset];
671+
// Bus elements that are zero on this row contribute nothing — skip the
672+
// F×E multiply. (Covers the constant(0) bus-width padding plus any
673+
// variable element that is zero on this row; α⁰ = 1 covers the bus-id
674+
// term separately.)
675+
if result != FieldElement::<F>::zero() {
676+
*acc += &result * &alpha_powers[alpha_offset];
677+
}
672678
1
673679
}
674680
}
@@ -778,7 +784,12 @@ impl BusValue {
778784
}
779785
}
780786
}
781-
*acc += result * &alpha_powers[alpha_offset];
787+
// Bus elements that are zero on this row contribute nothing — skip the
788+
// F×E multiply. (Covers the constant(0) bus-width padding plus any
789+
// variable element that is zero on this row.)
790+
if result != FieldElement::<A>::zero() {
791+
*acc += result * &alpha_powers[alpha_offset];
792+
}
782793
1
783794
}
784795
}
@@ -1483,11 +1494,10 @@ where
14831494
// fp[k*chunk_len + i] = interaction k at row chunk_start+i.
14841495
let mut fingerprints: Vec<FieldElement<E>> = Vec::with_capacity(n * chunk_len);
14851496
for interaction in interactions.iter() {
1497+
// α⁰ = 1: the bus-id term needs no multiply — embed it into E once.
1498+
let bus_id_e = FieldElement::<E>::from(interaction.bus_id);
14861499
for row in chunk_start..chunk_start + chunk_len {
1487-
// alpha_powers[0] is always 1, so the bus_id term is just the
1488-
// embedded bus id — skip the base×ext multiply and build the
1489-
// extension element straight from the bus id.
1490-
let mut lc = FieldElement::<E>::from(interaction.bus_id);
1500+
let mut lc = bus_id_e.clone();
14911501
let mut alpha_offset = 1;
14921502
for bv in &interaction.values {
14931503
alpha_offset += bv.accumulate_fingerprint(
@@ -1675,17 +1685,15 @@ fn compute_multiplicity_from_step<A: IsSubFieldOf<B>, B: IsField>(
16751685

16761686
/// Computes the fingerprint for an interaction from a `TableView`.
16771687
///
1678-
/// Returns `z - (bus_id*α^0 + v[0]*α^1 + v[1]*α^2 + ...)`
1688+
/// Returns `z - (bus_id + α·v[0] + α²·v[1] + ...)`
16791689
fn compute_fingerprint_from_step<A: IsSubFieldOf<B>, B: IsField>(
16801690
step: &TableView<A, B>,
16811691
interaction: &BusInteraction,
16821692
z: &FieldElement<B>,
16831693
alpha_powers: &[FieldElement<B>],
16841694
shifts: &PackingShifts<A>,
16851695
) -> FieldElement<B> {
1686-
// alpha_powers[0] is always 1, so the bus_id term is just the embedded bus
1687-
// id — skip the base×ext multiply and build the extension element straight
1688-
// from the bus id.
1696+
// α⁰ = 1: the bus-id term needs no multiply — embed it into B directly.
16891697
let mut linear_combination = FieldElement::<B>::from(interaction.bus_id);
16901698
let mut alpha_idx = 1;
16911699
for bv in &interaction.values {

0 commit comments

Comments
 (0)