Skip to main content

elliptic_curve/
sec1.rs

1//! Support for SEC1 elliptic curve encoding formats.
2//!
3//! <https://www.secg.org/sec1-v2.pdf>
4
5pub use sec1::point::{Coordinates, ModulusSize, Tag};
6
7use crate::{Curve, Error, FieldBytesSize, Result, SecretKey, array::Array, ctutils::CtOption};
8
9#[cfg(feature = "arithmetic")]
10use crate::{AffinePoint, CurveArithmetic};
11#[cfg(feature = "alloc")]
12use {crate::point::PointCompression, alloc::boxed::Box};
13
14/// Encoded elliptic curve point with point compression.
15pub type CompressedPoint<C> = Array<u8, CompressedPointSize<C>>;
16
17/// Size of a compressed elliptic curve point.
18pub type CompressedPointSize<C> = <FieldBytesSize<C> as ModulusSize>::CompressedPointSize;
19
20/// Encoded elliptic curve point *without* point compression.
21pub type UncompressedPoint<C> = Array<u8, UncompressedPointSize<C>>;
22
23/// Size of an uncompressed elliptic curve point.
24pub type UncompressedPointSize<C> = <FieldBytesSize<C> as ModulusSize>::UncompressedPointSize;
25
26/// SEC1-encoded elliptic curve point sized appropriately for a given curve.
27pub type Sec1Point<C> = ::sec1::point::EncodedPoint<FieldBytesSize<C>>;
28
29/// DEPRECATED: legacy name for [`Sec1Point`].
30#[deprecated(since = "0.14.0", note = "use `Sec1Point` instead")]
31pub type EncodedPoint<C> = Sec1Point<C>;
32
33/// Decode curve point using the `Octet-String-to-Elliptic-Curve-Point` conversion described in
34/// [SEC 1: Elliptic Curve Cryptography (Version 2.0)](https://www.secg.org/sec1-v2.pdf)
35/// §2.3.4 (page 11).
36pub trait FromSec1Point<C>
37where
38    Self: Sized,
39    C: Curve,
40    FieldBytesSize<C>: ModulusSize,
41{
42    /// Decode curve point from a SEC1 [`Sec1Point`].
43    fn from_sec1_point(point: &Sec1Point<C>) -> CtOption<Self>;
44
45    /// Decode curve point from the provided SEC1 encoding (compressed, uncompressed, or
46    /// identity) using the `Octet-String-to-Elliptic-Curve-Point` conversion.
47    ///
48    /// # Errors
49    /// - if `bytes` does not begin with a valid SEC1 tag
50    /// - if `bytes` is not the appropriate length for its SEC1 tag
51    /// - if `bytes` does not encode the coordinate(s) of a valid elliptic curve point
52    fn from_sec1_bytes(bytes: &[u8]) -> Result<Self> {
53        let point = Sec1Point::<C>::from_bytes(bytes)?;
54        Self::from_sec1_point(&point).into_option().ok_or(Error)
55    }
56
57    /// DEPRECATED: legacy name for [`FromSec1Point::from_sec1_point`].
58    #[deprecated(
59        since = "0.14.0",
60        note = "use `FromSec1Point::from_sec1_point` instead"
61    )]
62    fn from_encoded_point(point: &Sec1Point<C>) -> CtOption<Self> {
63        Self::from_sec1_point(point)
64    }
65}
66
67/// Encode curve point using the `Elliptic-Curve-Point-to-Octet-String` conversion described in
68/// [SEC 1: Elliptic Curve Cryptography (Version 2.0)](https://www.secg.org/sec1-v2.pdf)
69/// §2.3.3 (page 10).
70pub trait ToSec1Point<C>
71where
72    C: Curve,
73    FieldBytesSize<C>: ModulusSize,
74{
75    /// Serialize curve point as a SEC1 [`Sec1Point`], optionally applying point compression
76    /// according to the `compress` flag.
77    fn to_sec1_point(&self, compress: bool) -> Sec1Point<C>;
78
79    /// Encode curve point using the `Elliptic-Curve-Point-to-Octet-String` conversion and the
80    /// point compression default for this curve as specified by the [`PointCompression`] trait.
81    #[cfg(feature = "alloc")]
82    fn to_sec1_bytes(&self) -> Box<[u8]>
83    where
84        C: PointCompression,
85    {
86        self.to_sec1_point(C::COMPRESS_POINTS).to_bytes()
87    }
88
89    /// Serialize curve point as a [`CompressedPoint`].
90    fn to_compressed_point(&self) -> CompressedPoint<C> {
91        let mut ret = CompressedPoint::<C>::default();
92        ret.copy_from_slice(self.to_sec1_point(true).as_bytes());
93        ret
94    }
95
96    /// Serialize curve point as a [`CompressedPoint`].
97    fn to_uncompressed_point(&self) -> UncompressedPoint<C> {
98        let mut ret = UncompressedPoint::<C>::default();
99        ret.copy_from_slice(self.to_sec1_point(false).as_bytes());
100        ret
101    }
102
103    /// DEPRECATED: legacy name for [`ToSec1Point::to_sec1_point`].
104    #[deprecated(since = "0.14.0", note = "use `ToSec1Point::to_sec1_point` instead")]
105    fn to_encoded_point(&self, compress: bool) -> Sec1Point<C> {
106        self.to_sec1_point(compress)
107    }
108}
109
110/// DEPRECATED: stub trait to help discover the new name for [`FromSec1Point`].
111#[deprecated(since = "0.14.0", note = "use `FromSec1Point` instead")]
112pub trait FromEncodedPoint<C>: FromSec1Point<C>
113where
114    Self: Sized,
115    C: Curve,
116    FieldBytesSize<C>: ModulusSize,
117{
118}
119
120#[allow(deprecated)]
121impl<P, C> FromEncodedPoint<C> for P
122where
123    Self: FromSec1Point<C> + Sized,
124    C: Curve,
125    FieldBytesSize<C>: ModulusSize,
126{
127}
128
129/// DEPRECATED: stub trait to help discover the new name for [`ToSec1Point`].
130#[deprecated(since = "0.14.0", note = "use `ToSec1Point` instead")]
131pub trait ToEncodedPoint<C>: ToSec1Point<C>
132where
133    C: Curve,
134    FieldBytesSize<C>: ModulusSize,
135{
136}
137
138#[allow(deprecated)]
139impl<T, C> ToEncodedPoint<C> for T
140where
141    Self: ToSec1Point<C>,
142    C: Curve,
143    FieldBytesSize<C>: ModulusSize,
144{
145}
146
147/// Trait for serializing a value to a SEC1 encoded curve point with compaction.
148///
149/// This is intended for use with the `AffinePoint` type for a given elliptic curve.
150pub trait ToCompactSec1Point<C>
151where
152    C: Curve,
153    FieldBytesSize<C>: ModulusSize,
154{
155    /// Serialize this value as a SEC1 [`Sec1Point`], optionally applying
156    /// point compression.
157    fn to_compact_encoded_point(&self) -> CtOption<Sec1Point<C>>;
158}
159
160/// Validate that the given [`Sec1Point`] represents the encoded public key
161/// value of the given secret.
162///
163/// Curve implementations which also impl [`CurveArithmetic`] will receive a blanket default impl of
164/// this trait.
165pub trait ValidatePublicKey
166where
167    Self: Curve,
168    FieldBytesSize<Self>: ModulusSize,
169{
170    /// Validate that the given [`Sec1Point`] is a valid public key for the provided secret value.
171    ///
172    /// # Errors
173    /// If the given SEC1 point does not represent the correct public key for this secret key.
174    #[allow(unused_variables)]
175    fn validate_public_key(
176        secret_key: &SecretKey<Self>,
177        public_key: &Sec1Point<Self>,
178    ) -> Result<()> {
179        // Provide a default "always succeeds" implementation.
180        // This is the intended default for curve implementations which
181        // do not provide an arithmetic implementation, since they have no
182        // way to verify this.
183        //
184        // Implementations with an arithmetic impl will receive a blanket impl
185        // of this trait.
186        Ok(())
187    }
188}
189
190#[cfg(feature = "arithmetic")]
191impl<C> ValidatePublicKey for C
192where
193    C: CurveArithmetic,
194    AffinePoint<C>: FromSec1Point<C> + ToSec1Point<C>,
195    FieldBytesSize<C>: ModulusSize,
196{
197    fn validate_public_key(secret_key: &SecretKey<C>, public_key: &Sec1Point<C>) -> Result<()> {
198        let pk = secret_key
199            .public_key()
200            .to_sec1_point(public_key.is_compressed());
201
202        if public_key == &pk {
203            Ok(())
204        } else {
205            Err(Error)
206        }
207    }
208}