Skip to content

Commit

Permalink
Added widemul for u256.
Browse files Browse the repository at this point in the history
commit-id:7c544b0c
  • Loading branch information
orizi committed May 10, 2023
1 parent 44fdeb2 commit 41a30a9
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 0 deletions.
37 changes: 37 additions & 0 deletions corelib/src/integer.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -1080,6 +1080,43 @@ impl U256BitNot of BitNot<u256> {
}
}

#[derive(Copy, Drop, PartialEq, Serde)]
struct u512 {
limb0: u128,
limb1: u128,
limb2: u128,
limb3: u128,
}

// Returns the result of u128 addition, including an overflow word.
fn u128_add_with_carry(a: u128, b: u128) -> (u128, u128) nopanic {
match u128_overflowing_add(a, b) {
Result::Ok(v) => (v, 0),
Result::Err(v) => (v, 1),
}
}

fn u256_wide_mul(a: u256, b: u256) -> u512 nopanic {
let (limb1, limb0) = u128_wide_mul(a.low, b.low);
let (limb2, limb1_part) = u128_wide_mul(a.low, b.high);
let (limb1, limb1_overflow0) = u128_add_with_carry(limb1, limb1_part);
let (limb2_part, limb1_part) = u128_wide_mul(a.high, b.low);
let (limb1, limb1_overflow1) = u128_add_with_carry(limb1, limb1_part);
let (limb2, limb2_overflow) = u128_add_with_carry(limb2, limb2_part);
let (limb3, limb2_part) = u128_wide_mul(a.high, b.high);
// No overflow since no limb4.
let limb3 = u128_wrapping_add(limb3, limb2_overflow);
let (limb2, limb2_overflow) = u128_add_with_carry(limb2, limb2_part);
// No overflow since no limb4.
let limb3 = u128_wrapping_add(limb3, limb2_overflow);
// No overflow possible in this addition since both operands are 0/1.
let limb1_overflow = u128_wrapping_add(limb1_overflow0, limb1_overflow1);
let (limb2, limb2_overflow) = u128_add_with_carry(limb2, limb1_overflow);
// No overflow since no limb4.
let limb3 = u128_wrapping_add(limb3, limb2_overflow);
u512 { limb0, limb1, limb2, limb3 }
}

/// Bounded
trait BoundedInt<T> {
fn min() -> T nopanic;
Expand Down
19 changes: 19 additions & 0 deletions corelib/src/test/integer_test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,25 @@ fn test_u256_mul_overflow_2() {
pow_2_127() * 0x200000000000000000000000000000000;
}

use integer::{u512, u256_wide_mul};

#[test]
fn test_u256_wide_mul() {
assert(u256_wide_mul(0, 0) == u512 { limb0: 0, limb1: 0, limb2: 0, limb3: 0 }, '0 * 0 != 0');
assert(
u256_wide_mul(
0x1001001001001001001001001001001001001001001001001001,
0x1000100010001000100010001000100010001000100010001000100010001
) == u512 {
limb0: 0x33233223222222122112111111011001,
limb1: 0x54455445544554454444443443343333,
limb2: 0x21222222322332333333433443444444,
limb3: 0x1001101111112112
},
'long calculation failed'
);
}

#[test]
fn test_min() {
let min_u8: u8 = BoundedInt::min();
Expand Down

0 comments on commit 41a30a9

Please sign in to comment.