sp1_lib/
ecdsa.rs

1//! An implementation of the types needed for [`CurveArithmetic`].
2//!
3//! [`CurveArithmetic`] is a trait that is used in [RustCryptos ECDSA](https://github.com/RustCrypto/signatures).
4//!
5//! [`CurveArithmetic`] contains all the types needed to implement the ECDSA algorithm over some
6//! curve.
7//!
8//! This implementation is specifically for use inside of SP1, and internally uses SP1's Weierstrass
9//! precompiles. Weierstrass precompiles.
10//!
11//! In summary, SP1 overrides curve arithmetic entirely, and patches upstream field operations
12//! to be more efficient in the VM, such as `sqrt` or `inverse`.
13
14use crate::utils::AffinePoint as SP1AffinePointTrait;
15
16use elliptic_curve::{
17    ff, generic_array::typenum::consts::U32, subtle::CtOption, CurveArithmetic, FieldBytes,
18};
19use std::{fmt::Debug, ops::Neg};
20
21/// The affine point type for SP1.
22pub mod affine;
23pub use affine::AffinePoint;
24
25/// The projective point type for SP1.
26pub mod projective;
27pub use projective::ProjectivePoint;
28
29/// NOTE: The only supported ECDSA curves are secp256k1 and secp256r1, which both
30/// have 8 limbs in their field elements.
31const POINT_LIMBS: usize = 8 * 2;
32
33/// The number of bytes in a field element as an [`usize`].
34const FIELD_BYTES_SIZE_USIZE: usize = 32;
35
36/// The number of bytes in a field element as an [`elliptic_curve::generic_array::U32`].
37#[allow(non_camel_case_types)]
38type FIELD_BYTES_SIZE = U32;
39
40/// A [`CurveArithmetic`] extension for SP1 acceleration.
41///
42/// Patched crates implement this trait to take advantage of SP1-specific acceleration in the zkVM
43/// context.
44///
45/// Note: This trait only supports 32 byte base field curves.
46pub trait ECDSACurve
47where
48    Self: CurveArithmetic<
49        FieldBytesSize = FIELD_BYTES_SIZE,
50        AffinePoint = AffinePoint<Self>,
51        ProjectivePoint = ProjectivePoint<Self>,
52    >,
53{
54    type FieldElement: Field<Self> + Neg<Output = Self::FieldElement>;
55
56    /// The underlying [`SP1AffinePointTrait`] implementation.
57    type SP1AffinePoint: ECDSAPoint;
58
59    /// The `a` coefficient in the curve equation.
60    const EQUATION_A: Self::FieldElement;
61
62    /// The `b` coefficient in the curve equation.
63    const EQUATION_B: Self::FieldElement;
64}
65
66/// Alias trait for the [`ff::PrimeField`] with 32 byte field elements.
67///
68/// Note: All bytes should be considered to be in big-endian format.
69pub trait Field<C: ECDSACurve>: ff::PrimeField {
70    /// Create an instance of self from a FieldBytes.
71    fn from_bytes(bytes: &FieldBytes<C>) -> CtOption<Self>;
72
73    /// Convert self to a FieldBytes.
74    ///
75    /// Note: Implementers should ensure these methods normalize first.
76    fn to_bytes(self) -> FieldBytes<C>;
77
78    /// Ensure the field element is normalized.
79    fn normalize(self) -> Self;
80}
81
82pub type FieldElement<C> = <C as ECDSACurve>::FieldElement;
83
84/// Alias trait for the [`SP1AffinePointTrait`] with 32 byte field elements.
85pub trait ECDSAPoint:
86    SP1AffinePointTrait<POINT_LIMBS> + Clone + Copy + Debug + Send + Sync
87{
88    #[inline]
89    fn from(x: &[u8], y: &[u8]) -> Self {
90        <Self as SP1AffinePointTrait<POINT_LIMBS>>::from(x, y)
91    }
92}
93
94impl<P> ECDSAPoint for P where
95    P: SP1AffinePointTrait<POINT_LIMBS> + Clone + Copy + Debug + Send + Sync
96{
97}
98
99pub mod ecdh {
100    pub use elliptic_curve::ecdh::{diffie_hellman, EphemeralSecret, SharedSecret};
101
102    use super::{AffinePoint, ECDSACurve, Field};
103
104    impl<C: ECDSACurve> From<&AffinePoint<C>> for SharedSecret<C> {
105        fn from(affine: &AffinePoint<C>) -> SharedSecret<C> {
106            let (x, _) = affine.field_elements();
107
108            x.to_bytes().into()
109        }
110    }
111}