Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion soroban-sdk/src/_migrating.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
//! 2. Add support for [CAP-82: Checked 256-bit integer arithmetic host functions](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0082.md).
//! New `checked_*` methods on [`U256`] and [`I256`] (`checked_add`, `checked_sub`,
//! `checked_mul`, `checked_div`, `checked_pow`, `checked_rem_euclid`, `checked_shl`,
//! `checked_shr`) return `Option` instead of panicking on overflow.
//! `checked_shr`) return `Option` instead of panicking on overflow. Also adds
//! `min_value` and `max_value` methods on [`U256`] and [`I256`] to fetch the
//! value bounds of each type.
//!
//! 3. Add support for [CAP-80: Host functions for efficient ZK BN254 use cases](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0080.md).
//! [`BN254`] gains scalar field arithmetic (`Fr` `Add`/`Sub`/`Mul` traits, `pow`, `inv`),
Expand Down
94 changes: 86 additions & 8 deletions soroban-sdk/src/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,16 @@ impl_num_wrapping_val_type!(U256, U256Val, U256Small);
impl U256 {
pub const BITS: u32 = 256;

/// Returns the smallest value that can be represented by this type (0).
pub fn min_value(env: &Env) -> Self {
Self::from_u32(env, 0)
}

/// Returns the largest value that can be represented by this type (2^256 - 1).
pub fn max_value(env: &Env) -> Self {
Self::from_parts(env, u64::MAX, u64::MAX, u64::MAX, u64::MAX)
}

fn is_zero(&self) -> bool {
*self == U256::from_u32(&self.env, 0)
}
Expand Down Expand Up @@ -438,6 +448,16 @@ impl_num_wrapping_val_type!(I256, I256Val, I256Small);
impl I256 {
pub const BITS: u32 = 256;

/// Returns the smallest value that can be represented by this type (-2^255).
pub fn min_value(env: &Env) -> Self {
Self::from_parts(env, i64::MIN, 0, 0, 0)
}

/// Returns the largest value that can be represented by this type (2^255 - 1).
pub fn max_value(env: &Env) -> Self {
Self::from_parts(env, i64::MAX, u64::MAX, u64::MAX, u64::MAX)
}

fn is_zero(&self) -> bool {
*self == I256::from_i32(&self.env, 0)
}
Expand All @@ -446,11 +466,6 @@ impl I256 {
*self == I256::from_i32(&self.env, -1)
}

/// Returns the minimum value of I256 (-2^255).
pub fn min_value(env: &Env) -> Self {
I256::from_parts(env, i64::MIN, 0, 0, 0)
}

pub fn from_i32(env: &Env, i: i32) -> Self {
I256 {
env: env.clone(),
Expand Down Expand Up @@ -847,6 +862,36 @@ mod test {
assert_eq!(u3.rem_euclid(&u4), U256::from_u32(&env, 3));
}

#[test]
fn test_u256_min() {
let env = Env::default();

let min = U256::min_value(&env);
assert_eq!(min, U256::from_u32(&env, 0));

let one = U256::from_u32(&env, 1);
assert_eq!(min.checked_sub(&one), None);
assert!(min.checked_add(&one).is_some());
}

#[test]
fn test_u256_max() {
let env = Env::default();

let max = U256::max_value(&env);
assert_eq!(
max,
U256::from_parts(&env, u64::MAX, u64::MAX, u64::MAX, u64::MAX)
);

let u128_max = U256::from_u128(&env, u128::MAX);
assert!(max > u128_max);

let one = U256::from_u32(&env, 1);
assert_eq!(max.checked_add(&one), None);
assert!(max.checked_sub(&one).is_some());
}

#[test]
fn test_u256_checked_arith() {
let env = Env::default();
Expand All @@ -873,7 +918,7 @@ mod test {
let zero = U256::from_u32(&env, 0);
let one = U256::from_u32(&env, 1);
let two = U256::from_u32(&env, 2);
let max = U256::from_parts(&env, u64::MAX, u64::MAX, u64::MAX, u64::MAX);
let max = U256::max_value(&env);
assert_eq!(max.checked_add(&one), None);
assert_eq!(zero.checked_sub(&one), None);
assert_eq!(max.checked_mul(&two), None);
Expand Down Expand Up @@ -921,6 +966,39 @@ mod test {
assert_eq!(u3.rem_euclid(&u4), I256::from_i32(&env, 1));
}

#[test]
fn test_i256_min() {
let env = Env::default();

let min = I256::min_value(&env);
assert_eq!(min, I256::from_parts(&env, i64::MIN, 0, 0, 0));

let i128_min = I256::from_i128(&env, i128::MIN);
assert!(min < i128_min);

let one = I256::from_i32(&env, 1);
assert_eq!(min.checked_sub(&one), None);
assert!(min.checked_add(&one).is_some());
}

#[test]
fn test_i256_max() {
let env = Env::default();

let max = I256::max_value(&env);
assert_eq!(
max,
I256::from_parts(&env, i64::MAX, u64::MAX, u64::MAX, u64::MAX)
);

let i128_max = I256::from_i128(&env, i128::MAX);
assert!(max > i128_max);

let one = I256::from_i32(&env, 1);
assert_eq!(max.checked_add(&one), None);
assert!(max.checked_sub(&one).is_some());
}

#[test]
fn test_i256_checked_arith() {
let env = Env::default();
Expand Down Expand Up @@ -948,8 +1026,8 @@ mod test {
let one = I256::from_i32(&env, 1);
let negative_one = I256::from_i32(&env, -1);
let two = I256::from_i32(&env, 2);
let max = I256::from_parts(&env, i64::MAX, u64::MAX, u64::MAX, u64::MAX);
let min = I256::from_parts(&env, i64::MIN, 0, 0, 0);
let max = I256::max_value(&env);
let min = I256::min_value(&env);
assert_eq!(max.checked_add(&one), None);
assert_eq!(min.checked_sub(&one), None);
assert_eq!(max.checked_mul(&two), None);
Expand Down
Loading