Skip to content

Commit 35b2992

Browse files
authored
Cherry-pick fixes. (#6859)
2 parents 1de4816 + 8e1ecf6 commit 35b2992

File tree

83 files changed

+23637
-21271
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+23637
-21271
lines changed

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

corelib/src/byte_array.cairo

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@
4545
use crate::array::{ArrayTrait, SpanTrait};
4646
#[allow(unused_imports)]
4747
use crate::bytes_31::{
48-
BYTES_IN_BYTES31, Bytes31Trait, one_shift_left_bytes_felt252, one_shift_left_bytes_u128,
49-
POW_2_128, POW_2_8, U128IntoBytes31, U8IntoBytes31,
48+
BYTES_IN_BYTES31, Bytes31Trait, POW_2_128, POW_2_8, U128IntoBytes31, U8IntoBytes31,
49+
one_shift_left_bytes_felt252, one_shift_left_bytes_u128, split_u128, u8_at_u256,
5050
};
5151
use crate::clone::Clone;
5252
use crate::cmp::min;
@@ -277,29 +277,21 @@ pub impl ByteArrayImpl of ByteArrayTrait {
277277
/// assert!(byte == 98);
278278
/// ```
279279
fn at(self: @ByteArray, index: usize) -> Option<u8> {
280-
let (word_index, index_in_word) = DivRem::div_rem(
281-
index, BYTES_IN_BYTES31.try_into().unwrap(),
282-
);
283-
284-
let data_len = self.data.len();
285-
if word_index == data_len {
280+
let (word_index, index_in_word) = DivRem::div_rem(index, 31);
281+
if word_index == self.data.len() {
286282
// Index is in pending word.
287283
if index_in_word >= *self.pending_word_len {
288284
return Option::None;
289285
}
290286
// index_in_word is from MSB, we need index from LSB.
291-
let index_from_lsb = *self.pending_word_len - 1 - index_in_word;
292-
let pending_bytes31: bytes31 = (*self.pending_word).try_into().unwrap();
293-
return Option::Some(pending_bytes31.at(index_from_lsb));
294-
}
295-
296-
if word_index > data_len {
297-
return Option::None;
287+
return Option::Some(
288+
u8_at_u256((*self.pending_word).into(), *self.pending_word_len - 1 - index_in_word),
289+
);
298290
}
299291

292+
let data_word: bytes31 = *self.data.get(word_index)?.deref();
300293
// index_in_word is from MSB, we need index from LSB.
301-
let index_from_lsb = BYTES_IN_BYTES31 - 1 - index_in_word;
302-
Option::Some(self.data.at(word_index).at(index_from_lsb))
294+
Option::Some(data_word.at(BYTES_IN_BYTES31 - 1 - index_in_word))
303295
}
304296

305297
/// Returns a `ByteArray` with the reverse order of `self`.
@@ -350,9 +342,7 @@ pub impl ByteArrayImpl of ByteArrayTrait {
350342
if index == low_part_limit {
351343
break;
352344
}
353-
let curr_byte_as_u128 = (low / one_shift_left_bytes_u128(index)) % POW_2_8;
354-
355-
self.append_byte(curr_byte_as_u128.try_into().unwrap());
345+
self.append_byte(core::bytes_31::get_lsb(split_u128(low, index).high));
356346
index += 1;
357347
};
358348
if low_part_limit == BYTES_IN_U128 {
@@ -362,10 +352,10 @@ pub impl ByteArrayImpl of ByteArrayTrait {
362352
if index_in_high_part == high_part_len {
363353
break;
364354
}
365-
let curr_byte_as_u128 = (high
366-
/ one_shift_left_bytes_u128(index_in_high_part)) % POW_2_8;
367-
368-
self.append_byte(curr_byte_as_u128.try_into().unwrap());
355+
self
356+
.append_byte(
357+
core::bytes_31::get_lsb(split_u128(high, index_in_high_part).high),
358+
);
369359
index_in_high_part += 1;
370360
}
371361
}
@@ -402,13 +392,11 @@ pub impl ByteArrayImpl of ByteArrayTrait {
402392
fn append_split_index_lt_16(ref self: ByteArray, word: felt252, split_index: usize) {
403393
let u256 { low, high } = word.into();
404394

405-
let (low_quotient, low_remainder) = u128_safe_divmod(
406-
low, one_shift_left_bytes_u128(split_index).try_into().unwrap(),
407-
);
395+
let low_result = split_u128(low, split_index);
408396
let left = high.into() * one_shift_left_bytes_u128(BYTES_IN_U128 - split_index).into()
409-
+ low_quotient.into();
397+
+ low_result.high.into();
410398

411-
self.append_split(left, low_remainder.into());
399+
self.append_split(left, low_result.low.into());
412400
}
413401

414402
/// Appends a single word to the end of `self`, given that the index of splitting `word` is
@@ -437,12 +425,10 @@ pub impl ByteArrayImpl of ByteArrayTrait {
437425
fn append_split_index_gt_16(ref self: ByteArray, word: felt252, split_index: usize) {
438426
let u256 { low, high } = word.into();
439427

440-
let (high_quotient, high_remainder) = u128_safe_divmod(
441-
high, one_shift_left_bytes_u128(split_index - BYTES_IN_U128).try_into().unwrap(),
442-
);
443-
let right = high_remainder.into() * POW_2_128 + low.into();
428+
let high_result = split_u128(high, split_index - BYTES_IN_U128);
429+
let right = high_result.low.into() * POW_2_128 + low.into();
444430

445-
self.append_split(high_quotient.into(), right);
431+
self.append_split(high_result.high.into(), right);
446432
}
447433

448434
/// A helper function to append a remainder to `self`, by:

corelib/src/bytes_31.cairo

Lines changed: 96 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,55 @@
1-
use crate::traits::{Into, TryInto};
2-
use crate::option::OptionTrait;
1+
//! Definitions and utilities for the `bytes31` type.
2+
//!
3+
//! The `bytes31` type is a compact, indexable 31-byte type.
4+
//!
5+
//! # Examples
6+
//!
7+
//! Creating a `bytes31` from a `felt252`:
8+
//! ```
9+
//! let value: bytes31 = 0xaabb.try_into().unwrap();
10+
//! ```
11+
//!
12+
//! Accessing a byte by index:
13+
//! ```
14+
//! assert!(value[0] == 0xbb);
15+
//! ```
16+
317
#[allow(unused_imports)]
418
use crate::integer::{u128_safe_divmod, u128_to_felt252};
19+
#[allow(unused_imports)]
20+
use crate::option::OptionTrait;
521
use crate::RangeCheck;
22+
use crate::traits::{Into, TryInto};
623

724
pub(crate) const BYTES_IN_BYTES31: usize = 31;
825
const BYTES_IN_U128: usize = 16;
926
pub(crate) const POW_2_128: felt252 = 0x100000000000000000000000000000000;
1027
pub(crate) const POW_2_8: u128 = 0x100;
1128

29+
/// Represents a 31-byte fixed-size byte type.
1230
#[derive(Copy, Drop)]
1331
pub extern type bytes31;
1432

1533
pub(crate) extern fn bytes31_const<const value: felt252>() -> bytes31 nopanic;
1634
extern fn bytes31_try_from_felt252(value: felt252) -> Option<bytes31> implicits(RangeCheck) nopanic;
1735
extern fn bytes31_to_felt252(value: bytes31) -> felt252 nopanic;
1836

37+
/// A trait for accessing a specific byte of a `bytes31` type.
1938
#[generate_trait]
2039
pub impl Bytes31Impl of Bytes31Trait {
21-
/// Gets the byte at the given index (LSB's index is 0), assuming that
22-
/// `index < BYTES_IN_BYTES31`. If the assumption is not met, the behavior is undefined.
40+
/// Returns the byte at the given index (LSB's index is 0).
41+
///
42+
/// Assumes that `index < BYTES_IN_BYTES31`. If the assumption is not met, the behavior is
43+
/// undefined.
44+
///
45+
/// # Examples
46+
///
47+
/// ```
48+
/// let bytes: bytes31 = 1_u8.into();
49+
/// assert!(bytes.at(0) == 1);
50+
/// ```
2351
fn at(self: @bytes31, index: usize) -> u8 {
24-
let u256 { low, high } = (*self).into();
25-
let res_u128 = if index < BYTES_IN_U128 {
26-
(low / one_shift_left_bytes_u128(index)) % POW_2_8
27-
} else {
28-
(high / one_shift_left_bytes_u128(index - BYTES_IN_U128)) % POW_2_8
29-
};
30-
res_u128.try_into().unwrap()
52+
u8_at_u256((*self).into(), index)
3153
}
3254
}
3355

@@ -70,34 +92,40 @@ pub(crate) impl U8IntoBytes31 of Into<u8, bytes31> {
7092
crate::integer::upcast(self)
7193
}
7294
}
95+
7396
impl U16IntoBytes31 of Into<u16, bytes31> {
7497
fn into(self: u16) -> bytes31 {
7598
crate::integer::upcast(self)
7699
}
77100
}
101+
78102
impl U32IntoBytes31 of Into<u32, bytes31> {
79103
fn into(self: u32) -> bytes31 {
80104
crate::integer::upcast(self)
81105
}
82106
}
107+
83108
impl U64IntoBytes31 of Into<u64, bytes31> {
84109
fn into(self: u64) -> bytes31 {
85110
crate::integer::upcast(self)
86111
}
87112
}
113+
88114
pub(crate) impl U128IntoBytes31 of Into<u128, bytes31> {
89115
fn into(self: u128) -> bytes31 {
90116
crate::integer::upcast(self)
91117
}
92118
}
93119

94-
/// Splits a bytes31 into two bytes31s at the given index (LSB's index is 0).
95-
/// The bytes31s are represented using felt252s to improve performance.
120+
/// Splits a `bytes31` into two `bytes31`s at the given index (LSB's index is 0).
121+
/// The input `bytes31` and the output `bytes31`s are represented using `felt252`s to improve
122+
/// performance.
123+
///
96124
/// Note: this function assumes that:
97-
/// 1. `word` is validly convertible to a bytes31 which has no more than `len` bytes of data.
98-
/// 2. index <= len.
99-
/// 3. len <= BYTES_IN_BYTES31.
100-
/// If these assumptions are not met, it can corrupt the ByteArray. Thus, this should be a
125+
/// 1. `word` is validly convertible to a `bytes31`` which has no more than `len` bytes of data.
126+
/// 2. `index <= len`.
127+
/// 3. `len <= BYTES_IN_BYTES31`.
128+
/// If these assumptions are not met, it can corrupt the `byte31`s. Thus, this should be a
101129
/// private function. We could add masking/assertions but it would be more expansive.
102130
pub(crate) fn split_bytes31(word: felt252, len: usize, index: usize) -> (felt252, felt252) {
103131
if index == 0 {
@@ -114,32 +142,27 @@ pub(crate) fn split_bytes31(word: felt252, len: usize, index: usize) -> (felt252
114142
}
115143

116144
if len <= BYTES_IN_U128 {
117-
let (quotient, remainder) = u128_safe_divmod(
118-
low, one_shift_left_bytes_u128(index).try_into().unwrap(),
119-
);
120-
return (remainder.into(), quotient.into());
145+
let result = split_u128(low, index);
146+
return (result.low.into(), result.high.into());
121147
}
122148

123149
// len > BYTES_IN_U128
124150
if index < BYTES_IN_U128 {
125-
let (low_quotient, low_remainder) = u128_safe_divmod(
126-
low, one_shift_left_bytes_u128(index).try_into().unwrap(),
127-
);
151+
let low_result = split_u128(low, index);
128152
let right = high.into() * one_shift_left_bytes_u128(BYTES_IN_U128 - index).into()
129-
+ low_quotient.into();
130-
return (low_remainder.into(), right);
153+
+ low_result.high.into();
154+
return (low_result.low.into(), right);
131155
}
132156

133157
// len > BYTES_IN_U128 && index > BYTES_IN_U128
134-
let (high_quotient, high_remainder) = u128_safe_divmod(
135-
high, one_shift_left_bytes_u128(index - BYTES_IN_U128).try_into().unwrap(),
136-
);
137-
let left = high_remainder.into() * POW_2_128 + low.into();
138-
return (left, high_quotient.into());
158+
159+
let high_result = split_u128(high, index - BYTES_IN_U128);
160+
let left = high_result.low.into() * POW_2_128 + low.into();
161+
return (left, high_result.high.into());
139162
}
140163

141164

142-
/// Returns 1 << (8 * `n_bytes`) as felt252, assuming that `n_bytes < BYTES_IN_BYTES31`.
165+
/// Returns `1 << (8 * n_bytes)` as `felt252`, assuming that `n_bytes < BYTES_IN_BYTES31`.
143166
///
144167
/// Note: if `n_bytes >= BYTES_IN_BYTES31`, the behavior is undefined. If one wants to
145168
/// assert that in the callsite, it's sufficient to assert that `n_bytes != BYTES_IN_BYTES31`
@@ -152,10 +175,33 @@ pub(crate) fn one_shift_left_bytes_felt252(n_bytes: usize) -> felt252 {
152175
}
153176
}
154177

155-
/// Returns 1 << (8 * `n_bytes`) as u128, where `n_bytes` must be < BYTES_IN_U128.
178+
/// Returns `1 << (8 * n_bytes)` as `u128`, where `n_bytes` must be < `BYTES_IN_U128`.
156179
///
157180
/// Panics if `n_bytes >= BYTES_IN_U128`.
158181
pub(crate) fn one_shift_left_bytes_u128(n_bytes: usize) -> u128 {
182+
one_shift_left_bytes_u128_nz(n_bytes).into()
183+
}
184+
185+
/// Splits a u128 into two words as a `u256` - the `low` is the first `n_bytes` the `high` is the
186+
/// rest.
187+
pub(crate) fn split_u128(value: u128, n_bytes: usize) -> u256 {
188+
let (high, low) = DivRem::div_rem(value, one_shift_left_bytes_u128_nz(n_bytes));
189+
u256 { low, high }
190+
}
191+
192+
/// Returns the `u8` at `index` if you look at `value` as an array of 32 `u8`s.
193+
pub(crate) fn u8_at_u256(value: u256, index: usize) -> u8 {
194+
get_lsb(
195+
if index < BYTES_IN_U128 {
196+
split_u128(value.low, index).high
197+
} else {
198+
split_u128(value.high, index - BYTES_IN_U128).high
199+
},
200+
)
201+
}
202+
203+
/// Same as `one_shift_left_bytes_u128` but returns `NonZero` value.
204+
fn one_shift_left_bytes_u128_nz(n_bytes: usize) -> NonZero<u128> {
159205
match n_bytes {
160206
0 => 0x1,
161207
1 => 0x100,
@@ -184,3 +230,20 @@ impl Bytes31PartialEq of PartialEq<bytes31> {
184230
lhs_as_felt252 == rhs_as_felt252
185231
}
186232
}
233+
234+
mod helpers {
235+
use core::internal::bounded_int::{DivRemHelper, BoundedInt, div_rem};
236+
237+
impl DivRemU128By256 of DivRemHelper<u128, BoundedInt<256, 256>> {
238+
type DivT = BoundedInt<0, 0xffffffffffffffffffffffffffffff>;
239+
type RemT = BoundedInt<0, 0xff>;
240+
}
241+
242+
/// Returns the least significant byte of the given u128.
243+
pub fn get_lsb(value: u128) -> u8 {
244+
let (_, res) = div_rem::<_, BoundedInt<256, 256>>(value, 256);
245+
core::integer::upcast(res)
246+
}
247+
}
248+
249+
pub(crate) use helpers::get_lsb;

0 commit comments

Comments
 (0)