From c364aa832ea2865358fd70307b300c9740cbe35c Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 27 Sep 2021 17:36:59 +0200 Subject: [PATCH 1/8] Implement const conversion Uint128 -> Uint256 --- packages/std/src/math/uint128.rs | 2 +- packages/std/src/math/uint256.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/packages/std/src/math/uint128.rs b/packages/std/src/math/uint128.rs index 933ea574de..d60662abee 100644 --- a/packages/std/src/math/uint128.rs +++ b/packages/std/src/math/uint128.rs @@ -47,7 +47,7 @@ impl Uint128 { } /// Returns a copy of the internal data - pub fn u128(&self) -> u128 { + pub const fn u128(&self) -> u128 { self.0 } diff --git a/packages/std/src/math/uint256.rs b/packages/std/src/math/uint256.rs index 96dbfc68b4..c64d8ba08c 100644 --- a/packages/std/src/math/uint256.rs +++ b/packages/std/src/math/uint256.rs @@ -99,6 +99,23 @@ impl Uint256 { Uint256(U256(words)) } + pub const fn from_uint128(num: Uint128) -> Self { + let num = num.u128(); + let bytes = num.to_le_bytes(); + let words: [u64; 4] = [ + u64::from_le_bytes([ + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], + ]), + u64::from_le_bytes([ + bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], + bytes[15], + ]), + 0, + 0, + ]; + Self(U256(words)) + } + /// Returns a copy of the number as big endian bytes. pub const fn to_be_bytes(self) -> [u8; 32] { let words = [ @@ -1006,6 +1023,19 @@ mod tests { ); } + #[test] + fn uint256_from_uint128() { + assert_eq!( + Uint256::from_uint128(Uint128::new(123)), + Uint256::from_str("123").unwrap() + ); + + assert_eq!( + Uint256::from_uint128(Uint128::new(9785746283745)), + Uint256::from_str("9785746283745").unwrap() + ); + } + #[test] fn uint256_implements_display() { let a = Uint256::from(12345u32); From 8f82748f52d67b629fb9f422b9e53e8e0efcf97e Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 27 Sep 2021 17:45:43 +0200 Subject: [PATCH 2/8] Implement const conversion Uint128 -> Uint256 --- packages/std/src/math/uint256.rs | 4 +++ packages/std/src/math/uint512.rs | 42 ++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/packages/std/src/math/uint256.rs b/packages/std/src/math/uint256.rs index c64d8ba08c..b635c9a61e 100644 --- a/packages/std/src/math/uint256.rs +++ b/packages/std/src/math/uint256.rs @@ -286,6 +286,10 @@ impl Uint256 { pub fn saturating_mul(self, other: Self) -> Self { Self(self.0.saturating_mul(other.0)) } + + pub(crate) const fn to_words(self) -> [u64; 4] { + self.0 .0 + } } impl From for Uint256 { diff --git a/packages/std/src/math/uint512.rs b/packages/std/src/math/uint512.rs index 0b159337c7..cae8582a23 100644 --- a/packages/std/src/math/uint512.rs +++ b/packages/std/src/math/uint512.rs @@ -99,6 +99,22 @@ impl Uint512 { Uint512(U512::from_little_endian(&value)) } + pub const fn from_uint256(num: Uint256) -> Self { + let uint256_words = num.to_words(); + let words: [u64; 8] = [ + uint256_words[0], + uint256_words[1], + uint256_words[2], + uint256_words[3], + 0, + 0, + 0, + 0, + ]; + + Self(U512(words)) + } + /// Returns a copy of the number as big endian bytes. pub const fn to_be_bytes(self) -> [u8; 64] { let words = [ @@ -719,6 +735,32 @@ mod tests { ); } + #[test] + fn uint512_from_uint256() { + assert_eq!( + Uint512::from_uint256(Uint256::from_str("123").unwrap()), + Uint512::from_str("123").unwrap() + ); + + assert_eq!( + Uint512::from_uint256(Uint256::from_str("9785746283745").unwrap()), + Uint512::from_str("9785746283745").unwrap() + ); + + assert_eq!( + Uint512::from_uint256( + Uint256::from_str( + "97857462837575757832978493758398593853985452378423874623874628736482736487236" + ) + .unwrap() + ), + Uint512::from_str( + "97857462837575757832978493758398593853985452378423874623874628736482736487236" + ) + .unwrap() + ); + } + #[test] fn uint512_implements_display() { let a = Uint512::from(12345u32); From 219afe7640010cb4a04978b1332d5bd1be486157 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 27 Sep 2021 17:55:32 +0200 Subject: [PATCH 3/8] Remove DECIMAL_FRACTIONAL_UINT* from decimals --- packages/std/src/math/decimal.rs | 8 ++------ packages/std/src/math/decimal256.rs | 9 ++------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/packages/std/src/math/decimal.rs b/packages/std/src/math/decimal.rs index e851d3711b..6cc197a36f 100644 --- a/packages/std/src/math/decimal.rs +++ b/packages/std/src/math/decimal.rs @@ -21,10 +21,6 @@ impl Decimal { const DECIMAL_FRACTIONAL: Uint128 = Uint128::new(1_000_000_000_000_000_000u128); // 1*10**18 const DECIMAL_FRACTIONAL_SQUARED: Uint128 = Uint128::new(1_000_000_000_000_000_000_000_000_000_000_000_000u128); // (1*10**18)**2 = 1*10**36 - const DECIMAL_FRACTIONAL_UINT256: Uint256 = Uint256::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 224, 182, 179, - 167, 100, 0, 0, - ]); // Python: `[b for b in (1*10**18).to_bytes(32, "big")]` const DECIMAL_PLACES: usize = 18; // This needs to be an even number. pub const MAX: Self = Self(Uint128::MAX); @@ -220,8 +216,8 @@ impl ops::Mul for Decimal { // (a.numerator() * b.numerator()) / (a.denominator() * b.denominator()) // = (a.numerator() * b.numerator()) / a.denominator() / b.denominator() - let result_as_uint256 = - self.numerator().full_mul(other.numerator()) / Self::DECIMAL_FRACTIONAL_UINT256; + let result_as_uint256 = self.numerator().full_mul(other.numerator()) + / Uint256::from_uint128(Self::DECIMAL_FRACTIONAL); // from_uint128 is a const method and should be "free" match result_as_uint256.try_into() { Ok(result) => Self(result), Err(_) => panic!("attempt to multiply with overflow"), diff --git a/packages/std/src/math/decimal256.rs b/packages/std/src/math/decimal256.rs index 07d6dac880..4203e7d124 100644 --- a/packages/std/src/math/decimal256.rs +++ b/packages/std/src/math/decimal256.rs @@ -32,11 +32,6 @@ impl Decimal256 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 151, 206, 123, 201, 7, 21, 179, 75, 159, 16, 0, 0, 0, 0, ]); - const DECIMAL_FRACTIONAL_UINT512: Uint512 = Uint512::from_be_bytes([ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 224, 182, - 179, 167, 100, 0, 0, - ]); // Python: `[b for b in (1*10**18).to_bytes(32, "big")]` pub const MAX: Self = Self(Uint256::MAX); @@ -231,8 +226,8 @@ impl ops::Mul for Decimal256 { // (a.numerator() * b.numerator()) / (a.denominator() * b.denominator()) // = (a.numerator() * b.numerator()) / a.denominator() / b.denominator() - let result_as_uint512 = - self.numerator().full_mul(other.numerator()) / Self::DECIMAL_FRACTIONAL_UINT512; + let result_as_uint512 = self.numerator().full_mul(other.numerator()) + / Uint512::from_uint256(Self::DECIMAL_FRACTIONAL); // from_uint256 is a const method and should be "free" match result_as_uint512.try_into() { Ok(result) => Self(result), Err(_) => panic!("attempt to multiply with overflow"), From a5135a470367da0aaee0d1c9d794b62b2251a8ed Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 27 Sep 2021 18:17:29 +0200 Subject: [PATCH 4/8] Refactor Uint256::from_uint126 --- packages/std/src/math/uint256.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/packages/std/src/math/uint256.rs b/packages/std/src/math/uint256.rs index b635c9a61e..665cc10ac0 100644 --- a/packages/std/src/math/uint256.rs +++ b/packages/std/src/math/uint256.rs @@ -102,18 +102,12 @@ impl Uint256 { pub const fn from_uint128(num: Uint128) -> Self { let num = num.u128(); let bytes = num.to_le_bytes(); - let words: [u64; 4] = [ - u64::from_le_bytes([ - bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], - ]), - u64::from_le_bytes([ - bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], - bytes[15], - ]), - 0, - 0, - ]; - Self(U256(words)) + + Self::from_le_bytes([ + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], + bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15], + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]) } /// Returns a copy of the number as big endian bytes. From 03c77d992f9c69d248fda2966c2747cfa761ef40 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 27 Sep 2021 22:36:57 +0200 Subject: [PATCH 5/8] docs --- packages/std/src/math/uint256.rs | 2 ++ packages/std/src/math/uint512.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/packages/std/src/math/uint256.rs b/packages/std/src/math/uint256.rs index 665cc10ac0..ad7fab64e5 100644 --- a/packages/std/src/math/uint256.rs +++ b/packages/std/src/math/uint256.rs @@ -99,6 +99,8 @@ impl Uint256 { Uint256(U256(words)) } + /// A conversion from `Uint128` that, unlike the one provided by the `From` trait, + /// can be used in a `const` context. pub const fn from_uint128(num: Uint128) -> Self { let num = num.u128(); let bytes = num.to_le_bytes(); diff --git a/packages/std/src/math/uint512.rs b/packages/std/src/math/uint512.rs index cae8582a23..f09169247a 100644 --- a/packages/std/src/math/uint512.rs +++ b/packages/std/src/math/uint512.rs @@ -99,6 +99,8 @@ impl Uint512 { Uint512(U512::from_little_endian(&value)) } + /// A conversion from `Uint256` that, unlike the one provided by the `From` trait, + /// can be used in a `const` context. pub const fn from_uint256(num: Uint256) -> Self { let uint256_words = num.to_words(); let words: [u64; 8] = [ From fe9d41946385801ef08ca445b3bdb996dbf2f410 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 27 Sep 2021 22:17:12 +0200 Subject: [PATCH 6/8] style Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com> --- packages/std/src/math/uint256.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/std/src/math/uint256.rs b/packages/std/src/math/uint256.rs index ad7fab64e5..dbc42137c4 100644 --- a/packages/std/src/math/uint256.rs +++ b/packages/std/src/math/uint256.rs @@ -102,7 +102,6 @@ impl Uint256 { /// A conversion from `Uint128` that, unlike the one provided by the `From` trait, /// can be used in a `const` context. pub const fn from_uint128(num: Uint128) -> Self { - let num = num.u128(); let bytes = num.to_le_bytes(); Self::from_le_bytes([ From 20106b6459e3dc4b0aaee3a186fc10a76ee77bc0 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 27 Sep 2021 23:13:53 +0200 Subject: [PATCH 7/8] Improve the way `Uint:512::from_uint256` works --- CHANGELOG.md | 1 + packages/std/src/math/uint256.rs | 4 --- packages/std/src/math/uint512.rs | 52 +++++++++++++++++++++++--------- 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c74e9d1b3..581c8c4b86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ and this project adheres to such that `Decimal::numerator` and `::denominator` now return `Uint128`. - cosmwasm-std: Make methods `Uint256::to_be_bytes`/`::to_le_bytes` const. - cosmwasm-std: Make methods `Uint512::to_be_bytes`/`::to_le_bytes` const. +- cosmwasm-std: Make method `Uint512::from_le_bytes` const. ### Removed diff --git a/packages/std/src/math/uint256.rs b/packages/std/src/math/uint256.rs index dbc42137c4..cd422bc28f 100644 --- a/packages/std/src/math/uint256.rs +++ b/packages/std/src/math/uint256.rs @@ -281,10 +281,6 @@ impl Uint256 { pub fn saturating_mul(self, other: Self) -> Self { Self(self.0.saturating_mul(other.0)) } - - pub(crate) const fn to_words(self) -> [u64; 4] { - self.0 .0 - } } impl From for Uint256 { diff --git a/packages/std/src/math/uint512.rs b/packages/std/src/math/uint512.rs index f09169247a..1329989bb6 100644 --- a/packages/std/src/math/uint512.rs +++ b/packages/std/src/math/uint512.rs @@ -95,26 +95,48 @@ impl Uint512 { Self(U512(words)) } - pub fn from_le_bytes(value: [u8; 64]) -> Self { - Uint512(U512::from_little_endian(&value)) + pub const fn from_le_bytes(data: [u8; 64]) -> Self { + let words: [u64; 8] = [ + u64::from_le_bytes([ + data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], + ]), + u64::from_le_bytes([ + data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], + ]), + u64::from_le_bytes([ + data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23], + ]), + u64::from_le_bytes([ + data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31], + ]), + u64::from_le_bytes([ + data[32], data[33], data[34], data[35], data[36], data[37], data[38], data[39], + ]), + u64::from_le_bytes([ + data[40], data[41], data[42], data[43], data[44], data[45], data[46], data[47], + ]), + u64::from_le_bytes([ + data[48], data[49], data[50], data[51], data[52], data[53], data[54], data[55], + ]), + u64::from_le_bytes([ + data[56], data[57], data[58], data[59], data[60], data[61], data[62], data[63], + ]), + ]; + Self(U512(words)) } /// A conversion from `Uint256` that, unlike the one provided by the `From` trait, /// can be used in a `const` context. pub const fn from_uint256(num: Uint256) -> Self { - let uint256_words = num.to_words(); - let words: [u64; 8] = [ - uint256_words[0], - uint256_words[1], - uint256_words[2], - uint256_words[3], - 0, - 0, - 0, - 0, - ]; - - Self(U512(words)) + let bytes = num.to_le_bytes(); + Self::from_le_bytes([ + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], + bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15], + bytes[16], bytes[17], bytes[18], bytes[19], bytes[20], bytes[21], bytes[22], bytes[23], + bytes[24], bytes[25], bytes[26], bytes[27], bytes[28], bytes[29], bytes[30], bytes[31], + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ]) } /// Returns a copy of the number as big endian bytes. From 58974bb83f34da2acee4080a3674fb99c2c6e279 Mon Sep 17 00:00:00 2001 From: Tomasz Kurcz Date: Mon, 27 Sep 2021 23:17:59 +0200 Subject: [PATCH 8/8] CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 581c8c4b86..20639693a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ and this project adheres to the contract call was executed in. - cosmwasm-std: Implement `ops::Mul` for `Decimal` and `Decimal256`. - cosmwasm-std: New const methods `Uint128::to_be_bytes`/`::to_le_bytes`. +- cosmwasm-std: New const conversion methods `Uint256::from_uint128` and + `Uint512::from_uint256`. ### Changed