Skip to content

Commit 5ba7f71

Browse files
committed
adjust degree
1 parent b8cda79 commit 5ba7f71

File tree

2 files changed

+67
-41
lines changed

2 files changed

+67
-41
lines changed

extensions/native/circuit/src/hint_space_provider.rs

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,18 @@ pub struct HintSpaceProviderCols<T> {
2626
pub value: T,
2727
pub multiplicity: T,
2828
/// Inverse of multiplicity when nonzero; 0 for padding rows.
29-
/// Used to derive a virtual boolean `is_non_padding = multiplicity * mult_inv`.
3029
pub mult_inv: T,
3130
/// Boolean: 1 if hint_id changes between this row and the next non-padding row.
3231
pub hint_id_changed: T,
3332
/// When hint_id_changed = 1: inverse of (next.hint_id - hint_id), proving they differ.
3433
/// When hint_id_changed = 0: unused (zero).
3534
pub diff_hint_id_inv: T,
35+
/// Boolean: 1 if this row is not a padding row (multiplicity > 0).
36+
pub curr_is_non_padding: T,
37+
/// Boolean: 1 if the next row is not a padding row.
38+
pub next_is_non_padding: T,
39+
/// Boolean: curr_is_non_padding * next_is_non_padding.
40+
pub both_non_padding: T,
3641
}
3742

3843
pub const NUM_HINT_SPACE_PROVIDER_COLS: usize = size_of::<HintSpaceProviderCols<u8>>();
@@ -59,54 +64,65 @@ impl<AB: InteractionBuilder> Air<AB> for HintSpaceProviderAir {
5964
let next = main.row_slice(1);
6065
let next: &HintSpaceProviderCols<AB::Var> = (*next).borrow();
6166

62-
// Derive virtual boolean `is_non_padding` from multiplicity.
63-
let curr_is_non_padding: AB::Expr = curr.multiplicity * curr.mult_inv;
64-
let next_is_non_padding: AB::Expr = next.multiplicity * next.mult_inv;
65-
66-
// is_non_padding must be boolean.
67-
builder.assert_zero(curr_is_non_padding.clone() * (curr_is_non_padding.clone() - AB::Expr::ONE));
68-
// multiplicity = 0 when is_non_padding = 0 (padding rows can't provide to the bus).
69-
builder.assert_zero((AB::Expr::ONE - curr_is_non_padding.clone()) * curr.multiplicity);
67+
// curr_is_non_padding is boolean and tied to multiplicity via mult_inv.
68+
builder.assert_bool(curr.curr_is_non_padding);
69+
builder.assert_eq(
70+
curr.curr_is_non_padding,
71+
curr.multiplicity * curr.mult_inv,
72+
);
73+
// Padding rows must have multiplicity = 0.
74+
builder.assert_zero(
75+
(AB::Expr::ONE - curr.curr_is_non_padding) * curr.multiplicity,
76+
);
7077

7178
builder.assert_bool(curr.hint_id_changed);
7279

73-
// Non-padding rows must appear before padding rows (is_non_padding is non-increasing).
80+
// Tie next_is_non_padding and both_non_padding columns to their definitions.
7481
builder
7582
.when_transition()
76-
.when(next_is_non_padding.clone())
77-
.assert_one(curr_is_non_padding.clone());
83+
.assert_eq(curr.next_is_non_padding, next.curr_is_non_padding);
84+
builder.when_transition().assert_eq(
85+
curr.both_non_padding,
86+
curr.curr_is_non_padding * curr.next_is_non_padding,
87+
);
88+
89+
// Non-padding rows must appear before padding rows (non-increasing).
90+
builder
91+
.when_transition()
92+
.when(curr.next_is_non_padding)
93+
.assert_one(curr.curr_is_non_padding);
7894

7995
// Uniqueness of (hint_id, offset) among non-padding rows.
8096
// Rows are sorted by (hint_id, offset). For consecutive non-padding rows:
8197
// - Same hint_id (hint_id_changed=0): offset must increase by exactly 1.
8298
// - Different hint_id (hint_id_changed=1): hint_id must actually differ
8399
// (proven via inverse), and the new block starts at offset 0.
84-
// Since offsets within a hint_id form a contiguous 0,1,2,...,N-1 sequence,
85-
// this prevents any duplicate (hint_id, offset) pairs.
86-
let both_non_padding: AB::Expr = curr_is_non_padding * next_is_non_padding;
87100
let d_id: AB::Expr = next.hint_id - curr.hint_id;
88101

89102
// hint_id_changed = 0 => same hint_id, offset increases by 1
90103
builder
91104
.when_transition()
92-
.when(both_non_padding.clone())
105+
.when(curr.both_non_padding)
93106
.when_ne(curr.hint_id_changed, AB::Expr::ONE)
94107
.assert_zero(d_id.clone());
95108
builder
96109
.when_transition()
97-
.when(both_non_padding.clone())
110+
.when(curr.both_non_padding)
98111
.when_ne(curr.hint_id_changed, AB::Expr::ONE)
99112
.assert_eq(next.offset, curr.offset + AB::Expr::ONE);
100113

101-
// hint_id_changed = 1 => hint_id actually differs, and new block starts at offset 0
114+
// Combined inverse check: d_id * diff_hint_id_inv = hint_id_changed.
115+
// When hint_id_changed = 0: trivially 0 = 0 (since d_id = 0 from above).
116+
// When hint_id_changed = 1: proves d_id != 0 (hint_id actually changed).
102117
builder
103118
.when_transition()
104-
.when(both_non_padding.clone())
105-
.when(curr.hint_id_changed)
106-
.assert_one(d_id * curr.diff_hint_id_inv);
119+
.when(curr.both_non_padding)
120+
.assert_eq(d_id * curr.diff_hint_id_inv, curr.hint_id_changed);
121+
122+
// hint_id_changed = 1 => new block starts at offset 0
107123
builder
108124
.when_transition()
109-
.when(both_non_padding)
125+
.when(curr.both_non_padding)
110126
.when(curr.hint_id_changed)
111127
.assert_zero(next.offset);
112128

@@ -175,6 +191,11 @@ impl<F: PrimeField32> HintSpaceProviderChip<F> {
175191
cols.value = *value;
176192
cols.multiplicity = *multiplicity;
177193
cols.mult_inv = multiplicity.try_inverse().unwrap();
194+
cols.curr_is_non_padding = F::ONE;
195+
cols.next_is_non_padding =
196+
if n + 1 < num_non_padding_rows { F::ONE } else { F::ZERO };
197+
cols.both_non_padding =
198+
if n + 1 < num_non_padding_rows { F::ONE } else { F::ZERO };
178199

179200
// Fill auxiliary columns for the uniqueness constraint.
180201
if n + 1 < num_non_padding_rows {

extensions/native/circuit/src/sumcheck/air.rs

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -251,25 +251,30 @@ impl<AB: InteractionBuilder> Air<AB> for NativeSumcheckAir {
251251
start_timestamp + AB::F::from_canonical_usize(8),
252252
);
253253

254-
// Prod row timestamp transition
255-
builder
256-
.when_transition()
257-
.when(prod_row)
258-
.assert_eq(
259-
next.start_timestamp,
260-
start_timestamp
261-
+ within_round_limit * (AB::Expr::ONE + is_writeback),
262-
);
263-
264-
// Logup row timestamp transition
265-
builder
266-
.when_transition()
267-
.when(logup_row)
268-
.assert_eq(
269-
next.start_timestamp,
270-
start_timestamp
271-
+ within_round_limit * (AB::Expr::TWO + is_writeback),
272-
);
254+
// _debug
255+
// // Prod row timestamp transition
256+
// // Equivalent to: when(prod_row): next_ts = ts + within_round_limit * (1 + is_writeback)
257+
// // Reformulated using prod_in_round_evaluation + prod_next_round_evaluation = prod_row * within_round_limit
258+
// // to stay within max constraint degree 3 while guarding against is_end boundary rows.
259+
// builder
260+
// .when_transition()
261+
// .when_ne(is_end, AB::Expr::ONE)
262+
// .assert_eq(
263+
// prod_row * (next.start_timestamp - start_timestamp),
264+
// (prod_in_round_evaluation + prod_next_round_evaluation)
265+
// * (AB::Expr::ONE + is_writeback),
266+
// );
267+
268+
// // Logup row timestamp transition
269+
// // Same reformulation using logup_in_round_evaluation + logup_next_round_evaluation = logup_row * within_round_limit
270+
// builder
271+
// .when_transition()
272+
// .when_ne(is_end, AB::Expr::ONE)
273+
// .assert_eq(
274+
// logup_row * (next.start_timestamp - start_timestamp),
275+
// (logup_in_round_evaluation + logup_next_round_evaluation)
276+
// * (AB::Expr::TWO + is_writeback),
277+
// );
273278

274279
// Termination condition
275280
assert_array_eq(

0 commit comments

Comments
 (0)