@@ -47,19 +47,23 @@ const MAX_PRIVATE_INPUT_SIZE: u64 = 6700000;
4747const PRIVATE_INPUT_START_INDEX : u64 = 0xFF000000 ;
4848
4949#[ derive( Default , Debug ) ]
50- pub struct Memory ( U64HashMap < [ u8 ; 4 ] > ) ;
50+ pub struct Memory {
51+ data : U64HashMap < [ u8 ; 4 ] > ,
52+ /// Committed public output bytes, stored separately so std cleanup can't overwrite them.
53+ committed_output : Vec < u8 > ,
54+ }
5155
5256impl Memory {
5357 pub fn load_byte ( & self , address : u64 ) -> u8 {
5458 let aligned_address = address - address % 4 ;
55- let value = self . 0 . get ( & aligned_address) . cloned ( ) . unwrap_or_default ( ) ;
59+ let value = self . data . get ( & aligned_address) . cloned ( ) . unwrap_or_default ( ) ;
5660 value[ ( address % 4 ) as usize ]
5761 }
5862
5963 pub fn store_byte ( & mut self , address : u64 , value : u8 ) {
6064 let aligned_address = address - address % 4 ;
6165 let entry = self
62- . 0
66+ . data
6367 . entry ( aligned_address)
6468 . or_insert_with ( || [ 0 , 0 , 0 , 0 ] ) ;
6569 entry[ ( address % 4 ) as usize ] = value;
@@ -69,7 +73,7 @@ impl Memory {
6973 if !address. is_multiple_of ( 4 ) {
7074 return Err ( MemoryError :: UnalignedAccess ) ;
7175 }
72- let bytes = self . 0 . get ( & address) . cloned ( ) . unwrap_or_default ( ) ;
76+ let bytes = self . data . get ( & address) . cloned ( ) . unwrap_or_default ( ) ;
7377 Ok ( u32:: from_le_bytes ( bytes) )
7478 }
7579
@@ -78,7 +82,7 @@ impl Memory {
7882 return Err ( MemoryError :: UnalignedAccess ) ;
7983 }
8084 let bytes = value. to_le_bytes ( ) ;
81- self . 0 . insert ( address, bytes) ;
85+ self . data . insert ( address, bytes) ;
8286 Ok ( ( ) )
8387 }
8488
@@ -87,8 +91,8 @@ impl Memory {
8791 if !address. is_multiple_of ( 8 ) {
8892 return Err ( MemoryError :: UnalignedAccess ) ;
8993 }
90- let low_bytes = self . 0 . get ( & address) . cloned ( ) . unwrap_or_default ( ) ;
91- let high_bytes = self . 0 . get ( & ( address + 4 ) ) . cloned ( ) . unwrap_or_default ( ) ;
94+ let low_bytes = self . data . get ( & address) . cloned ( ) . unwrap_or_default ( ) ;
95+ let high_bytes = self . data . get ( & ( address + 4 ) ) . cloned ( ) . unwrap_or_default ( ) ;
9296 let low = u32:: from_le_bytes ( low_bytes) as u64 ;
9397 let high = u32:: from_le_bytes ( high_bytes) as u64 ;
9498 Ok ( low | ( high << 32 ) )
@@ -101,8 +105,8 @@ impl Memory {
101105 }
102106 let low = ( value & 0xFFFFFFFF ) as u32 ;
103107 let high = ( value >> 32 ) as u32 ;
104- self . 0 . insert ( address, low. to_le_bytes ( ) ) ;
105- self . 0 . insert ( address + 4 , high. to_le_bytes ( ) ) ;
108+ self . data . insert ( address, low. to_le_bytes ( ) ) ;
109+ self . data . insert ( address + 4 , high. to_le_bytes ( ) ) ;
106110 Ok ( ( ) )
107111 }
108112
@@ -114,7 +118,7 @@ impl Memory {
114118 ) ;
115119 }
116120 let aligned_address = address - address % 4 ;
117- let bytes = self . 0 . get ( & aligned_address) . cloned ( ) . unwrap_or_default ( ) ;
121+ let bytes = self . data . get ( & aligned_address) . cloned ( ) . unwrap_or_default ( ) ;
118122 let value = & bytes[ ( address % 4 ) as usize ..( address % 4 ) as usize + 2 ] ;
119123 Ok ( u16:: from_le_bytes (
120124 value. try_into ( ) . map_err ( |_| MemoryError :: LoadHalf ) ?,
@@ -127,7 +131,7 @@ impl Memory {
127131 }
128132 let aligned_address = address - address % 4 ;
129133 let entry = self
130- . 0
134+ . data
131135 . entry ( aligned_address)
132136 . or_insert_with ( || [ 0 , 0 , 0 , 0 ] ) ;
133137 let bytes = value. to_le_bytes ( ) ;
@@ -140,15 +144,17 @@ impl Memory {
140144 if length > MAX_PUBLIC_OUTPUT_COMMIT_SIZE {
141145 return Err ( MemoryError :: CommitSizeExceeded ) ;
142146 }
147+ // Store in the regular memory address space (for prover trace compatibility)
143148 self . store_word ( PUBLIC_OUTPUT_START_INDEX , length as u32 ) ?;
144149 let inputs = self . load_bytes ( address, length) ;
145150 self . set_bytes_aligned ( PUBLIC_OUTPUT_START_INDEX + 4 , & inputs) ?;
151+ // Also store in the dedicated field so std runtime cleanup can't overwrite it
152+ self . committed_output = inputs;
146153 Ok ( ( ) )
147154 }
148155
149156 pub fn read_return_value ( & self ) -> Result < Vec < u8 > , MemoryError > {
150- let size = self . load_word ( PUBLIC_OUTPUT_START_INDEX ) ?;
151- Ok ( self . load_bytes ( PUBLIC_OUTPUT_START_INDEX + 4 , size as u64 ) )
157+ Ok ( self . committed_output . clone ( ) )
152158 }
153159
154160 pub fn store_private_inputs ( & mut self , inputs : Vec < u8 > ) -> Result < ( ) , MemoryError > {
@@ -172,7 +178,7 @@ impl Memory {
172178 let end = addr + len;
173179 while addr < end {
174180 let aligned = addr - ( addr % 4 ) ;
175- let bytes = self . 0 . get ( & aligned) . cloned ( ) . unwrap_or_default ( ) ;
181+ let bytes = self . data . get ( & aligned) . cloned ( ) . unwrap_or_default ( ) ;
176182 let offset = ( addr % 4 ) as usize ;
177183 let take = std:: cmp:: min ( 4 - offset, ( end - addr) as usize ) ;
178184 result. extend_from_slice ( & bytes[ offset..offset + take] ) ;
@@ -190,7 +196,7 @@ impl Memory {
190196 for chunk in inputs. chunks ( 4 ) {
191197 let mut bytes = [ 0u8 ; 4 ] ;
192198 bytes[ ..chunk. len ( ) ] . copy_from_slice ( chunk) ;
193- self . 0 . insert ( addr, bytes) ;
199+ self . data . insert ( addr, bytes) ;
194200 addr += 4 ;
195201 }
196202 Ok ( ( ) )
0 commit comments