halo2curves_axiom/
arithmetic.rs

1//! This module provides common utilities, traits and structures for group and
2//! field arithmetic.
3//!
4//! This module is temporary, and the extension traits defined here are expected to be
5//! upstreamed into the `ff` and `group` crates after some refactoring.
6
7use crate::CurveExt;
8
9pub(crate) struct EndoParameters {
10    pub(crate) gamma1: [u64; 4],
11    pub(crate) gamma2: [u64; 4],
12    pub(crate) b1: [u64; 4],
13    pub(crate) b2: [u64; 4],
14}
15
16pub trait CurveEndo: CurveExt {
17    fn decompose_scalar(e: &Self::ScalarExt) -> (u128, bool, u128, bool);
18}
19
20/// Compute a + b + carry, returning the result and the new carry over.
21#[inline(always)]
22pub(crate) const fn adc(a: u64, b: u64, carry: u64) -> (u64, u64) {
23    let ret = (a as u128) + (b as u128) + (carry as u128);
24    (ret as u64, (ret >> 64) as u64)
25}
26
27/// Compute a - (b + borrow), returning the result and the new borrow.
28#[inline(always)]
29pub(crate) const fn sbb(a: u64, b: u64, borrow: u64) -> (u64, u64) {
30    let ret = (a as u128).wrapping_sub((b as u128) + ((borrow >> 63) as u128));
31    (ret as u64, (ret >> 64) as u64)
32}
33
34/// Compute a + (b * c) + carry, returning the result and the new carry over.
35#[inline(always)]
36pub(crate) const fn mac(a: u64, b: u64, c: u64, carry: u64) -> (u64, u64) {
37    let ret = (a as u128) + ((b as u128) * (c as u128)) + (carry as u128);
38    (ret as u64, (ret >> 64) as u64)
39}
40
41/// Compute a + (b * c), returning the result and the new carry over.
42#[inline(always)]
43pub(crate) const fn macx(a: u64, b: u64, c: u64) -> (u64, u64) {
44    let res = (a as u128) + ((b as u128) * (c as u128));
45    (res as u64, (res >> 64) as u64)
46}
47
48/// Returns a >= b
49#[inline(always)]
50pub(crate) const fn bigint_geq(a: &[u64; 4], b: &[u64; 4]) -> bool {
51    if a[3] > b[3] {
52        return true;
53    } else if a[3] < b[3] {
54        return false;
55    }
56    if a[2] > b[2] {
57        return true;
58    } else if a[2] < b[2] {
59        return false;
60    }
61    if a[1] > b[1] {
62        return true;
63    } else if a[1] < b[1] {
64        return false;
65    }
66    if a[0] >= b[0] {
67        return true;
68    }
69    false
70}
71
72/// Compute a * b, returning the result.
73#[inline(always)]
74pub(crate) fn mul_512(a: [u64; 4], b: [u64; 4]) -> [u64; 8] {
75    let (r0, carry) = macx(0, a[0], b[0]);
76    let (r1, carry) = macx(carry, a[0], b[1]);
77    let (r2, carry) = macx(carry, a[0], b[2]);
78    let (r3, carry_out) = macx(carry, a[0], b[3]);
79
80    let (r1, carry) = macx(r1, a[1], b[0]);
81    let (r2, carry) = mac(r2, a[1], b[1], carry);
82    let (r3, carry) = mac(r3, a[1], b[2], carry);
83    let (r4, carry_out) = mac(carry_out, a[1], b[3], carry);
84
85    let (r2, carry) = macx(r2, a[2], b[0]);
86    let (r3, carry) = mac(r3, a[2], b[1], carry);
87    let (r4, carry) = mac(r4, a[2], b[2], carry);
88    let (r5, carry_out) = mac(carry_out, a[2], b[3], carry);
89
90    let (r3, carry) = macx(r3, a[3], b[0]);
91    let (r4, carry) = mac(r4, a[3], b[1], carry);
92    let (r5, carry) = mac(r5, a[3], b[2], carry);
93    let (r6, carry_out) = mac(carry_out, a[3], b[3], carry);
94
95    [r0, r1, r2, r3, r4, r5, r6, carry_out]
96}
97
98pub trait CurveAffineExt: pasta_curves::arithmetic::CurveAffine {
99    /// Unlike the `Coordinates` trait, this just returns the raw affine coordinates without checking `is_on_curve`
100    fn into_coordinates(self) -> (Self::Base, Self::Base) {
101        // fallback implementation
102        let coordinates = self.coordinates().unwrap();
103        (*coordinates.x(), *coordinates.y())
104    }
105}