Skip to main content

xdid_method_key/keys/
p384.rs

1use jose_jwk::Jwk;
2use p384::{
3    SecretKey,
4    ecdsa::{
5        Signature,
6        SigningKey,
7        signature::Signer as _,
8    },
9    elliptic_curve::{
10        rand_core::OsRng,
11        sec1::{
12            FromEncodedPoint,
13            ToEncodedPoint,
14        },
15        zeroize::Zeroizing,
16    },
17    pkcs8::{
18        DecodePrivateKey,
19        EncodePrivateKey,
20        LineEnding,
21    },
22};
23
24use super::{
25    DidKeyPair,
26    KeyParser,
27    Multicodec,
28    PublicKey,
29    Signer,
30    WithMulticodec,
31};
32use crate::parser::ParseError;
33
34/// Multicodec `p384-pub`, as an unsigned varint.
35const CODE: &[u8] = &[0x81, 0x24];
36
37#[derive(Clone)]
38pub struct P384KeyPair(SecretKey);
39
40impl DidKeyPair for P384KeyPair {
41    fn generate() -> Self {
42        let mut rng = OsRng;
43        Self(SecretKey::random(&mut rng))
44    }
45
46    fn public(&self) -> impl PublicKey {
47        P384PublicKey(self.0.public_key())
48    }
49
50    fn to_pkcs8_pem(&self) -> anyhow::Result<Zeroizing<String>> {
51        Ok(self.0.to_pkcs8_pem(LineEnding::LF)?)
52    }
53
54    fn from_pkcs8_pem(pem: &str) -> anyhow::Result<Self> {
55        Ok(Self(SecretKey::from_pkcs8_pem(pem)?))
56    }
57}
58
59impl Signer for P384KeyPair {
60    fn sign(&self, message: &[u8]) -> anyhow::Result<Vec<u8>> {
61        let signing_key = SigningKey::from(&self.0);
62        let sig: Signature = signing_key.try_sign(message)?;
63        Ok(sig.to_der().as_bytes().to_vec())
64    }
65}
66
67#[derive(Clone, PartialEq, Eq)]
68struct P384PublicKey(p384::PublicKey);
69
70impl PublicKey for P384PublicKey {
71    fn to_encoded_point_bytes(&self) -> Box<[u8]> {
72        self.0.to_encoded_point(true).as_bytes().into()
73    }
74
75    fn to_jwk(&self) -> Jwk {
76        let jwk_str = self.0.to_jwk_string();
77        serde_json::from_str(&jwk_str).expect("p384 crate guarantees valid JWK")
78    }
79}
80
81impl WithMulticodec for P384PublicKey {
82    fn codec(&self) -> Box<dyn Multicodec> {
83        Box::new(P384Codec)
84    }
85}
86
87pub(crate) struct P384KeyParser;
88
89impl KeyParser for P384KeyParser {
90    fn parse(&self, public_key: &[u8]) -> Result<Box<dyn PublicKey>, ParseError> {
91        let point =
92            p384::EncodedPoint::from_bytes(public_key).map_err(|_| ParseError::InvalidPublicKey)?;
93        let key = p384::PublicKey::from_encoded_point(&point)
94            .into_option()
95            .ok_or(ParseError::InvalidPublicKey)?;
96        Ok(Box::new(P384PublicKey(key)))
97    }
98}
99
100impl WithMulticodec for P384KeyParser {
101    fn codec(&self) -> Box<dyn Multicodec> {
102        Box::new(P384Codec)
103    }
104}
105
106struct P384Codec;
107
108impl Multicodec for P384Codec {
109    fn code(&self) -> &'static [u8] {
110        CODE
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use p384::ecdsa::{
117        Signature as EcdsaSignature,
118        VerifyingKey,
119        signature::Verifier,
120    };
121
122    use super::*;
123    use crate::parser::DidKeyParser;
124
125    #[test]
126    fn test_display() {
127        let did = P384KeyPair::generate().public().to_did();
128        assert!(did.to_string().starts_with("did:key:z82"));
129    }
130
131    #[test]
132    fn test_jwk() {
133        let _ = P384KeyPair::generate().public().to_jwk();
134    }
135
136    #[test]
137    fn test_jwk_has_no_private_component() {
138        let jwk = P384KeyPair::generate().public().to_jwk();
139        let json = serde_json::to_string(&jwk).expect("serialization should succeed");
140
141        assert!(!json.contains("\"d\""), "private scalar leaked into JWK");
142    }
143
144    #[test]
145    fn test_parse() {
146        let did = P384KeyPair::generate().public().to_did();
147        DidKeyParser::default()
148            .parse(&did)
149            .expect("parse should succeed");
150    }
151
152    #[test]
153    fn test_sign_verify() {
154        let pair = P384KeyPair::generate();
155
156        let msg = vec![0, 1, 2, 3, 4, 5, 6, 7, 8];
157        let signature = pair.sign(&msg).expect("signing should succeed");
158
159        let verifying_key = VerifyingKey::from(pair.0.public_key());
160        let sig = EcdsaSignature::from_der(&signature).expect("valid signature");
161        verifying_key
162            .verify(&msg, &sig)
163            .expect("verification should succeed");
164    }
165}