Skip to content

Conversation

giladchase
Copy link
Contributor

@giladchase giladchase commented Sep 14, 2025

  1. When a slice ends before a word boundary (it's last word isn't a full 31 bytes long)
    , it's last word is copied into the remainder word.
    Rationale: this is consistent with ByteArray's pending word, and allows slices of full bytes31
    that include an end_suffix to be shifted-right without allocating a new array.

  2. When slices include a start-offset, the offset is applied lazily only upon intoing into a
    ByteArray, otherwise it's only recorded in the first_char_start_offset field.

@reviewable-StarkWare
Copy link

This change is Reviewable

Copy link
Contributor Author

giladchase commented Sep 14, 2025

@giladchase giladchase marked this pull request as ready for review September 14, 2025 08:27
@giladchase giladchase force-pushed the gilad/09-14-feat_byte_array_add_slice_ branch from efdd998 to d530eee Compare September 14, 2025 08:29
Copy link
Collaborator

@orizi orizi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 3 files reviewed, 5 unresolved discussions (waiting on @TomerStarkware)


corelib/src/byte_array.cairo line 628 at r2 (raw file):

    /// Returns a slice of the ByteSpan from the given start position with the given length.
    fn slice(self: @ByteSpan, start: usize, len: usize) -> Option<ByteSpan> {

should slice alway be option based?

Code quote:

    /// Returns a slice of the ByteSpan from the given start position with the given length.
    fn slice(self: @ByteSpan, start: usize, len: usize) -> Option<ByteSpan> {

corelib/src/byte_array.cairo line 636 at r2 (raw file):

        }

        let abs_start = upcast(*self.first_char_start_offset) + start;

this may be a fallible function now - and i d

Code quote:

        let abs_start = upcast(*self.first_char_start_offset) + start;

corelib/src/byte_array.cairo line 653 at r2 (raw file):

                ByteSpan {
                    data: [].span(),
                    first_char_start_offset: downcast(0).unwrap(),

Suggestion:

                    first_char_start_offset: 0,

corelib/src/byte_array.cairo line 664 at r2 (raw file):

            true => slice_bytes31((*self.data[end_word]).into(), BYTES_IN_BYTES31, 0, end_offset),
            false => slice_bytes31(*self.remainder_word, remainder_len, 0, end_offset),
        };

Suggestion:

        // Multi-word slice - data words plus optional remainder
        let remainder = if end_word < data_len {
            slice_bytes31((*self.data[end_word]).into(), BYTES_IN_BYTES31, 0, end_offset)
        } else {
            slice_bytes31(*self.remainder_word, remainder_len, 0, end_offset)
        };

corelib/src/bytes_31.cairo line 191 at r2 (raw file):

    let (without_prefix_and_suffix, _) = split_bytes31(without_suffix, start + len, len);
    without_prefix_and_suffix
}

no reason for this to be in another file.

Code quote:

/// Extracts a slice of bytes from a word.
/// Returns bytes [start, start+len) where byte 0 is the leftmost (most significant) byte.
/// The input `bytes31` and the output `bytes31`s are represented using `felt252`s to improve
/// performance.
///
/// Note: this function assumes that:
/// 1. `word` is validly convertible to a `bytes31` which has no more than `word_len` bytes of data.
/// 2. `start + len <= word_len`.
/// 3. `word_len <= BYTES_IN_BYTES31`.
/// If these assumptions are not met, it can corrupt the result. Thus, this should be a
/// private function. We could add masking/assertions but it would be more expensive.
pub(crate) fn slice_bytes31(word: felt252, word_len: usize, start: usize, len: usize) -> felt252 {
    if len == 0 {
        return 0;
    }
    // Remove suffix: keep only bytes [0, start+len).
    let (_, without_suffix) = split_bytes31(word, word_len, word_len - (start + len));
    let (without_prefix_and_suffix, _) = split_bytes31(without_suffix, start + len, len);
    without_prefix_and_suffix
}

@giladchase giladchase force-pushed the gilad/09-14-feat_byte_array_add_slice_ branch from d530eee to 68080c4 Compare September 14, 2025 09:43
@giladchase giladchase force-pushed the gilad/09-11-feat_byte_array_add_bytespan_into_ branch from d1f1e71 to 3ba3ba2 Compare September 14, 2025 09:43
@giladchase giladchase changed the base branch from gilad/09-11-feat_byte_array_add_bytespan_into_ to graphite-base/8417 September 14, 2025 10:18
@giladchase giladchase force-pushed the gilad/09-14-feat_byte_array_add_slice_ branch from 68080c4 to d4f7ade Compare September 14, 2025 11:06
Copy link
Contributor Author

@giladchase giladchase left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 3 files reviewed, 5 unresolved discussions (waiting on @orizi and @TomerStarkware)


corelib/src/byte_array.cairo line 628 at r2 (raw file):

Previously, orizi wrote…

should slice alway be option based?

Wasn't sure, my reasoning was to allow users more choice: they can use slice for checked behavior, and indexing for panic behavior.
Also this allow us to add later on slice_unchecked like rust used to do (they renamed slice->get but point still stands), whereas making this return non-option will require a breaking change later on.

Cons: in array Span::slice we dont return an option, and it sucks to break consistency with it.

WDYT?


corelib/src/byte_array.cairo line 636 at r2 (raw file):

Previously, orizi wrote…

this may be a fallible function now - and i d

Missing the end of yr message?

You mean addition overflow or upcast?
upcast says it panics in Sierra stage if the cast isn't legal, but since its boundedint<0,31> it should always fir in start: usize, unless there's something i'm missing about this.

However there were 3 overflow issues (unchecked arithmetic), fixed and added tests for all cases. The remaining unchecked arithmetic ops are guaranteed to succeed (they don't involve user input so are legal by construction).


corelib/src/bytes_31.cairo line 191 at r2 (raw file):

Previously, orizi wrote…

no reason for this to be in another file.

Done.


corelib/src/byte_array.cairo line 653 at r2 (raw file):

                ByteSpan {
                    data: [].span(),
                    first_char_start_offset: downcast(0).unwrap(),

Done.


corelib/src/byte_array.cairo line 664 at r2 (raw file):

            true => slice_bytes31((*self.data[end_word]).into(), BYTES_IN_BYTES31, 0, end_offset),
            false => slice_bytes31(*self.remainder_word, remainder_len, 0, end_offset),
        };

Done + other place.

@giladchase giladchase changed the base branch from graphite-base/8417 to gilad/09-11-feat_byte_array_add_bytespan_into_ September 14, 2025 11:07
Copy link
Collaborator

@orizi orizi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 3 files reviewed, 1 unresolved discussion (waiting on @TomerStarkware)


corelib/src/byte_array.cairo line 628 at r2 (raw file):

Previously, giladchase wrote…

Wasn't sure, my reasoning was to allow users more choice: they can use slice for checked behavior, and indexing for panic behavior.
Also this allow us to add later on slice_unchecked like rust used to do (they renamed slice->get but point still stands), whereas making this return non-option will require a breaking change later on.

Cons: in array Span::slice we dont return an option, and it sucks to break consistency with it.

WDYT?

sounds to leave as is.


corelib/src/byte_array.cairo line 636 at r2 (raw file):

Previously, giladchase wrote…

Missing the end of yr message?

You mean addition overflow or upcast?
upcast says it panics in Sierra stage if the cast isn't legal, but since its boundedint<0,31> it should always fir in start: usize, unless there's something i'm missing about this.

However there were 3 overflow issues (unchecked arithmetic), fixed and added tests for all cases. The remaining unchecked arithmetic ops are guaranteed to succeed (they don't involve user input so are legal by construction).

it was mostly about the add - that can't really fail - but better now in any case.


corelib/src/byte_array.cairo line 635 at r3 (raw file):

        if start.checked_add(len)? > self.len() {
            return None;
        }

consider - the later accesses would fail as well - so you maybe not need to do all the calculations.

Code quote:

        if start.checked_add(len)? > self.len() {
            return None;
        }

@giladchase giladchase changed the base branch from gilad/09-11-feat_byte_array_add_bytespan_into_ to graphite-base/8417 September 14, 2025 13:50
@giladchase giladchase force-pushed the gilad/09-14-feat_byte_array_add_slice_ branch from d4f7ade to e9c1e71 Compare September 16, 2025 10:06
@giladchase giladchase changed the base branch from graphite-base/8417 to gilad/09-11-feat_byte_array_add_bytespan_into_ September 16, 2025 10:06
@giladchase giladchase force-pushed the gilad/09-14-feat_byte_array_add_slice_ branch from e9c1e71 to d2487b7 Compare September 16, 2025 10:30
Copy link
Contributor Author

@giladchase giladchase left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 3 files reviewed, 1 unresolved discussion (waiting on @orizi and @TomerStarkware)


corelib/src/byte_array.cairo line 636 at r2 (raw file):

Previously, orizi wrote…

it was mostly about the add - that can't really fail - but better now in any case.

OK, note that reverted the checked_add here in favor of the one above, due to this thread


corelib/src/byte_array.cairo line 635 at r3 (raw file):

Previously, orizi wrote…

consider - the later accesses would fail as well - so you maybe not need to do all the calculations.

Right, only the first one was needed, removed the later two checked_adds.

@giladchase giladchase force-pushed the gilad/09-11-feat_byte_array_add_bytespan_into_ branch from 558ac51 to 9c5f473 Compare September 18, 2025 07:11
@giladchase giladchase force-pushed the gilad/09-14-feat_byte_array_add_slice_ branch 2 times, most recently from 235db8b to eeaa0bf Compare September 18, 2025 08:17
@giladchase giladchase force-pushed the gilad/09-14-feat_byte_array_add_slice_ branch from 45abe52 to afd7694 Compare September 28, 2025 06:44
Copy link
Collaborator

@orizi orizi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 0 of 3 files reviewed, 2 unresolved discussions (waiting on @TomerStarkware)


corelib/src/test/byte_array_test.cairo line 713 at r6 (raw file):

    // Test to demonstrate the optimization of lazy start-offset trimming.
    // Multiple slicing operations on remainder word should be more efficient.
    let ba: ByteArray = "abcdef"; // 10 bytes in remainder

i see 6.

Code quote:

    let ba: ByteArray = "abcdef"; // 10 bytes in remainder

corelib/src/byte_array.cairo line 691 at r6 (raw file):

    /// Returns a slice of the ByteSpan from the given start position with the given length.
    fn slice(self: @ByteSpan, start: usize, len: usize) -> Option<ByteSpan> {

and use range style trait.

Suggestion:

 fn slice(self: ByteSpan,

@giladchase giladchase force-pushed the gilad/09-14-feat_byte_array_add_slice_ branch from afd7694 to 9ab073e Compare September 28, 2025 08:26
@giladchase giladchase force-pushed the gilad/09-11-feat_byte_array_add_bytespan_into_ branch from 6be5ef1 to c5a931d Compare September 28, 2025 12:30
@giladchase giladchase force-pushed the gilad/09-14-feat_byte_array_add_slice_ branch 2 times, most recently from b38e4cc to 20ea89a Compare September 28, 2025 13:00
@giladchase giladchase force-pushed the gilad/09-11-feat_byte_array_add_bytespan_into_ branch from c5a931d to 7e5ddc0 Compare September 28, 2025 13:00
@giladchase giladchase force-pushed the gilad/09-14-feat_byte_array_add_slice_ branch from 20ea89a to bc5dfbf Compare September 29, 2025 06:44
@giladchase giladchase force-pushed the gilad/09-11-feat_byte_array_add_bytespan_into_ branch from 7e5ddc0 to da91b41 Compare September 29, 2025 07:26
@giladchase giladchase force-pushed the gilad/09-14-feat_byte_array_add_slice_ branch from bc5dfbf to 50fdc8e Compare September 29, 2025 07:26
@giladchase giladchase force-pushed the gilad/09-11-feat_byte_array_add_bytespan_into_ branch from da91b41 to 12b43bb Compare September 29, 2025 10:15
@giladchase giladchase force-pushed the gilad/09-14-feat_byte_array_add_slice_ branch from 50fdc8e to 079403d Compare September 29, 2025 10:15
@giladchase giladchase force-pushed the gilad/09-11-feat_byte_array_add_bytespan_into_ branch from 12b43bb to 595a075 Compare September 29, 2025 10:22
@giladchase giladchase force-pushed the gilad/09-14-feat_byte_array_add_slice_ branch from 079403d to 04b050b Compare September 29, 2025 10:22
@giladchase giladchase force-pushed the gilad/09-11-feat_byte_array_add_bytespan_into_ branch from 595a075 to dc1e38d Compare September 29, 2025 10:25
@giladchase giladchase force-pushed the gilad/09-14-feat_byte_array_add_slice_ branch 2 times, most recently from 7331124 to cfb20a9 Compare September 29, 2025 10:35
@giladchase giladchase force-pushed the gilad/09-11-feat_byte_array_add_bytespan_into_ branch 2 times, most recently from 02b3ccb to b769bea Compare September 29, 2025 12:29
@giladchase giladchase force-pushed the gilad/09-14-feat_byte_array_add_slice_ branch from cfb20a9 to 471439b Compare September 29, 2025 12:29
@giladchase giladchase force-pushed the gilad/09-11-feat_byte_array_add_bytespan_into_ branch from b769bea to ac251eb Compare September 29, 2025 13:45
@giladchase giladchase force-pushed the gilad/09-14-feat_byte_array_add_slice_ branch from 471439b to 5b966b7 Compare September 29, 2025 13:45
@giladchase giladchase force-pushed the gilad/09-11-feat_byte_array_add_bytespan_into_ branch from ac251eb to 672763a Compare September 29, 2025 14:02
@giladchase giladchase force-pushed the gilad/09-14-feat_byte_array_add_slice_ branch from 5b966b7 to f03f22e Compare September 29, 2025 14:02
@giladchase giladchase force-pushed the gilad/09-11-feat_byte_array_add_bytespan_into_ branch from 672763a to 127e45d Compare September 29, 2025 14:11
@giladchase giladchase force-pushed the gilad/09-14-feat_byte_array_add_slice_ branch from f03f22e to 4ffc000 Compare September 29, 2025 14:11
1. When a slice ends before a word boundary (it's last word isn't a full 31 bytes long)
, it's last word is copied into the remainder word.
Rationale: this is consistent with `ByteArray`'s `pending word`, and allows slices of full bytes31
that include an end_suffix to be shifted-right without allocating a new array.

2. When slices include a start-offset, the offset is applied lazily only upon `into`ing into a
   `ByteArray`, otherwise it's only recorded in the `first_char_start_offset` field.
@giladchase giladchase force-pushed the gilad/09-11-feat_byte_array_add_bytespan_into_ branch from 127e45d to 1000d8d Compare September 30, 2025 09:23
@giladchase giladchase force-pushed the gilad/09-14-feat_byte_array_add_slice_ branch from 4ffc000 to 5faa3d7 Compare September 30, 2025 09:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants