Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of rlp::decode() #405

Merged
merged 18 commits into from
Oct 18, 2023
Merged
9 changes: 6 additions & 3 deletions crates/utils/src/errors.cairo
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
// LENGTH
const RLP_INVALID_LENGTH: felt252 = 'KKT: RlpInvalidLength';
const RLP_EMPTY_INPUT: felt252 = 'KKT: RlpEmptyInput';
const RLP_INPUT_TOO_SHORT: felt252 = 'KKT: RlpInputTooShort';

#[derive(Drop, Copy, PartialEq)]
enum RLPError {
RlpInvalidLength: felt252,
RlpEmptyInput: felt252,
RlpInputTooShort: felt252,
}


impl RLPErrorIntoU256 of Into<RLPError, u256> {
fn into(self: RLPError) -> u256 {
match self {
RLPError::RlpInvalidLength(error_message) => error_message.into(),
RLPError::RlpEmptyInput(error_message) => error_message.into(),
RLPError::RlpInputTooShort(error_message) => error_message.into(),
}
}
}
31 changes: 15 additions & 16 deletions crates/utils/src/helpers.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use utils::constants::{
POW_256_16,
};
use keccak::u128_split;
use utils::num::{Zero, One, SizeOf};
use utils::math::Bitshift;


Expand Down Expand Up @@ -505,35 +506,34 @@ impl SpanExtension<T, +Copy<T>, +Drop<T>> of SpanExtensionTrait<T> {
}
}

impl SpanU8TryIntoU32 of TryInto<Span<u8>, u32> {
fn try_into(self: Span<u8>) -> Option<u32> {
let len = self.len();
trait BytesSerde<T> {
/// Serialize/deserialize bytes into/from
/// an array of bytes.
fn deserialize(self: @Span<u8>) -> Option<T>;
Quentash marked this conversation as resolved.
Show resolved Hide resolved
}

impl BytesSerdeU32Impl of BytesSerde<u32> {
fn deserialize(self: @Span<u8>) -> Option<u32> {
let len = (*self).len();
Quentash marked this conversation as resolved.
Show resolved Hide resolved
if len > 4 {
return Option::None(());
}

if self.is_empty() {
return Option::Some(0);
}

let offset = len.into() - 1;
let offset: u32 = len - 1;
let mut result: u32 = 0;
let mut i: usize = 0;
let mut i: u32 = 0;
loop {
if i >= len {
if i == len {
break ();
}
let byte: u32 = (*self.at(i)).into();
result += byte.shl(8 * (offset - i.into()));
let byte: u32 = (*(*self).at(i)).into();
Quentash marked this conversation as resolved.
Show resolved Hide resolved
result += byte.shl(8 * (offset - i));

i += 1;
};

Option::Some(result)
}
}


#[generate_trait]
impl U256Impl of U256Trait {
/// Splits an u256 into 4 little endian u64.
Expand All @@ -551,4 +551,3 @@ impl U256Impl of U256Trait {
u256 { low: new_low, high: new_high }
}
}

159 changes: 17 additions & 142 deletions crates/utils/src/math.cairo
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use integer::{
u256, u256_overflow_mul, u256_overflowing_add, u512, BoundedInt, u128_overflowing_mul
};
use math::Oneable;
use utils::num::{Zero, One, SizeOf};


// === Exponentiation ===

trait Exponentiation<T> {
/// Raise a number to a power.
Expand Down Expand Up @@ -235,19 +238,24 @@ impl U128WrappingBitshiftImpl of WrappingBitshift<u128> {
}
}

impl U32ExpImpl of Exponentiation<u32> {
fn pow(self: u32, mut exponent: u32) -> u32 {
if self == 0 {
impl U256WrappingBitshiftImpl of WrappingBitshift<u256> {
fn wrapping_shl(self: u256, shift: u256) -> u256 {
let (result, _) = u256_overflow_mul(self, 2.wrapping_pow(shift));
result
}

fn wrapping_shr(self: u256, shift: u256) -> u256 {
// if we shift by more than 255 bits, the result is 0 (the type is 256 bits wide)
// we early return to save gas
// and prevent unexpected behavior, e.g. 2.pow(256) == 0 mod 2^256, given we can't divide by zero
if shift > 255 {
return 0;
}
if exponent == 0 {
return 1;
} else {
return self * Exponentiation::pow(self, exponent - 1);
}
self / 2.pow(shift)
}
}

// === Standalone functions ===

/// Adds two 256-bit unsigned integers, returning a 512-bit unsigned integer result.
///
Expand All @@ -269,136 +277,3 @@ fn u256_wide_add(a: u256, b: u256) -> u512 {

u512 { limb0, limb1, limb2, limb3 }
}

trait Bitshift<T> {
// Shift a number left by a given number of bits.
// # Panics
// Panics if the shift is greater than 255.
// Panics if the result overflows the type T.
fn shl(self: T, shift: T) -> T;

// Shift a number right by a given number of bits.
// # Panics
// Panics if the shift is greater than 255.
fn shr(self: T, shift: T) -> T;
}

impl U256BitshiftImpl of Bitshift<u256> {
fn shl(self: u256, shift: u256) -> u256 {
if shift > 255 {
// 2.pow(shift) for shift > 255 will panic with 'u256_mul Overflow'
panic_with_felt252('u256_mul Overflow');
}
self * 2.pow(shift)
}

fn shr(self: u256, shift: u256) -> u256 {
if shift > 255 {
// 2.pow(shift) for shift > 255 will panic with 'u256_mul Overflow'
panic_with_felt252('u256_mul Overflow');
}
self / 2.pow(shift)
}
}

impl U32BitshiftImpl of Bitshift<u32> {
fn shl(self: u32, shift: u32) -> u32 {
if shift > 31 {
// 2.pow(shift) for shift > 32 will panic with 'u32_mul Overflow'
panic_with_felt252('u32_mul Overflow');
}
self * 2.pow(shift)
}

fn shr(self: u32, shift: u32) -> u32 {
if shift > 31 {
// 2.pow(shift) for shift > 32 will panic with 'u32_mul Overflow'
panic_with_felt252('u32_mul Overflow');
}
self / 2.pow(shift)
}
}

trait WrappingBitshift<T> {
// Shift a number left by a given number of bits.
// If the shift is greater than 255, the result is 0.
// The bits moved after the 256th one are discarded, the new bits are set to 0.
fn wrapping_shl(self: T, shift: T) -> T;

// Shift a number right by a given number of bits.
// If the shift is greater than 255, the result is 0.
fn wrapping_shr(self: T, shift: T) -> T;
}

impl Felt252WrappingBitshiftImpl of WrappingBitshift<felt252> {
fn wrapping_shl(self: felt252, shift: felt252) -> felt252 {
self * 2.wrapping_pow(shift)
}

fn wrapping_shr(self: felt252, shift: felt252) -> felt252 {
// converting to u256
let val: u256 = self.into();
let shift: u256 = shift.into();

// early return to save gas if shift > 255
if shift > 255 {
return 0;
}

let shifted_u256 = val / 2_u256.wrapping_pow(shift);

// convert back to felt252
shifted_u256.try_into().unwrap()
}
}

impl U256WrappingBitshiftImpl of WrappingBitshift<u256> {
fn wrapping_shl(self: u256, shift: u256) -> u256 {
let (result, _) = u256_overflow_mul(self, 2.wrapping_pow(shift));
result
}

fn wrapping_shr(self: u256, shift: u256) -> u256 {
// if we shift by more than 255 bits, the result is 0 (the type is 256 bits wide)
// we early return to save gas
// and prevent unexpected behavior, e.g. 2.pow(256) == 0 mod 2^256, given we can't divide by zero
if shift > 255 {
return 0;
}
self / 2.pow(shift)
}
}

impl U128BitshiftImpl of Bitshift<u128> {
fn shl(self: u128, shift: u128) -> u128 {
if shift > 127 {
// 2.pow(shift) for shift > 255 will panic with 'u128_mul Overflow'
panic_with_felt252('u128_mul Overflow');
}
self * 2.pow(shift)
}

fn shr(self: u128, shift: u128) -> u128 {
if shift > 127 {
return 0;
}
self / 2.pow(shift)
}
}

impl U128WrappingBitshiftImpl of WrappingBitshift<u128> {
fn wrapping_shl(self: u128, shift: u128) -> u128 {
let (result, _) = u128_overflowing_mul(self, 2.wrapping_pow(shift));
result
}

fn wrapping_shr(self: u128, shift: u128) -> u128 {
// if we shift by more than 255 bits, the result is 0 (the type is 128 bits wide)
// we early return to save gas
// and prevent unexpected behavior, e.g. 2.pow(128) == 0 mod 2^128, given we can't divide by zero
if shift > 127 {
return 0;
}
self / 2.pow(shift)
}
}
33 changes: 33 additions & 0 deletions crates/utils/src/num.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,22 @@ impl Felt252Zero of Zero<felt252> {
}
}

impl U32Zero of Zero<u32> {
#[inline(always)]
fn zero() -> u32 {
0
}

#[inline(always)]
fn is_zero(self: @u32) -> bool {
*self == Zero::zero()
}

#[inline(always)]
fn is_non_zero(self: @u32) -> bool {
!self.is_zero()
}
}

impl U128Zero of Zero<u128> {
#[inline(always)]
Expand Down Expand Up @@ -171,6 +187,23 @@ impl Felt252One of One<felt252> {
}
}

impl U32One of One<u32> {
#[inline(always)]
fn one() -> u32 {
1
}

#[inline(always)]
fn is_one(self: @u32) -> bool {
*self == One::one()
}

#[inline(always)]
fn is_non_one(self: @u32) -> bool {
!self.is_one()
}
}

impl U128One of One<u128> {
#[inline(always)]
fn one() -> u128 {
Expand Down
Loading