identity_jose/jwk/conversion/
from_jwk.rs

1// Copyright 2020-2025 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::error::Error;
5use crate::jwk::Jwk;
6use crate::jwk::JwkParams;
7use crate::jwk::JwkParamsEc;
8use crate::jwu;
9use anyhow::anyhow;
10use anyhow::Context as _;
11use fastcrypto::ed25519::Ed25519KeyPair;
12use fastcrypto::ed25519::Ed25519PublicKey;
13use fastcrypto::secp256k1::Secp256k1KeyPair;
14use fastcrypto::secp256r1::Secp256r1KeyPair;
15use iota_interaction::types::crypto::IotaKeyPair;
16use iota_interaction::types::crypto::PublicKey;
17use iota_interaction::types::crypto::SignatureScheme as IotaSignatureScheme;
18
19use super::ed25519;
20use super::secp256k1;
21use super::secp256r1;
22
23/// Helper trait to convert implementing conversion from `Jwk`.
24pub trait FromJwk: Sized {
25  /// Error type used
26  type Error;
27
28  /// Create instance from `Jwk`.
29  fn from_jwk(jwk: &Jwk) -> Result<Self, Self::Error>;
30}
31
32impl FromJwk for IotaKeyPair {
33  type Error = Error;
34
35  fn from_jwk(jwk: &Jwk) -> Result<Self, Self::Error> {
36    let maybe_ed22519 = Ed25519KeyPair::from_jwk(jwk).map(IotaKeyPair::from);
37    let maybe_secp256r1 = Secp256r1KeyPair::from_jwk(jwk).map(IotaKeyPair::from);
38    let maybe_secp256k1 = Secp256k1KeyPair::from_jwk(jwk).map(IotaKeyPair::from);
39
40    maybe_ed22519
41      .or(maybe_secp256k1)
42      .or(maybe_secp256r1)
43      .map_err(|err| Error::KeyConversion(err.to_string()))
44  }
45}
46
47impl FromJwk for PublicKey {
48  type Error = Error;
49
50  fn from_jwk(jwk: &Jwk) -> Result<Self, Self::Error> {
51    match jwk.params() {
52      JwkParams::Okp(params) => {
53        if params.crv != "Ed25519" {
54          return Err(Error::KeyConversion(format!("unsupported key type {}", params.crv)));
55        }
56
57        jwu::decode_b64(&params.x)
58          .context("failed to base64 decode key")
59          .and_then(|pk_bytes| {
60            PublicKey::try_from_bytes(IotaSignatureScheme::ED25519, &pk_bytes).map_err(|e| anyhow!("{e}"))
61          })
62          .map_err(|err| Error::KeyConversion(err.to_string()))
63      }
64      JwkParams::Ec(JwkParamsEc { crv, x, y, .. }) => {
65        let pk_bytes = {
66          let mut decoded_x_bytes =
67            jwu::decode_b64(x).map_err(|e| Error::KeyConversion(format!("failed to decode b64 x parameter: {e}")))?;
68          let decoded_y_bytes =
69            jwu::decode_b64(y).map_err(|e| Error::KeyConversion(format!("failed to decode b64 y parameter: {e}")))?;
70
71          // build compressed public key
72          let last_y = decoded_y_bytes
73            .last()
74            .ok_or_else(|| Error::KeyConversion("y parameter should not be empty".to_string()))?;
75          if last_y % 2 == 0 {
76            decoded_x_bytes.insert(0, 2);
77          } else {
78            decoded_x_bytes.insert(0, 3);
79          }
80
81          decoded_x_bytes
82        };
83
84        if jwk.alg() == Some("ES256") || crv == "P-256" {
85          PublicKey::try_from_bytes(IotaSignatureScheme::Secp256r1, &pk_bytes)
86            .map_err(|e| Error::KeyConversion(format!("not a secp256r1 key: {e}")))
87        } else if jwk.alg() == Some("ES256K") || crv == "K-256" || crv == "secp256k1" {
88          PublicKey::try_from_bytes(IotaSignatureScheme::Secp256k1, &pk_bytes)
89            .map_err(|e| Error::KeyConversion(format!("not a secp256k1 key: {e}")))
90        } else {
91          Err(Error::KeyError("invalid EC key"))
92        }
93      }
94      _ => Err(Error::KeyConversion("unsupported key".to_string())),
95    }
96  }
97}
98
99impl FromJwk for Ed25519KeyPair {
100  type Error = Error;
101
102  fn from_jwk(jwk: &Jwk) -> Result<Self, Self::Error> {
103    ed25519::jwk_to_keypair(jwk).map_err(|err| Error::KeyConversion(err.to_string()))
104  }
105}
106
107impl FromJwk for Secp256r1KeyPair {
108  type Error = Error;
109
110  fn from_jwk(jwk: &Jwk) -> Result<Self, Self::Error> {
111    secp256r1::jwk_to_keypair(jwk).map_err(|err| Error::KeyConversion(err.to_string()))
112  }
113}
114
115impl FromJwk for Secp256k1KeyPair {
116  type Error = Error;
117
118  fn from_jwk(jwk: &Jwk) -> Result<Self, Self::Error> {
119    secp256k1::jwk_to_keypair(jwk).map_err(|err| Error::KeyConversion(err.to_string()))
120  }
121}
122
123impl FromJwk for Ed25519PublicKey {
124  type Error = Error;
125
126  fn from_jwk(jwk: &Jwk) -> Result<Self, Self::Error> {
127    ed25519::from_public_jwk(jwk).map_err(|err| Error::KeyConversion(err.to_string()))
128  }
129}
130
131#[cfg(test)]
132mod tests {
133  use super::FromJwk;
134  use crate::jwk::Jwk;
135  use crate::jwu::encode_b64;
136
137  #[derive(PartialEq)]
138  enum KeyType {
139    Private,
140    Public,
141  }
142
143  fn get_ed25519_jwk(key_type: KeyType) -> Jwk {
144    use fastcrypto::traits::KeyPair as _;
145
146    let keypair = fastcrypto::ed25519::Ed25519KeyPair::generate(&mut rand::thread_rng());
147    let mut params = crate::jwk::JwkParamsOkp::new();
148    let x = encode_b64(keypair.public().as_ref());
149    params.x = x;
150    if key_type == KeyType::Private {
151      let d = encode_b64(keypair.private().as_ref());
152      params.d = Some(d);
153    }
154    params.crv = crate::jwk::EdCurve::Ed25519.name().to_string();
155
156    Jwk::from_params(params)
157  }
158
159  fn get_secp256r1_jwk(key_type: KeyType) -> Jwk {
160    let sk = p256::SecretKey::random(&mut rand::thread_rng());
161    let jwk_string = if key_type == KeyType::Private {
162      &sk.to_jwk_string()
163    } else {
164      &sk.public_key().to_jwk_string()
165    };
166    let jwk: Jwk = serde_json::from_str(jwk_string).unwrap();
167
168    jwk
169  }
170
171  fn get_secp256k1_jwk(key_type: KeyType) -> Jwk {
172    let sk = k256::SecretKey::random(&mut rand::thread_rng());
173    let jwk_string = if key_type == KeyType::Private {
174      &sk.to_jwk_string()
175    } else {
176      &sk.public_key().to_jwk_string()
177    };
178    let jwk: Jwk = serde_json::from_str(jwk_string).unwrap();
179    dbg!(jwk_string);
180
181    jwk
182  }
183
184  #[test]
185  fn can_convert_from_jwk_to_ed22519_iota_keypair() {
186    let jwk = get_ed25519_jwk(KeyType::Private);
187    let result = iota_interaction::types::crypto::IotaKeyPair::from_jwk(&jwk);
188
189    assert!(result.is_ok());
190  }
191
192  #[test]
193  fn can_convert_from_jwk_to_ecp256r1_iota_keypair() {
194    let jwk = get_secp256r1_jwk(KeyType::Private);
195    let result = iota_interaction::types::crypto::IotaKeyPair::from_jwk(&jwk);
196    dbg!(&result);
197
198    assert!(result.is_ok());
199  }
200
201  #[test]
202  fn can_convert_from_jwk_to_secp256k1_iota_keypair() {
203    let jwk = get_secp256k1_jwk(KeyType::Private);
204    let result = iota_interaction::types::crypto::IotaKeyPair::from_jwk(&jwk);
205    dbg!(&result);
206
207    assert!(result.is_ok());
208  }
209
210  #[test]
211  fn can_convert_from_octet_keypair_jwk_to_iota_public_key() {
212    let jwk = get_ed25519_jwk(KeyType::Public);
213    let result = iota_interaction::types::crypto::PublicKey::from_jwk(&jwk);
214
215    assert!(result.is_ok());
216  }
217
218  #[test]
219  fn can_convert_from_secp256r1_jwk_to_iota_public_key() {
220    let jwk = get_secp256r1_jwk(KeyType::Public);
221    let result = iota_interaction::types::crypto::PublicKey::from_jwk(&jwk);
222
223    assert!(result.is_ok());
224  }
225
226  #[test]
227  fn can_convert_from_secp256k1_jwk_to_iota_public_key() {
228    let jwk = get_secp256k1_jwk(KeyType::Public);
229    let result = iota_interaction::types::crypto::PublicKey::from_jwk(&jwk);
230
231    assert!(result.is_ok());
232  }
233
234  #[test]
235  fn can_convert_from_jwk_to_ed25519_key_pair() {
236    let jwk = get_ed25519_jwk(KeyType::Private);
237    let result = fastcrypto::ed25519::Ed25519KeyPair::from_jwk(&jwk);
238
239    assert!(result.is_ok());
240  }
241
242  #[test]
243  fn can_convert_from_jwk_to_secp256r1_key_pair() {
244    let jwk = get_secp256r1_jwk(KeyType::Private);
245    let result = fastcrypto::secp256r1::Secp256r1KeyPair::from_jwk(&jwk);
246
247    assert!(result.is_ok());
248  }
249
250  #[test]
251  fn can_convert_from_jwk_to_secp256k1_key_pair() {
252    let jwk = get_secp256k1_jwk(KeyType::Private);
253    let result = fastcrypto::secp256k1::Secp256k1KeyPair::from_jwk(&jwk);
254
255    assert!(result.is_ok());
256  }
257
258  #[test]
259  fn can_convert_from_jwk_to_ed25519_public_key() {
260    let jwk = get_ed25519_jwk(KeyType::Public);
261    let result = fastcrypto::ed25519::Ed25519PublicKey::from_jwk(&jwk);
262
263    assert!(result.is_ok());
264  }
265}