@@ -222,63 +222,52 @@ impl Stack {
222
222
Ok ( ( ) )
223
223
}
224
224
225
- /// Push a slice of bytes of `N` length onto the stack.
226
- ///
227
- /// If it will exceed the stack limit, returns `StackOverflow` error and leaves the stack
228
- /// unchanged.
225
+ /// Pushes an arbitrary length slice of bytes onto the stack, padding the last word with zeros
226
+ /// if necessary.
229
227
#[ inline]
230
- pub fn push_slice < const N : usize > ( & mut self , slice : & [ u8 ] ) -> Result < ( ) , InstructionResult > {
231
- let new_len = self . data . len ( ) + 1 ;
228
+ pub fn push_slice ( & mut self , slice : & [ u8 ] ) -> Result < ( ) , InstructionResult > {
229
+ if slice. is_empty ( ) {
230
+ return Ok ( ( ) ) ;
231
+ }
232
+
233
+ let n_words = ( slice. len ( ) + 31 ) / 32 ;
234
+ let new_len = self . data . len ( ) + n_words;
232
235
if new_len > STACK_LIMIT {
233
236
return Err ( InstructionResult :: StackOverflow ) ;
234
237
}
235
238
236
- let slot;
237
- // Safety: check above ensures us that we are okay in increment len.
239
+ // SAFETY: length checked above.
238
240
unsafe {
239
- self . data . set_len ( new_len) ;
240
- slot = self . data . get_unchecked_mut ( new_len - 1 ) ;
241
- }
241
+ let dst = self . data . as_mut_ptr ( ) . add ( self . data . len ( ) ) . cast :: < u64 > ( ) ;
242
+ let mut i = 0 ;
242
243
243
- unsafe {
244
- * slot. as_limbs_mut ( ) = [ 0u64 ; 4 ] ;
245
- let mut dangling = [ 0u8 ; 8 ] ;
246
- if N < 8 {
247
- dangling[ 8 - N ..] . copy_from_slice ( slice) ;
248
- slot. as_limbs_mut ( ) [ 0 ] = u64:: from_be_bytes ( dangling) ;
249
- } else if N < 16 {
250
- slot. as_limbs_mut ( ) [ 0 ] =
251
- u64:: from_be_bytes ( slice[ N - 8 ..N ] . try_into ( ) . expect ( "Infallible" ) ) ;
252
- if N != 8 {
253
- dangling[ 8 * 2 - N ..] . copy_from_slice ( & slice[ ..N - 8 ] ) ;
254
- slot. as_limbs_mut ( ) [ 1 ] = u64:: from_be_bytes ( dangling) ;
255
- }
256
- } else if N < 24 {
257
- slot. as_limbs_mut ( ) [ 0 ] =
258
- u64:: from_be_bytes ( slice[ N - 8 ..N ] . try_into ( ) . expect ( "Infallible" ) ) ;
259
- slot. as_limbs_mut ( ) [ 1 ] =
260
- u64:: from_be_bytes ( slice[ N - 16 ..N - 8 ] . try_into ( ) . expect ( "Infallible" ) ) ;
261
- if N != 16 {
262
- dangling[ 8 * 3 - N ..] . copy_from_slice ( & slice[ ..N - 16 ] ) ;
263
- slot. as_limbs_mut ( ) [ 2 ] = u64:: from_be_bytes ( dangling) ;
264
- }
265
- } else {
266
- // M<32
267
- slot. as_limbs_mut ( ) [ 0 ] =
268
- u64:: from_be_bytes ( slice[ N - 8 ..N ] . try_into ( ) . expect ( "Infallible" ) ) ;
269
- slot. as_limbs_mut ( ) [ 1 ] =
270
- u64:: from_be_bytes ( slice[ N - 16 ..N - 8 ] . try_into ( ) . expect ( "Infallible" ) ) ;
271
- slot. as_limbs_mut ( ) [ 2 ] =
272
- u64:: from_be_bytes ( slice[ N - 24 ..N - 16 ] . try_into ( ) . expect ( "Infallible" ) ) ;
273
- if N == 32 {
274
- slot. as_limbs_mut ( ) [ 3 ] =
275
- u64:: from_be_bytes ( slice[ ..N - 24 ] . try_into ( ) . expect ( "Infallible" ) ) ;
276
- } else if N != 24 {
277
- dangling[ 8 * 4 - N ..] . copy_from_slice ( & slice[ ..N - 24 ] ) ;
278
- slot. as_limbs_mut ( ) [ 3 ] = u64:: from_be_bytes ( dangling) ;
279
- }
244
+ // write full words
245
+ let limbs = slice. rchunks_exact ( 8 ) ;
246
+ let rem = limbs. remainder ( ) ;
247
+ for limb in limbs {
248
+ * dst. add ( i) = u64:: from_be_bytes ( limb. try_into ( ) . unwrap ( ) ) ;
249
+ i += 1 ;
280
250
}
251
+
252
+ // write remainder by padding with zeros
253
+ if !rem. is_empty ( ) {
254
+ let mut tmp = [ 0u8 ; 8 ] ;
255
+ tmp[ 8 - rem. len ( ) ..] . copy_from_slice ( rem) ;
256
+ * dst. add ( i) = u64:: from_be_bytes ( tmp) ;
257
+ i += 1 ;
258
+ }
259
+
260
+ debug_assert_eq ! ( ( i + 3 ) / 4 , n_words, "wrote beyond end of stack" ) ;
261
+
262
+ // zero out upper bytes of last word
263
+ let m = i % 4 ; // 32 / 8
264
+ if m != 0 {
265
+ dst. add ( i) . write_bytes ( 0 , 4 - m) ;
266
+ }
267
+
268
+ self . data . set_len ( new_len) ;
281
269
}
270
+
282
271
Ok ( ( ) )
283
272
}
284
273
0 commit comments