Skip to main content

uselesskey_ecdsa/
spec.rs

1/// ECDSA algorithm specification.
2///
3/// # Examples
4///
5/// ```
6/// use uselesskey_ecdsa::EcdsaSpec;
7///
8/// let es256 = EcdsaSpec::es256();
9/// assert_eq!(es256.alg_name(), "ES256");
10/// assert_eq!(es256.curve_name(), "P-256");
11///
12/// let es384 = EcdsaSpec::es384();
13/// assert_eq!(es384.alg_name(), "ES384");
14/// assert_eq!(es384.curve_name(), "P-384");
15/// ```
16#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
17pub enum EcdsaSpec {
18    /// P-256 / secp256r1 / prime256v1 (for ES256 JWT signing).
19    Es256,
20    /// P-384 / secp384r1 (for ES384 JWT signing).
21    Es384,
22}
23
24impl EcdsaSpec {
25    /// Spec suitable for ES256 JWT signing.
26    ///
27    /// # Examples
28    ///
29    /// ```
30    /// use uselesskey_ecdsa::EcdsaSpec;
31    ///
32    /// let spec = EcdsaSpec::es256();
33    /// assert_eq!(spec.alg_name(), "ES256");
34    /// assert_eq!(spec.curve_name(), "P-256");
35    /// ```
36    pub fn es256() -> Self {
37        Self::Es256
38    }
39
40    /// Spec suitable for ES384 JWT signing.
41    ///
42    /// # Examples
43    ///
44    /// ```
45    /// use uselesskey_ecdsa::EcdsaSpec;
46    ///
47    /// let spec = EcdsaSpec::es384();
48    /// assert_eq!(spec.alg_name(), "ES384");
49    /// assert_eq!(spec.curve_name(), "P-384");
50    /// ```
51    pub fn es384() -> Self {
52        Self::Es384
53    }
54
55    /// Returns the JWT algorithm name.
56    ///
57    /// # Examples
58    ///
59    /// ```
60    /// use uselesskey_ecdsa::EcdsaSpec;
61    ///
62    /// assert_eq!(EcdsaSpec::es256().alg_name(), "ES256");
63    /// assert_eq!(EcdsaSpec::es384().alg_name(), "ES384");
64    /// ```
65    pub fn alg_name(&self) -> &'static str {
66        match self {
67            Self::Es256 => "ES256",
68            Self::Es384 => "ES384",
69        }
70    }
71
72    /// Returns the curve name.
73    ///
74    /// # Examples
75    ///
76    /// ```
77    /// use uselesskey_ecdsa::EcdsaSpec;
78    ///
79    /// assert_eq!(EcdsaSpec::es256().curve_name(), "P-256");
80    /// assert_eq!(EcdsaSpec::es384().curve_name(), "P-384");
81    /// ```
82    pub fn curve_name(&self) -> &'static str {
83        match self {
84            Self::Es256 => "P-256",
85            Self::Es384 => "P-384",
86        }
87    }
88
89    /// Returns the expected coordinate length in bytes for uncompressed points.
90    ///
91    /// # Examples
92    ///
93    /// ```
94    /// use uselesskey_ecdsa::EcdsaSpec;
95    ///
96    /// assert_eq!(EcdsaSpec::es256().coordinate_len_bytes(), 32);
97    /// assert_eq!(EcdsaSpec::es384().coordinate_len_bytes(), 48);
98    /// ```
99    pub fn coordinate_len_bytes(&self) -> usize {
100        match self {
101            Self::Es256 => 32,
102            Self::Es384 => 48,
103        }
104    }
105
106    /// Stable encoding for cache keys / deterministic derivation.
107    ///
108    /// If you change this, bump the derivation version in `uselesskey-core`.
109    ///
110    /// # Examples
111    ///
112    /// ```
113    /// use uselesskey_ecdsa::EcdsaSpec;
114    ///
115    /// let bytes = EcdsaSpec::es256().stable_bytes();
116    /// assert_eq!(bytes.len(), 4);
117    /// ```
118    pub fn stable_bytes(&self) -> [u8; 4] {
119        match self {
120            Self::Es256 => [0, 0, 0, 1],
121            Self::Es384 => [0, 0, 0, 2],
122        }
123    }
124}
125
126#[cfg(test)]
127mod tests {
128    use super::*;
129
130    #[test]
131    fn alg_and_curve_names_match_specs() {
132        let es256 = EcdsaSpec::es256();
133        assert_eq!(es256.alg_name(), "ES256");
134        assert_eq!(es256.curve_name(), "P-256");
135        assert_eq!(es256.coordinate_len_bytes(), 32);
136
137        let es384 = EcdsaSpec::es384();
138        assert_eq!(es384.alg_name(), "ES384");
139        assert_eq!(es384.curve_name(), "P-384");
140        assert_eq!(es384.coordinate_len_bytes(), 48);
141    }
142
143    #[test]
144    fn stable_bytes_are_unique() {
145        let es256 = EcdsaSpec::es256().stable_bytes();
146        let es384 = EcdsaSpec::es384().stable_bytes();
147        assert_ne!(es256, es384);
148    }
149}