sp1_curves/weierstrass/
mod.rs1use generic_array::GenericArray;
2use num::{BigUint, Zero};
3use serde::{Deserialize, Serialize};
4
5use super::CurveType;
6use crate::{
7 params::{FieldParameters, NumLimbs, NumWords},
8 utils::biguint_to_bits_le,
9 AffinePoint, EllipticCurve, EllipticCurveParameters,
10};
11
12#[cfg(feature = "bigint-rug")]
13use crate::utils::{biguint_to_rug, rug_to_biguint};
14
15pub mod bls12_381;
16pub mod bn254;
17pub mod secp256k1;
18pub mod secp256r1;
19
20pub trait WeierstrassParameters: EllipticCurveParameters {
22 const A: GenericArray<u8, <Self::BaseField as NumLimbs>::Limbs>;
23 const B: GenericArray<u8, <Self::BaseField as NumLimbs>::Limbs>;
24
25 fn generator() -> (BigUint, BigUint);
26
27 fn prime_group_order() -> BigUint;
28
29 fn a_int() -> BigUint {
30 let mut modulus = BigUint::zero();
31 for (i, limb) in Self::A.iter().enumerate() {
32 modulus += BigUint::from(*limb) << (8 * i);
33 }
34 modulus
35 }
36
37 fn b_int() -> BigUint {
38 let mut modulus = BigUint::zero();
39 for (i, limb) in Self::B.iter().enumerate() {
40 modulus += BigUint::from(*limb) << (8 * i);
41 }
42 modulus
43 }
44
45 fn nb_scalar_bits() -> usize {
46 Self::BaseField::NB_LIMBS * 16
47 }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
51pub struct SwCurve<E>(pub E);
52
53impl<E: WeierstrassParameters> WeierstrassParameters for SwCurve<E> {
54 const A: GenericArray<u8, <Self::BaseField as NumLimbs>::Limbs> = E::A;
55 const B: GenericArray<u8, <Self::BaseField as NumLimbs>::Limbs> = E::B;
56
57 fn a_int() -> BigUint {
58 E::a_int()
59 }
60
61 fn b_int() -> BigUint {
62 E::b_int()
63 }
64
65 fn generator() -> (BigUint, BigUint) {
66 E::generator()
67 }
68
69 fn nb_scalar_bits() -> usize {
70 E::nb_scalar_bits()
71 }
72
73 fn prime_group_order() -> BigUint {
74 E::prime_group_order()
75 }
76}
77
78impl<E: WeierstrassParameters> EllipticCurveParameters for SwCurve<E> {
79 type BaseField = E::BaseField;
80
81 const CURVE_TYPE: CurveType = E::CURVE_TYPE;
82}
83
84impl<E: WeierstrassParameters> EllipticCurve for SwCurve<E> {
85 const NB_LIMBS: usize = Self::BaseField::NB_LIMBS;
86 const NB_WITNESS_LIMBS: usize = Self::BaseField::NB_WITNESS_LIMBS;
87
88 fn ec_add(p: &AffinePoint<Self>, q: &AffinePoint<Self>) -> AffinePoint<Self> {
89 p.sw_add(q)
90 }
91
92 fn ec_double(p: &AffinePoint<Self>) -> AffinePoint<Self> {
93 p.sw_double()
94 }
95
96 fn ec_generator() -> AffinePoint<Self> {
97 let (x, y) = E::generator();
98 AffinePoint::new(x, y)
99 }
100
101 fn ec_neutral() -> Option<AffinePoint<Self>> {
102 None
103 }
104
105 fn ec_neg(p: &AffinePoint<Self>) -> AffinePoint<Self> {
106 let modulus = E::BaseField::modulus();
107 AffinePoint::new(p.x.clone(), modulus - &p.y)
108 }
109}
110
111impl<E: WeierstrassParameters> SwCurve<E> {
112 pub fn generator() -> AffinePoint<SwCurve<E>> {
113 let (x, y) = E::generator();
114
115 AffinePoint::new(x, y)
116 }
117
118 pub fn a_int() -> BigUint {
119 E::a_int()
120 }
121
122 pub fn b_int() -> BigUint {
123 E::b_int()
124 }
125}
126
127impl<E: WeierstrassParameters> AffinePoint<SwCurve<E>> {
128 pub fn sw_scalar_mul(&self, scalar: &BigUint) -> Self {
129 let mut result: Option<AffinePoint<SwCurve<E>>> = None;
130 let mut temp = self.clone();
131 let bits = biguint_to_bits_le(scalar, E::nb_scalar_bits());
132 for bit in bits {
133 if bit {
134 result = result.map(|r| r.sw_add(&temp)).or(Some(temp.clone()));
135 }
136 temp = temp.sw_double();
137 }
138 result.unwrap()
139 }
140}
141
142pub fn biguint_to_dashu(integer: &BigUint) -> dashu::integer::UBig {
143 dashu::integer::UBig::from_le_bytes(integer.to_bytes_le().as_slice())
144}
145
146pub fn dashu_to_biguint(integer: &dashu::integer::UBig) -> BigUint {
147 BigUint::from_bytes_le(&integer.to_le_bytes())
148}
149
150pub fn dashu_modpow(
151 base: &dashu::integer::UBig,
152 exponent: &dashu::integer::UBig,
153 modulus: &dashu::integer::UBig,
154) -> dashu::integer::UBig {
155 if modulus == &dashu::integer::UBig::from(1u32) {
156 return dashu::integer::UBig::from(0u32);
157 }
158
159 let mut result = dashu::integer::UBig::from(1u32);
160 let mut base = base.clone() % modulus;
161 let mut exp = exponent.clone();
162
163 while exp > dashu::integer::UBig::from(0u32) {
164 if &exp % dashu::integer::UBig::from(2u32) == dashu::integer::UBig::from(1u32) {
165 result = (result * &base) % modulus;
166 }
167 exp >>= 1;
168 base = (&base * &base) % modulus;
169 }
170
171 result
172}
173
174impl<E: WeierstrassParameters> AffinePoint<SwCurve<E>> {
175 pub fn sw_add(&self, other: &AffinePoint<SwCurve<E>>) -> AffinePoint<SwCurve<E>> {
176 if self.x == other.x && self.y == other.y {
177 panic!("Error: Points are the same. Use sw_double instead.");
178 }
179
180 cfg_if::cfg_if! {
181 if #[cfg(feature = "bigint-rug")] {
182 self.sw_add_rug(other)
183 } else {
184 let p = biguint_to_dashu(&E::BaseField::modulus());
185 let self_x = biguint_to_dashu(&self.x);
186 let self_y = biguint_to_dashu(&self.y);
187 let other_x = biguint_to_dashu(&other.x);
188 let other_y = biguint_to_dashu(&other.y);
189
190 let slope_numerator = (&p + &other_y - &self_y) % &p;
191 let slope_denominator = (&p + &other_x - &self_x) % &p;
192 let slope_denom_inverse =
193 dashu_modpow(&slope_denominator, &(&p - &dashu::integer::UBig::from(2u32)), &p);
194 let slope = (slope_numerator * &slope_denom_inverse) % &p;
195
196 let x_3n = (&slope * &slope + &p + &p - &self_x - &other_x) % &p;
197 let y_3n = (&slope * &(&p + &self_x - &x_3n) + &p - &self_y) % &p;
198
199 AffinePoint::new(dashu_to_biguint(&x_3n), dashu_to_biguint(&y_3n))
200 }
201 }
202 }
203
204 pub fn sw_double(&self) -> AffinePoint<SwCurve<E>> {
205 cfg_if::cfg_if! {
206 if #[cfg(feature = "bigint-rug")] {
207 self.sw_double_rug()
208 } else {
209 let p = biguint_to_dashu(&E::BaseField::modulus());
210 let a = biguint_to_dashu(&E::a_int());
211
212 let self_x = biguint_to_dashu(&self.x);
213 let self_y = biguint_to_dashu(&self.y);
214
215 let slope_numerator = (&a + &(&self_x * &self_x) * 3u32) % &p;
216
217 let slope_denominator = (&self_y * 2u32) % &p;
218 let slope_denom_inverse =
219 dashu_modpow(&slope_denominator, &(&p - &dashu::integer::UBig::from(2u32)), &p);
220 let slope = (slope_numerator * &slope_denom_inverse) % &p;
222
223 let x_3n = (&slope * &slope + &p + &p - &self_x - &self_x) % &p;
224
225 let y_3n = (&slope * &(&p + &self_x - &x_3n) + &p - &self_y) % &p;
226
227 AffinePoint::new(dashu_to_biguint(&x_3n), dashu_to_biguint(&y_3n))
228 }
229 }
230 }
231
232 #[cfg(feature = "bigint-rug")]
233 pub fn sw_add_rug(&self, other: &AffinePoint<SwCurve<E>>) -> AffinePoint<SwCurve<E>> {
234 use rug::Complete;
235 let p = biguint_to_rug(&E::BaseField::modulus());
236 let self_x = biguint_to_rug(&self.x);
237 let self_y = biguint_to_rug(&self.y);
238 let other_x = biguint_to_rug(&other.x);
239 let other_y = biguint_to_rug(&other.y);
240
241 let slope_numerator = ((&p + &other_y).complete() - &self_y) % &p;
242 let slope_denominator = ((&p + &other_x).complete() - &self_x) % &p;
243 let slope_denom_inverse = slope_denominator
244 .pow_mod_ref(&(&p - &rug::Integer::from(2u32)).complete(), &p)
245 .unwrap()
246 .complete();
247 let slope = (slope_numerator * &slope_denom_inverse) % &p;
248
249 let x_3n = ((&slope * &slope + &p).complete() + &p - &self_x - &other_x) % &p;
250 let y_3n = ((&slope * &((&p + &self_x).complete() - &x_3n) + &p).complete() - &self_y) % &p;
251
252 AffinePoint::new(rug_to_biguint(&x_3n), rug_to_biguint(&y_3n))
253 }
254
255 #[cfg(feature = "bigint-rug")]
256 pub fn sw_double_rug(&self) -> AffinePoint<SwCurve<E>> {
257 use rug::Complete;
258 let p = biguint_to_rug(&E::BaseField::modulus());
259 let a = biguint_to_rug(&E::a_int());
260
261 let self_x = biguint_to_rug(&self.x);
262 let self_y = biguint_to_rug(&self.y);
263
264 let slope_numerator = (&a + &(&self_x * &self_x).complete() * 3u32).complete() % &p;
265
266 let slope_denominator = (&self_y * 2u32).complete() % &p;
267 let slope_denom_inverse = slope_denominator
268 .pow_mod_ref(&(&p - &rug::Integer::from(2u32)).complete(), &p)
269 .unwrap()
270 .complete();
271
272 let slope = (slope_numerator * &slope_denom_inverse) % &p;
273
274 let x_3n = ((&slope * &slope + &p).complete() + ((&p - &self_x).complete() - &self_x)) % &p;
275
276 let y_3n = ((&slope * &((&p + &self_x).complete() - &x_3n) + &p).complete() - &self_y) % &p;
277
278 AffinePoint::new(rug_to_biguint(&x_3n), rug_to_biguint(&y_3n))
279 }
280}
281
282#[derive(Debug)]
283pub enum FieldType {
284 Bls12381,
285 Bn254,
286}
287
288pub trait FpOpField: FieldParameters + NumWords {
289 const FIELD_TYPE: FieldType;
290}
291
292#[cfg(test)]
293mod tests {
294
295 use num::bigint::RandBigInt;
296 use rand::thread_rng;
297
298 use super::bn254;
299
300 #[test]
301 fn test_weierstrass_biguint_scalar_mul() {
302 type E = bn254::Bn254;
303 let base = E::generator();
304
305 let mut rng = thread_rng();
306 for _ in 0..10 {
307 let x = rng.gen_biguint(24);
308 let y = rng.gen_biguint(25);
309
310 let x_base = base.sw_scalar_mul(&x);
311 let y_x_base = x_base.sw_scalar_mul(&y);
312 let xy = &x * &y;
313 let xy_base = base.sw_scalar_mul(&xy);
314 assert_eq!(y_x_base, xy_base);
315 }
316 }
317}