1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use subtle::{Choice, ConditionallySelectable, CtOption};
pub trait CurveAffineExt: pasta_curves::arithmetic::CurveAffine {
fn batch_add<const COMPLETE: bool, const LOAD_POINTS: bool>(
points: &mut [Self],
output_indices: &[u32],
num_points: usize,
offset: usize,
bases: &[Self],
base_positions: &[u32],
);
fn into_coordinates(self) -> (Self::Base, Self::Base) {
let coordinates = self.coordinates().unwrap();
(*coordinates.x(), *coordinates.y())
}
}
pub(crate) fn sqrt_tonelli_shanks<F: ff::PrimeField, S: AsRef<[u64]>>(
f: &F,
tm1d2: S,
) -> CtOption<F> {
use subtle::ConstantTimeEq;
let w = f.pow_vartime(tm1d2);
let mut v = F::S;
let mut x = w * f;
let mut b = x * w;
let mut z = F::root_of_unity();
for max_v in (1..=F::S).rev() {
let mut k = 1;
let mut tmp = b.square();
let mut j_less_than_v: Choice = 1.into();
for j in 2..max_v {
let tmp_is_one = tmp.ct_eq(&F::one());
let squared = F::conditional_select(&tmp, &z, tmp_is_one).square();
tmp = F::conditional_select(&squared, &tmp, tmp_is_one);
let new_z = F::conditional_select(&z, &squared, tmp_is_one);
j_less_than_v &= !j.ct_eq(&v);
k = u32::conditional_select(&j, &k, tmp_is_one);
z = F::conditional_select(&z, &new_z, j_less_than_v);
}
let result = x * z;
x = F::conditional_select(&result, &x, b.ct_eq(&F::one()));
z = z.square();
b *= z;
v = k;
}
CtOption::new(
x,
(x * x).ct_eq(f), )
}
#[inline(always)]
pub(crate) const fn adc(a: u64, b: u64, carry: bool) -> (u64, bool) {
a.carrying_add(b, carry)
}
#[inline(always)]
pub(crate) const fn sbb(a: u64, b: u64, borrow: bool) -> (u64, bool) {
a.borrowing_sub(b, borrow)
}
#[inline(always)]
pub(crate) const fn macx(a: u64, b: u64, c: u64) -> (u64, u64) {
b.carrying_mul(c, a)
}
#[inline(always)]
pub(crate) const fn mac(a: u64, b: u64, c: u64, carry: u64) -> (u64, u64) {
let (lo, hi) = b.carrying_mul(c, a);
let (lo, carry) = lo.overflowing_add(carry);
(lo, hi + carry as u64)
}
#[inline(always)]
pub(crate) fn mul_512(a: [u64; 4], b: [u64; 4]) -> [u64; 8] {
let (r0, carry) = macx(0, a[0], b[0]);
let (r1, carry) = macx(carry, a[0], b[1]);
let (r2, carry) = macx(carry, a[0], b[2]);
let (r3, carry_out) = macx(carry, a[0], b[3]);
let (r1, carry) = macx(r1, a[1], b[0]);
let (r2, carry) = mac(r2, a[1], b[1], carry);
let (r3, carry) = mac(r3, a[1], b[2], carry);
let (r4, carry_out) = mac(carry_out, a[1], b[3], carry);
let (r2, carry) = macx(r2, a[2], b[0]);
let (r3, carry) = mac(r3, a[2], b[1], carry);
let (r4, carry) = mac(r4, a[2], b[2], carry);
let (r5, carry_out) = mac(carry_out, a[2], b[3], carry);
let (r3, carry) = macx(r3, a[3], b[0]);
let (r4, carry) = mac(r4, a[3], b[1], carry);
let (r5, carry) = mac(r5, a[3], b[2], carry);
let (r6, carry_out) = mac(carry_out, a[3], b[3], carry);
[r0, r1, r2, r3, r4, r5, r6, carry_out]
}