diff --git a/CHANGELOG.md b/CHANGELOG.md index fc49aaa74e..ca42d3f221 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to - cosmwasm-std: Implement `Mul`/`MulAssign` for `Uint64`. - cosmwasm-std: Implement `RemAssign` for `Uint64`/`Uint128`/`Uint256`/`Uint512`. +- cosmwasm-std: Implement `pow`/`checked_pow` for `Uint64`/`Uint128`/`Uint512`. - cosmwasm-crypto: Upgrade ed25519-zebra to version 3. ### Changed diff --git a/packages/std/src/math/uint128.rs b/packages/std/src/math/uint128.rs index 1654485809..2cde35fdd2 100644 --- a/packages/std/src/math/uint128.rs +++ b/packages/std/src/math/uint128.rs @@ -67,6 +67,10 @@ impl Uint128 { self.0 == 0 } + pub fn pow(self, exp: u32) -> Self { + self.0.pow(exp).into() + } + pub fn checked_add(self, other: Self) -> Result { self.0 .checked_add(other.0) @@ -726,6 +730,18 @@ mod tests { assert_eq!(a, Uint128::from(30u32)); } + #[test] + fn uint128_pow_works() { + assert_eq!(Uint128::from(2u32).pow(2), Uint128::from(4u32)); + assert_eq!(Uint128::from(2u32).pow(10), Uint128::from(1024u32)); + } + + #[test] + #[should_panic] + fn uint128_pow_overflow_panics() { + Uint128::MAX.pow(2u32); + } + #[test] fn uint128_multiply_ratio_works() { let base = Uint128(500); @@ -788,7 +804,7 @@ mod tests { fn uint128_methods() { // checked_* assert!(matches!( - Uint128(u128::MAX).checked_add(Uint128(1)), + Uint128::MAX.checked_add(Uint128(1)), Err(OverflowError { .. }) )); assert!(matches!( @@ -796,42 +812,40 @@ mod tests { Err(OverflowError { .. }) )); assert!(matches!( - Uint128(u128::MAX).checked_mul(Uint128(2)), + Uint128::MAX.checked_mul(Uint128(2)), + Err(OverflowError { .. }) + )); + assert!(matches!( + Uint128::MAX.checked_pow(2u32), Err(OverflowError { .. }) )); assert!(matches!( - Uint128(u128::MAX).checked_div(Uint128(0)), + Uint128::MAX.checked_div(Uint128(0)), Err(DivideByZeroError { .. }) )); assert!(matches!( - Uint128(u128::MAX).checked_div_euclid(Uint128(0)), + Uint128::MAX.checked_div_euclid(Uint128(0)), Err(DivideByZeroError { .. }) )); assert!(matches!( - Uint128(u128::MAX).checked_rem(Uint128(0)), + Uint128::MAX.checked_rem(Uint128(0)), Err(DivideByZeroError { .. }) )); // saturating_* - assert_eq!( - Uint128(u128::MAX).saturating_add(Uint128(1)), - Uint128(u128::MAX) - ); + assert_eq!(Uint128::MAX.saturating_add(Uint128(1)), Uint128::MAX); assert_eq!(Uint128(0).saturating_sub(Uint128(1)), Uint128(0)); - assert_eq!( - Uint128(u128::MAX).saturating_mul(Uint128(2)), - Uint128(u128::MAX) - ); - assert_eq!(Uint128(u128::MAX).saturating_pow(2), Uint128(u128::MAX)); + assert_eq!(Uint128::MAX.saturating_mul(Uint128(2)), Uint128::MAX); + assert_eq!(Uint128::MAX.saturating_pow(2), Uint128::MAX); // wrapping_* - assert_eq!(Uint128(u128::MAX).wrapping_add(Uint128(1)), Uint128(0)); - assert_eq!(Uint128(0).wrapping_sub(Uint128(1)), Uint128(u128::MAX)); + assert_eq!(Uint128::MAX.wrapping_add(Uint128(1)), Uint128(0)); + assert_eq!(Uint128(0).wrapping_sub(Uint128(1)), Uint128::MAX); assert_eq!( - Uint128(u128::MAX).wrapping_mul(Uint128(2)), + Uint128::MAX.wrapping_mul(Uint128(2)), Uint128(u128::MAX - 1) ); - assert_eq!(Uint128(u128::MAX).wrapping_pow(2), Uint128(1)); + assert_eq!(Uint128::MAX.wrapping_pow(2), Uint128(1)); } #[test] diff --git a/packages/std/src/math/uint256.rs b/packages/std/src/math/uint256.rs index 824613f7de..7b506b1f23 100644 --- a/packages/std/src/math/uint256.rs +++ b/packages/std/src/math/uint256.rs @@ -210,6 +210,11 @@ impl Uint256 { self.0.is_zero() } + pub fn pow(self, exp: u32) -> Self { + let res = self.0.pow(exp.into()); + Self(res) + } + pub fn checked_add(self, other: Self) -> Result { self.0 .checked_add(other.0) @@ -231,6 +236,13 @@ impl Uint256 { .ok_or_else(|| OverflowError::new(OverflowOperation::Mul, self, other)) } + pub fn checked_pow(self, exp: u32) -> Result { + self.0 + .checked_pow(exp.into()) + .map(Self) + .ok_or_else(|| OverflowError::new(OverflowOperation::Pow, self, exp)) + } + pub fn checked_div(self, other: Self) -> Result { self.0 .checked_div(other.0) @@ -245,18 +257,6 @@ impl Uint256 { .ok_or_else(|| DivideByZeroError::new(self)) } - pub fn checked_pow(self, exp: u32) -> Result { - self.0 - .checked_pow(exp.into()) - .map(Self) - .ok_or_else(|| OverflowError::new(OverflowOperation::Pow, self, exp)) - } - - pub fn pow(self, exp: u32) -> Self { - self.checked_pow(exp) - .expect("attempt to raise to a power with overflow") - } - pub fn checked_shr(self, other: u32) -> Result { if other >= 256 { return Err(OverflowError::new(OverflowOperation::Shr, self, other)); @@ -1285,6 +1285,18 @@ mod tests { assert_eq!(a, Uint256::from(30u32)); } + #[test] + fn uint256_pow_works() { + assert_eq!(Uint256::from(2u32).pow(2), Uint256::from(4u32)); + assert_eq!(Uint256::from(2u32).pow(10), Uint256::from(1024u32)); + } + + #[test] + #[should_panic] + fn uint256_pow_overflow_panics() { + Uint256::MAX.pow(2u32); + } + #[test] fn uint256_multiply_ratio_works() { let base = Uint256::from(500u32); @@ -1390,6 +1402,10 @@ mod tests { Uint256::MAX.checked_mul(Uint256::from(2u32)), Err(OverflowError { .. }) )); + assert!(matches!( + Uint256::MAX.checked_pow(2u32), + Err(OverflowError { .. }) + )); assert!(matches!( Uint256::MAX.checked_div(Uint256::from(0u32)), Err(DivideByZeroError { .. }) diff --git a/packages/std/src/math/uint512.rs b/packages/std/src/math/uint512.rs index 6c65f3bad9..7c7aa0fb52 100644 --- a/packages/std/src/math/uint512.rs +++ b/packages/std/src/math/uint512.rs @@ -309,6 +309,11 @@ impl Uint512 { self.0.is_zero() } + pub fn pow(self, exp: u32) -> Self { + let res = self.0.pow(exp.into()); + Self(res) + } + pub fn checked_add(self, other: Self) -> Result { self.0 .checked_add(other.0) @@ -330,6 +335,13 @@ impl Uint512 { .ok_or_else(|| OverflowError::new(OverflowOperation::Mul, self, other)) } + pub fn checked_pow(self, exp: u32) -> Result { + self.0 + .checked_pow(exp.into()) + .map(Self) + .ok_or_else(|| OverflowError::new(OverflowOperation::Pow, self, exp)) + } + pub fn checked_div(self, other: Self) -> Result { self.0 .checked_div(other.0) @@ -1056,6 +1068,18 @@ mod tests { assert_eq!(a, Uint512::from(30u32)); } + #[test] + fn uint512_pow_works() { + assert_eq!(Uint512::from(2u32).pow(2), Uint512::from(4u32)); + assert_eq!(Uint512::from(2u32).pow(10), Uint512::from(1024u32)); + } + + #[test] + #[should_panic] + fn uint512_pow_overflow_panics() { + Uint512::MAX.pow(2u32); + } + #[test] fn uint512_shr_works() { let original = Uint512::new([ @@ -1113,6 +1137,10 @@ mod tests { Uint512::MAX.checked_mul(Uint512::from(2u32)), Err(OverflowError { .. }) )); + assert!(matches!( + Uint512::MAX.checked_pow(2u32), + Err(OverflowError { .. }) + )); assert!(matches!( Uint512::MAX.checked_div(Uint512::from(0u32)), Err(DivideByZeroError { .. }) diff --git a/packages/std/src/math/uint64.rs b/packages/std/src/math/uint64.rs index 3e6ec72dc0..a719d90613 100644 --- a/packages/std/src/math/uint64.rs +++ b/packages/std/src/math/uint64.rs @@ -63,6 +63,10 @@ impl Uint64 { self.0 == 0 } + pub fn pow(self, exp: u32) -> Self { + self.0.pow(exp).into() + } + pub fn checked_add(self, other: Self) -> Result { self.0 .checked_add(other.0) @@ -84,6 +88,13 @@ impl Uint64 { .ok_or_else(|| OverflowError::new(OverflowOperation::Mul, self, other)) } + pub fn checked_pow(self, exp: u32) -> Result { + self.0 + .checked_pow(exp) + .map(Self) + .ok_or_else(|| OverflowError::new(OverflowOperation::Pow, self, exp)) + } + pub fn checked_div(self, other: Self) -> Result { self.0 .checked_div(other.0) @@ -633,6 +644,18 @@ mod tests { assert_eq!(a, Uint64::from(30u32)); } + #[test] + fn uint64_pow_works() { + assert_eq!(Uint64::from(2u32).pow(2), Uint64::from(4u32)); + assert_eq!(Uint64::from(2u32).pow(10), Uint64::from(1024u32)); + } + + #[test] + #[should_panic] + fn uint64_pow_overflow_panics() { + Uint64::MAX.pow(2u32); + } + #[test] #[should_panic] fn uint64_math_overflow_panics() { @@ -703,7 +726,7 @@ mod tests { fn uint64_methods() { // checked_* assert!(matches!( - Uint64(u64::MAX).checked_add(Uint64(1)), + Uint64::MAX.checked_add(Uint64(1)), Err(OverflowError { .. }) )); assert!(matches!( @@ -711,36 +734,37 @@ mod tests { Err(OverflowError { .. }) )); assert!(matches!( - Uint64(u64::MAX).checked_mul(Uint64(2)), + Uint64::MAX.checked_mul(Uint64(2)), Err(OverflowError { .. }) )); assert!(matches!( - Uint64(u64::MAX).checked_div(Uint64(0)), + Uint64::MAX.checked_pow(2u32), + Err(OverflowError { .. }) + )); + assert!(matches!( + Uint64::MAX.checked_div(Uint64(0)), Err(DivideByZeroError { .. }) )); assert!(matches!( - Uint64(u64::MAX).checked_div_euclid(Uint64(0)), + Uint64::MAX.checked_div_euclid(Uint64(0)), Err(DivideByZeroError { .. }) )); assert!(matches!( - Uint64(u64::MAX).checked_rem(Uint64(0)), + Uint64::MAX.checked_rem(Uint64(0)), Err(DivideByZeroError { .. }) )); // saturating_* - assert_eq!(Uint64(u64::MAX).saturating_add(Uint64(1)), Uint64(u64::MAX)); + assert_eq!(Uint64::MAX.saturating_add(Uint64(1)), Uint64::MAX); assert_eq!(Uint64(0).saturating_sub(Uint64(1)), Uint64(0)); - assert_eq!(Uint64(u64::MAX).saturating_mul(Uint64(2)), Uint64(u64::MAX)); - assert_eq!(Uint64(u64::MAX).saturating_pow(2), Uint64(u64::MAX)); + assert_eq!(Uint64::MAX.saturating_mul(Uint64(2)), Uint64::MAX); + assert_eq!(Uint64::MAX.saturating_pow(2), Uint64::MAX); // wrapping_* - assert_eq!(Uint64(u64::MAX).wrapping_add(Uint64(1)), Uint64(0)); - assert_eq!(Uint64(0).wrapping_sub(Uint64(1)), Uint64(u64::MAX)); - assert_eq!( - Uint64(u64::MAX).wrapping_mul(Uint64(2)), - Uint64(u64::MAX - 1) - ); - assert_eq!(Uint64(u64::MAX).wrapping_pow(2), Uint64(1)); + assert_eq!(Uint64::MAX.wrapping_add(Uint64(1)), Uint64(0)); + assert_eq!(Uint64(0).wrapping_sub(Uint64(1)), Uint64::MAX); + assert_eq!(Uint64::MAX.wrapping_mul(Uint64(2)), Uint64(u64::MAX - 1)); + assert_eq!(Uint64::MAX.wrapping_pow(2), Uint64(1)); } #[test]