crypto_bigint/
primitives.rs

1use crate::{WideWord, Word};
2
3/// Multiplies `x` and `y`, returning the most significant
4/// and the least significant words as `(hi, lo)`.
5#[inline(always)]
6pub(crate) const fn mulhilo(x: Word, y: Word) -> (Word, Word) {
7    let res = (x as WideWord) * (y as WideWord);
8    ((res >> Word::BITS) as Word, res as Word)
9}
10
11/// Adds wide numbers represented by pairs of (most significant word, least significant word)
12/// and returns the result in the same format `(hi, lo)`.
13#[inline(always)]
14pub(crate) const fn addhilo(x_hi: Word, x_lo: Word, y_hi: Word, y_lo: Word) -> (Word, Word) {
15    let res = (((x_hi as WideWord) << Word::BITS) | (x_lo as WideWord))
16        + (((y_hi as WideWord) << Word::BITS) | (y_lo as WideWord));
17    ((res >> Word::BITS) as Word, res as Word)
18}
19
20/// Computes `lhs + rhs + carry`, returning the result along with the new carry (0, 1, or 2).
21#[inline(always)]
22pub const fn adc(lhs: Word, rhs: Word, carry: Word) -> (Word, Word) {
23    // We could use `Word::overflowing_add()` here analogous to `overflowing_add()`,
24    // but this version seems to produce a slightly better assembly.
25    let a = lhs as WideWord;
26    let b = rhs as WideWord;
27    let carry = carry as WideWord;
28    let ret = a + b + carry;
29    (ret as Word, (ret >> Word::BITS) as Word)
30}
31
32/// Computes `lhs + rhs`, returning the result along with the carry (0 or 1).
33#[inline(always)]
34pub const fn overflowing_add(lhs: Word, rhs: Word) -> (Word, Word) {
35    let (res, carry) = lhs.overflowing_add(rhs);
36    (res, carry as Word)
37}
38
39/// Computes `self - (rhs + borrow)`, returning the result along with the new borrow.
40#[inline(always)]
41pub const fn sbb(lhs: Word, rhs: Word, borrow: Word) -> (Word, Word) {
42    let a = lhs as WideWord;
43    let b = rhs as WideWord;
44    let borrow = (borrow >> (Word::BITS - 1)) as WideWord;
45    let ret = a.wrapping_sub(b + borrow);
46    (ret as Word, (ret >> Word::BITS) as Word)
47}
48
49/// Computes `lhs * rhs`, returning the low and the high words of the result.
50#[inline(always)]
51pub const fn mul_wide(lhs: Word, rhs: Word) -> (Word, Word) {
52    let a = lhs as WideWord;
53    let b = rhs as WideWord;
54    let ret = a * b;
55    (ret as Word, (ret >> Word::BITS) as Word)
56}
57
58/// Computes `a + (b * c) + carry`, returning the result along with the new carry.
59#[inline(always)]
60pub(crate) const fn mac(a: Word, b: Word, c: Word, carry: Word) -> (Word, Word) {
61    let a = a as WideWord;
62    let b = b as WideWord;
63    let c = c as WideWord;
64    let carry = carry as WideWord;
65    let ret = a + (b * c) + carry;
66    (ret as Word, (ret >> Word::BITS) as Word)
67}