xdid_method_key/keys/
p256.rs

1use jose_jwk::Jwk;
2use p256::{
3    SecretKey,
4    elliptic_curve::{
5        rand_core::OsRng,
6        sec1::{FromEncodedPoint, ToEncodedPoint},
7        zeroize::Zeroizing,
8    },
9    pkcs8::{DecodePrivateKey, EncodePrivateKey, LineEnding},
10};
11use ring::{
12    rand::SystemRandom,
13    signature::{ECDSA_P256_SHA256_ASN1_SIGNING, EcdsaKeyPair},
14};
15
16use super::{DidKeyPair, KeyParser, Multicodec, PublicKey, Signer, WithMulticodec};
17
18#[derive(Clone, PartialEq, Eq)]
19pub struct P256KeyPair(SecretKey);
20
21impl DidKeyPair for P256KeyPair {
22    fn generate() -> Self {
23        let mut rng = OsRng;
24        let secret = SecretKey::random(&mut rng);
25        Self(secret)
26    }
27
28    fn public(&self) -> impl PublicKey {
29        P256PublicKey(self.0.public_key())
30    }
31
32    fn to_pkcs8_pem(&self) -> anyhow::Result<Zeroizing<String>> {
33        let pem = self.0.to_pkcs8_pem(LineEnding::LF)?;
34        Ok(pem)
35    }
36    fn from_pkcs8_pem(pem: &str) -> anyhow::Result<Self> {
37        let key = SecretKey::from_pkcs8_pem(pem)?;
38        Ok(Self(key))
39    }
40}
41
42impl Signer for P256KeyPair {
43    fn sign(&self, message: &[u8]) -> anyhow::Result<Vec<u8>> {
44        let rng = SystemRandom::new();
45
46        let signer = EcdsaKeyPair::from_private_key_and_public_key(
47            &ECDSA_P256_SHA256_ASN1_SIGNING,
48            &self.0.to_bytes(),
49            &self.0.public_key().to_sec1_bytes(),
50            &rng,
51        )
52        .map_err(|_| anyhow::anyhow!("failed to create key pair from private key"))?;
53
54        signer
55            .sign(&rng, message)
56            .map(|v| v.as_ref().to_vec())
57            .map_err(|_| anyhow::anyhow!("signing failed"))
58    }
59}
60
61#[derive(Clone, PartialEq, Eq)]
62struct P256PublicKey(p256::PublicKey);
63
64impl PublicKey for P256PublicKey {
65    fn to_sec1_bytes(&self) -> Box<[u8]> {
66        self.0.to_sec1_bytes()
67    }
68    fn to_encoded_point_bytes(&self) -> Box<[u8]> {
69        self.0.to_encoded_point(true).as_bytes().into()
70    }
71
72    fn to_jwk(&self) -> Jwk {
73        let jwk_str = self.0.to_jwk_string();
74        serde_json::from_str(&jwk_str).expect("p256 crate guarantees valid JWK")
75    }
76}
77
78impl WithMulticodec for P256PublicKey {
79    fn codec(&self) -> Box<dyn Multicodec> {
80        Box::new(P256Codec)
81    }
82}
83
84pub(crate) struct P256KeyParser;
85
86impl KeyParser for P256KeyParser {
87    fn parse(&self, public_key: Vec<u8>) -> Result<Box<dyn PublicKey>, crate::parser::ParseError> {
88        let point = p256::EncodedPoint::from_bytes(public_key)
89            .map_err(|_| crate::parser::ParseError::InvalidPublicKey)?;
90        let key = p256::PublicKey::from_encoded_point(&point)
91            .into_option()
92            .ok_or(crate::parser::ParseError::InvalidPublicKey)?;
93        Ok(Box::new(P256PublicKey(key)))
94    }
95}
96
97impl WithMulticodec for P256KeyParser {
98    fn codec(&self) -> Box<dyn Multicodec> {
99        Box::new(P256Codec)
100    }
101}
102
103struct P256Codec;
104
105impl Multicodec for P256Codec {
106    fn code_u64(&self) -> u64 {
107        0x1200
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use ring::signature::{ECDSA_P256_SHA256_ASN1, VerificationAlgorithm};
114
115    use crate::parser::DidKeyParser;
116
117    use super::*;
118
119    #[test]
120    fn test_display() {
121        let pair = P256KeyPair::generate();
122        let did = pair.public().to_did();
123
124        let did_str = did.to_string();
125        println!("{did_str}");
126        assert!(did_str.starts_with("did:key:zDn"));
127    }
128
129    #[test]
130    fn test_jwk() {
131        let pair = P256KeyPair::generate();
132        let _ = pair.public().to_jwk();
133    }
134
135    #[test]
136    fn test_parse() {
137        let pair = P256KeyPair::generate();
138        let did = pair.public().to_did();
139
140        let parser = DidKeyParser::default();
141        let _ = parser.parse(&did).expect("parse should succeed");
142    }
143
144    #[test]
145    fn test_sign_verify() {
146        let pair = P256KeyPair::generate();
147
148        let msg = vec![0, 1, 2, 3, 4, 5, 6, 7, 8];
149        let signature = pair.sign(&msg).expect("signing should succeed");
150
151        if let Err(e) = ECDSA_P256_SHA256_ASN1.verify(
152            pair.public().to_sec1_bytes().as_ref().into(),
153            msg.as_slice().into(),
154            signature.as_slice().into(),
155        ) {
156            panic!("{e:?}")
157        }
158    }
159}