1111//! - `timestamp`: DWordWL (64-bit timestamp, 2 cols)
1212//! - `write2/4/8`: Bit (access width flags)
1313//! - `old[8]`: BaseField[8] (previous values at address)
14- //! - `add_limb_overflow [7]`: Bit[7] (carry flags for base_address + i)
14+ //! - `carry [7]`: Bit[7] (carry flags for base_address + i)
1515//! - `old_timestamp[8]`: DWordWL[8] (previous timestamps, 16 cols)
1616//! - `mu_read`, `mu_write`: multiplicity columns
1717//!
1818//! ## Virtual (computed inline)
19- //! - `address_add[i]` = (base_address_0 + i+1 - 2^32 * overflow [i], base_address_1 + overflow [i])
19+ //! - `address_add[i]` = (base_address_0 + i+1 - 2^32 * carry [i], base_address_1 + carry [i])
2020//! - `w2`: write2 + write4 + write8 (writing at least 2 bytes)
2121//! - `w4`: write4 + write8 (writing at least 4 bytes)
2222//! - `μ_sum`: μ_read + μ_write
2525//! - 8 LT timestamp checks (old_timestamp[i] < timestamp)
2626//! - 16 Memory bus tokens (read old + write new, per byte)
2727//! - 2 MEMW output interactions (read + write, from CPU)
28+ //!
29+ //! ## Constraints (11 total: 2 custom + 2 IS_BIT for multiplicities + 7 IS_BIT for carry)
2830
2931use math:: field:: element:: FieldElement ;
3032use math:: field:: traits:: { IsField , IsSubFieldOf } ;
@@ -72,8 +74,8 @@ pub mod cols {
7274 pub const OLD : [ usize ; 8 ] = [ 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 ] ;
7375
7476 // Auxiliary columns
75- /// add_limb_overflow [7]: Bit columns indicating carry when adding i+1 to base_address_0
76- pub const ADD_LIMB_OVERFLOW : [ usize ; 7 ] = [ 24 , 25 , 26 , 27 , 28 , 29 , 30 ] ;
77+ /// carry [7]: Bit columns indicating carry when adding i+1 to base_address_0
78+ pub const CARRY : [ usize ; 7 ] = [ 24 , 25 , 26 , 27 , 28 , 29 , 30 ] ;
7779
7880 /// old_timestamp[8]: each is DWordWL (2 words = 2 columns)
7981 /// Total: 8 * 2 = 16 columns
@@ -206,11 +208,11 @@ pub fn generate_memw_trace(
206208 data[ base + cols:: OLD [ i] ] = FE :: from ( op. old [ i] ) ;
207209 }
208210
209- // Auxiliary: add_limb_overflow [7]
210- // overflow [i] = 1 if (base_address_lo + i+1) >= 2^32
211+ // Auxiliary: carry [7]
212+ // carry [i] = 1 if (base_address_lo + i+1) >= 2^32
211213 for i in 0 ..7 {
212214 let overflows = base_addr_lo + ( i as u64 + 1 ) >= ( 1u64 << 32 ) ;
213- data[ base + cols:: ADD_LIMB_OVERFLOW [ i] ] = FE :: from ( overflows as u64 ) ;
215+ data[ base + cols:: CARRY [ i] ] = FE :: from ( overflows as u64 ) ;
214216 }
215217
216218 // Auxiliary: old_timestamp[8] - each as DWordWL (2 words)
@@ -245,18 +247,17 @@ pub fn bus_interactions() -> Vec<BusInteraction> {
245247 // Memory bus interactions (16 total)
246248 // -------------------------------------------------------------------------
247249 // address_add[i] is VIRTUAL:
248- // lo = base_address_0 + (i+1) - 2^32 * add_limb_overflow [i]
249- // hi = base_address_1 + add_limb_overflow [i]
250+ // lo = base_address_0 + (i+1) - 2^32 * carry [i]
251+ // hi = base_address_1 + carry [i]
250252 //
251253 // Safety: `hi` is at most `base_address_1 + 1`. This never reaches 2^32
252254 // because the CPU table splits addresses into (lo, hi) with both halves
253255 // in [0, 2^32), and the Memw bus ties MEMW's base_address to the CPU's
254256 // value. MEMW only receives accesses where base_address_1 <= 0xFFFF_FFFE
255257 // (addresses near u64::MAX are rejected by the executor before proving).
256- // Consequently, `add_limb_overflow[i]` is implicitly correct: a wrong
257- // carry bit produces a memory token at a wrong address that has no
258- // matching PAGE/REGISTER token, causing multiset imbalance and an
259- // invalid proof.
258+ // Consequently, `carry[i]` is implicitly correct: a wrong carry bit
259+ // produces a memory token at a wrong address that has no matching
260+ // PAGE/REGISTER token, causing multiset imbalance and an invalid proof.
260261
261262 // CM8: memory[is_register, base_address, old_timestamp[0], old[0]] with +μ_sum
262263 interactions. push ( BusInteraction :: sender (
@@ -323,8 +324,8 @@ pub fn bus_interactions() -> Vec<BusInteraction> {
323324 ) ) ;
324325
325326 // CM10/11: byte 1, multiplicity w2 = write2 + write4 + write8
326- // address_add[0] is virtual: lo = base_address_0 + 1 - 2^32 * overflow [0]
327- // hi = base_address_1 + overflow [0]
327+ // address_add[0] is virtual: lo = base_address_0 + 1 - 2^32 * carry [0]
328+ // hi = base_address_1 + carry [0]
328329 let addr_add_0_lo = BusValue :: linear ( vec ! [
329330 LinearTerm :: Column {
330331 coefficient: 1 ,
@@ -333,7 +334,7 @@ pub fn bus_interactions() -> Vec<BusInteraction> {
333334 LinearTerm :: Constant ( 1 ) ,
334335 LinearTerm :: Column {
335336 coefficient: -( 1i64 << 32 ) ,
336- column: cols:: ADD_LIMB_OVERFLOW [ 0 ] ,
337+ column: cols:: CARRY [ 0 ] ,
337338 } ,
338339 ] ) ;
339340 let addr_add_0_hi = BusValue :: linear ( vec ! [
@@ -343,7 +344,7 @@ pub fn bus_interactions() -> Vec<BusInteraction> {
343344 } ,
344345 LinearTerm :: Column {
345346 coefficient: 1 ,
346- column: cols:: ADD_LIMB_OVERFLOW [ 0 ] ,
347+ column: cols:: CARRY [ 0 ] ,
347348 } ,
348349 ] ) ;
349350
@@ -401,7 +402,7 @@ pub fn bus_interactions() -> Vec<BusInteraction> {
401402
402403 // CM12/13: bytes 2-3 with multiplicity w4 = write4 + write8
403404 for i in 2 ..=3 {
404- let overflow_col = cols:: ADD_LIMB_OVERFLOW [ i - 1 ] ;
405+ let overflow_col = cols:: CARRY [ i - 1 ] ;
405406 let addr_add_lo = BusValue :: linear ( vec ! [
406407 LinearTerm :: Column {
407408 coefficient: 1 ,
@@ -479,7 +480,7 @@ pub fn bus_interactions() -> Vec<BusInteraction> {
479480
480481 // CM14/15: bytes 4-7 with multiplicity write8
481482 for i in 4 ..=7 {
482- let overflow_col = cols:: ADD_LIMB_OVERFLOW [ i - 1 ] ;
483+ let overflow_col = cols:: CARRY [ i - 1 ] ;
483484 let addr_add_lo = BusValue :: linear ( vec ! [
484485 LinearTerm :: Column {
485486 coefficient: 1 ,
@@ -857,7 +858,7 @@ where
857858}
858859
859860// =========================================================================
860- // Constraints (9 total: 2 custom + 7 IS_BIT)
861+ // Constraints (11 total: 2 custom + 2 IS_BIT for multiplicities + 7 IS_BIT for carry )
861862// =========================================================================
862863
863864/// MEMW table constraint kinds.
@@ -946,10 +947,12 @@ impl TransitionConstraint<GoldilocksField, GoldilocksExtension> for MemwConstrai
946947
947948/// Creates all constraints for the MEMW table.
948949///
949- /// 9 constraints total:
950+ /// 11 constraints total:
950951/// - IS_BIT<μ_sum> (1)
951952/// - w2 => μ_sum (1)
952- /// - IS_BIT for add_limb_overflow[0..6] (7)
953+ /// - IS_BIT<μ_read> (1)
954+ /// - IS_BIT<μ_write> (1)
955+ /// - IS_BIT for carry[0..6] (7)
953956pub fn constraints ( ) -> Vec < Box < dyn TransitionConstraint < GoldilocksField , GoldilocksExtension > > > {
954957 let mut constraints: Vec < Box < dyn TransitionConstraint < GoldilocksField , GoldilocksExtension > > > =
955958 Vec :: new ( ) ;
@@ -970,8 +973,19 @@ pub fn constraints() -> Vec<Box<dyn TransitionConstraint<GoldilocksField, Goldil
970973 ) ) ) ;
971974 idx += 1 ;
972975
973- // IS_BIT for add_limb_overflow[0..6]
974- for & col in & cols:: ADD_LIMB_OVERFLOW {
976+ // IS_BIT<μ_read>
977+ constraints. push ( Box :: new ( IsBitConstraint :: unconditional ( cols:: MU_READ , idx) ) ) ;
978+ idx += 1 ;
979+
980+ // IS_BIT<μ_write>
981+ constraints. push ( Box :: new ( IsBitConstraint :: unconditional (
982+ cols:: MU_WRITE ,
983+ idx,
984+ ) ) ) ;
985+ idx += 1 ;
986+
987+ // IS_BIT for carry[0..6]
988+ for & col in & cols:: CARRY {
975989 constraints. push ( Box :: new ( IsBitConstraint :: unconditional ( col, idx) ) ) ;
976990 idx += 1 ;
977991 }
@@ -1013,45 +1027,45 @@ mod tests {
10131027 }
10141028
10151029 #[ test]
1016- fn test_add_limb_overflow ( ) {
1017- // Address 0xFFFF_FFFF should overflow when adding 1
1030+ fn test_carry_flags ( ) {
1031+ // Address 0xFFFF_FFFF should carry when adding 1
10181032 let op =
10191033 MemwOperation :: new ( false , 0xFFFF_FFFF , [ 0 ; 8 ] , 100 , 8 , false ) . with_old ( [ 0 ; 8 ] , [ 50 ; 8 ] ) ;
10201034 let trace = generate_memw_trace ( & [ op] ) ;
10211035
1022- // All 7 overflow flags should be 1 since 0xFFFF_FFFF + i >= 2^32 for i >= 1
1036+ // All 7 carry flags should be 1 since 0xFFFF_FFFF + i >= 2^32 for i >= 1
10231037 for i in 0 ..7 {
1024- let val = trace. get_main ( 0 , cols:: ADD_LIMB_OVERFLOW [ i] ) ;
1025- assert_eq ! ( * val, FE :: one( ) , "overflow [{i}] should be 1" ) ;
1038+ let val = trace. get_main ( 0 , cols:: CARRY [ i] ) ;
1039+ assert_eq ! ( * val, FE :: one( ) , "carry [{i}] should be 1" ) ;
10261040 }
10271041
1028- // Address 0x0000_0000 should not overflow
1042+ // Address 0x0000_0000 should not carry
10291043 let op2 =
10301044 MemwOperation :: new ( false , 0x0000_0000 , [ 0 ; 8 ] , 100 , 8 , false ) . with_old ( [ 0 ; 8 ] , [ 50 ; 8 ] ) ;
10311045 let trace2 = generate_memw_trace ( & [ op2] ) ;
10321046 for i in 0 ..7 {
1033- let val = trace2. get_main ( 0 , cols:: ADD_LIMB_OVERFLOW [ i] ) ;
1034- assert_eq ! ( * val, FE :: zero( ) , "overflow [{i}] should be 0" ) ;
1047+ let val = trace2. get_main ( 0 , cols:: CARRY [ i] ) ;
1048+ assert_eq ! ( * val, FE :: zero( ) , "carry [{i}] should be 0" ) ;
10351049 }
10361050
10371051 // Address 0xFFFF_FFFE with width=8 exercises mixed per-byte carry bits:
1038- // overflow [0]=0 (0xFFFF_FFFE+1 = 0xFFFF_FFFF < 2^32)
1039- // overflow [1..6]=1 (0xFFFF_FFFE+2..8 >= 2^32)
1052+ // carry [0]=0 (0xFFFF_FFFE+1 = 0xFFFF_FFFF < 2^32)
1053+ // carry [1..6]=1 (0xFFFF_FFFE+2..8 >= 2^32)
10401054 let op3 =
10411055 MemwOperation :: new ( false , 0xFFFF_FFFE , [ 0 ; 8 ] , 100 , 8 , false ) . with_old ( [ 0 ; 8 ] , [ 50 ; 8 ] ) ;
10421056 let trace3 = generate_memw_trace ( & [ op3] ) ;
1043- let val0 = trace3. get_main ( 0 , cols:: ADD_LIMB_OVERFLOW [ 0 ] ) ;
1057+ let val0 = trace3. get_main ( 0 , cols:: CARRY [ 0 ] ) ;
10441058 assert_eq ! (
10451059 * val0,
10461060 FE :: zero( ) ,
1047- "overflow [0] should be 0 for base 0xFFFF_FFFE"
1061+ "carry [0] should be 0 for base 0xFFFF_FFFE"
10481062 ) ;
10491063 for i in 1 ..7 {
1050- let val = trace3. get_main ( 0 , cols:: ADD_LIMB_OVERFLOW [ i] ) ;
1064+ let val = trace3. get_main ( 0 , cols:: CARRY [ i] ) ;
10511065 assert_eq ! (
10521066 * val,
10531067 FE :: one( ) ,
1054- "overflow [{i}] should be 1 for base 0xFFFF_FFFE"
1068+ "carry [{i}] should be 1 for base 0xFFFF_FFFE"
10551069 ) ;
10561070 }
10571071 }
0 commit comments