sp1_curves/
lib.rs

1pub mod edwards;
2pub mod params;
3// pub mod polynomial;
4pub mod scalar_mul;
5pub mod uint256;
6pub mod utils;
7pub mod weierstrass;
8
9pub mod curve25519_dalek {
10    /// In "Edwards y" / "Ed25519" format, the curve point \\((x,y)\\) is
11    /// determined by the \\(y\\)-coordinate and the sign of \\(x\\).
12    ///
13    /// The first 255 bits of a `CompressedEdwardsY` represent the
14    /// \\(y\\)-coordinate.  The high bit of the 32nd byte gives the sign of \\(x\\).
15    ///
16    /// Note: This is taken from the `curve25519-dalek` crate.
17    #[derive(Copy, Clone, Eq, PartialEq, Hash)]
18    pub struct CompressedEdwardsY(pub [u8; 32]);
19
20    impl CompressedEdwardsY {
21        /// View this `CompressedEdwardsY` as a byte array.
22        pub fn as_bytes(&self) -> &[u8; 32] {
23            &self.0
24        }
25
26        /// Consume this `CompressedEdwardsY` and return the underlying byte array.
27        pub fn to_bytes(&self) -> [u8; 32] {
28            self.0
29        }
30
31        /// Construct a `CompressedEdwardsY` from a slice of bytes.
32        ///
33        /// # Errors
34        ///
35        /// Returns [`TryFromSliceError`] if the input `bytes` slice does not have
36        /// a length of 32.
37        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_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 = 8;
60pub const NUM_BYTES_FIELD_ELEMENT: usize = NUM_WORDS_FIELD_ELEMENT * WORD_SIZE;
61pub const COMPRESSED_POINT_BYTES: usize = 32;
62
63/// Number of words needed to represent a point on an elliptic curve. This is twice the number of
64/// words needed to represent a field element as a point consists of the x and y coordinates.
65pub 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 from_words_le(words: &[u32]) -> Self {
102        let x_bytes =
103            words[0..words.len() / 2].iter().flat_map(|n| n.to_le_bytes()).collect::<Vec<_>>();
104        let y_bytes =
105            &words[words.len() / 2..].iter().flat_map(|n| n.to_le_bytes()).collect::<Vec<_>>();
106        let x = BigUint::from_bytes_le(x_bytes.as_slice());
107        let y = BigUint::from_bytes_le(y_bytes.as_slice());
108        Self { x, y, _marker: std::marker::PhantomData }
109    }
110
111    pub fn to_words_le(&self) -> Vec<u32> {
112        let num_words = <E::BaseField as NumWords>::WordsCurvePoint::USIZE;
113        let num_bytes = num_words * 4;
114        let half_words = num_words / 2;
115
116        let mut x_bytes = self.x.to_bytes_le();
117        x_bytes.resize(num_bytes / 2, 0u8);
118        let mut y_bytes = self.y.to_bytes_le();
119        y_bytes.resize(num_bytes / 2, 0u8);
120
121        let mut words = vec![0u32; num_words];
122
123        for i in 0..half_words {
124            let x = u32::from_le_bytes([
125                x_bytes[4 * i],
126                x_bytes[4 * i + 1],
127                x_bytes[4 * i + 2],
128                x_bytes[4 * i + 3],
129            ]);
130            let y = u32::from_le_bytes([
131                y_bytes[4 * i],
132                y_bytes[4 * i + 1],
133                y_bytes[4 * i + 2],
134                y_bytes[4 * i + 3],
135            ]);
136
137            words[i] = x;
138            words[half_words + i] = y;
139        }
140
141        words
142    }
143}
144
145pub trait EllipticCurveParameters:
146    Debug + Send + Sync + Copy + Serialize + DeserializeOwned + 'static
147{
148    type BaseField: FieldParameters + NumWords;
149
150    const CURVE_TYPE: CurveType;
151}
152
153/// An interface for elliptic curve groups.
154pub trait EllipticCurve: EllipticCurveParameters {
155    const NB_LIMBS: usize = Self::BaseField::NB_LIMBS;
156
157    const NB_WITNESS_LIMBS: usize = Self::BaseField::NB_WITNESS_LIMBS;
158    /// Adds two different points on the curve.
159    ///
160    /// Warning: This method assumes that the two points are different.
161    fn ec_add(p: &AffinePoint<Self>, q: &AffinePoint<Self>) -> AffinePoint<Self>;
162
163    /// Doubles a point on the curve.
164    fn ec_double(p: &AffinePoint<Self>) -> AffinePoint<Self>;
165
166    /// Returns the generator of the curve group for a curve/subgroup of prime order.
167    fn ec_generator() -> AffinePoint<Self>;
168
169    /// Returns the neutral element of the curve group, if this element is affine (such as in the
170    /// case of the Edwards curve group). Otherwise, returns `None`.
171    fn ec_neutral() -> Option<AffinePoint<Self>>;
172
173    /// Returns the negative of a point on the curve.
174    fn ec_neg(p: &AffinePoint<Self>) -> AffinePoint<Self>;
175
176    /// Returns the number of bits needed to represent a scalar in the group.
177    fn nb_scalar_bits() -> usize {
178        Self::BaseField::NB_LIMBS * Self::BaseField::NB_BITS_PER_LIMB
179    }
180}
181
182impl<E: EllipticCurve> Add<&AffinePoint<E>> for &AffinePoint<E> {
183    type Output = AffinePoint<E>;
184
185    fn add(self, other: &AffinePoint<E>) -> AffinePoint<E> {
186        E::ec_add(self, other)
187    }
188}
189
190impl<E: EllipticCurve> Add<AffinePoint<E>> for AffinePoint<E> {
191    type Output = AffinePoint<E>;
192
193    fn add(self, other: AffinePoint<E>) -> AffinePoint<E> {
194        &self + &other
195    }
196}
197
198impl<E: EllipticCurve> Add<&AffinePoint<E>> for AffinePoint<E> {
199    type Output = AffinePoint<E>;
200
201    fn add(self, other: &AffinePoint<E>) -> AffinePoint<E> {
202        &self + other
203    }
204}
205
206impl<E: EllipticCurve> Neg for &AffinePoint<E> {
207    type Output = AffinePoint<E>;
208
209    fn neg(self) -> AffinePoint<E> {
210        E::ec_neg(self)
211    }
212}
213
214impl<E: EllipticCurve> Neg for AffinePoint<E> {
215    type Output = AffinePoint<E>;
216
217    fn neg(self) -> AffinePoint<E> {
218        -&self
219    }
220}