in math/src/field/f128/mod.rs [407:444]
fn mul(a: u128, b: u128) -> u128 {
let (x0, x1, x2) = mul_128x64(a, (b >> 64) as u64); // x = a * b_hi
let (mut x0, mut x1, x2) = mul_reduce(x0, x1, x2); // x = x - (x >> 128) * m
if x2 == 1 {
// if there was an overflow beyond 128 bits, subtract
// modulus from the result to make sure it fits into
// 128 bits; this can potentially be removed in favor
// of checking overflow later
let (t0, t1) = sub_modulus(x0, x1); // x = x - m
x0 = t0;
x1 = t1;
}
let (y0, y1, y2) = mul_128x64(a, b as u64); // y = a * b_lo
let (mut y1, carry) = add64_with_carry(y1, x0, 0); // y = y + (x << 64)
let (mut y2, y3) = add64_with_carry(y2, x1, carry);
if y3 == 1 {
// if there was an overflow beyond 192 bits, subtract
// modulus * 2^64 from the result to make sure it fits
// into 192 bits; this can potentially replace the
// previous overflow check (but needs to be proven)
let (t0, t1) = sub_modulus(y1, y2); // y = y - (m << 64)
y1 = t0;
y2 = t1;
}
let (mut z0, mut z1, z2) = mul_reduce(y0, y1, y2); // z = y - (y >> 128) * m
// make sure z is smaller than m
if z2 == 1 || (z1 == (M >> 64) as u64 && z0 >= (M as u64)) {
let (t0, t1) = sub_modulus(z0, z1); // z = z - m
z0 = t0;
z1 = t1;
}
((z1 as u128) << 64) + (z0 as u128)
}