diff --git a/Scarb.lock b/Scarb.lock index f6adb87a..a2a5eea6 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -39,6 +39,7 @@ name = "alexandria_math" version = "0.2.0" dependencies = [ "alexandria_data_structures", + "alexandria_encoding", ] [[package]] diff --git a/src/data_structures/src/byte_appender.cairo b/src/data_structures/src/byte_appender.cairo new file mode 100644 index 00000000..d12d3d5f --- /dev/null +++ b/src/data_structures/src/byte_appender.cairo @@ -0,0 +1,279 @@ +use alexandria_encoding::reversible::reversing; +use byte_array::ByteArrayTrait; +use bytes_31::{one_shift_left_bytes_felt252, one_shift_left_bytes_u128}; +use integer::u512; + +trait ByteAppenderSupportTrait { + fn append_bytes_be(ref self: T, bytes: felt252, count: usize); + fn append_bytes_le(ref self: T, bytes: felt252, count: usize); +} + +impl ByteAppenderSupportArrayU8Impl of ByteAppenderSupportTrait> { + fn append_bytes_be(ref self: Array, bytes: felt252, count: usize) { + assert(count <= 16, 'count too big'); + let u256{low, high } = bytes.into(); + let mut index = count; + loop { + if index == 0 { + break; + } + let next = (low / one_shift_left_bytes_u128(index - 1)) % 0x100; + self.append(next.try_into().unwrap()); + index -= 1; + }; + } + + fn append_bytes_le(ref self: Array, bytes: felt252, count: usize) { + assert(count <= 16, 'count too big'); + let u256{mut low, high } = bytes.into(); + let mut index = 0; + loop { + if index == count { + break; + } + let (remaining_bytes, next) = DivRem::div_rem(low, 0x100_u128.try_into().unwrap()); + low = remaining_bytes; + self.append(next.try_into().unwrap()); + index += 1; + }; + } +} +impl ByteAppenderSupportByteArrayImpl of ByteAppenderSupportTrait { + #[inline] + fn append_bytes_be(ref self: ByteArray, bytes: felt252, count: usize) { + assert(count <= 16, 'count too big'); + self.append_word(bytes.into(), count); + } + + #[inline] + fn append_bytes_le(ref self: ByteArray, bytes: felt252, count: usize) { + assert(count <= 16, 'count too big'); + let u256{low, high } = bytes.into(); + let (reversed, _) = reversing(low, count, 0x100); + self.append_word(reversed.into(), count); + } +} + +trait ByteAppender { + /// Appends an unsigned 16 bit integer encoded in big endian + /// # Arguments + /// * `word` - a 16 bit unsigned integer typed as u16 + fn append_u16(ref self: T, word: u16); + /// Appends an unsigned 16 bit integer encoded in little endian + /// # Arguments + /// * `word` - a 16 bit unsigned integer typed as u16 + fn append_u16_le(ref self: T, word: u16); + /// Appends an unsigned 32 bit integer encoded in big endian + /// # Arguments + /// * `word` - a 32 bit unsigned integer typed as u32 + fn append_u32(ref self: T, word: u32); + /// Appends an unsigned 32 bit integer encoded in little endian + /// # Arguments + /// * `word` - a 32 bit unsigned integer typed as u32 + fn append_u32_le(ref self: T, word: u32); + /// Appends an unsigned 64 bit integer encoded in big endian + /// # Arguments + /// * `word` - a 64 bit unsigned integer typed as u64 + fn append_u64(ref self: T, word: u64); + /// Appends an unsigned 64 bit integer encoded in little endian + /// # Arguments + /// * `word` - a 64 bit unsigned integer typed as u64 + fn append_u64_le(ref self: T, word: u64); + /// Appends an unsigned 128 bit integer encoded in big endian + /// # Arguments + /// * `word` - a 128 bit unsigned integer typed as u128 + fn append_u128(ref self: T, word: u128); + /// Appends an unsigned 128 bit integer encoded in little endian + /// # Arguments + /// * `word` - a 128 bit unsigned integer typed as u128 + fn append_u128_le(ref self: T, word: u128); + /// Appends an unsigned 256 bit integer encoded in big endian + /// # Arguments + /// * `word` - a 256 bit unsigned integer typed as u256 + fn append_u256(ref self: T, word: u256); + /// Appends an unsigned 256 bit integer encoded in little endian + /// # Arguments + /// * `word` - a 256 bit unsigned integer typed as u256 + fn append_u256_le(ref self: T, word: u256); + /// Appends an unsigned 512 bit integer encoded in big endian + /// # Arguments + /// * `word` - a 512 bit unsigned integer typed as u32 + fn append_u512(ref self: T, word: u512); + /// Appends an unsigned 512 bit integer encoded in little endian + /// # Arguments + /// * `word` - a 512 bit unsigned integer typed as u32 + fn append_u512_le(ref self: T, word: u512); + /// Appends a signed 8 bit integer + /// # Arguments + /// * `word` - an 8 bit signed integer typed as i8 + fn append_i8(ref self: T, word: i8); + /// Appends a signed 16 bit integer encoded in big endian + /// # Arguments + /// * `word` - a 16 bit signed integer typed as i16 + fn append_i16(ref self: T, word: i16); + /// Appends a signed 16 bit integer encoded in little endian + /// # Arguments + /// * `word` - a 16 bit signed integer typed as i16 + fn append_i16_le(ref self: T, word: i16); + /// Appends a signed 32 bit integer encoded in big endian + /// # Arguments + /// * `word` - a 32 bit signed integer typed as i32 + fn append_i32(ref self: T, word: i32); + /// Appends a signed 32 bit integer encoded in little endian + /// # Arguments + /// * `word` - a 32 bit signed integer typed as i32 + fn append_i32_le(ref self: T, word: i32); + /// Appends a signed 64 bit integer encoded in big endian + /// # Arguments + /// * `word` - a 64 bit signed integer typed as i64 + fn append_i64(ref self: T, word: i64); + /// Appends a signed 64 bit integer encoded in little endian + /// # Arguments + /// * `word` - a 64 bit signed integer typed as i64 + fn append_i64_le(ref self: T, word: i64); + /// Appends a signed 128 bit integer encoded in big endian + /// # Arguments + /// * `word` - a 128 bit signed integer typed as i128 + fn append_i128(ref self: T, word: i128); + /// Appends a signed 128 bit integer encoded in little endian + /// # Arguments + /// * `word` - a 128 bit signed integer typed as i128 + fn append_i128_le(ref self: T, word: i128); +} + +impl ByteAppenderImpl, +ByteAppenderSupportTrait> of ByteAppender { + fn append_u16(ref self: T, word: u16) { + self.append_bytes_be(word.into(), 2); + } + + fn append_u16_le(ref self: T, word: u16) { + self.append_bytes_le(word.into(), 2); + } + + fn append_u32(ref self: T, word: u32) { + self.append_bytes_be(word.into(), 4); + } + + fn append_u32_le(ref self: T, word: u32) { + self.append_bytes_le(word.into(), 4); + } + + fn append_u64(ref self: T, word: u64) { + self.append_bytes_be(word.into(), 8); + } + + fn append_u64_le(ref self: T, word: u64) { + self.append_bytes_le(word.into(), 8); + } + + fn append_u128(ref self: T, word: u128) { + self.append_bytes_be(word.into(), 16); + } + + fn append_u128_le(ref self: T, word: u128) { + self.append_bytes_le(word.into(), 16); + } + + fn append_u256(ref self: T, word: u256) { + let u256{low, high } = word; + self.append_u128(high); + self.append_u128(low); + } + + fn append_u256_le(ref self: T, word: u256) { + let u256{low, high } = word; + self.append_u128_le(low); + self.append_u128_le(high); + } + + fn append_u512(ref self: T, word: u512) { + let u512{limb0, limb1, limb2, limb3 } = word; + self.append_u128(limb3); + self.append_u128(limb2); + self.append_u128(limb1); + self.append_u128(limb0); + } + + fn append_u512_le(ref self: T, word: u512) { + let u512{limb0, limb1, limb2, limb3 } = word; + self.append_u128_le(limb0); + self.append_u128_le(limb1); + self.append_u128_le(limb2); + self.append_u128_le(limb3); + } + + fn append_i8(ref self: T, word: i8) { + if word >= 0_i8 { + self.append_bytes_be(word.into(), 1); + } else { + self.append_bytes_be(word.into() + one_shift_left_bytes_felt252(1), 1); + } + } + + fn append_i16(ref self: T, word: i16) { + if word >= 0_i16 { + self.append_bytes_be(word.into(), 2); + } else { + self.append_bytes_be(word.into() + one_shift_left_bytes_felt252(2), 2); + } + } + + fn append_i16_le(ref self: T, word: i16) { + if word >= 0_i16 { + self.append_bytes_le(word.into(), 2); + } else { + self.append_bytes_le(word.into() + one_shift_left_bytes_felt252(2), 2); + } + } + + fn append_i32(ref self: T, word: i32) { + if word >= 0_i32 { + self.append_bytes_be(word.into(), 4); + } else { + self.append_bytes_be(word.into() + one_shift_left_bytes_felt252(4), 4); + } + } + + fn append_i32_le(ref self: T, word: i32) { + if word >= 0_i32 { + self.append_bytes_le(word.into(), 4); + } else { + self.append_bytes_le(word.into() + one_shift_left_bytes_felt252(4), 4); + } + } + + fn append_i64(ref self: T, word: i64) { + if word >= 0_i64 { + self.append_bytes_be(word.into(), 8); + } else { + self.append_bytes_be(word.into() + one_shift_left_bytes_felt252(8), 8); + } + } + + fn append_i64_le(ref self: T, word: i64) { + if word >= 0_i64 { + self.append_bytes_le(word.into(), 8); + } else { + self.append_bytes_le(word.into() + one_shift_left_bytes_felt252(8), 8); + } + } + + fn append_i128(ref self: T, word: i128) { + if word >= 0_i128 { + self.append_bytes_be(word.into(), 16); + } else { + self.append_bytes_be(word.into() + one_shift_left_bytes_felt252(16), 16); + } + } + + fn append_i128_le(ref self: T, word: i128) { + if word >= 0_i128 { + self.append_bytes_le(word.into(), 16); + } else { + self.append_bytes_le(word.into() + one_shift_left_bytes_felt252(16), 16); + } + } +} + +impl ArrayU8ByteAppenderImpl = ByteAppenderImpl>; +impl ByteArrayByteAppenderImpl = ByteAppenderImpl; diff --git a/src/data_structures/src/byte_array_ext.cairo b/src/data_structures/src/byte_array_ext.cairo index 465f23bc..d328d0b1 100644 --- a/src/data_structures/src/byte_array_ext.cairo +++ b/src/data_structures/src/byte_array_ext.cairo @@ -1,450 +1,11 @@ -use alexandria_data_structures::byte_array_reader::{ByteArrayReader, ByteArrayReaderTrait}; -use alexandria_encoding::reversible::ArrayReversibleBytes; +use alexandria_data_structures::byte_appender::ByteAppender; +use alexandria_data_structures::byte_reader::ByteReader; use array::{serialize_array_helper, deserialize_array_helper}; -use byte_array::ByteArray; -use bytes_31::{one_shift_left_bytes_felt252, one_shift_left_bytes_u128, BYTES_IN_BYTES31}; -use integer::u512; +use bytes_31::BYTES_IN_BYTES31; use traits::DivRem; use core::serde::into_felt252_based::SerdeImpl; +use traits::Into; -trait ByteArrayTraitExt { - /// Appends an unsigned 16 bit integer encoded in big endian - /// # Arguments - /// * `word` - a 16 bit unsigned integer typed as u16 - fn append_u16(ref self: ByteArray, word: u16); - /// Appends an unsigned 16 bit integer encoded in little endian - /// # Arguments - /// * `word` - a 16 bit unsigned integer typed as u16 - fn append_u16_le(ref self: ByteArray, word: u16); - /// Appends an unsigned 32 bit integer encoded in big endian - /// # Arguments - /// * `word` - a 32 bit unsigned integer typed as u32 - fn append_u32(ref self: ByteArray, word: u32); - /// Appends an unsigned 32 bit integer encoded in little endian - /// # Arguments - /// * `word` - a 32 bit unsigned integer typed as u32 - fn append_u32_le(ref self: ByteArray, word: u32); - /// Appends an unsigned 64 bit integer encoded in big endian - /// # Arguments - /// * `word` - a 64 bit unsigned integer typed as u64 - fn append_u64(ref self: ByteArray, word: u64); - /// Appends an unsigned 64 bit integer encoded in little endian - /// # Arguments - /// * `word` - a 64 bit unsigned integer typed as u64 - fn append_u64_le(ref self: ByteArray, word: u64); - /// Appends an unsigned 128 bit integer encoded in big endian - /// # Arguments - /// * `word` - a 128 bit unsigned integer typed as u128 - fn append_u128(ref self: ByteArray, word: u128); - /// Appends an unsigned 128 bit integer encoded in little endian - /// # Arguments - /// * `word` - a 128 bit unsigned integer typed as u128 - fn append_u128_le(ref self: ByteArray, word: u128); - /// Appends an unsigned 256 bit integer encoded in big endian - /// # Arguments - /// * `word` - a 256 bit unsigned integer typed as u256 - fn append_u256(ref self: ByteArray, word: u256); - /// Appends an unsigned 256 bit integer encoded in little endian - /// # Arguments - /// * `word` - a 256 bit unsigned integer typed as u256 - fn append_u256_le(ref self: ByteArray, word: u256); - /// Appends an unsigned 512 bit integer encoded in big endian - /// # Arguments - /// * `word` - a 512 bit unsigned integer typed as u32 - fn append_u512(ref self: ByteArray, word: u512); - /// Appends an unsigned 512 bit integer encoded in little endian - /// # Arguments - /// * `word` - a 512 bit unsigned integer typed as u32 - fn append_u512_le(ref self: ByteArray, word: u512); - /// Appends a signed 8 bit integer - /// # Arguments - /// * `word` - an 8 bit signed integer typed as i8 - fn append_i8(ref self: ByteArray, word: i8); - /// Appends a signed 16 bit integer encoded in big endian - /// # Arguments - /// * `word` - a 16 bit signed integer typed as i16 - fn append_i16(ref self: ByteArray, word: i16); - /// Appends a signed 16 bit integer encoded in little endian - /// # Arguments - /// * `word` - a 16 bit signed integer typed as i16 - fn append_i16_le(ref self: ByteArray, word: i16); - /// Appends a signed 32 bit integer encoded in big endian - /// # Arguments - /// * `word` - a 32 bit signed integer typed as i32 - fn append_i32(ref self: ByteArray, word: i32); - /// Appends a signed 32 bit integer encoded in little endian - /// # Arguments - /// * `word` - a 32 bit signed integer typed as i32 - fn append_i32_le(ref self: ByteArray, word: i32); - /// Appends a signed 64 bit integer encoded in big endian - /// # Arguments - /// * `word` - a 64 bit signed integer typed as i64 - fn append_i64(ref self: ByteArray, word: i64); - /// Appends a signed 64 bit integer encoded in little endian - /// # Arguments - /// * `word` - a 64 bit signed integer typed as i64 - fn append_i64_le(ref self: ByteArray, word: i64); - /// Appends a signed 128 bit integer encoded in big endian - /// # Arguments - /// * `word` - a 128 bit signed integer typed as i128 - fn append_i128(ref self: ByteArray, word: i128); - /// Appends a signed 128 bit integer encoded in little endian - /// # Arguments - /// * `word` - a 128 bit signed integer typed as i128 - fn append_i128_le(ref self: ByteArray, word: i128); - /// Reads consecutive bytes from a specified offset as an unsigned integer in big endian - /// # Arguments - /// * `offset` - the start location of the consecutive bytes to read - /// # Returns - /// * `Option` - Returns an integer if there are enough consecutive bytes available in the ByteArray - fn word_u16(self: @ByteArray, offset: usize) -> Option; - /// Reads consecutive bytes from a specified offset as an unsigned integer in little endian - /// # Arguments - /// * `offset` - the start location of the consecutive bytes to read - /// # Returns - /// * `Option` - Returns an integer if there are enough consecutive bytes available in the ByteArray - fn word_u16_le(self: @ByteArray, offset: usize) -> Option; - /// Reads consecutive bytes from a specified offset as an unsigned integer in big endian - /// # Arguments - /// * `offset` - the start location of the consecutive bytes to read - /// # Returns - /// * `Option` - Returns an integer if there are enough consecutive bytes available in the ByteArray - fn word_u32(self: @ByteArray, offset: usize) -> Option; - /// Reads consecutive bytes from a specified offset as an unsigned integer in little endian - /// # Arguments - /// * `offset` - the start location of the consecutive bytes to read - /// # Returns - /// * `Option` - Returns an integer if there are enough consecutive bytes available in the ByteArray - fn word_u32_le(self: @ByteArray, offset: usize) -> Option; - /// Reads consecutive bytes from a specified offset as an unsigned integer in big endian - /// # Arguments - /// * `offset` - the start location of the consecutive bytes to read - /// # Returns - /// * `Option` - Returns an integer if there are enough consecutive bytes available in the ByteArray - fn word_u64(self: @ByteArray, offset: usize) -> Option; - /// Reads consecutive bytes from a specified offset as an unsigned integer in little endian - /// # Arguments - /// * `offset` - the start location of the consecutive bytes to read - /// # Returns - /// * `Option` - Returns an integer if there are enough consecutive bytes available in the ByteArray - fn word_u64_le(self: @ByteArray, offset: usize) -> Option; - /// Reads consecutive bytes from a specified offset as an unsigned integer in big endian - /// # Arguments - /// * `offset` - the start location of the consecutive bytes to read - /// # Returns - /// * `Option` - Returns an integer if there are enough consecutive bytes available in the ByteArray - fn word_u128(self: @ByteArray, offset: usize) -> Option; - /// Reads consecutive bytes from a specified offset as an unsigned integer in little endian - /// # Arguments - /// * `offset` - the start location of the consecutive bytes to read - /// # Returns - /// * `Option` - Returns an integer if there are enough consecutive bytes available in the ByteArray - fn word_u128_le(self: @ByteArray, offset: usize) -> Option; - /// Wraps the ByteArray in a ByteArrayReader for sequential consumption of integers and/or bytes - /// # Returns - /// * `ByteArrayReader` - The reader struct wrapping a read-only snapshot of this ByteArray - fn reader(self: @ByteArray) -> ByteArrayReader; -} - -impl ByteArrayImpl of ByteArrayTraitExt { - fn append_u16(ref self: ByteArray, word: u16) { - self.append_word(word.into(), 2); - } - - fn append_u16_le(ref self: ByteArray, word: u16) { - self.append_word(word.reverse_bytes().into(), 2); - } - - fn append_u32(ref self: ByteArray, word: u32) { - self.append_word(word.into(), 4); - } - - fn append_u32_le(ref self: ByteArray, word: u32) { - self.append_word(word.reverse_bytes().into(), 4); - } - - fn append_u64(ref self: ByteArray, word: u64) { - self.append_word(word.into(), 8); - } - - fn append_u64_le(ref self: ByteArray, word: u64) { - self.append_word(word.reverse_bytes().into(), 8); - } - - fn append_u128(ref self: ByteArray, word: u128) { - self.append_word(word.into(), 16); - } - - fn append_u128_le(ref self: ByteArray, word: u128) { - self.append_word(word.reverse_bytes().into(), 16); - } - - fn append_u256(ref self: ByteArray, word: u256) { - let u256{low, high } = word; - self.append_u128(high); - self.append_u128(low); - } - - fn append_u256_le(ref self: ByteArray, word: u256) { - let u256{low, high } = word; - self.append_u128_le(low); - self.append_u128_le(high); - } - - fn append_u512(ref self: ByteArray, word: u512) { - let u512{limb0, limb1, limb2, limb3 } = word; - self.append_u128(limb3); - self.append_u128(limb2); - self.append_u128(limb1); - self.append_u128(limb0); - } - - fn append_u512_le(ref self: ByteArray, word: u512) { - let u512{limb0, limb1, limb2, limb3 } = word; - self.append_u128_le(limb0); - self.append_u128_le(limb1); - self.append_u128_le(limb2); - self.append_u128_le(limb3); - } - - fn append_i8(ref self: ByteArray, word: i8) { - if word >= 0_i8 { - self.append_word(word.into(), 1); - } else { - self.append_word(word.into() + one_shift_left_bytes_felt252(1), 1); - } - } - - fn append_i16(ref self: ByteArray, word: i16) { - if word >= 0_i16 { - self.append_word(word.into(), 2); - } else { - self.append_word(word.into() + one_shift_left_bytes_felt252(2), 2); - } - } - - fn append_i16_le(ref self: ByteArray, word: i16) { - let felt: felt252 = if word >= 0_i16 { - word.into() - } else { - word.into() + one_shift_left_bytes_felt252(2) - }; - let unsigned: u16 = felt.try_into().unwrap(); - self.append_word(unsigned.reverse_bytes().into(), 2); - } - - fn append_i32(ref self: ByteArray, word: i32) { - if word >= 0_i32 { - self.append_word(word.into(), 4); - } else { - self.append_word(word.into() + one_shift_left_bytes_felt252(4), 4); - } - } - - fn append_i32_le(ref self: ByteArray, word: i32) { - let felt: felt252 = if word >= 0_i32 { - word.into() - } else { - word.into() + one_shift_left_bytes_felt252(4) - }; - let unsigned: u32 = felt.try_into().unwrap(); - self.append_word(unsigned.reverse_bytes().into(), 4); - } - - fn append_i64(ref self: ByteArray, word: i64) { - if word >= 0_i64 { - self.append_word(word.into(), 8); - } else { - self.append_word(word.into() + one_shift_left_bytes_felt252(8), 8); - } - } - - fn append_i64_le(ref self: ByteArray, word: i64) { - let felt: felt252 = if word >= 0_i64 { - word.into() - } else { - word.into() + one_shift_left_bytes_felt252(8) - }; - let unsigned: u64 = felt.try_into().unwrap(); - self.append_word(unsigned.reverse_bytes().into(), 8); - } - - fn append_i128(ref self: ByteArray, word: i128) { - if word >= 0_i128 { - self.append_word(word.into(), 16); - } else { - self.append_word(word.into() + one_shift_left_bytes_felt252(16), 16); - } - } - - fn append_i128_le(ref self: ByteArray, word: i128) { - let felt: felt252 = if word >= 0_i128 { - word.into() - } else { - word.into() + one_shift_left_bytes_felt252(16) - }; - let unsigned: u128 = felt.try_into().unwrap(); - self.append_word(unsigned.reverse_bytes().into(), 16); - } - - fn word_u16(self: @ByteArray, offset: usize) -> Option { - let b1 = self.at(offset)?; - let b2 = self.at(offset + 1)?; - Option::Some(b1.into() * one_shift_left_bytes_u128(1).try_into().unwrap() + b2.into()) - } - - fn word_u16_le(self: @ByteArray, offset: usize) -> Option { - let b1 = self.at(offset)?; - let b2 = self.at(offset + 1)?; - Option::Some(b1.into() + b2.into() * one_shift_left_bytes_u128(1).try_into().unwrap()) - } - - fn word_u32(self: @ByteArray, offset: usize) -> Option { - let b1 = self.at(offset)?; - let b2 = self.at(offset + 1)?; - let b3 = self.at(offset + 2)?; - let b4 = self.at(offset + 3)?; - Option::Some( - b1.into() * one_shift_left_bytes_u128(3).try_into().unwrap() - + b2.into() * one_shift_left_bytes_u128(2).try_into().unwrap() - + b3.into() * one_shift_left_bytes_u128(1).try_into().unwrap() - + b4.into() - ) - } - - fn word_u32_le(self: @ByteArray, offset: usize) -> Option { - let b1 = self.at(offset)?; - let b2 = self.at(offset + 1)?; - let b3 = self.at(offset + 2)?; - let b4 = self.at(offset + 3)?; - Option::Some( - b1.into() - + b2.into() * one_shift_left_bytes_u128(1).try_into().unwrap() - + b3.into() * one_shift_left_bytes_u128(2).try_into().unwrap() - + b4.into() * one_shift_left_bytes_u128(3).try_into().unwrap() - ) - } - - fn word_u64(self: @ByteArray, offset: usize) -> Option { - let b1 = self.at(offset)?; - let b2 = self.at(offset + 1)?; - let b3 = self.at(offset + 2)?; - let b4 = self.at(offset + 3)?; - let b5 = self.at(offset + 4)?; - let b6 = self.at(offset + 5)?; - let b7 = self.at(offset + 6)?; - let b8 = self.at(offset + 7)?; - Option::Some( - b1.into() * one_shift_left_bytes_u128(7).try_into().unwrap() - + b2.into() * one_shift_left_bytes_u128(6).try_into().unwrap() - + b3.into() * one_shift_left_bytes_u128(5).try_into().unwrap() - + b4.into() * one_shift_left_bytes_u128(4).try_into().unwrap() - + b5.into() * one_shift_left_bytes_u128(3).try_into().unwrap() - + b6.into() * one_shift_left_bytes_u128(2).try_into().unwrap() - + b7.into() * one_shift_left_bytes_u128(1).try_into().unwrap() - + b8.into() - ) - } - - fn word_u64_le(self: @ByteArray, offset: usize) -> Option { - let b1 = self.at(offset)?; - let b2 = self.at(offset + 1)?; - let b3 = self.at(offset + 2)?; - let b4 = self.at(offset + 3)?; - let b5 = self.at(offset + 4)?; - let b6 = self.at(offset + 5)?; - let b7 = self.at(offset + 6)?; - let b8 = self.at(offset + 7)?; - Option::Some( - b1.into() - + b2.into() * one_shift_left_bytes_u128(1).try_into().unwrap() - + b3.into() * one_shift_left_bytes_u128(2).try_into().unwrap() - + b4.into() * one_shift_left_bytes_u128(3).try_into().unwrap() - + b5.into() * one_shift_left_bytes_u128(4).try_into().unwrap() - + b6.into() * one_shift_left_bytes_u128(5).try_into().unwrap() - + b7.into() * one_shift_left_bytes_u128(6).try_into().unwrap() - + b8.into() * one_shift_left_bytes_u128(7).try_into().unwrap() - ) - } - - fn word_u128(self: @ByteArray, offset: usize) -> Option { - let b01 = self.at(offset)?; - let b02 = self.at(offset + 1)?; - let b03 = self.at(offset + 2)?; - let b04 = self.at(offset + 3)?; - let b05 = self.at(offset + 4)?; - let b06 = self.at(offset + 5)?; - let b07 = self.at(offset + 6)?; - let b08 = self.at(offset + 7)?; - let b09 = self.at(offset + 8)?; - let b10 = self.at(offset + 9)?; - let b11 = self.at(offset + 10)?; - let b12 = self.at(offset + 11)?; - let b13 = self.at(offset + 12)?; - let b14 = self.at(offset + 13)?; - let b15 = self.at(offset + 14)?; - let b16 = self.at(offset + 15)?; - Option::Some( - b01.into() * one_shift_left_bytes_u128(15).try_into().unwrap() - + b02.into() * one_shift_left_bytes_u128(14).try_into().unwrap() - + b03.into() * one_shift_left_bytes_u128(13).try_into().unwrap() - + b04.into() * one_shift_left_bytes_u128(12).try_into().unwrap() - + b05.into() * one_shift_left_bytes_u128(11).try_into().unwrap() - + b06.into() * one_shift_left_bytes_u128(10).try_into().unwrap() - + b07.into() * one_shift_left_bytes_u128(09).try_into().unwrap() - + b08.into() * one_shift_left_bytes_u128(08).try_into().unwrap() - + b09.into() * one_shift_left_bytes_u128(07).try_into().unwrap() - + b10.into() * one_shift_left_bytes_u128(06).try_into().unwrap() - + b11.into() * one_shift_left_bytes_u128(05).try_into().unwrap() - + b12.into() * one_shift_left_bytes_u128(04).try_into().unwrap() - + b13.into() * one_shift_left_bytes_u128(03).try_into().unwrap() - + b14.into() * one_shift_left_bytes_u128(02).try_into().unwrap() - + b15.into() * one_shift_left_bytes_u128(01).try_into().unwrap() - + b16.into() - ) - } - - fn word_u128_le(self: @ByteArray, offset: usize) -> Option { - let b01 = self.at(offset)?; - let b02 = self.at(offset + 1)?; - let b03 = self.at(offset + 2)?; - let b04 = self.at(offset + 3)?; - let b05 = self.at(offset + 4)?; - let b06 = self.at(offset + 5)?; - let b07 = self.at(offset + 6)?; - let b08 = self.at(offset + 7)?; - let b09 = self.at(offset + 8)?; - let b10 = self.at(offset + 9)?; - let b11 = self.at(offset + 10)?; - let b12 = self.at(offset + 11)?; - let b13 = self.at(offset + 12)?; - let b14 = self.at(offset + 13)?; - let b15 = self.at(offset + 14)?; - let b16 = self.at(offset + 15)?; - Option::Some( - b01.into() - + b02.into() * one_shift_left_bytes_u128(01).try_into().unwrap() - + b03.into() * one_shift_left_bytes_u128(02).try_into().unwrap() - + b04.into() * one_shift_left_bytes_u128(03).try_into().unwrap() - + b05.into() * one_shift_left_bytes_u128(04).try_into().unwrap() - + b06.into() * one_shift_left_bytes_u128(05).try_into().unwrap() - + b07.into() * one_shift_left_bytes_u128(06).try_into().unwrap() - + b08.into() * one_shift_left_bytes_u128(07).try_into().unwrap() - + b09.into() * one_shift_left_bytes_u128(08).try_into().unwrap() - + b10.into() * one_shift_left_bytes_u128(09).try_into().unwrap() - + b11.into() * one_shift_left_bytes_u128(10).try_into().unwrap() - + b12.into() * one_shift_left_bytes_u128(11).try_into().unwrap() - + b13.into() * one_shift_left_bytes_u128(12).try_into().unwrap() - + b14.into() * one_shift_left_bytes_u128(13).try_into().unwrap() - + b15.into() * one_shift_left_bytes_u128(14).try_into().unwrap() - + b16.into() * one_shift_left_bytes_u128(15).try_into().unwrap() - ) - } - - fn reader(self: @ByteArray) -> ByteArrayReader { - ByteArrayReaderTrait::new(self) - } -} impl ByteArraySerde of Serde { fn serialize(self: @ByteArray, ref output: Array) { @@ -481,3 +42,38 @@ impl ByteArraySerde of Serde { ) } } + +impl SpanU8IntoBytearray of Into, ByteArray> { + #[inline] + fn into(self: Span) -> ByteArray { + let mut reader = self.reader(); + let mut result: ByteArray = Default::default(); + loop { + match reader.read_u8() { + Option::Some(byte) => result.append_byte(byte), + Option::None => { break; }, + } + }; + result + } +} + +impl ArrayU8IntoByteArray of Into, ByteArray> { + fn into(self: Array) -> ByteArray { + self.span().into() + } +} + +impl ByteArrayIntoArrayU8 of Into> { + fn into(self: ByteArray) -> Array { + let mut reader = self.reader(); + let mut result = array![]; + loop { + match reader.read_u8() { + Option::Some(byte) => result.append(byte), + Option::None => { break; }, + } + }; + result + } +} diff --git a/src/data_structures/src/byte_array_reader.cairo b/src/data_structures/src/byte_array_reader.cairo deleted file mode 100644 index a97d0d5a..00000000 --- a/src/data_structures/src/byte_array_reader.cairo +++ /dev/null @@ -1,277 +0,0 @@ -use integer::u512; -use bytes_31::one_shift_left_bytes_felt252; -use byte_array::ByteArray; -use alexandria_data_structures::byte_array_ext::ByteArrayTraitExt; -use core::clone::Clone; - -/// A read-only snapshot of an underlying ByteArray that maintains -/// sequential access to the integers encoded in the array -#[derive(Copy, Drop)] -struct ByteArrayReader { - /// A snapshot of the ByteArray - data: @ByteArray, - /// The `read_index` is incremented in accordance with the integers consumed - reader_index: usize, -} - -trait ByteArrayReaderTrait { - /// Creates a ByteArrayReader from a ByteArray snapshot - /// # Arguments - /// * `from` - a ByteArray snapshot to read from - /// # Returns - /// `ByteArrayReader` - a new reader starting at the beginning of the underlying ByteArray - fn new(from: @ByteArray) -> ByteArrayReader; - /// Reads a u8 unsigned integer - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_u8(ref self: ByteArrayReader) -> Option; - /// Reads a u16 unsigned integer in big endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_u16(ref self: ByteArrayReader) -> Option; - /// Reads a u16 unsigned integer in little endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_u16_le(ref self: ByteArrayReader) -> Option; - /// Reads a u32 unsigned integer in big endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_u32(ref self: ByteArrayReader) -> Option; - /// Reads a u32 unsigned integer in little endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_u32_le(ref self: ByteArrayReader) -> Option; - /// Reads a u64 unsigned integer in big endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_u64(ref self: ByteArrayReader) -> Option; - /// Reads a u64 unsigned integer in little endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_u64_le(ref self: ByteArrayReader) -> Option; - /// Reads a u128 unsigned integer in big endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_u128(ref self: ByteArrayReader) -> Option; - /// Reads a u128 unsigned integer in little endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_u128_le(ref self: ByteArrayReader) -> Option; - /// Reads a u256 unsigned integer in big endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_u256(ref self: ByteArrayReader) -> Option; - /// Reads a u256 unsigned integer in little endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_u256_le(ref self: ByteArrayReader) -> Option; - /// Reads a u512 unsigned integer in big endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_u512(ref self: ByteArrayReader) -> Option; - /// Reads a u512 unsigned integer in little endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_u512_le(ref self: ByteArrayReader) -> Option; - /// Reads an i8 signed integer in two's complement encoding from the ByteArray - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_i8(ref self: ByteArrayReader) -> Option; - /// Reads an i16 signed integer in two's complement encoding from the ByteArray in big endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_i16(ref self: ByteArrayReader) -> Option; - /// Reads an i16 signed integer in two's complement encoding from the ByteArray in little endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_i16_le(ref self: ByteArrayReader) -> Option; - /// Reads an i32 signed integer in two's complement encoding from the ByteArray in big endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_i32(ref self: ByteArrayReader) -> Option; - /// Reads an i32 signed integer in two's complement encoding from the ByteArray in little endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_i32_le(ref self: ByteArrayReader) -> Option; - /// Reads an i64 signed integer in two's complement encoding from the ByteArray in big endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_i64(ref self: ByteArrayReader) -> Option; - /// Reads an i64 signed integer in two's complement encoding from the ByteArray in little endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_i64_le(ref self: ByteArrayReader) -> Option; - /// Reads an i128 signed integer in two's complement encoding from the ByteArray in big endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_i128(ref self: ByteArrayReader) -> Option; - /// Reads an i128 signed integer in two's complement encoding from the ByteArray in little endian byte order - /// # Returns - /// `Option` - If there are enough bytes remaining an optional integer is returned - fn read_i128_le(ref self: ByteArrayReader) -> Option; - /// Returns the remaining length of the ByteArrayReader - /// # Returns - /// `usize` - The number of bytes remaining, considering the number of bytes that have already been consumed - fn len(self: @ByteArrayReader) -> usize; -} - -impl ByteArrayReaderImpl of ByteArrayReaderTrait { - fn new(from: @ByteArray) -> ByteArrayReader { - ByteArrayReader { data: from, reader_index: 0, } - } - - fn read_u8(ref self: ByteArrayReader) -> Option { - let byte = self.data.at(self.reader_index)?; - self.reader_index += 1; - Option::Some(byte) - } - - fn read_u16(ref self: ByteArrayReader) -> Option { - let result = self.data.word_u16(self.reader_index)?; - self.reader_index += 2; - Option::Some(result) - } - - fn read_u16_le(ref self: ByteArrayReader) -> Option { - let result = self.data.word_u16_le(self.reader_index)?; - self.reader_index += 2; - Option::Some(result) - } - - fn read_u32(ref self: ByteArrayReader) -> Option { - let result = self.data.word_u32(self.reader_index)?; - self.reader_index += 4; - Option::Some(result) - } - - fn read_u32_le(ref self: ByteArrayReader) -> Option { - let result = self.data.word_u32_le(self.reader_index)?; - self.reader_index += 4; - Option::Some(result) - } - - fn read_u64(ref self: ByteArrayReader) -> Option { - let result = self.data.word_u64(self.reader_index)?; - self.reader_index += 8; - Option::Some(result) - } - - fn read_u64_le(ref self: ByteArrayReader) -> Option { - let result = self.data.word_u64_le(self.reader_index)?; - self.reader_index += 8; - Option::Some(result) - } - - fn read_u128(ref self: ByteArrayReader) -> Option { - let result = self.data.word_u128(self.reader_index)?; - self.reader_index += 16; - Option::Some(result) - } - - fn read_u128_le(ref self: ByteArrayReader) -> Option { - let result = self.data.word_u128_le(self.reader_index)?; - self.reader_index += 16; - Option::Some(result) - } - - fn read_u256(ref self: ByteArrayReader) -> Option { - let result = u256 { - high: self.data.word_u128(self.reader_index)?, - low: self.data.word_u128(self.reader_index + 16)? - }; - self.reader_index += 32; - Option::Some(result) - } - - fn read_u256_le(ref self: ByteArrayReader) -> Option { - let result = u256 { - low: self.data.word_u128_le(self.reader_index)?, - high: self.data.word_u128_le(self.reader_index + 16)? - }; - self.reader_index += 32; - Option::Some(result) - } - - fn read_u512(ref self: ByteArrayReader) -> Option { - let result = u512 { - limb3: self.data.word_u128(self.reader_index)?, - limb2: self.data.word_u128(self.reader_index + 16)?, - limb1: self.data.word_u128(self.reader_index + 32)?, - limb0: self.data.word_u128(self.reader_index + 48)? - }; - self.reader_index += 64; - Option::Some(result) - } - - fn read_u512_le(ref self: ByteArrayReader) -> Option { - let result = u512 { - limb0: self.data.word_u128_le(self.reader_index)?, - limb1: self.data.word_u128_le(self.reader_index + 16)?, - limb2: self.data.word_u128_le(self.reader_index + 32)?, - limb3: self.data.word_u128_le(self.reader_index + 48)? - }; - self.reader_index += 64; - Option::Some(result) - } - - fn read_i8(ref self: ByteArrayReader) -> Option { - let felt: felt252 = self.read_u8()?.into(); - Option::Some(parse_signed(felt, 1).unwrap()) - } - - fn read_i16(ref self: ByteArrayReader) -> Option { - let felt: felt252 = self.read_u16()?.into(); - Option::Some(parse_signed(felt, 2).unwrap()) - } - - fn read_i16_le(ref self: ByteArrayReader) -> Option { - let felt: felt252 = self.read_u16_le()?.into(); - Option::Some(parse_signed(felt, 2).unwrap()) - } - - fn read_i32(ref self: ByteArrayReader) -> Option { - let felt: felt252 = self.read_u32()?.into(); - Option::Some(parse_signed(felt, 4).unwrap()) - } - - fn read_i32_le(ref self: ByteArrayReader) -> Option { - let felt: felt252 = self.read_u32_le()?.into(); - Option::Some(parse_signed(felt, 4).unwrap()) - } - - fn read_i64(ref self: ByteArrayReader) -> Option { - let felt: felt252 = self.read_u64()?.into(); - Option::Some(parse_signed(felt, 8).unwrap()) - } - - fn read_i64_le(ref self: ByteArrayReader) -> Option { - let felt: felt252 = self.read_u64_le()?.into(); - Option::Some(parse_signed(felt, 8).unwrap()) - } - - fn read_i128(ref self: ByteArrayReader) -> Option { - let felt: felt252 = self.read_u128()?.into(); - Option::Some(parse_signed(felt, 16).unwrap()) - } - - fn read_i128_le(ref self: ByteArrayReader) -> Option { - let felt: felt252 = self.read_u128_le()?.into(); - Option::Some(parse_signed(felt, 16).unwrap()) - } - - fn len(self: @ByteArrayReader) -> usize { - let byte_array = *self.data; - let byte_array_len = byte_array.len(); - byte_array_len - *self.reader_index - } -} - -fn parse_signed>(value: felt252, bytes: usize) -> Option { - match value.try_into() { - Option::Some(pos) => Option::Some(pos), - Option::None => { - let negated: felt252 = value - one_shift_left_bytes_felt252(bytes); - negated.try_into() - }, - } -} diff --git a/src/data_structures/src/byte_reader.cairo b/src/data_structures/src/byte_reader.cairo new file mode 100644 index 00000000..38c26411 --- /dev/null +++ b/src/data_structures/src/byte_reader.cairo @@ -0,0 +1,550 @@ +use bytes_31::{one_shift_left_bytes_u128, one_shift_left_bytes_felt252}; +use integer::u512; + +#[derive(Copy, Clone, Drop)] +struct ByteReaderState { + data: @T, + index: usize, +} + +trait ByteReader { + /// Wraps the array of bytes in a ByteReader for sequential consumption of integers and/or bytes + /// # Returns + /// * `ByteReader` - The reader struct wrapping a read-only snapshot of this ByteArray + fn reader(self: @T) -> ByteReaderState; + /// Checks that there are enoguh remaining bytes available + /// # Arguments + /// * `at` - the start index position of the byte data + /// * `count` - the number of bytes required + /// # Returns + /// * `Option<()>` - `Some(())` when there are `count` bytes remaining, `None` otherwise. + fn remaining(self: @T, at: usize, count: usize) -> Option<()>; + /// Reads consecutive bytes from a specified offset as an unsigned integer in big endian + /// # Arguments + /// * `offset` - the start location of the consecutive bytes to read + /// # Returns + /// * `Option` - Returns an integer if there are enough consecutive bytes available in the ByteArray + fn word_u16(self: @T, offset: usize) -> Option; + /// Reads consecutive bytes from a specified offset as an unsigned integer in little endian + /// # Arguments + /// * `offset` - the start location of the consecutive bytes to read + /// # Returns + /// * `Option` - Returns an integer if there are enough consecutive bytes available in the ByteArray + fn word_u16_le(self: @T, offset: usize) -> Option; + /// Reads consecutive bytes from a specified offset as an unsigned integer in big endian + /// # Arguments + /// * `offset` - the start location of the consecutive bytes to read + /// # Returns + /// * `Option` - Returns an integer if there are enough consecutive bytes available in the ByteArray + fn word_u32(self: @T, offset: usize) -> Option; + /// Reads consecutive bytes from a specified offset as an unsigned integer in little endian + /// # Arguments + /// * `offset` - the start location of the consecutive bytes to read + /// # Returns + /// * `Option` - Returns an integer if there are enough consecutive bytes available in the ByteArray + fn word_u32_le(self: @T, offset: usize) -> Option; + /// Reads consecutive bytes from a specified offset as an unsigned integer in big endian + /// # Arguments + /// * `offset` - the start location of the consecutive bytes to read + /// # Returns + /// * `Option` - Returns an integer if there are enough consecutive bytes available in the ByteArray + fn word_u64(self: @T, offset: usize) -> Option; + /// Reads consecutive bytes from a specified offset as an unsigned integer in little endian + /// # Arguments + /// * `offset` - the start location of the consecutive bytes to read + /// # Returns + /// * `Option` - Returns an integer if there are enough consecutive bytes available in the ByteArray + fn word_u64_le(self: @T, offset: usize) -> Option; + /// Reads consecutive bytes from a specified offset as an unsigned integer in big endian + /// # Arguments + /// * `offset` - the start location of the consecutive bytes to read + /// # Returns + /// * `Option` - Returns an integer if there are enough consecutive bytes available in the ByteArray + fn word_u128(self: @T, offset: usize) -> Option; + /// Reads consecutive bytes from a specified offset as an unsigned integer in little endian + /// # Arguments + /// * `offset` - the start location of the consecutive bytes to read + /// # Returns + /// * `Option` - Returns an integer if there are enough consecutive bytes available in the ByteArray + fn word_u128_le(self: @T, offset: usize) -> Option; + /// Reads a u8 unsigned integer + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_u8(ref self: ByteReaderState) -> Option; + /// Reads a u16 unsigned integer in big endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_u16(ref self: ByteReaderState) -> Option; + /// Reads a u16 unsigned integer in little endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_u16_le(ref self: ByteReaderState) -> Option; + /// Reads a u32 unsigned integer in big endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_u32(ref self: ByteReaderState) -> Option; + /// Reads a u32 unsigned integer in little endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_u32_le(ref self: ByteReaderState) -> Option; + /// Reads a u64 unsigned integer in big endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_u64(ref self: ByteReaderState) -> Option; + /// Reads a u64 unsigned integer in little endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_u64_le(ref self: ByteReaderState) -> Option; + /// Reads a u128 unsigned integer in big endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_u128(ref self: ByteReaderState) -> Option; + /// Reads a u128 unsigned integer in little endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_u128_le(ref self: ByteReaderState) -> Option; + /// Reads a u256 unsigned integer in big endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_u256(ref self: ByteReaderState) -> Option; + /// Reads a u256 unsigned integer in little endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_u256_le(ref self: ByteReaderState) -> Option; + /// Reads a u512 unsigned integer in big endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_u512(ref self: ByteReaderState) -> Option; + /// Reads a u512 unsigned integer in little endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_u512_le(ref self: ByteReaderState) -> Option; + /// Reads an i8 signed integer in two's complement encoding from the ByteArray + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_i8(ref self: ByteReaderState) -> Option; + /// Reads an i16 signed integer in two's complement encoding from the ByteArray in big endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_i16(ref self: ByteReaderState) -> Option; + /// Reads an i16 signed integer in two's complement encoding from the ByteArray in little endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_i16_le(ref self: ByteReaderState) -> Option; + /// Reads an i32 signed integer in two's complement encoding from the ByteArray in big endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_i32(ref self: ByteReaderState) -> Option; + /// Reads an i32 signed integer in two's complement encoding from the ByteArray in little endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_i32_le(ref self: ByteReaderState) -> Option; + /// Reads an i64 signed integer in two's complement encoding from the ByteArray in big endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_i64(ref self: ByteReaderState) -> Option; + /// Reads an i64 signed integer in two's complement encoding from the ByteArray in little endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_i64_le(ref self: ByteReaderState) -> Option; + /// Reads an i128 signed integer in two's complement encoding from the ByteArray in big endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_i128(ref self: ByteReaderState) -> Option; + /// Reads an i128 signed integer in two's complement encoding from the ByteArray in little endian byte order + /// # Returns + /// `Option` - If there are enough bytes remaining an optional integer is returned + fn read_i128_le(ref self: ByteReaderState) -> Option; + /// Remaining length count relative to what has already been consume/read + /// # Returns + /// `usize` - count number of bytes remaining + fn len(self: @ByteReaderState) -> usize; +} + +impl ByteReaderImpl, +Len, +IndexView> of ByteReader { + #[inline] + fn reader(self: @T) -> ByteReaderState { + ByteReaderState { data: self, index: 0 } + } + + #[inline] + fn remaining(self: @T, at: usize, count: usize) -> Option<()> { + if at + count - 1 < self.len() { + Option::Some(()) + } else { + Option::None + } + } + + #[inline] + fn word_u16(self: @T, offset: usize) -> Option { + self.remaining(offset, 2)?; + let b1 = *self[offset]; + let b2 = *self[offset + 1]; + Option::Some(b1.into() * one_shift_left_bytes_u128(1).try_into().unwrap() + b2.into()) + } + + #[inline] + fn word_u16_le(self: @T, offset: usize) -> Option { + self.remaining(offset, 2)?; + let b1 = *self[offset]; + let b2 = *self[offset + 1]; + Option::Some(b1.into() + b2.into() * one_shift_left_bytes_u128(1).try_into().unwrap()) + } + + #[inline] + fn word_u32(self: @T, offset: usize) -> Option { + self.remaining(offset, 4)?; + let b1 = *self[offset]; + let b2 = *self[offset + 1]; + let b3 = *self[offset + 2]; + let b4 = *self[offset + 3]; + Option::Some( + b1.into() * one_shift_left_bytes_u128(3).try_into().unwrap() + + b2.into() * one_shift_left_bytes_u128(2).try_into().unwrap() + + b3.into() * one_shift_left_bytes_u128(1).try_into().unwrap() + + b4.into() + ) + } + + #[inline] + fn word_u32_le(self: @T, offset: usize) -> Option { + self.remaining(offset, 4)?; + let b1 = *self[offset]; + let b2 = *self[offset + 1]; + let b3 = *self[offset + 2]; + let b4 = *self[offset + 3]; + Option::Some( + b1.into() + + b2.into() * one_shift_left_bytes_u128(1).try_into().unwrap() + + b3.into() * one_shift_left_bytes_u128(2).try_into().unwrap() + + b4.into() * one_shift_left_bytes_u128(3).try_into().unwrap() + ) + } + + #[inline] + fn word_u64(self: @T, offset: usize) -> Option { + self.remaining(offset, 8)?; + let b1 = *self[offset]; + let b2 = *self[offset + 1]; + let b3 = *self[offset + 2]; + let b4 = *self[offset + 3]; + let b5 = *self[offset + 4]; + let b6 = *self[offset + 5]; + let b7 = *self[offset + 6]; + let b8 = *self[offset + 7]; + Option::Some( + b1.into() * one_shift_left_bytes_u128(7).try_into().unwrap() + + b2.into() * one_shift_left_bytes_u128(6).try_into().unwrap() + + b3.into() * one_shift_left_bytes_u128(5).try_into().unwrap() + + b4.into() * one_shift_left_bytes_u128(4).try_into().unwrap() + + b5.into() * one_shift_left_bytes_u128(3).try_into().unwrap() + + b6.into() * one_shift_left_bytes_u128(2).try_into().unwrap() + + b7.into() * one_shift_left_bytes_u128(1).try_into().unwrap() + + b8.into() + ) + } + + #[inline] + fn word_u64_le(self: @T, offset: usize) -> Option { + self.remaining(offset, 8)?; + let b1 = *self[offset]; + let b2 = *self[offset + 1]; + let b3 = *self[offset + 2]; + let b4 = *self[offset + 3]; + let b5 = *self[offset + 4]; + let b6 = *self[offset + 5]; + let b7 = *self[offset + 6]; + let b8 = *self[offset + 7]; + Option::Some( + b1.into() + + b2.into() * one_shift_left_bytes_u128(1).try_into().unwrap() + + b3.into() * one_shift_left_bytes_u128(2).try_into().unwrap() + + b4.into() * one_shift_left_bytes_u128(3).try_into().unwrap() + + b5.into() * one_shift_left_bytes_u128(4).try_into().unwrap() + + b6.into() * one_shift_left_bytes_u128(5).try_into().unwrap() + + b7.into() * one_shift_left_bytes_u128(6).try_into().unwrap() + + b8.into() * one_shift_left_bytes_u128(7).try_into().unwrap() + ) + } + + #[inline] + fn word_u128(self: @T, offset: usize) -> Option { + self.remaining(offset, 16)?; + let b01 = *self[offset]; + let b02 = *self[offset + 1]; + let b03 = *self[offset + 2]; + let b04 = *self[offset + 3]; + let b05 = *self[offset + 4]; + let b06 = *self[offset + 5]; + let b07 = *self[offset + 6]; + let b08 = *self[offset + 7]; + let b09 = *self[offset + 8]; + let b10 = *self[offset + 9]; + let b11 = *self[offset + 10]; + let b12 = *self[offset + 11]; + let b13 = *self[offset + 12]; + let b14 = *self[offset + 13]; + let b15 = *self[offset + 14]; + let b16 = *self[offset + 15]; + Option::Some( + b01.into() * one_shift_left_bytes_u128(15).try_into().unwrap() + + b02.into() * one_shift_left_bytes_u128(14).try_into().unwrap() + + b03.into() * one_shift_left_bytes_u128(13).try_into().unwrap() + + b04.into() * one_shift_left_bytes_u128(12).try_into().unwrap() + + b05.into() * one_shift_left_bytes_u128(11).try_into().unwrap() + + b06.into() * one_shift_left_bytes_u128(10).try_into().unwrap() + + b07.into() * one_shift_left_bytes_u128(09).try_into().unwrap() + + b08.into() * one_shift_left_bytes_u128(08).try_into().unwrap() + + b09.into() * one_shift_left_bytes_u128(07).try_into().unwrap() + + b10.into() * one_shift_left_bytes_u128(06).try_into().unwrap() + + b11.into() * one_shift_left_bytes_u128(05).try_into().unwrap() + + b12.into() * one_shift_left_bytes_u128(04).try_into().unwrap() + + b13.into() * one_shift_left_bytes_u128(03).try_into().unwrap() + + b14.into() * one_shift_left_bytes_u128(02).try_into().unwrap() + + b15.into() * one_shift_left_bytes_u128(01).try_into().unwrap() + + b16.into() + ) + } + + #[inline] + fn word_u128_le(self: @T, offset: usize) -> Option { + self.remaining(offset, 16)?; + let b01 = *self[offset]; + let b02 = *self[offset + 1]; + let b03 = *self[offset + 2]; + let b04 = *self[offset + 3]; + let b05 = *self[offset + 4]; + let b06 = *self[offset + 5]; + let b07 = *self[offset + 6]; + let b08 = *self[offset + 7]; + let b09 = *self[offset + 8]; + let b10 = *self[offset + 9]; + let b11 = *self[offset + 10]; + let b12 = *self[offset + 11]; + let b13 = *self[offset + 12]; + let b14 = *self[offset + 13]; + let b15 = *self[offset + 14]; + let b16 = *self[offset + 15]; + Option::Some( + b01.into() + + b02.into() * one_shift_left_bytes_u128(01).try_into().unwrap() + + b03.into() * one_shift_left_bytes_u128(02).try_into().unwrap() + + b04.into() * one_shift_left_bytes_u128(03).try_into().unwrap() + + b05.into() * one_shift_left_bytes_u128(04).try_into().unwrap() + + b06.into() * one_shift_left_bytes_u128(05).try_into().unwrap() + + b07.into() * one_shift_left_bytes_u128(06).try_into().unwrap() + + b08.into() * one_shift_left_bytes_u128(07).try_into().unwrap() + + b09.into() * one_shift_left_bytes_u128(08).try_into().unwrap() + + b10.into() * one_shift_left_bytes_u128(09).try_into().unwrap() + + b11.into() * one_shift_left_bytes_u128(10).try_into().unwrap() + + b12.into() * one_shift_left_bytes_u128(11).try_into().unwrap() + + b13.into() * one_shift_left_bytes_u128(12).try_into().unwrap() + + b14.into() * one_shift_left_bytes_u128(13).try_into().unwrap() + + b15.into() * one_shift_left_bytes_u128(14).try_into().unwrap() + + b16.into() * one_shift_left_bytes_u128(15).try_into().unwrap() + ) + } + + fn read_u8(ref self: ByteReaderState) -> Option { + self.data.remaining(self.index, 1)?; + let result = *self.data[self.index]; + self.index += 1; + Option::Some(result) + } + + fn read_u16(ref self: ByteReaderState) -> Option { + let result = self.data.word_u16(self.index)?; + self.index += 2; + Option::Some(result) + } + + fn read_u16_le(ref self: ByteReaderState) -> Option { + let result = self.data.word_u16_le(self.index)?; + self.index += 2; + Option::Some(result) + } + + fn read_u32(ref self: ByteReaderState) -> Option { + let result = self.data.word_u32(self.index)?; + self.index += 4; + Option::Some(result) + } + + fn read_u32_le(ref self: ByteReaderState) -> Option { + let result = self.data.word_u32_le(self.index)?; + self.index += 4; + Option::Some(result) + } + + fn read_u64(ref self: ByteReaderState) -> Option { + let result = self.data.word_u64(self.index)?; + self.index += 8; + Option::Some(result) + } + + fn read_u64_le(ref self: ByteReaderState) -> Option { + let result = self.data.word_u64_le(self.index)?; + self.index += 8; + Option::Some(result) + } + + fn read_u128(ref self: ByteReaderState) -> Option { + let result = self.data.word_u128(self.index)?; + self.index += 16; + Option::Some(result) + } + + fn read_u128_le(ref self: ByteReaderState) -> Option { + let result = self.data.word_u128_le(self.index)?; + self.index += 16; + Option::Some(result) + } + + fn read_u256(ref self: ByteReaderState) -> Option { + let result = u256 { + high: self.data.word_u128(self.index)?, low: self.data.word_u128(self.index + 16)? + }; + self.index += 32; + Option::Some(result) + } + + fn read_u256_le(ref self: ByteReaderState) -> Option { + let result = u256 { + low: self.data.word_u128_le(self.index)?, high: self.data.word_u128_le(self.index + 16)? + }; + self.index += 32; + Option::Some(result) + } + + fn read_u512(ref self: ByteReaderState) -> Option { + let result = u512 { + limb3: self.data.word_u128(self.index)?, + limb2: self.data.word_u128(self.index + 16)?, + limb1: self.data.word_u128(self.index + 32)?, + limb0: self.data.word_u128(self.index + 48)? + }; + self.index += 64; + Option::Some(result) + } + + fn read_u512_le(ref self: ByteReaderState) -> Option { + let result = u512 { + limb0: self.data.word_u128_le(self.index)?, + limb1: self.data.word_u128_le(self.index + 16)?, + limb2: self.data.word_u128_le(self.index + 32)?, + limb3: self.data.word_u128_le(self.index + 48)? + }; + self.index += 64; + Option::Some(result) + } + + fn read_i8(ref self: ByteReaderState) -> Option { + let felt: felt252 = self.read_u8()?.into(); + Option::Some(parse_signed(felt, 1).unwrap()) + } + + fn read_i16(ref self: ByteReaderState) -> Option { + let felt: felt252 = self.read_u16()?.into(); + Option::Some(parse_signed(felt, 2).unwrap()) + } + + fn read_i16_le(ref self: ByteReaderState) -> Option { + let felt: felt252 = self.read_u16_le()?.into(); + Option::Some(parse_signed(felt, 2).unwrap()) + } + + fn read_i32(ref self: ByteReaderState) -> Option { + let felt: felt252 = self.read_u32()?.into(); + Option::Some(parse_signed(felt, 4).unwrap()) + } + + fn read_i32_le(ref self: ByteReaderState) -> Option { + let felt: felt252 = self.read_u32_le()?.into(); + Option::Some(parse_signed(felt, 4).unwrap()) + } + + fn read_i64(ref self: ByteReaderState) -> Option { + let felt: felt252 = self.read_u64()?.into(); + Option::Some(parse_signed(felt, 8).unwrap()) + } + + fn read_i64_le(ref self: ByteReaderState) -> Option { + let felt: felt252 = self.read_u64_le()?.into(); + Option::Some(parse_signed(felt, 8).unwrap()) + } + + fn read_i128(ref self: ByteReaderState) -> Option { + let felt: felt252 = self.read_u128()?.into(); + Option::Some(parse_signed(felt, 16).unwrap()) + } + + fn read_i128_le(ref self: ByteReaderState) -> Option { + let felt: felt252 = self.read_u128_le()?.into(); + Option::Some(parse_signed(felt, 16).unwrap()) + } + + #[inline] + fn len(self: @ByteReaderState) -> usize { + Len::len(self) + } +} + +fn parse_signed>(value: felt252, bytes: usize) -> Option { + match value.try_into() { + Option::Some(pos) => Option::Some(pos), + Option::None => { + let negated: felt252 = value - one_shift_left_bytes_felt252(bytes); + negated.try_into() + }, + } +} + +/// Len trait that abstracts the `len()` property of `Array`, `Span` and `ByteArray` types +trait Len { + fn len(self: @T) -> usize; +} + +impl ArrayU8LenImpl of Len> { + #[inline] + fn len(self: @Array) -> usize { + core::array::array_len::(self) + } +} + +impl SpanU8LenImpl of Len> { + #[inline] + fn len(self: @Span) -> usize { + SpanTrait::::len(*self) + } +} + + +impl ByteArrayLenImpl of Len { + #[inline] + fn len(self: @ByteArray) -> usize { + ByteArrayTrait::len(self) + } +} + +impl ByteReaderLenImpl> of Len> { + /// Returns the remaining length of the ByteReader + /// # Returns + /// `usize` - The number of bytes remaining, considering the number of bytes that have already been consumed + #[inline] + fn len(self: @ByteReaderState) -> usize { + let byte_array = *self.data; + let byte_array_len = byte_array.len(); + byte_array_len - *self.index + } +} + +impl ByteArrayIndexViewAsSnapshotImpl of IndexView { + fn index(self: @ByteArray, index: usize) -> @u8 { + @self.at(index).expect('Index out of bounds') + } +} + +impl ArrayU8ReaderImpl = ByteReaderImpl>; +impl SpanU8ReaderImpl = ByteReaderImpl>; +impl ByteArrayReaderImpl = ByteReaderImpl; diff --git a/src/data_structures/src/lib.cairo b/src/data_structures/src/lib.cairo index f7b8d55c..57572e1f 100644 --- a/src/data_structures/src/lib.cairo +++ b/src/data_structures/src/lib.cairo @@ -1,7 +1,8 @@ mod array_ext; mod bit_array; +mod byte_appender; mod byte_array_ext; -mod byte_array_reader; +mod byte_reader; mod queue; mod stack; mod vec; diff --git a/src/data_structures/src/tests.cairo b/src/data_structures/src/tests.cairo index 6cf4c864..ef2ec32a 100644 --- a/src/data_structures/src/tests.cairo +++ b/src/data_structures/src/tests.cairo @@ -1,7 +1,8 @@ mod array_ext_test; mod bit_array_test; +mod byte_appender_test; mod byte_array_ext_test; -mod byte_array_reader_test; +mod byte_reader_test; mod queue_test; mod stack_test; mod vec_test; diff --git a/src/data_structures/src/tests/byte_appender_test.cairo b/src/data_structures/src/tests/byte_appender_test.cairo new file mode 100644 index 00000000..e4edec23 --- /dev/null +++ b/src/data_structures/src/tests/byte_appender_test.cairo @@ -0,0 +1,625 @@ +use alexandria_data_structures::byte_appender::ByteAppender; +use alexandria_data_structures::tests::byte_reader_test::{ + test_array_8, test_array_16, test_array_16_neg, test_array_32, test_array_64, test_byte_array_8, + test_byte_array_16, test_byte_array_16_neg, test_byte_array_32, test_byte_array_64 +}; +use integer::u512; + +#[test] +#[available_gas(1000000)] +fn test_append_u16() { + let mut ba: ByteArray = Default::default(); + ba.append_u16(0x0102_u16); + ba.append_u16(0x0304_u16); + ba.append_u16(0x0506_u16); + ba.append_u16(0x0708_u16); + assert(ba == test_byte_array_8(), 'u16 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_u16_arr() { + let mut ba: Array = array![]; + ba.append_u16(0x0102_u16); + ba.append_u16(0x0304_u16); + ba.append_u16(0x0506_u16); + ba.append_u16(0x0708_u16); + assert(ba == test_array_8(), 'u16 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_u16_le() { + let mut ba: ByteArray = Default::default(); + ba.append_u16_le(0x0201_u16); + ba.append_u16_le(0x0403_u16); + ba.append_u16_le(0x0605_u16); + ba.append_u16_le(0x0807_u16); + assert(ba == test_byte_array_8(), 'u16 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_u16_le_arr() { + let mut ba: Array = array![]; + ba.append_u16_le(0x0201_u16); + ba.append_u16_le(0x0403_u16); + ba.append_u16_le(0x0605_u16); + ba.append_u16_le(0x0807_u16); + assert(ba == test_array_8(), 'u16 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_u32() { + let mut ba: ByteArray = Default::default(); + ba.append_u32(0x01020304_u32); + ba.append_u32(0x05060708_u32); + assert(ba == test_byte_array_8(), 'u32 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_u32_arr() { + let mut ba: Array = array![]; + ba.append_u32(0x01020304_u32); + ba.append_u32(0x05060708_u32); + assert(ba == test_array_8(), 'u32 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_u32_le() { + let mut ba: ByteArray = Default::default(); + ba.append_u32_le(0x04030201_u32); + ba.append_u32_le(0x08070605_u32); + assert(ba == test_byte_array_8(), 'u32 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_u32_le_arr() { + let mut ba: Array = array![]; + ba.append_u32_le(0x04030201_u32); + ba.append_u32_le(0x08070605_u32); + assert(ba == test_array_8(), 'u32 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_u64() { + let mut ba: ByteArray = Default::default(); + ba.append_u64(0x0102030405060708_u64); + ba.append_u64(0x090a0b0c0d0e0f10_u64); + assert(ba == test_byte_array_16(), 'u64 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_u64_arr() { + let mut ba: Array = array![]; + ba.append_u64(0x0102030405060708_u64); + ba.append_u64(0x090a0b0c0d0e0f10_u64); + assert(ba == test_array_16(), 'u64 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_u64_le() { + let mut ba: ByteArray = Default::default(); + ba.append_u64_le(0x0807060504030201_u64); + ba.append_u64_le(0x100f0e0d0c0b0a09_u64); + assert(ba == test_byte_array_16(), 'u64 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_u64_le_arr() { + let mut ba: Array = array![]; + ba.append_u64_le(0x0807060504030201_u64); + ba.append_u64_le(0x100f0e0d0c0b0a09_u64); + assert(ba == test_array_16(), 'u64 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_u128() { + let mut ba: ByteArray = Default::default(); + ba.append_u128(0x0102030405060708090a0b0c0d0e0f10_u128); + ba.append_u128(0x1112131415161718191a1b1c1d1e1f20_u128); + assert(ba == test_byte_array_32(), 'u128 differs'); +} + +#[test] +#[available_gas(10000000)] +fn test_append_u128_arr() { + let mut ba: Array = array![]; + ba.append_u128(0x0102030405060708090a0b0c0d0e0f10_u128); + ba.append_u128(0x1112131415161718191a1b1c1d1e1f20_u128); + assert(ba == test_array_32(), 'u128 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_u128_le() { + let mut ba: ByteArray = Default::default(); + ba.append_u128_le(0x100f0e0d0c0b0a090807060504030201_u128); + ba.append_u128_le(0x201f1e1d1c1b1a191817161514131211_u128); + assert(ba == test_byte_array_32(), 'u128 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_u128_le_arr() { + let mut ba: Array = array![]; + ba.append_u128_le(0x100f0e0d0c0b0a090807060504030201_u128); + ba.append_u128_le(0x201f1e1d1c1b1a191817161514131211_u128); + assert(ba == test_array_32(), 'u128 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_u256() { + let mut ba: ByteArray = Default::default(); + let word = u256 { + high: 0x0102030405060708090a0b0c0d0e0f10_u128, low: 0x1112131415161718191a1b1c1d1e1f20_u128, + }; + ba.append_u256(word); + assert(ba == test_byte_array_32(), 'u256 differs'); +} + +#[test] +#[available_gas(10000000)] +fn test_append_u256_arr() { + let mut ba: Array = array![]; + let word = u256 { + high: 0x0102030405060708090a0b0c0d0e0f10_u128, low: 0x1112131415161718191a1b1c1d1e1f20_u128, + }; + ba.append_u256(word); + assert(ba == test_array_32(), 'u256 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_u256_le() { + let mut ba: ByteArray = Default::default(); + let word = u256 { + low: 0x100f0e0d0c0b0a090807060504030201_u128, high: 0x201f1e1d1c1b1a191817161514131211_u128, + }; + ba.append_u256_le(word); + assert(ba == test_byte_array_32(), 'u256 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_u256_le_arr() { + let mut ba: Array = array![]; + let word = u256 { + low: 0x100f0e0d0c0b0a090807060504030201_u128, high: 0x201f1e1d1c1b1a191817161514131211_u128, + }; + ba.append_u256_le(word); + assert(ba == test_array_32(), 'u256 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_u512() { + let test64 = u512 { + limb3: 0x0102030405060708090a0b0c0d0e0f10_u128, + limb2: 0x1112131415161718191a1b1c1d1e1f20_u128, + limb1: 0x2122232425262728292a2b2c2d2e2f30_u128, + limb0: 0x3132333435363738393a3b3c3d3e3f40_u128, + }; + + let mut ba: ByteArray = Default::default(); + ba.append_u512(test64); + assert(ba == test_byte_array_64(), 'test64 differs'); +} + +#[test] +#[available_gas(10000000)] +fn test_append_u512_arr() { + let test64 = u512 { + limb3: 0x0102030405060708090a0b0c0d0e0f10_u128, + limb2: 0x1112131415161718191a1b1c1d1e1f20_u128, + limb1: 0x2122232425262728292a2b2c2d2e2f30_u128, + limb0: 0x3132333435363738393a3b3c3d3e3f40_u128, + }; + + let mut ba: Array = array![]; + ba.append_u512(test64); + assert(ba == test_array_64(), 'test64 differs'); +} + +#[test] +#[available_gas(10000000)] +fn test_append_u512_le() { + let test64 = u512 { + limb0: 0x100f0e0d0c0b0a090807060504030201_u128, + limb1: 0x201f1e1d1c1b1a191817161514131211_u128, + limb2: 0x302f2e2d2c2b2a292827262524232221_u128, + limb3: 0x403f3e3d3c3b3a393837363534333231_u128, + }; + + let mut ba: ByteArray = Default::default(); + ba.append_u512_le(test64); + assert(ba == test_byte_array_64(), 'test64 differs'); +} + +#[test] +#[available_gas(10000000)] +fn test_append_u512_le_arr() { + let test64 = u512 { + limb0: 0x100f0e0d0c0b0a090807060504030201_u128, + limb1: 0x201f1e1d1c1b1a191817161514131211_u128, + limb2: 0x302f2e2d2c2b2a292827262524232221_u128, + limb3: 0x403f3e3d3c3b3a393837363534333231_u128, + }; + + let mut ba: Array = array![]; + ba.append_u512_le(test64); + assert(ba == test_array_64(), 'test64 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i8() { + let mut ba1: ByteArray = Default::default(); + ba1.append_i8(127_i8); + let mut ba2: ByteArray = Default::default(); + ba2.append_byte(0x7f_u8); + assert(ba1 == ba2, 'i8 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i8_arr() { + let mut ba1: Array = array![]; + ba1.append_i8(127_i8); + let mut ba2: Array = array![]; + ba2.append(0x7f_u8); + assert(ba1 == ba2, 'i8 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i8_neg() { + let mut ba1: ByteArray = Default::default(); + ba1.append_i8(-128_i8); + let mut ba2: ByteArray = Default::default(); + ba2.append_byte(0x80_u8); + assert(ba1 == ba2, 'negative i8 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i8_neg_arr() { + let mut ba1: Array = array![]; + ba1.append_i8(-128_i8); + let mut ba2: Array = array![]; + ba2.append(0x80_u8); + assert(ba1 == ba2, 'negative i8 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i16() { + let mut ba1: ByteArray = Default::default(); + ba1.append_i16(0x0102_i16); + ba1.append_i16(0x0304_i16); + ba1.append_i16(0x0506_i16); + ba1.append_i16(0x0708_i16); + assert(ba1 == test_byte_array_8(), 'i16 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i16_arr() { + let mut ba1: Array = array![]; + ba1.append_i16(0x0102_i16); + ba1.append_i16(0x0304_i16); + ba1.append_i16(0x0506_i16); + ba1.append_i16(0x0708_i16); + assert(ba1 == test_array_8(), 'i16 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i16_le() { + let mut ba1: ByteArray = Default::default(); + ba1.append_i16_le(0x0201_i16); + ba1.append_i16_le(0x0403_i16); + ba1.append_i16_le(0x0605_i16); + ba1.append_i16_le(0x0807_i16); + assert(ba1 == test_byte_array_8(), 'i16 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i16_le_arr() { + let mut ba1: Array = array![]; + ba1.append_i16_le(0x0201_i16); + ba1.append_i16_le(0x0403_i16); + ba1.append_i16_le(0x0605_i16); + ba1.append_i16_le(0x0807_i16); + assert(ba1 == test_array_8(), 'i16 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i16_neg() { + let mut ba1: ByteArray = Default::default(); + ba1.append_i16(-1_i16); + ba1.append_i16(-1_i16); + ba1.append_i16(-1_i16); + ba1.append_i16(-1_i16); + ba1.append_i16(-1_i16); + ba1.append_i16(-1_i16); + ba1.append_i16(-1_i16); + ba1.append_i16(-2_i16); + assert(ba1 == test_byte_array_16_neg(), 'negative i16 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i16_neg_arr() { + let mut ba1: Array = array![]; + ba1.append_i16(-1_i16); + ba1.append_i16(-1_i16); + ba1.append_i16(-1_i16); + ba1.append_i16(-1_i16); + ba1.append_i16(-1_i16); + ba1.append_i16(-1_i16); + ba1.append_i16(-1_i16); + ba1.append_i16(-2_i16); + assert(ba1 == test_array_16_neg(), 'negative i16 differs'); +} + +#[test] +#[available_gas(10000000)] +fn test_append_i16_le_neg() { + let mut ba1: ByteArray = Default::default(); + ba1.append_i16_le(-1_i16); + ba1.append_i16_le(-1_i16); + ba1.append_i16_le(-1_i16); + ba1.append_i16_le(-1_i16); + ba1.append_i16_le(-1_i16); + ba1.append_i16_le(-1_i16); + ba1.append_i16_le(-1_i16); + ba1.append_i16_le(-257_i16); + assert(ba1 == test_byte_array_16_neg(), 'negative i16 differs'); +} + +#[test] +#[available_gas(10000000)] +fn test_append_i16_le_neg_arr() { + let mut ba1: Array = array![]; + ba1.append_i16_le(-1_i16); + ba1.append_i16_le(-1_i16); + ba1.append_i16_le(-1_i16); + ba1.append_i16_le(-1_i16); + ba1.append_i16_le(-1_i16); + ba1.append_i16_le(-1_i16); + ba1.append_i16_le(-1_i16); + ba1.append_i16_le(-257_i16); + assert(ba1 == test_array_16_neg(), 'negative i16 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i32() { + let mut ba: ByteArray = Default::default(); + ba.append_i32(0x01020304_i32); + ba.append_i32(0x05060708_i32); + assert(ba == test_byte_array_8(), 'i32 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i32_arr() { + let mut ba: Array = array![]; + ba.append_i32(0x01020304_i32); + ba.append_i32(0x05060708_i32); + assert(ba == test_array_8(), 'i32 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i32_le() { + let mut ba: ByteArray = Default::default(); + ba.append_i32_le(0x04030201_i32); + ba.append_i32_le(0x08070605_i32); + assert(ba == test_byte_array_8(), 'i32 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i32_le_arr() { + let mut ba: Array = array![]; + ba.append_i32_le(0x04030201_i32); + ba.append_i32_le(0x08070605_i32); + assert(ba == test_array_8(), 'i32 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i32_neg() { + let mut ba: ByteArray = Default::default(); + ba.append_i32(-1_i32); + ba.append_i32(-1_i32); + ba.append_i32(-1_i32); + ba.append_i32(-2_i32); + assert(ba == test_byte_array_16_neg(), 'negative i32 differs'); +} +#[test] +#[available_gas(1000000)] +fn test_append_i32_neg_arr() { + let mut ba: Array = array![]; + ba.append_i32(-1_i32); + ba.append_i32(-1_i32); + ba.append_i32(-1_i32); + ba.append_i32(-2_i32); + assert(ba == test_array_16_neg(), 'negative i32 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i32_le_neg() { + let mut ba: ByteArray = Default::default(); + ba.append_i32_le(-1_i32); + ba.append_i32_le(-1_i32); + ba.append_i32_le(-1_i32); + ba.append_i32_le(-16777217_i32); + assert(ba == test_byte_array_16_neg(), 'negative i32 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i32_le_neg_arr() { + let mut ba: Array = array![]; + ba.append_i32_le(-1_i32); + ba.append_i32_le(-1_i32); + ba.append_i32_le(-1_i32); + ba.append_i32_le(-16777217_i32); + assert(ba == test_array_16_neg(), 'negative i32 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i64() { + let mut ba: ByteArray = Default::default(); + ba.append_i64(0x0102030405060708_i64); + ba.append_i64(0x090a0b0c0d0e0f10_i64); + assert(ba == test_byte_array_16(), 'i64 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i64_arr() { + let mut ba: Array = array![]; + ba.append_i64(0x0102030405060708_i64); + ba.append_i64(0x090a0b0c0d0e0f10_i64); + assert(ba == test_array_16(), 'i64 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i64_le() { + let mut ba: ByteArray = Default::default(); + ba.append_i64_le(0x0807060504030201_i64); + ba.append_i64_le(0x100f0e0d0c0b0a09_i64); + assert(ba == test_byte_array_16(), 'i64 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i64_le_arr() { + let mut ba: Array = array![]; + ba.append_i64_le(0x0807060504030201_i64); + ba.append_i64_le(0x100f0e0d0c0b0a09_i64); + assert(ba == test_array_16(), 'i64 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i64_neg() { + let mut ba: ByteArray = Default::default(); + ba.append_i64(-1_i64); + ba.append_i64(-2_i64); + assert(ba == test_byte_array_16_neg(), 'negative i64 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i64_neg_arr() { + let mut ba: Array = array![]; + ba.append_i64(-1_i64); + ba.append_i64(-2_i64); + assert(ba == test_array_16_neg(), 'negative i64 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i64_le_neg() { + let mut ba: ByteArray = Default::default(); + ba.append_i64_le(-1_i64); + ba.append_i64_le(-72057594037927937_i64); + assert(ba == test_byte_array_16_neg(), 'negative i64 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i64_le_neg_arr() { + let mut ba: Array = array![]; + ba.append_i64_le(-1_i64); + ba.append_i64_le(-72057594037927937_i64); + assert(ba == test_array_16_neg(), 'negative i64 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i128() { + let mut ba: ByteArray = Default::default(); + ba.append_i128(0x0102030405060708090a0b0c0d0e0f10_i128); + ba.append_i128(0x1112131415161718191a1b1c1d1e1f20_i128); + assert(ba == test_byte_array_32(), 'i128 differs'); +} + +#[test] +#[available_gas(10000000)] +fn test_append_i128_arr() { + let mut ba: Array = array![]; + ba.append_i128(0x0102030405060708090a0b0c0d0e0f10_i128); + ba.append_i128(0x1112131415161718191a1b1c1d1e1f20_i128); + assert(ba == test_array_32(), 'i128 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i128_le() { + let mut ba: ByteArray = Default::default(); + ba.append_i128_le(0x100f0e0d0c0b0a090807060504030201_i128); + ba.append_i128_le(0x201f1e1d1c1b1a191817161514131211_i128); + assert(ba == test_byte_array_32(), 'i128 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i128_le_arr() { + let mut ba: Array = array![]; + ba.append_i128_le(0x100f0e0d0c0b0a090807060504030201_i128); + ba.append_i128_le(0x201f1e1d1c1b1a191817161514131211_i128); + assert(ba == test_array_32(), 'i128 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i128_neg() { + let mut ba: ByteArray = Default::default(); + ba.append_i128(-2_i128); + assert(ba == test_byte_array_16_neg(), 'negative i128 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i128_neg_arr() { + let mut ba: Array = array![]; + ba.append_i128(-2_i128); + assert(ba == test_array_16_neg(), 'negative i128 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i128_le_neg() { + let mut ba: ByteArray = Default::default(); + ba.append_i128_le(-1329227995784915872903807060280344577_i128); + assert(ba == test_byte_array_16_neg(), 'negative i128 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_append_i128_le_neg_arr() { + let mut ba: Array = array![]; + ba.append_i128_le(-1329227995784915872903807060280344577_i128); + assert(ba == test_array_16_neg(), 'negative i128 differs'); +} diff --git a/src/data_structures/src/tests/byte_array_ext_test.cairo b/src/data_structures/src/tests/byte_array_ext_test.cairo index fc932229..b6199a3a 100644 --- a/src/data_structures/src/tests/byte_array_ext_test.cairo +++ b/src/data_structures/src/tests/byte_array_ext_test.cairo @@ -1,435 +1,6 @@ -use alexandria_data_structures::byte_array_ext::{ByteArraySerde, ByteArrayTraitExt}; -use integer::u512; - -#[test] -#[available_gas(1000000)] -fn test_append_u16() { - let mut ba: ByteArray = Default::default(); - ba.append_u16(0x0102_u16); - ba.append_u16(0x0304_u16); - ba.append_u16(0x0506_u16); - ba.append_u16(0x0708_u16); - assert(ba == test_byte_array_8(), 'u16 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_u16_le() { - let mut ba: ByteArray = Default::default(); - ba.append_u16_le(0x0201_u16); - ba.append_u16_le(0x0403_u16); - ba.append_u16_le(0x0605_u16); - ba.append_u16_le(0x0807_u16); - assert(ba == test_byte_array_8(), 'u16 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_u32() { - let mut ba: ByteArray = Default::default(); - ba.append_u32(0x01020304_u32); - ba.append_u32(0x05060708_u32); - assert(ba == test_byte_array_8(), 'u32 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_u32_le() { - let mut ba: ByteArray = Default::default(); - ba.append_u32_le(0x04030201_u32); - ba.append_u32_le(0x08070605_u32); - assert(ba == test_byte_array_8(), 'u32 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_u64() { - let mut ba: ByteArray = Default::default(); - ba.append_u64(0x0102030405060708_u64); - ba.append_u64(0x090a0b0c0d0e0f10_u64); - assert(ba == test_byte_array_16(), 'u64 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_u64_le() { - let mut ba: ByteArray = Default::default(); - ba.append_u64_le(0x0807060504030201_u64); - ba.append_u64_le(0x100f0e0d0c0b0a09_u64); - assert(ba == test_byte_array_16(), 'u64 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_u128() { - let mut ba: ByteArray = Default::default(); - ba.append_u128(0x0102030405060708090a0b0c0d0e0f10_u128); - ba.append_u128(0x1112131415161718191a1b1c1d1e1f20_u128); - assert(ba == test_byte_array_32(), 'u128 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_u128_le() { - let mut ba: ByteArray = Default::default(); - ba.append_u128_le(0x100f0e0d0c0b0a090807060504030201_u128); - ba.append_u128_le(0x201f1e1d1c1b1a191817161514131211_u128); - assert(ba == test_byte_array_32(), 'u128 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_u256() { - let mut ba: ByteArray = Default::default(); - let word = u256 { - high: 0x0102030405060708090a0b0c0d0e0f10_u128, low: 0x1112131415161718191a1b1c1d1e1f20_u128, - }; - ba.append_u256(word); - assert(ba == test_byte_array_32(), 'u256 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_u256_le() { - let mut ba: ByteArray = Default::default(); - let word = u256 { - low: 0x100f0e0d0c0b0a090807060504030201_u128, high: 0x201f1e1d1c1b1a191817161514131211_u128, - }; - ba.append_u256_le(word); - assert(ba == test_byte_array_32(), 'u256 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_u512() { - let test64 = u512 { - limb3: 0x0102030405060708090a0b0c0d0e0f10_u128, - limb2: 0x1112131415161718191a1b1c1d1e1f20_u128, - limb1: 0x2122232425262728292a2b2c2d2e2f30_u128, - limb0: 0x3132333435363738393a3b3c3d3e3f40_u128, - }; - - let mut ba: ByteArray = Default::default(); - ba.append_u512(test64); - assert(ba == test_byte_array_64(), 'test64 differs'); -} - -#[test] -#[available_gas(10000000)] -fn test_append_u512_le() { - let test64 = u512 { - limb0: 0x100f0e0d0c0b0a090807060504030201_u128, - limb1: 0x201f1e1d1c1b1a191817161514131211_u128, - limb2: 0x302f2e2d2c2b2a292827262524232221_u128, - limb3: 0x403f3e3d3c3b3a393837363534333231_u128, - }; - - let mut ba: ByteArray = Default::default(); - ba.append_u512_le(test64); - assert(ba == test_byte_array_64(), 'test64 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_i8() { - let mut ba1 = Default::default(); - ba1.append_i8(127_i8); - let mut ba2 = Default::default(); - ba2.append_byte(0x7f_u8); - assert(ba1 == ba2, 'i8 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_i8_neg() { - let mut ba1 = Default::default(); - ba1.append_i8(-128_i8); - let mut ba2 = Default::default(); - ba2.append_byte(0x80_u8); - assert(ba1 == ba2, 'negative i8 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_i16() { - let mut ba1 = Default::default(); - ba1.append_i16(0x0102_i16); - ba1.append_i16(0x0304_i16); - ba1.append_i16(0x0506_i16); - ba1.append_i16(0x0708_i16); - assert(ba1 == test_byte_array_8(), 'i16 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_i16_le() { - let mut ba1 = Default::default(); - ba1.append_i16_le(0x0201_i16); - ba1.append_i16_le(0x0403_i16); - ba1.append_i16_le(0x0605_i16); - ba1.append_i16_le(0x0807_i16); - assert(ba1 == test_byte_array_8(), 'i16 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_i16_neg() { - let mut ba1 = Default::default(); - ba1.append_i16(-1_i16); - ba1.append_i16(-1_i16); - ba1.append_i16(-1_i16); - ba1.append_i16(-1_i16); - ba1.append_i16(-1_i16); - ba1.append_i16(-1_i16); - ba1.append_i16(-1_i16); - ba1.append_i16(-2_i16); - assert(ba1 == test_byte_array_16_neg(), 'negative i16 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_i16_le_neg() { - let mut ba1 = Default::default(); - ba1.append_i16_le(-1_i16); - ba1.append_i16_le(-1_i16); - ba1.append_i16_le(-1_i16); - ba1.append_i16_le(-1_i16); - ba1.append_i16_le(-1_i16); - ba1.append_i16_le(-1_i16); - ba1.append_i16_le(-1_i16); - ba1.append_i16_le(-257_i16); - assert(ba1 == test_byte_array_16_neg(), 'negative i16 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_i32() { - let mut ba = Default::default(); - ba.append_i32(0x01020304_i32); - ba.append_i32(0x05060708_i32); - assert(ba == test_byte_array_8(), 'i32 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_i32_le() { - let mut ba = Default::default(); - ba.append_i32_le(0x04030201_i32); - ba.append_i32_le(0x08070605_i32); - assert(ba == test_byte_array_8(), 'i32 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_i32_neg() { - let mut ba = Default::default(); - ba.append_i32(-1_i32); - ba.append_i32(-1_i32); - ba.append_i32(-1_i32); - ba.append_i32(-2_i32); - assert(ba == test_byte_array_16_neg(), 'negative i32 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_i32_le_neg() { - let mut ba = Default::default(); - ba.append_i32_le(-1_i32); - ba.append_i32_le(-1_i32); - ba.append_i32_le(-1_i32); - ba.append_i32_le(-16777217_i32); - assert(ba == test_byte_array_16_neg(), 'negative i32 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_i64() { - let mut ba: ByteArray = Default::default(); - ba.append_i64(0x0102030405060708_i64); - ba.append_i64(0x090a0b0c0d0e0f10_i64); - assert(ba == test_byte_array_16(), 'i64 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_i64_le() { - let mut ba: ByteArray = Default::default(); - ba.append_i64_le(0x0807060504030201_i64); - ba.append_i64_le(0x100f0e0d0c0b0a09_i64); - assert(ba == test_byte_array_16(), 'i64 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_i64_neg() { - let mut ba: ByteArray = Default::default(); - ba.append_i64(-1_i64); - ba.append_i64(-2_i64); - assert(ba == test_byte_array_16_neg(), 'negative i64 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_i64_le_neg() { - let mut ba: ByteArray = Default::default(); - ba.append_i64_le(-1_i64); - ba.append_i64_le(-72057594037927937_i64); - assert(ba == test_byte_array_16_neg(), 'negative i64 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_i128() { - let mut ba: ByteArray = Default::default(); - ba.append_i128(0x0102030405060708090a0b0c0d0e0f10_i128); - ba.append_i128(0x1112131415161718191a1b1c1d1e1f20_i128); - assert(ba == test_byte_array_32(), 'i128 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_i128_le() { - let mut ba: ByteArray = Default::default(); - ba.append_i128_le(0x100f0e0d0c0b0a090807060504030201_i128); - ba.append_i128_le(0x201f1e1d1c1b1a191817161514131211_i128); - assert(ba == test_byte_array_32(), 'i128 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_i128_neg() { - let mut ba: ByteArray = Default::default(); - ba.append_i128(-2_i128); - assert(ba == test_byte_array_16_neg(), 'negative i128 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_append_i128_le_neg() { - let mut ba: ByteArray = Default::default(); - ba.append_i128_le(-1329227995784915872903807060280344577_i128); - assert(ba == test_byte_array_16_neg(), 'negative i128 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_word_u16() { - let word = test_byte_array_64().word_u16(62).unwrap(); - assert(word == 0x3f40_u16, 'word u16 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_word_u16_le() { - let word = test_byte_array_64().word_u16_le(62).unwrap(); - assert(word == 0x403f_u16, 'word u16 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_word_u16_none() { - let is_none = test_byte_array_64().word_u16(63).is_none(); - assert(is_none, 'word u16 should be empty'); -} - -#[test] -#[available_gas(1000000)] -fn test_word_u16_le_none() { - let is_none = test_byte_array_64().word_u16_le(63).is_none(); - assert(is_none, 'word u16 should be empty'); -} - -#[test] -#[available_gas(1000000)] -fn test_word_u32() { - let word = test_byte_array_64().word_u32(60).unwrap(); - assert(word == 0x3d3e3f40_u32, 'word u32 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_word_u32_le() { - let word = test_byte_array_64().word_u32_le(60).unwrap(); - assert(word == 0x403f3e3d_u32, 'word u32 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_word_u32_none() { - let is_none = test_byte_array_64().word_u32(61).is_none(); - assert(is_none, 'word u32 should be empty'); -} - -#[test] -#[available_gas(1000000)] -fn test_word_u32_le_none() { - let is_none = test_byte_array_64().word_u32_le(61).is_none(); - assert(is_none, 'word u32 should be empty'); -} - -#[test] -#[available_gas(1000000)] -fn test_word_u64() { - let word = test_byte_array_64().word_u64(56).unwrap(); - assert(word == 0x393a3b3c3d3e3f40_u64, 'word u64 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_word_u64_le() { - let word = test_byte_array_64().word_u64_le(56).unwrap(); - assert(word == 0x403f3e3d3c3b3a39_u64, 'word u64 differs'); -} - -#[test] -#[available_gas(1000000)] -fn test_word_u64_none() { - let is_none = test_byte_array_64().word_u64(57).is_none(); - assert(is_none, 'word u64 should be empty'); -} - -#[test] -#[available_gas(1000000)] -fn test_word_u64_le_none() { - let is_none = test_byte_array_64().word_u64_le(57).is_none(); - assert(is_none, 'word u64 should be empty'); -} - -#[test] -#[available_gas(2000000)] -fn test_word_u128() { - let word = test_byte_array_64().word_u128(48).unwrap(); - assert(word == 0x3132333435363738393a3b3c3d3e3f40_u128, 'word u128 differs'); -} - -#[test] -#[available_gas(2000000)] -fn test_word_u128_le() { - let word = test_byte_array_64().word_u128_le(48).unwrap(); - assert(word == 0x403f3e3d3c3b3a393837363534333231_u128, 'word u128 differs'); -} - -#[test] -#[available_gas(2000000)] -fn test_word_u128_none() { - let is_none = test_byte_array_64().word_u128(49).is_none(); - assert(is_none, 'word u128 should be empty'); -} - -#[test] -#[available_gas(2000000)] -fn test_word_u128_le_none() { - let is_none = test_byte_array_64().word_u128_le(49).is_none(); - assert(is_none, 'word u128 should be empty'); -} - -#[test] -#[available_gas(2000000)] -fn test_reader_helper() { - let ba = test_byte_array_64(); - let reader = ba.reader(); - assert(reader.data == @ba, 'reader failed'); -} +use alexandria_data_structures::byte_array_ext::{ + ByteArraySerde, ByteArrayIntoArrayU8, SpanU8IntoBytearray +}; #[test] #[available_gas(1000000)] @@ -449,37 +20,33 @@ fn test_deserialize() { assert(ba == test_byte_array_64(), 'deserialized ByteArray differs'); } -// helpers -fn test_byte_array_8() -> ByteArray { - let mut ba1 = Default::default(); - ba1.append_word(0x0102030405060708, 8); - ba1 -} - -fn test_byte_array_16() -> ByteArray { - let mut ba1 = Default::default(); - ba1.append_word(0x0102030405060708090a0b0c0d0e0f10, 16); - ba1 -} - -fn test_byte_array_32() -> ByteArray { - let mut ba1 = Default::default(); - ba1.append_word(0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f, 31); - ba1.append_word(0x20, 1); - ba1 -} - -fn test_byte_array_32_neg() -> ByteArray { - let mut ba1 = Default::default(); - ba1.append_word(0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1, 31); - ba1.append_word(0xe0, 1); - ba1 +#[test] +#[available_gas(1000000)] +fn test_span_u8_into_byte_array() { + let array: Array = array![1, 2, 3, 4, 5, 6, 7, 8,]; + let ba: ByteArray = array.span().into(); + let mut index = 0_usize; + loop { + match ba.at(index) { + Option::Some(byte) => assert(*(array[index]) == byte, 'should equal'), + Option::None => { break; } + }; + index += 1; + }; } -fn test_byte_array_16_neg() -> ByteArray { - let mut ba1 = Default::default(); - ba1.append_word(0xfffffffffffffffffffffffffffffffe, 16); - ba1 +#[test] +#[available_gas(10000000)] +fn test_byte_array_into_array_u8() { + let array: Array = test_byte_array_64().into(); + let mut index = 0_usize; + loop { + if index == 0x40 { + break; + } + assert((*array[index]).into() == index + 1, 'unexpected result'); + index += 1; + } } fn test_byte_array_64() -> ByteArray { diff --git a/src/data_structures/src/tests/byte_array_reader_test.cairo b/src/data_structures/src/tests/byte_array_reader_test.cairo deleted file mode 100644 index 3fffb9e6..00000000 --- a/src/data_structures/src/tests/byte_array_reader_test.cairo +++ /dev/null @@ -1,127 +0,0 @@ -use integer::u512; -use alexandria_data_structures::byte_array_ext::ByteArrayTraitExt; -use alexandria_data_structures::byte_array_reader::ByteArrayReaderTrait; -use alexandria_data_structures::tests::byte_array_ext_test::test_byte_array_64; - -#[test] -#[available_gas(10000000)] -fn test_clone_byte_array_reader() { - let ba = test_byte_array_64(); - let mut rd1 = ba.reader(); - let temp = rd1.read_u256().unwrap(); - let mut rd2 = rd1.clone(); - let a = rd1.read_u128().unwrap(); - let b = rd2.read_u128().unwrap(); - assert(a == b, 'copy ByteArrayReader failed'); -} - -#[test] -#[available_gas(20000000)] -fn test_len() { - let ba = test_byte_array_64(); - let mut rd = ba.reader(); - assert(64 == rd.len(), 'expected len 64'); - let _ = rd.read_u8().expect('some'); - assert(63 == rd.len(), 'expected len 63'); - let _ = rd.read_u256().expect('some'); - assert(31 == rd.len(), 'expected len 31'); - let _ = rd.read_u128().expect('some'); - assert(15 == rd.len(), 'expected len 15'); - let _ = rd.read_u64().expect('some'); - assert(7 == rd.len(), 'expected len 7'); - let _ = rd.read_u32().expect('some'); - assert(3 == rd.len(), 'expected len 3'); - let _ = rd.read_u16().expect('some'); - assert(1 == rd.len(), 'expected len 1'); - let _ = rd.read_i8().expect('some'); - assert(0 == rd.len(), 'expected len 0'); -} - -#[test] -#[available_gas(20000000)] -fn test_read() { - let ba = test_byte_array_64(); - let mut rd = ba.reader(); - assert(rd.read_i8() == Option::Some(1), 'expected 1'); - assert( - rd.read_i128() == Option::Some(0x02030405060708090a0b0c0d0e0f1011), 'not 0x0203040506...' - ); - assert( - rd.read_u128() == Option::Some(0x12131415161718191a1b1c1d1e1f2021), 'not 0x1213141516...' - ); - assert(rd.read_i64() == Option::Some(0x2223242526272829), 'not 0x22232425...'); - assert( - rd.read_u128() == Option::Some(0x2a2b2c2d2e2f30313233343536373839), 'not 0x2a2b2c2d2e...' - ); - assert(rd.read_u32() == Option::Some(0x3a3b3c3d), 'not 0x3a3b3c3d'); - assert(rd.read_i16() == Option::Some(0x3e3f), 'not 0x3e3f'); - assert(rd.read_u8() == Option::Some(0x40), 'not 0x40'); - assert(rd.read_u8().is_none(), 'expected none'); -} - -#[test] -#[available_gas(20000000)] -fn test_read_le() { - let ba = test_byte_array_64(); - let mut rd = ba.reader(); - assert(rd.read_i8() == Option::Some(1), 'expected 1'); - assert( - rd.read_i128_le() == Option::Some(0x11100f0e0d0c0b0a0908070605040302), 'not 0x11100f0e0...' - ); - assert( - rd.read_u128_le() == Option::Some(0x21201f1e1d1c1b1a1918171615141312), 'not 0x21201f1e1d...' - ); - assert(rd.read_i64_le() == Option::Some(0x2928272625242322), 'not 0x29282726...'); - assert( - rd.read_u128_le() == Option::Some(0x393837363534333231302f2e2d2c2b2a), 'not 0x3938373635...' - ); - assert(rd.read_u32_le() == Option::Some(0x3d3c3b3a), 'not 0x3d3c3b3a'); - assert(rd.read_i16_le() == Option::Some(0x3f3e), 'not 0x3f3e'); - assert(rd.read_u8() == Option::Some(0x40), 'not 0x40'); - assert(rd.read_u8().is_none(), 'expected none'); -} - -#[test] -#[available_gas(20000000)] -fn test_read_u256() { - let ba = test_byte_array_64(); - let mut rd = ba.reader(); - let u256{low: low1, high: high1 } = rd.read_u256().unwrap(); - assert(high1 == 0x0102030405060708090a0b0c0d0e0f10_u128, 'wrong value for high1'); - assert(low1 == 0x1112131415161718191a1b1c1d1e1f20_u128, 'wrong value for low1'); -} - -#[test] -#[available_gas(20000000)] -fn test_read_u256_le() { - let ba = test_byte_array_64(); - let mut rd = ba.reader(); - let u256{low: low1, high: high1 } = rd.read_u256_le().unwrap(); - assert(high1 == 0x201f1e1d1c1b1a191817161514131211_u128, 'wrong value for high1'); - assert(low1 == 0x100f0e0d0c0b0a090807060504030201_u128, 'wrong value for low1'); -} - -#[test] -#[available_gas(20000000)] -fn test_read_u512() { - let ba = test_byte_array_64(); - let mut rd = ba.reader(); - let u512{limb0, limb1, limb2, limb3 } = rd.read_u512().unwrap(); - - assert(limb3 == 0x0102030405060708090a0b0c0d0e0f10_u128, 'wrong value for limb3'); - assert(limb2 == 0x1112131415161718191a1b1c1d1e1f20_u128, 'wrong value for limb2'); - assert(limb1 == 0x2122232425262728292a2b2c2d2e2f30_u128, 'wrong value for limb1'); - assert(limb0 == 0x3132333435363738393a3b3c3d3e3f40_u128, 'wrong value for limb0'); -} - -#[test] -#[available_gas(20000000)] -fn test_read_u512_le() { - let ba = test_byte_array_64(); - let mut rd = ba.reader(); - let u512{limb0, limb1, limb2, limb3 } = rd.read_u512_le().unwrap(); - assert(limb0 == 0x100f0e0d0c0b0a090807060504030201_u128, 'wrong value for limb0'); - assert(limb1 == 0x201f1e1d1c1b1a191817161514131211_u128, 'wrong value for limb1'); - assert(limb2 == 0x302f2e2d2c2b2a292827262524232221_u128, 'wrong value for limb2'); - assert(limb3 == 0x403f3e3d3c3b3a393837363534333231_u128, 'wrong value for limb3'); -} diff --git a/src/data_structures/src/tests/byte_reader_test.cairo b/src/data_structures/src/tests/byte_reader_test.cairo new file mode 100644 index 00000000..6ebcdc46 --- /dev/null +++ b/src/data_structures/src/tests/byte_reader_test.cairo @@ -0,0 +1,731 @@ +use alexandria_data_structures::byte_reader::ByteReader; +use integer::u512; + +#[test] +#[available_gas(1000000)] +fn test_word_u16() { + let word = test_byte_array_64().word_u16(62).unwrap(); + assert(word == 0x3f40_u16, 'word u16 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u16_arr() { + let word = test_array_64().word_u16(62).unwrap(); + assert(word == 0x3f40_u16, 'word u16 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u16_le() { + let word = test_byte_array_64().word_u16_le(62).unwrap(); + assert(word == 0x403f_u16, 'word u16 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u16_le_arr() { + let word = test_array_64().word_u16_le(62).unwrap(); + assert(word == 0x403f_u16, 'word u16 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u16_none() { + let is_none = test_byte_array_64().word_u16(63).is_none(); + assert(is_none, 'word u16 should be empty'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u16_none_arr() { + let is_none = test_array_64().word_u16(63).is_none(); + assert(is_none, 'word u16 should be empty'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u16_le_none() { + let is_none = test_byte_array_64().word_u16_le(63).is_none(); + assert(is_none, 'word u16 should be empty'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u16_le_none_arr() { + let is_none = test_array_64().word_u16_le(63).is_none(); + assert(is_none, 'word u16 should be empty'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u32() { + let word = test_byte_array_64().word_u32(60).unwrap(); + assert(word == 0x3d3e3f40_u32, 'word u32 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u32_arr() { + let word = test_array_64().word_u32(60).unwrap(); + assert(word == 0x3d3e3f40_u32, 'word u32 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u32_le() { + let word = test_byte_array_64().word_u32_le(60).unwrap(); + assert(word == 0x403f3e3d_u32, 'word u32 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u32_le_arr() { + let word = test_array_64().word_u32_le(60).unwrap(); + assert(word == 0x403f3e3d_u32, 'word u32 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u32_none() { + let is_none = test_byte_array_64().word_u32(61).is_none(); + assert(is_none, 'word u32 should be empty'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u32_none_arr() { + let is_none = test_array_64().word_u32(61).is_none(); + assert(is_none, 'word u32 should be empty'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u32_le_none() { + let is_none = test_byte_array_64().word_u32_le(61).is_none(); + assert(is_none, 'word u32 should be empty'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u32_le_none_arr() { + let is_none = test_array_64().word_u32_le(61).is_none(); + assert(is_none, 'word u32 should be empty'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u64() { + let word = test_byte_array_64().word_u64(56).unwrap(); + assert(word == 0x393a3b3c3d3e3f40_u64, 'word u64 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u64_arr() { + let word = test_array_64().word_u64(56).unwrap(); + assert(word == 0x393a3b3c3d3e3f40_u64, 'word u64 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u64_le() { + let word = test_byte_array_64().word_u64_le(56).unwrap(); + assert(word == 0x403f3e3d3c3b3a39_u64, 'word u64 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u64_le_arr() { + let word = test_array_64().word_u64_le(56).unwrap(); + assert(word == 0x403f3e3d3c3b3a39_u64, 'word u64 differs'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u64_none() { + let is_none = test_byte_array_64().word_u64(57).is_none(); + assert(is_none, 'word u64 should be empty'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u64_none_arr() { + let is_none = test_array_64().word_u64(57).is_none(); + assert(is_none, 'word u64 should be empty'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u64_le_none() { + let is_none = test_byte_array_64().word_u64_le(57).is_none(); + assert(is_none, 'word u64 should be empty'); +} + +#[test] +#[available_gas(1000000)] +fn test_word_u64_le_none_arr() { + let is_none = test_array_64().word_u64_le(57).is_none(); + assert(is_none, 'word u64 should be empty'); +} + +#[test] +#[available_gas(2000000)] +fn test_word_u128() { + let word = test_byte_array_64().word_u128(48).unwrap(); + assert(word == 0x3132333435363738393a3b3c3d3e3f40_u128, 'word u128 differs'); +} + +#[test] +#[available_gas(2000000)] +fn test_word_u128_arr() { + let word = test_array_64().word_u128(48).unwrap(); + assert(word == 0x3132333435363738393a3b3c3d3e3f40_u128, 'word u128 differs'); +} + +#[test] +#[available_gas(2000000)] +fn test_word_u128_le() { + let word = test_byte_array_64().word_u128_le(48).unwrap(); + assert(word == 0x403f3e3d3c3b3a393837363534333231_u128, 'word u128 differs'); +} + +#[test] +#[available_gas(2000000)] +fn test_word_u128_le_arr() { + let word = test_array_64().word_u128_le(48).unwrap(); + assert(word == 0x403f3e3d3c3b3a393837363534333231_u128, 'word u128 differs'); +} + +#[test] +#[available_gas(2000000)] +fn test_word_u128_none() { + let is_none = test_byte_array_64().word_u128(49).is_none(); + assert(is_none, 'word u128 should be empty'); +} + +fn test_word_u128_none_arr() { + let is_none = test_array_64().word_u128(49).is_none(); + assert(is_none, 'word u128 should be empty'); +} + +#[test] +#[available_gas(2000000)] +fn test_word_u128_le_none() { + let is_none = test_byte_array_64().word_u128_le(49).is_none(); + assert(is_none, 'word u128 should be empty'); +} + +#[test] +#[available_gas(2000000)] +fn test_word_u128_le_none_arr() { + let is_none = test_array_64().word_u128_le(49).is_none(); + assert(is_none, 'word u128 should be empty'); +} + +#[test] +#[available_gas(2000000)] +fn test_reader_helper() { + let ba = test_byte_array_64(); + let reader = ba.reader(); + assert(reader.data == @ba, 'reader failed'); +} + +#[test] +#[available_gas(2000000)] +fn test_reader_helper_arr() { + let ba = test_array_64(); + let reader = ba.reader(); + assert(reader.data == @ba, 'reader failed'); +} + +#[test] +#[available_gas(20000000)] +fn test_len() { + let ba = test_byte_array_64(); + let mut rd = ba.reader(); + assert(64 == rd.len(), 'expected len 64'); + let _ = rd.read_u8().expect('some'); + assert(63 == rd.len(), 'expected len 63'); + let _ = rd.read_u256().expect('some'); + assert(31 == rd.len(), 'expected len 31'); + let _ = rd.read_u128().expect('some'); + assert(15 == rd.len(), 'expected len 15'); + let _ = rd.read_u64().expect('some'); + assert(7 == rd.len(), 'expected len 7'); + let _ = rd.read_u32().expect('some'); + assert(3 == rd.len(), 'expected len 3'); + let _ = rd.read_u16().expect('some'); + assert(1 == rd.len(), 'expected len 1'); + let _ = rd.read_i8().expect('some'); + assert(0 == rd.len(), 'expected len 0'); +} + +#[test] +#[available_gas(20000000)] +fn test_len_arr() { + let ba = test_array_64(); + let mut rd = ba.reader(); + assert(64 == rd.len(), 'expected len 64'); + let _ = rd.read_u8().expect('some'); + assert(63 == rd.len(), 'expected len 63'); + let _ = rd.read_u256().expect('some'); + assert(31 == rd.len(), 'expected len 31'); + let _ = rd.read_u128().expect('some'); + assert(15 == rd.len(), 'expected len 15'); + let _ = rd.read_u64().expect('some'); + assert(7 == rd.len(), 'expected len 7'); + let _ = rd.read_u32().expect('some'); + assert(3 == rd.len(), 'expected len 3'); + let _ = rd.read_u16().expect('some'); + assert(1 == rd.len(), 'expected len 1'); + let _ = rd.read_i8().expect('some'); + assert(0 == rd.len(), 'expected len 0'); +} + +#[test] +#[available_gas(20000000)] +fn test_read_u256() { + let ba = test_byte_array_64(); + let mut rd = ba.reader(); + let u256{low: low1, high: high1 } = rd.read_u256().unwrap(); + assert(high1 == 0x0102030405060708090a0b0c0d0e0f10_u128, 'wrong value for high1'); + assert(low1 == 0x1112131415161718191a1b1c1d1e1f20_u128, 'wrong value for low1'); +} + +#[test] +#[available_gas(20000000)] +fn test_read_u256_arr() { + let ba = test_array_64(); + let mut rd = ba.reader(); + let u256{low: low1, high: high1 } = rd.read_u256().unwrap(); + assert(high1 == 0x0102030405060708090a0b0c0d0e0f10_u128, 'wrong value for high1'); + assert(low1 == 0x1112131415161718191a1b1c1d1e1f20_u128, 'wrong value for low1'); +} + +#[test] +#[available_gas(20000000)] +fn test_read_u256_le() { + let ba = test_byte_array_64(); + let mut rd = ba.reader(); + let u256{low: low1, high: high1 } = rd.read_u256_le().unwrap(); + assert(high1 == 0x201f1e1d1c1b1a191817161514131211_u128, 'wrong value for high1'); + assert(low1 == 0x100f0e0d0c0b0a090807060504030201_u128, 'wrong value for low1'); +} + +#[test] +#[available_gas(20000000)] +fn test_read_u256_le_arr() { + let ba = test_array_64(); + let mut rd = ba.reader(); + let u256{low: low1, high: high1 } = rd.read_u256_le().unwrap(); + assert(high1 == 0x201f1e1d1c1b1a191817161514131211_u128, 'wrong value for high1'); + assert(low1 == 0x100f0e0d0c0b0a090807060504030201_u128, 'wrong value for low1'); +} + +#[test] +#[available_gas(20000000)] +fn test_read_u512() { + let ba = test_byte_array_64(); + let mut rd = ba.reader(); + let u512{limb0, limb1, limb2, limb3 } = rd.read_u512().unwrap(); + + assert(limb3 == 0x0102030405060708090a0b0c0d0e0f10_u128, 'wrong value for limb3'); + assert(limb2 == 0x1112131415161718191a1b1c1d1e1f20_u128, 'wrong value for limb2'); + assert(limb1 == 0x2122232425262728292a2b2c2d2e2f30_u128, 'wrong value for limb1'); + assert(limb0 == 0x3132333435363738393a3b3c3d3e3f40_u128, 'wrong value for limb0'); +} + +#[test] +#[available_gas(20000000)] +fn test_read_u512_arr() { + let ba = test_array_64(); + let mut rd = ba.reader(); + let u512{limb0, limb1, limb2, limb3 } = rd.read_u512().unwrap(); + + assert(limb3 == 0x0102030405060708090a0b0c0d0e0f10_u128, 'wrong value for limb3'); + assert(limb2 == 0x1112131415161718191a1b1c1d1e1f20_u128, 'wrong value for limb2'); + assert(limb1 == 0x2122232425262728292a2b2c2d2e2f30_u128, 'wrong value for limb1'); + assert(limb0 == 0x3132333435363738393a3b3c3d3e3f40_u128, 'wrong value for limb0'); +} + +#[test] +#[available_gas(20000000)] +fn test_read_u512_le() { + let ba = test_byte_array_64(); + let mut rd = ba.reader(); + let u512{limb0, limb1, limb2, limb3 } = rd.read_u512_le().unwrap(); + assert(limb0 == 0x100f0e0d0c0b0a090807060504030201_u128, 'wrong value for limb0'); + assert(limb1 == 0x201f1e1d1c1b1a191817161514131211_u128, 'wrong value for limb1'); + assert(limb2 == 0x302f2e2d2c2b2a292827262524232221_u128, 'wrong value for limb2'); + assert(limb3 == 0x403f3e3d3c3b3a393837363534333231_u128, 'wrong value for limb3'); +} + +#[test] +#[available_gas(20000000)] +fn test_read_u512_le_arr() { + let ba = test_array_64(); + let mut rd = ba.reader(); + let u512{limb0, limb1, limb2, limb3 } = rd.read_u512_le().unwrap(); + assert(limb0 == 0x100f0e0d0c0b0a090807060504030201_u128, 'wrong value for limb0'); + assert(limb1 == 0x201f1e1d1c1b1a191817161514131211_u128, 'wrong value for limb1'); + assert(limb2 == 0x302f2e2d2c2b2a292827262524232221_u128, 'wrong value for limb2'); + assert(limb3 == 0x403f3e3d3c3b3a393837363534333231_u128, 'wrong value for limb3'); +} + +#[test] +#[available_gas(20000000)] +fn test_read_sequence() { + let ba = test_byte_array_64(); + let mut rd = ba.reader(); + assert(rd.read_i8() == Option::Some(1), 'expected 1'); + assert( + rd.read_i128() == Option::Some(0x02030405060708090a0b0c0d0e0f1011), 'not 0x0203040506...' + ); + assert( + rd.read_u128() == Option::Some(0x12131415161718191a1b1c1d1e1f2021), 'not 0x1213141516...' + ); + assert(rd.read_i64() == Option::Some(0x2223242526272829), 'not 0x22232425...'); + assert( + rd.read_u128() == Option::Some(0x2a2b2c2d2e2f30313233343536373839), 'not 0x2a2b2c2d2e...' + ); + assert(rd.read_u32() == Option::Some(0x3a3b3c3d), 'not 0x3a3b3c3d'); + assert(rd.read_i16() == Option::Some(0x3e3f), 'not 0x3e3f'); + assert(rd.read_u8() == Option::Some(0x40), 'not 0x40'); + assert(rd.read_u8().is_none(), 'expected none'); +} + +#[test] +#[available_gas(20000000)] +fn test_read_sequence_arr() { + let ba = test_array_64(); + let mut rd = ba.reader(); + assert(rd.read_i8() == Option::Some(1), 'expected 1'); + assert( + rd.read_i128() == Option::Some(0x02030405060708090a0b0c0d0e0f1011), 'not 0x0203040506...' + ); + assert( + rd.read_u128() == Option::Some(0x12131415161718191a1b1c1d1e1f2021), 'not 0x1213141516...' + ); + assert(rd.read_i64() == Option::Some(0x2223242526272829), 'not 0x22232425...'); + assert( + rd.read_u128() == Option::Some(0x2a2b2c2d2e2f30313233343536373839), 'not 0x2a2b2c2d2e...' + ); + assert(rd.read_u32() == Option::Some(0x3a3b3c3d), 'not 0x3a3b3c3d'); + assert(rd.read_i16() == Option::Some(0x3e3f), 'not 0x3e3f'); + assert(rd.read_u8() == Option::Some(0x40), 'not 0x40'); + assert(rd.read_u8().is_none(), 'expected none'); +} + +#[test] +#[available_gas(20000000)] +fn test_read_sequence_le() { + let ba = test_byte_array_64(); + let mut rd = ba.reader(); + assert(rd.read_i8() == Option::Some(1), 'expected 1'); + assert( + rd.read_i128_le() == Option::Some(0x11100f0e0d0c0b0a0908070605040302), 'not 0x11100f0e0...' + ); + assert( + rd.read_u128_le() == Option::Some(0x21201f1e1d1c1b1a1918171615141312), 'not 0x21201f1e1d...' + ); + assert(rd.read_i64_le() == Option::Some(0x2928272625242322), 'not 0x29282726...'); + assert( + rd.read_u128_le() == Option::Some(0x393837363534333231302f2e2d2c2b2a), 'not 0x3938373635...' + ); + assert(rd.read_u32_le() == Option::Some(0x3d3c3b3a), 'not 0x3d3c3b3a'); + assert(rd.read_i16_le() == Option::Some(0x3f3e), 'not 0x3f3e'); + assert(rd.read_u8() == Option::Some(0x40), 'not 0x40'); + assert(rd.read_u8().is_none(), 'expected none'); +} + +#[test] +#[available_gas(20000000)] +fn test_read_sequence_le_arr() { + let ba = test_array_64(); + let mut rd = ba.reader(); + assert(rd.read_i8() == Option::Some(1), 'expected 1'); + assert( + rd.read_i128_le() == Option::Some(0x11100f0e0d0c0b0a0908070605040302), 'not 0x11100f0e0...' + ); + assert( + rd.read_u128_le() == Option::Some(0x21201f1e1d1c1b1a1918171615141312), 'not 0x21201f1e1d...' + ); + assert(rd.read_i64_le() == Option::Some(0x2928272625242322), 'not 0x29282726...'); + assert( + rd.read_u128_le() == Option::Some(0x393837363534333231302f2e2d2c2b2a), 'not 0x3938373635...' + ); + assert(rd.read_u32_le() == Option::Some(0x3d3c3b3a), 'not 0x3d3c3b3a'); + assert(rd.read_i16_le() == Option::Some(0x3f3e), 'not 0x3f3e'); + assert(rd.read_u8() == Option::Some(0x40), 'not 0x40'); + assert(rd.read_u8().is_none(), 'expected none'); +} + +#[test] +#[available_gas(10000000)] +fn test_clone_byte_array_reader() { + let ba = test_byte_array_64(); + let mut rd1 = ba.reader(); + let temp = rd1.read_u256().unwrap(); + let mut rd2 = rd1.clone(); + let a = rd1.read_u128().unwrap(); + assert(rd1.index != rd2.index, 'indicies equal'); + let b = rd2.read_u128().unwrap(); + assert(rd1.index == rd2.index, 'indicies not equal'); + assert(a == b, 'copy ByteArrayReader failed'); +} + +#[test] +#[available_gas(10000000)] +fn test_clone_array_of_bytes_reader() { + let ba = test_array_64(); + let mut rd1 = ba.reader(); + let temp = rd1.read_u256().unwrap(); + let mut rd2 = rd1.clone(); + let a = rd1.read_u128().unwrap(); + assert(rd1.index != rd2.index, 'indicies equal'); + let b = rd2.read_u128().unwrap(); + assert(rd1.index == rd2.index, 'indicies not equal'); + assert(a == b, 'copy ByteArrayReader failed'); +} + +#[test] +#[available_gas(10000000)] +fn test_byte_array_reader_equals_array_of_bytes_reader() { + let mut ba = test_array_64().reader(); + let mut bb = test_byte_array_64().reader(); + assert(ba.read_u16() == bb.read_u16(), 'not equal'); + assert(ba.read_u16_le() == bb.read_u16_le(), 'not equal'); + assert(ba.read_i16() == bb.read_i16(), 'not equal'); + assert(ba.read_i16_le() == bb.read_i16_le(), 'not equal'); + assert(ba.read_u256() == bb.read_u256(), 'not equal'); +} + +// helpers +fn test_byte_array_8() -> ByteArray { + let mut ba1 = Default::default(); + ba1.append_word(0x0102030405060708, 8); + ba1 +} + +fn test_byte_array_16() -> ByteArray { + let mut ba1 = Default::default(); + ba1.append_word(0x0102030405060708090a0b0c0d0e0f10, 16); + ba1 +} + +fn test_byte_array_32() -> ByteArray { + let mut ba1 = Default::default(); + ba1.append_word(0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f, 31); + ba1.append_word(0x20, 1); + ba1 +} + +fn test_byte_array_32_neg() -> ByteArray { + let mut ba1 = Default::default(); + ba1.append_word(0xfffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1, 31); + ba1.append_word(0xe0, 1); + ba1 +} + +fn test_byte_array_16_neg() -> ByteArray { + let mut ba1 = Default::default(); + ba1.append_word(0xfffffffffffffffffffffffffffffffe, 16); + ba1 +} + +fn test_byte_array_64() -> ByteArray { + let mut ba1 = Default::default(); + ba1.append_word(0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f, 31); + ba1.append_word(0x202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e, 31); + ba1.append_word(0x3f40, 2); + ba1 +} + +fn test_array_8() -> Array { + let mut ba1 = array![1, 2, 3, 4, 5, 6, 7, 8]; + ba1 +} + +fn test_array_16() -> Array { + let mut ba1 = array![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + ba1 +} + +fn test_array_32() -> Array { + let mut ba1 = array![ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32 + ]; + ba1 +} + +fn test_array_32_neg() -> Array { + let mut ba1 = array![ + 0xff, + 0xfe, + 0xfd, + 0xfc, + 0xfb, + 0xfa, + 0xf9, + 0xf8, + 0xf7, + 0xf6, + 0xf5, + 0xf4, + 0xf3, + 0xf2, + 0xf1, + 0xf0, + 0xef, + 0xee, + 0xed, + 0xec, + 0xeb, + 0xea, + 0xe9, + 0xe8, + 0xe7, + 0xe6, + 0xe5, + 0xe4, + 0xe3, + 0xe2, + 0xe1, + 0xe0 + ]; + ba1 +} + +fn test_array_16_neg() -> Array { + let mut ba1 = array![ + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xff, + 0xfe + ]; + ba1 +} + +fn test_array_64() -> Array { + let mut ba1 = array![ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64 + ]; + ba1 +} + + +fn serialized_byte_array_64() -> Array { + array![ + 0x40, + 0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f, + 0x202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e, + 0x3f40 + ] +} diff --git a/src/math/Scarb.toml b/src/math/Scarb.toml index 94a810c4..c276cf1f 100644 --- a/src/math/Scarb.toml +++ b/src/math/Scarb.toml @@ -7,3 +7,5 @@ homepage = "https://github.com/keep-starknet-strange/alexandria/tree/main/src/ma [dependencies] # dependency due to ArrayTraitExt::concat in ed25519.cairo alexandria_data_structures = { path = "../data_structures" } +# dependency due to ReversibleBytes in siphash.cairo +alexandria_encoding = { path = "../encoding" } diff --git a/src/math/src/lib.cairo b/src/math/src/lib.cairo index ff778d81..ba99b455 100644 --- a/src/math/src/lib.cairo +++ b/src/math/src/lib.cairo @@ -124,6 +124,7 @@ mod mod_arithmetics; mod perfect_number; mod sha256; mod sha512; +mod siphash; mod zellers_congruence; mod keccak256; diff --git a/src/math/src/siphash.cairo b/src/math/src/siphash.cairo new file mode 100644 index 00000000..b247baf1 --- /dev/null +++ b/src/math/src/siphash.cairo @@ -0,0 +1,138 @@ +use alexandria_data_structures::byte_reader::{ByteReader, ByteReaderState}; +use alexandria_encoding::reversible::ReversibleBytes; +use traits::DivRem; +use integer::{u64_wide_mul, u64_wrapping_add}; + +const C0: u64 = 0x736f6d6570736575; +const C1: u64 = 0x646f72616e646f6d; +const C2: u64 = 0x6c7967656e657261; +const C3: u64 = 0x7465646279746573; + +trait SipHash { + /// Takes the input byte data and performs a SipHash-2-4: + /// it takes a 128-bit key, does 2 compression rounds, 4 + /// finalization rounds, and returns a 64-bit tag. + /// Note: When loading the key parts from a collection of + /// bytes, it is the little endian interpretation of each + /// key 64-bit part. + /// # Arguments + /// `self` - the byte data to be hashed by SipHash-2-4 + /// `key0` - the first 64 bits of the 128 bit key + /// `key1` - the last 64 bits of the 128 bit key + /// # Returns + /// `u64` - The little endian uint of the resulting bytes + fn sip_hash(self: @T, key0: u64, key1: u64) -> u64; +} + +impl SipHashImpl, +ByteReader> of SipHash { + fn sip_hash(self: @T, key0: u64, key1: u64) -> u64 { + let mut reader = self.reader(); + let mut state = _InternalSiphHash::::initialize(key0, key1); + state.sip_hash(ref reader) + } +} + +#[derive(Copy, Drop)] +struct SipHashState { + v0: u64, + v1: u64, + v2: u64, + v3: u64, +} + +#[generate_trait] +impl _InternalSiphHashImpl, +ByteReader> of _InternalSiphHash { + #[inline(always)] + fn initialize(key0: u64, key1: u64) -> SipHashState { + let key0 = key0; + let key1 = key1; + let v0 = C0 ^ key0; + let v1 = C1 ^ key1; + let v2 = C2 ^ key0; + let v3 = C3 ^ key1; + SipHashState { v0, v1, v2, v3 } + } + + #[inline(always)] + fn sipround(ref self: SipHashState) { + self.v0 = u64_wrapping_add(self.v0, self.v1); + self.v2 = u64_wrapping_add(self.v2, self.v3); + self.v1 = _rotl(self.v1, BITS_13); + self.v3 = _rotl(self.v3, BITS_16); + self.v1 = self.v1 ^ self.v0; + self.v3 = self.v3 ^ self.v2; + self.v0 = _rotl(self.v0, BITS_32); + self.v2 = u64_wrapping_add(self.v2, self.v1); + self.v0 = u64_wrapping_add(self.v0, self.v3); + self.v1 = _rotl(self.v1, BITS_17); + self.v3 = _rotl(self.v3, BITS_21); + self.v1 = self.v1 ^ self.v2; + self.v3 = self.v3 ^ self.v0; + self.v2 = _rotl(self.v2, BITS_32); + } + + #[inline(always)] + fn compression(ref self: SipHashState, word: u64) { + self.v3 = self.v3 ^ word; + self.sipround(); + self.sipround(); + self.v0 = self.v0 ^ word; + } + + #[inline] + fn sip_hash(ref self: SipHashState, ref reader: ByteReaderState) -> u64 { + let len: u64 = reader.len().into(); + let b = (len % 0x100) * 0x100000000000000; + loop { + match reader.read_u64_le() { + Option::Some(word) => { self.compression(word); }, + Option::None => { break; } + } + }; + let last_word = b + reader.load_last_word(); + self.compression(last_word); + self.finalize().reverse_bytes() // little endian byte order + } + + #[inline(always)] + fn finalize(ref self: SipHashState) -> u64 { + self.v2 = self.v2 ^ 0xff; + self.sipround(); + self.sipround(); + self.sipround(); + self.sipround(); + self.v0 ^ self.v1 ^ self.v2 ^ self.v3 + } + + #[inline] + fn load_last_word(ref self: ByteReaderState) -> u64 { + let mut last_word: u64 = 0; + let mut index = 0x1_u64; + loop { + match self.read_u8() { + Option::Some(byte) => { + last_word += byte.into() * index; + index *= 0x100; + }, + Option::None => { break; }, + } + }; + last_word + } +} + +// helper function optimized for the small number of rotl cases performed +// avoiding to call any power function for the precomputed values below +const BITS_13: u64 = 0b10000000000000; +const BITS_16: u64 = 0b10000000000000000; +const BITS_17: u64 = 0b100000000000000000; +const BITS_21: u64 = 0b1000000000000000000000; +const BITS_32: u64 = 0b100000000000000000000000000000000; +const PARTITION64_KEY: u128 = 0x00000000000000010000000000000000; + +#[inline(always)] +fn _rotl(word: u64, bits: u64) -> u64 { + let word128 = u64_wide_mul(word, bits); + let (quotient, remainder) = DivRem::div_rem(word128, PARTITION64_KEY.try_into().unwrap()); + (quotient + remainder).try_into().unwrap() +} diff --git a/src/math/src/tests.cairo b/src/math/src/tests.cairo index 46ba9084..5d5fb9f1 100644 --- a/src/math/src/tests.cairo +++ b/src/math/src/tests.cairo @@ -12,5 +12,6 @@ mod mod_arithmetics_test; mod perfect_number_test; mod sha256_test; mod sha512_test; +mod siphash_test; mod zellers_congruence_test; mod test_keccak256; diff --git a/src/math/src/tests/siphash_test.cairo b/src/math/src/tests/siphash_test.cairo new file mode 100644 index 00000000..012b6ad1 --- /dev/null +++ b/src/math/src/tests/siphash_test.cairo @@ -0,0 +1,567 @@ +use alexandria_math::siphash::SipHash; +use alexandria_data_structures::byte_reader::ByteReader; + +#[test] +#[available_gas(200000000)] +fn test_veorq_vectors_h() { + let expected_results = result_vector(); + let (key0, key1) = generate_keys(); + let mut ba = array![]; + let first_result = *expected_results[0]; + let first = ba.sip_hash(key0, key1); // empty byte data + assert(first == first_result, 'should be equal'); + let mut i = 0_u8; + loop { + if i == 63 { + break; + } + ba.append(i); + let expected = *expected_results[i.into() + 1]; + assert(ba.sip_hash(key0, key1) == expected, 'should equal'); + i += 1; + }; +} + +// helpers +fn generate_keys() -> (u64, u64) { + let mut key_bytes: Array = array![]; + let mut index = 0_usize; + loop { + if index == 16 { + break; + } + key_bytes.append(index.try_into().unwrap()); + index += 1; + }; + let mut reader = key_bytes.reader(); + (reader.read_u64_le().unwrap(), reader.read_u64_le().unwrap()) +} + +fn result_vector() -> Span { + let test_bytes = from_vectors_h(); + let mut reader = test_bytes.reader(); + let mut result: Array = array![]; + loop { + match reader.read_u64() { + Option::Some(word) => result.append(word), + Option::None => { break result.span(); } + } + } +} + +fn from_vectors_h() -> Array { + array![ + 0x31, + 0x0e, + 0x0e, + 0xdd, + 0x47, + 0xdb, + 0x6f, + 0x72, + 0xfd, + 0x67, + 0xdc, + 0x93, + 0xc5, + 0x39, + 0xf8, + 0x74, + 0x5a, + 0x4f, + 0xa9, + 0xd9, + 0x09, + 0x80, + 0x6c, + 0x0d, + 0x2d, + 0x7e, + 0xfb, + 0xd7, + 0x96, + 0x66, + 0x67, + 0x85, + 0xb7, + 0x87, + 0x71, + 0x27, + 0xe0, + 0x94, + 0x27, + 0xcf, + 0x8d, + 0xa6, + 0x99, + 0xcd, + 0x64, + 0x55, + 0x76, + 0x18, + 0xce, + 0xe3, + 0xfe, + 0x58, + 0x6e, + 0x46, + 0xc9, + 0xcb, + 0x37, + 0xd1, + 0x01, + 0x8b, + 0xf5, + 0x00, + 0x02, + 0xab, + 0x62, + 0x24, + 0x93, + 0x9a, + 0x79, + 0xf5, + 0xf5, + 0x93, + 0xb0, + 0xe4, + 0xa9, + 0x0b, + 0xdf, + 0x82, + 0x00, + 0x9e, + 0xf3, + 0xb9, + 0xdd, + 0x94, + 0xc5, + 0xbb, + 0x5d, + 0x7a, + 0xa7, + 0xad, + 0x6b, + 0x22, + 0x46, + 0x2f, + 0xb3, + 0xf4, + 0xfb, + 0xe5, + 0x0e, + 0x86, + 0xbc, + 0x8f, + 0x1e, + 0x75, + 0x90, + 0x3d, + 0x84, + 0xc0, + 0x27, + 0x56, + 0xea, + 0x14, + 0xee, + 0xf2, + 0x7a, + 0x8e, + 0x90, + 0xca, + 0x23, + 0xf7, + 0xe5, + 0x45, + 0xbe, + 0x49, + 0x61, + 0xca, + 0x29, + 0xa1, + 0xdb, + 0x9b, + 0xc2, + 0x57, + 0x7f, + 0xcc, + 0x2a, + 0x3f, + 0x94, + 0x47, + 0xbe, + 0x2c, + 0xf5, + 0xe9, + 0x9a, + 0x69, + 0x9c, + 0xd3, + 0x8d, + 0x96, + 0xf0, + 0xb3, + 0xc1, + 0x4b, + 0xbd, + 0x61, + 0x79, + 0xa7, + 0x1d, + 0xc9, + 0x6d, + 0xbb, + 0x98, + 0xee, + 0xa2, + 0x1a, + 0xf2, + 0x5c, + 0xd6, + 0xbe, + 0xc7, + 0x67, + 0x3b, + 0x2e, + 0xb0, + 0xcb, + 0xf2, + 0xd0, + 0x88, + 0x3e, + 0xa3, + 0xe3, + 0x95, + 0x67, + 0x53, + 0x93, + 0xc8, + 0xce, + 0x5c, + 0xcd, + 0x8c, + 0x03, + 0x0c, + 0xa8, + 0x94, + 0xaf, + 0x49, + 0xf6, + 0xc6, + 0x50, + 0xad, + 0xb8, + 0xea, + 0xb8, + 0x85, + 0x8a, + 0xde, + 0x92, + 0xe1, + 0xbc, + 0xf3, + 0x15, + 0xbb, + 0x5b, + 0xb8, + 0x35, + 0xd8, + 0x17, + 0xad, + 0xcf, + 0x6b, + 0x07, + 0x63, + 0x61, + 0x2e, + 0x2f, + 0xa5, + 0xc9, + 0x1d, + 0xa7, + 0xac, + 0xaa, + 0x4d, + 0xde, + 0x71, + 0x65, + 0x95, + 0x87, + 0x66, + 0x50, + 0xa2, + 0xa6, + 0x28, + 0xef, + 0x49, + 0x5c, + 0x53, + 0xa3, + 0x87, + 0xad, + 0x42, + 0xc3, + 0x41, + 0xd8, + 0xfa, + 0x92, + 0xd8, + 0x32, + 0xce, + 0x7c, + 0xf2, + 0x72, + 0x2f, + 0x51, + 0x27, + 0x71, + 0xe3, + 0x78, + 0x59, + 0xf9, + 0x46, + 0x23, + 0xf3, + 0xa7, + 0x38, + 0x12, + 0x05, + 0xbb, + 0x1a, + 0xb0, + 0xe0, + 0x12, + 0xae, + 0x97, + 0xa1, + 0x0f, + 0xd4, + 0x34, + 0xe0, + 0x15, + 0xb4, + 0xa3, + 0x15, + 0x08, + 0xbe, + 0xff, + 0x4d, + 0x31, + 0x81, + 0x39, + 0x62, + 0x29, + 0xf0, + 0x90, + 0x79, + 0x02, + 0x4d, + 0x0c, + 0xf4, + 0x9e, + 0xe5, + 0xd4, + 0xdc, + 0xca, + 0x5c, + 0x73, + 0x33, + 0x6a, + 0x76, + 0xd8, + 0xbf, + 0x9a, + 0xd0, + 0xa7, + 0x04, + 0x53, + 0x6b, + 0xa9, + 0x3e, + 0x0e, + 0x92, + 0x59, + 0x58, + 0xfc, + 0xd6, + 0x42, + 0x0c, + 0xad, + 0xa9, + 0x15, + 0xc2, + 0x9b, + 0xc8, + 0x06, + 0x73, + 0x18, + 0x95, + 0x2b, + 0x79, + 0xf3, + 0xbc, + 0x0a, + 0xa6, + 0xd4, + 0xf2, + 0x1d, + 0xf2, + 0xe4, + 0x1d, + 0x45, + 0x35, + 0xf9, + 0x87, + 0x57, + 0x75, + 0x19, + 0x04, + 0x8f, + 0x53, + 0xa9, + 0x10, + 0xa5, + 0x6c, + 0xf5, + 0xdf, + 0xcd, + 0x9a, + 0xdb, + 0xeb, + 0x75, + 0x09, + 0x5c, + 0xcd, + 0x98, + 0x6c, + 0xd0, + 0x51, + 0xa9, + 0xcb, + 0x9e, + 0xcb, + 0xa3, + 0x12, + 0xe6, + 0x96, + 0xaf, + 0xad, + 0xfc, + 0x2c, + 0xe6, + 0x66, + 0xc7, + 0x72, + 0xfe, + 0x52, + 0x97, + 0x5a, + 0x43, + 0x64, + 0xee, + 0x5a, + 0x16, + 0x45, + 0xb2, + 0x76, + 0xd5, + 0x92, + 0xa1, + 0xb2, + 0x74, + 0xcb, + 0x8e, + 0xbf, + 0x87, + 0x87, + 0x0a, + 0x6f, + 0x9b, + 0xb4, + 0x20, + 0x3d, + 0xe7, + 0xb3, + 0x81, + 0xea, + 0xec, + 0xb2, + 0xa3, + 0x0b, + 0x22, + 0xa8, + 0x7f, + 0x99, + 0x24, + 0xa4, + 0x3c, + 0xc1, + 0x31, + 0x57, + 0x24, + 0xbd, + 0x83, + 0x8d, + 0x3a, + 0xaf, + 0xbf, + 0x8d, + 0xb7, + 0x0b, + 0x1a, + 0x2a, + 0x32, + 0x65, + 0xd5, + 0x1a, + 0xea, + 0x13, + 0x50, + 0x79, + 0xa3, + 0x23, + 0x1c, + 0xe6, + 0x60, + 0x93, + 0x2b, + 0x28, + 0x46, + 0xe4, + 0xd7, + 0x06, + 0x66, + 0xe1, + 0x91, + 0x5f, + 0x5c, + 0xb1, + 0xec, + 0xa4, + 0x6c, + 0xf3, + 0x25, + 0x96, + 0x5c, + 0xa1, + 0x6d, + 0x62, + 0x9f, + 0x57, + 0x5f, + 0xf2, + 0x8e, + 0x60, + 0x38, + 0x1b, + 0xe5, + 0x72, + 0x45, + 0x06, + 0xeb, + 0x4c, + 0x32, + 0x8a, + 0x95, + ] +}