1pub mod edwards;
2pub mod params;
3pub mod scalar_mul;
5pub mod uint256;
6pub mod utils;
7pub mod weierstrass;
8
9pub mod curve25519_dalek {
10 #[derive(Copy, Clone, Eq, PartialEq, Hash)]
18 pub struct CompressedEdwardsY(pub [u8; 32]);
19
20 impl CompressedEdwardsY {
21 pub fn as_bytes(&self) -> &[u8; 32] {
23 &self.0
24 }
25
26 pub fn to_bytes(&self) -> [u8; 32] {
28 self.0
29 }
30
31 pub fn from_slice(
38 bytes: &[u8],
39 ) -> Result<CompressedEdwardsY, core::array::TryFromSliceError> {
40 bytes.try_into().map(CompressedEdwardsY)
41 }
42 }
43}
44
45pub use k256;
46pub use p256;
47
48use params::{FieldParameters, NumWords};
49use sp1_primitives::consts::WORD_BYTE_SIZE;
50use std::{
51 fmt::{Debug, Display, Formatter, Result},
52 ops::{Add, Neg},
53};
54use typenum::Unsigned;
55
56pub use num::{BigUint, Integer, One, Zero};
57use serde::{de::DeserializeOwned, Serialize};
58
59pub const NUM_WORDS_FIELD_ELEMENT: usize = 4;
60pub const NUM_BYTES_FIELD_ELEMENT: usize = NUM_WORDS_FIELD_ELEMENT * WORD_BYTE_SIZE;
61pub const COMPRESSED_POINT_BYTES: usize = 32;
62
63pub const NUM_WORDS_EC_POINT: usize = 2 * NUM_WORDS_FIELD_ELEMENT;
66
67#[derive(Debug, PartialEq, Eq)]
68pub enum CurveType {
69 Secp256k1,
70 Secp256r1,
71 Bn254,
72 Ed25519,
73 Bls12381,
74}
75
76impl Display for CurveType {
77 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
78 match self {
79 CurveType::Secp256k1 => write!(f, "Secp256k1"),
80 CurveType::Secp256r1 => write!(f, "Secp256r1"),
81 CurveType::Bn254 => write!(f, "Bn254"),
82 CurveType::Ed25519 => write!(f, "Ed25519"),
83 CurveType::Bls12381 => write!(f, "Bls12381"),
84 }
85 }
86}
87
88#[derive(Debug, Clone, PartialEq, Eq)]
89pub struct AffinePoint<E> {
90 pub x: BigUint,
91 pub y: BigUint,
92 _marker: std::marker::PhantomData<E>,
93}
94
95impl<E: EllipticCurveParameters> AffinePoint<E> {
96 #[allow(dead_code)]
97 pub const fn new(x: BigUint, y: BigUint) -> Self {
98 Self { x, y, _marker: std::marker::PhantomData }
99 }
100
101 pub fn to_sec1_uncompressed(&self) -> Vec<u8> {
102 fn le_to_fixed_be<E: EllipticCurveParameters>(n: &BigUint) -> Vec<u8> {
103 let le = n.to_bytes_le();
104
105 let mut buf = vec![0_u8; E::BaseField::NB_BYTES];
107 buf[..le.len()].copy_from_slice(&le);
108 buf.reverse();
109 buf
110 }
111
112 let mut out = vec![0u8; E::BaseField::NB_BYTES * 2 + 1];
113 out[0] = 0x04;
114 out[1..E::BaseField::NB_BYTES + 1].copy_from_slice(&le_to_fixed_be::<E>(&self.x));
115 out[E::BaseField::NB_BYTES + 1..].copy_from_slice(&le_to_fixed_be::<E>(&self.y));
116 out
117 }
118
119 pub fn from_words_le<'a>(words: impl IntoIterator<Item = &'a u64>) -> Self {
120 let words = words.into_iter().collect::<Vec<_>>();
121
122 let x_bytes =
123 words[0..words.len() / 2].iter().flat_map(|n| n.to_le_bytes()).collect::<Vec<_>>();
124
125 let y_bytes =
126 &words[words.len() / 2..].iter().flat_map(|n| n.to_le_bytes()).collect::<Vec<_>>();
127
128 let x = BigUint::from_bytes_le(x_bytes.as_slice());
129 let y = BigUint::from_bytes_le(y_bytes.as_slice());
130 Self { x, y, _marker: std::marker::PhantomData }
131 }
132
133 pub fn to_words_le(&self) -> Vec<u64> {
134 let num_words = <E::BaseField as NumWords>::WordsCurvePoint::USIZE;
135 let num_bytes = num_words * 8;
136 let half_words = num_words / 2;
137
138 let mut x_bytes = self.x.to_bytes_le();
139 x_bytes.resize(num_bytes / 2, 0u8);
140 let mut y_bytes = self.y.to_bytes_le();
141 y_bytes.resize(num_bytes / 2, 0u8);
142
143 let mut words = vec![0u64; num_words];
144
145 for i in 0..half_words {
146 let x = u64::from_le_bytes([
147 x_bytes[8 * i],
148 x_bytes[8 * i + 1],
149 x_bytes[8 * i + 2],
150 x_bytes[8 * i + 3],
151 x_bytes[8 * i + 4],
152 x_bytes[8 * i + 5],
153 x_bytes[8 * i + 6],
154 x_bytes[8 * i + 7],
155 ]);
156 let y = u64::from_le_bytes([
157 y_bytes[8 * i],
158 y_bytes[8 * i + 1],
159 y_bytes[8 * i + 2],
160 y_bytes[8 * i + 3],
161 y_bytes[8 * i + 4],
162 y_bytes[8 * i + 5],
163 y_bytes[8 * i + 6],
164 y_bytes[8 * i + 7],
165 ]);
166
167 words[i] = x;
168 words[half_words + i] = y;
169 }
170
171 words
172 }
173}
174
175pub trait EllipticCurveParameters:
176 Debug + Send + Sync + Copy + Serialize + DeserializeOwned + 'static
177{
178 type BaseField: FieldParameters + NumWords;
179
180 const CURVE_TYPE: CurveType;
181}
182
183pub trait EllipticCurve: EllipticCurveParameters {
185 const NB_LIMBS: usize = Self::BaseField::NB_LIMBS;
186
187 const NB_WITNESS_LIMBS: usize = Self::BaseField::NB_WITNESS_LIMBS;
188 fn ec_add(p: &AffinePoint<Self>, q: &AffinePoint<Self>) -> AffinePoint<Self>;
192
193 fn ec_double(p: &AffinePoint<Self>) -> AffinePoint<Self>;
195
196 fn ec_generator() -> AffinePoint<Self>;
198
199 fn ec_neutral() -> Option<AffinePoint<Self>>;
202
203 fn ec_neg(p: &AffinePoint<Self>) -> AffinePoint<Self>;
205
206 fn nb_scalar_bits() -> usize {
208 Self::BaseField::NB_LIMBS * Self::BaseField::NB_BITS_PER_LIMB
209 }
210}
211
212impl<E: EllipticCurve> Add<&AffinePoint<E>> for &AffinePoint<E> {
213 type Output = AffinePoint<E>;
214
215 fn add(self, other: &AffinePoint<E>) -> AffinePoint<E> {
216 E::ec_add(self, other)
217 }
218}
219
220impl<E: EllipticCurve> Add<AffinePoint<E>> for AffinePoint<E> {
221 type Output = AffinePoint<E>;
222
223 fn add(self, other: AffinePoint<E>) -> AffinePoint<E> {
224 &self + &other
225 }
226}
227
228impl<E: EllipticCurve> Add<&AffinePoint<E>> for AffinePoint<E> {
229 type Output = AffinePoint<E>;
230
231 fn add(self, other: &AffinePoint<E>) -> AffinePoint<E> {
232 &self + other
233 }
234}
235
236impl<E: EllipticCurve> Neg for &AffinePoint<E> {
237 type Output = AffinePoint<E>;
238
239 fn neg(self) -> AffinePoint<E> {
240 E::ec_neg(self)
241 }
242}
243
244impl<E: EllipticCurve> Neg for AffinePoint<E> {
245 type Output = AffinePoint<E>;
246
247 fn neg(self) -> AffinePoint<E> {
248 -&self
249 }
250}