use anyhow::Result;
use atproto_identity::key::{KeyData, KeyType, to_public};
use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD};
use elliptic_curve::{JwkEcKey, sec1::ToEncodedPoint};
use serde::{Deserialize, Serialize};
use serde_json::json;
use sha2::{Digest, Sha256};
use crate::errors::JWKError;
#[cfg(feature = "zeroize")]
use zeroize::{Zeroize, ZeroizeOnDrop};
#[derive(Serialize, Deserialize, Clone, PartialEq)]
#[cfg_attr(debug_assertions, derive(Debug))]
#[cfg_attr(feature = "zeroize", derive(Zeroize, ZeroizeOnDrop))]
pub struct WrappedJsonWebKey {
#[serde(skip_serializing_if = "Option::is_none", default)]
#[cfg_attr(feature = "zeroize", zeroize(skip))]
pub kid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", default)]
#[cfg_attr(feature = "zeroize", zeroize(skip))]
pub alg: Option<String>,
#[serde(rename = "use", skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "zeroize", zeroize(skip))]
pub _use: Option<String>,
#[serde(flatten)]
pub jwk: JwkEcKey,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct WrappedJsonWebKeySet {
pub keys: Vec<WrappedJsonWebKey>,
}
pub fn generate(key_data: &KeyData) -> Result<WrappedJsonWebKey> {
let alg = match key_data.key_type() {
KeyType::P256Public => Some("ES256".to_string()),
KeyType::P256Private => Some("ES256".to_string()),
KeyType::P384Public => Some("ES384".to_string()),
KeyType::P384Private => Some("ES384".to_string()),
KeyType::K256Public => Some("ES256K".to_string()),
KeyType::K256Private => Some("ES256K".to_string()),
};
let jwk = key_data.try_into()?;
let public_key = to_public(key_data)?;
let kid = Some(public_key.to_string());
Ok(WrappedJsonWebKey {
kid,
alg,
jwk,
_use: Some("sig".to_string()),
})
}
pub fn to_key_data(wrapped_jwk: &WrappedJsonWebKey) -> Result<KeyData, JWKError> {
let curve = wrapped_jwk.jwk.crv();
match curve {
"P-256" => {
if let Ok(secret_key) = p256::SecretKey::try_from(&wrapped_jwk.jwk) {
Ok(KeyData::new(
KeyType::P256Private,
secret_key.to_bytes().to_vec(),
))
} else if let Ok(public_key) = p256::PublicKey::try_from(&wrapped_jwk.jwk) {
let compressed = public_key.to_encoded_point(true);
Ok(KeyData::new(
KeyType::P256Public,
compressed.as_bytes().to_vec(),
))
} else {
Err(JWKError::P256ConversionFailed)
}
}
"P-384" => {
if let Ok(secret_key) = p384::SecretKey::try_from(&wrapped_jwk.jwk) {
Ok(KeyData::new(
KeyType::P384Private,
secret_key.to_bytes().to_vec(),
))
} else if let Ok(public_key) = p384::PublicKey::try_from(&wrapped_jwk.jwk) {
let compressed = public_key.to_encoded_point(true);
Ok(KeyData::new(
KeyType::P384Public,
compressed.as_bytes().to_vec(),
))
} else {
Err(JWKError::P384ConversionFailed)
}
}
"secp256k1" => {
if let Ok(secret_key) = k256::SecretKey::try_from(&wrapped_jwk.jwk) {
Ok(KeyData::new(
KeyType::K256Private,
secret_key.to_bytes().to_vec(),
))
} else if let Ok(public_key) = k256::PublicKey::try_from(&wrapped_jwk.jwk) {
let compressed = public_key.to_encoded_point(true);
Ok(KeyData::new(
KeyType::K256Public,
compressed.as_bytes().to_vec(),
))
} else {
Err(JWKError::K256ConversionFailed)
}
}
_ => Err(JWKError::UnsupportedCurve {
curve: curve.to_string(),
}),
}
}
pub fn thumbprint(wrapped_jwk: &WrappedJsonWebKey) -> Result<String, JWKError> {
let jwk_json =
serde_json::to_value(&wrapped_jwk.jwk).map_err(|e| JWKError::SerializationError {
message: e.to_string(),
})?;
let jwk_obj = jwk_json
.as_object()
.ok_or_else(|| JWKError::SerializationError {
message: "JWK is not a JSON object".to_string(),
})?;
let kty =
jwk_obj
.get("kty")
.and_then(|v| v.as_str())
.ok_or_else(|| JWKError::MissingField {
field: "kty".to_string(),
})?;
if kty != "EC" {
return Err(JWKError::UnsupportedKeyType {
kty: kty.to_string(),
});
}
let crv = jwk_obj.get("crv").ok_or_else(|| JWKError::MissingField {
field: "crv".to_string(),
})?;
let x = jwk_obj.get("x").ok_or_else(|| JWKError::MissingField {
field: "x".to_string(),
})?;
let y = jwk_obj.get("y").ok_or_else(|| JWKError::MissingField {
field: "y".to_string(),
})?;
let thumbprint_json = json!({
"crv": crv,
"kty": kty,
"x": x,
"y": y
});
let canonical_json =
serde_json::to_string(&thumbprint_json).map_err(|e| JWKError::SerializationError {
message: e.to_string(),
})?;
let mut hasher = Sha256::new();
hasher.update(canonical_json.as_bytes());
let hash = hasher.finalize();
Ok(URL_SAFE_NO_PAD.encode(hash))
}
impl TryFrom<WrappedJsonWebKey> for KeyData {
type Error = anyhow::Error;
fn try_from(wrapped_jwk: WrappedJsonWebKey) -> Result<Self, Self::Error> {
to_key_data(&wrapped_jwk).map_err(Into::into)
}
}
impl TryFrom<&WrappedJsonWebKey> for KeyData {
type Error = anyhow::Error;
fn try_from(wrapped_jwk: &WrappedJsonWebKey) -> Result<Self, Self::Error> {
to_key_data(wrapped_jwk).map_err(Into::into)
}
}
#[cfg(test)]
mod tests {
use super::*;
use atproto_identity::key::{generate_key, sign, to_public, validate};
#[test]
fn test_to_key_data_p256_private_round_trip() -> Result<()> {
let original_key = generate_key(KeyType::P256Private)?;
let wrapped_jwk = generate(&original_key)?;
assert_eq!(wrapped_jwk.alg, Some("ES256".to_string()));
assert_eq!(wrapped_jwk._use, Some("sig".to_string()));
assert_eq!(wrapped_jwk.jwk.crv(), "P-256");
let converted_key = to_key_data(&wrapped_jwk)?;
assert_eq!(*converted_key.key_type(), KeyType::P256Private);
assert_eq!(original_key.bytes(), converted_key.bytes());
let test_data = "P-256 private key round trip test".as_bytes();
let signature = sign(&converted_key, test_data)?;
validate(&converted_key, &signature, test_data)?;
Ok(())
}
#[test]
fn test_to_key_data_p256_public_round_trip() -> Result<()> {
let private_key = generate_key(KeyType::P256Private)?;
let original_public_key = to_public(&private_key)?;
let wrapped_jwk = generate(&original_public_key)?;
assert_eq!(wrapped_jwk.alg, Some("ES256".to_string()));
assert_eq!(wrapped_jwk.jwk.crv(), "P-256");
let converted_key = to_key_data(&wrapped_jwk)?;
assert_eq!(*converted_key.key_type(), KeyType::P256Public);
assert_eq!(original_public_key.bytes(), converted_key.bytes());
let test_data = "P-256 public key round trip test".as_bytes();
let signature = sign(&private_key, test_data)?;
validate(&converted_key, &signature, test_data)?;
Ok(())
}
#[test]
fn test_to_key_data_p384_private_round_trip() -> Result<()> {
let original_key = generate_key(KeyType::P384Private)?;
let wrapped_jwk = generate(&original_key)?;
assert_eq!(wrapped_jwk.alg, Some("ES384".to_string()));
assert_eq!(wrapped_jwk._use, Some("sig".to_string()));
assert_eq!(wrapped_jwk.jwk.crv(), "P-384");
let converted_key = to_key_data(&wrapped_jwk)?;
assert_eq!(*converted_key.key_type(), KeyType::P384Private);
assert_eq!(original_key.bytes(), converted_key.bytes());
let test_data = "P-384 private key round trip test".as_bytes();
let signature = sign(&converted_key, test_data)?;
validate(&converted_key, &signature, test_data)?;
Ok(())
}
#[test]
fn test_to_key_data_p384_public_round_trip() -> Result<()> {
let private_key = generate_key(KeyType::P384Private)?;
let original_public_key = to_public(&private_key)?;
let wrapped_jwk = generate(&original_public_key)?;
assert_eq!(wrapped_jwk.alg, Some("ES384".to_string()));
assert_eq!(wrapped_jwk.jwk.crv(), "P-384");
let converted_key = to_key_data(&wrapped_jwk)?;
assert_eq!(*converted_key.key_type(), KeyType::P384Public);
assert_eq!(original_public_key.bytes(), converted_key.bytes());
let test_data = "P-384 public key round trip test".as_bytes();
let signature = sign(&private_key, test_data)?;
validate(&converted_key, &signature, test_data)?;
Ok(())
}
#[test]
fn test_to_key_data_k256_private_round_trip() -> Result<()> {
let original_key = generate_key(KeyType::K256Private)?;
let wrapped_jwk = generate(&original_key)?;
assert_eq!(wrapped_jwk.alg, Some("ES256K".to_string()));
assert_eq!(wrapped_jwk._use, Some("sig".to_string()));
assert_eq!(wrapped_jwk.jwk.crv(), "secp256k1");
let converted_key = to_key_data(&wrapped_jwk)?;
assert_eq!(*converted_key.key_type(), KeyType::K256Private);
assert_eq!(original_key.bytes(), converted_key.bytes());
let test_data = "K-256 private key round trip test".as_bytes();
let signature = sign(&converted_key, test_data)?;
validate(&converted_key, &signature, test_data)?;
Ok(())
}
#[test]
fn test_to_key_data_k256_public_round_trip() -> Result<()> {
let private_key = generate_key(KeyType::K256Private)?;
let original_public_key = to_public(&private_key)?;
let wrapped_jwk = generate(&original_public_key)?;
assert_eq!(wrapped_jwk.alg, Some("ES256K".to_string()));
assert_eq!(wrapped_jwk.jwk.crv(), "secp256k1");
let converted_key = to_key_data(&wrapped_jwk)?;
assert_eq!(*converted_key.key_type(), KeyType::K256Public);
assert_eq!(original_public_key.bytes(), converted_key.bytes());
let test_data = "K-256 public key round trip test".as_bytes();
let signature = sign(&private_key, test_data)?;
validate(&converted_key, &signature, test_data)?;
Ok(())
}
#[test]
fn test_to_key_data_multiple_round_trips() -> Result<()> {
for _ in 0..3 {
let p256_private = generate_key(KeyType::P256Private)?;
let p256_private_jwk = generate(&p256_private)?;
let p256_private_converted = to_key_data(&p256_private_jwk)?;
assert_eq!(p256_private.bytes(), p256_private_converted.bytes());
let p256_public = to_public(&p256_private)?;
let p256_public_jwk = generate(&p256_public)?;
let p256_public_converted = to_key_data(&p256_public_jwk)?;
assert_eq!(p256_public.bytes(), p256_public_converted.bytes());
let p384_private = generate_key(KeyType::P384Private)?;
let p384_private_jwk = generate(&p384_private)?;
let p384_private_converted = to_key_data(&p384_private_jwk)?;
assert_eq!(p384_private.bytes(), p384_private_converted.bytes());
let p384_public = to_public(&p384_private)?;
let p384_public_jwk = generate(&p384_public)?;
let p384_public_converted = to_key_data(&p384_public_jwk)?;
assert_eq!(p384_public.bytes(), p384_public_converted.bytes());
let k256_private = generate_key(KeyType::K256Private)?;
let k256_private_jwk = generate(&k256_private)?;
let k256_private_converted = to_key_data(&k256_private_jwk)?;
assert_eq!(k256_private.bytes(), k256_private_converted.bytes());
let k256_public = to_public(&k256_private)?;
let k256_public_jwk = generate(&k256_public)?;
let k256_public_converted = to_key_data(&k256_public_jwk)?;
assert_eq!(k256_public.bytes(), k256_public_converted.bytes());
}
Ok(())
}
#[test]
fn test_to_key_data_cross_curve_verification() -> Result<()> {
let p256_private = generate_key(KeyType::P256Private)?;
let p384_private = generate_key(KeyType::P384Private)?;
let k256_private = generate_key(KeyType::K256Private)?;
let p256_jwk = generate(&p256_private)?;
let p384_jwk = generate(&p384_private)?;
let k256_jwk = generate(&k256_private)?;
let p256_converted = to_key_data(&p256_jwk)?;
let p384_converted = to_key_data(&p384_jwk)?;
let k256_converted = to_key_data(&k256_jwk)?;
let test_data = "Cross-curve verification test".as_bytes();
let p256_signature = sign(&p256_converted, test_data)?;
let p384_signature = sign(&p384_converted, test_data)?;
let k256_signature = sign(&k256_converted, test_data)?;
validate(&p256_converted, &p256_signature, test_data)?;
validate(&p384_converted, &p384_signature, test_data)?;
validate(&k256_converted, &k256_signature, test_data)?;
assert!(validate(&p256_converted, &p384_signature, test_data).is_err());
assert!(validate(&p256_converted, &k256_signature, test_data).is_err());
assert!(validate(&p384_converted, &p256_signature, test_data).is_err());
assert!(validate(&p384_converted, &k256_signature, test_data).is_err());
assert!(validate(&k256_converted, &p256_signature, test_data).is_err());
assert!(validate(&k256_converted, &p384_signature, test_data).is_err());
Ok(())
}
#[test]
fn test_to_key_data_algorithm_consistency() -> Result<()> {
let p256_key = generate_key(KeyType::P256Private)?;
let p384_key = generate_key(KeyType::P384Private)?;
let k256_key = generate_key(KeyType::K256Private)?;
let p256_jwk = generate(&p256_key)?;
let p384_jwk = generate(&p384_key)?;
let k256_jwk = generate(&k256_key)?;
assert_eq!(p256_jwk.alg, Some("ES256".to_string()));
assert_eq!(p384_jwk.alg, Some("ES384".to_string()));
assert_eq!(k256_jwk.alg, Some("ES256K".to_string()));
assert_eq!(p256_jwk.jwk.crv(), "P-256");
assert_eq!(p384_jwk.jwk.crv(), "P-384");
assert_eq!(k256_jwk.jwk.crv(), "secp256k1");
let p256_converted = to_key_data(&p256_jwk)?;
let p384_converted = to_key_data(&p384_jwk)?;
let k256_converted = to_key_data(&k256_jwk)?;
assert_eq!(*p256_converted.key_type(), KeyType::P256Private);
assert_eq!(*p384_converted.key_type(), KeyType::P384Private);
assert_eq!(*k256_converted.key_type(), KeyType::K256Private);
Ok(())
}
#[test]
fn test_to_key_data_key_sizes() -> Result<()> {
let p256_private = generate_key(KeyType::P256Private)?;
let p384_private = generate_key(KeyType::P384Private)?;
let k256_private = generate_key(KeyType::K256Private)?;
let p256_public = to_public(&p256_private)?;
let p384_public = to_public(&p384_private)?;
let k256_public = to_public(&k256_private)?;
let keys = [
(&p256_private, 32), (&p384_private, 48), (&k256_private, 32), (&p256_public, 33), (&p384_public, 49), (&k256_public, 33), ];
for (original_key, expected_size) in keys {
let jwk = generate(original_key)?;
let converted_key = to_key_data(&jwk)?;
assert_eq!(
converted_key.bytes().len(),
expected_size,
"Key size mismatch for {:?}",
original_key.key_type()
);
assert_eq!(original_key.bytes(), converted_key.bytes());
}
Ok(())
}
#[test]
fn test_to_key_data_did_string_consistency() -> Result<()> {
let test_keys = [
generate_key(KeyType::P256Private)?,
generate_key(KeyType::P384Private)?,
generate_key(KeyType::K256Private)?,
];
for original_key in test_keys {
let original_did = format!("{}", original_key);
let jwk = generate(&original_key)?;
let converted_key = to_key_data(&jwk)?;
let converted_did = format!("{}", converted_key);
assert_eq!(
original_did,
converted_did,
"DID string mismatch for {:?}",
original_key.key_type()
);
let public_key = to_public(&original_key)?;
let public_did = format!("{}", public_key);
let public_jwk = generate(&public_key)?;
let converted_public_key = to_key_data(&public_jwk)?;
let converted_public_did = format!("{}", converted_public_key);
assert_eq!(
public_did,
converted_public_did,
"Public DID string mismatch for {:?}",
public_key.key_type()
);
}
Ok(())
}
#[test]
fn test_to_key_data_unsupported_curve() {
let valid_key = generate_key(KeyType::P256Private).unwrap();
let valid_jwk = generate(&valid_key).unwrap();
let result = to_key_data(&valid_jwk);
assert!(result.is_ok());
}
#[test]
fn test_to_key_data_invalid_jwk_conversion() {
use serde_json::json;
let invalid_jwk_json = json!({
"kty": "EC",
"crv": "P-256",
"x": "invalid-base64-data!!!",
"y": "also-invalid-base64!!!"
});
let _jwk_result: Result<elliptic_curve::JwkEcKey, _> =
serde_json::from_value(invalid_jwk_json);
let p256_key = generate_key(KeyType::P256Private).unwrap();
let valid_jwk = generate(&p256_key).unwrap();
let result = to_key_data(&valid_jwk);
assert!(result.is_ok());
}
#[test]
fn test_to_key_data_round_trip_with_existing_keys() -> Result<()> {
use atproto_identity::key::identify_key;
let test_keys = [
"did:key:z42tnbHmmnhF11nwSnp5kQJbcZQw2Vbw5WF3ABDSxPtDgU2o", "did:key:zDnaeXduWbJ1b1Kgjf3uCdCpMDF1LEDizUiyxAxGwerou3Nh2", "did:key:z3vLY4nbXy2rV4Qr65gUtfnSF3A8Be7gmYzUiCX6eo2PR1Rt", "did:key:zQ3shNzMp4oaaQ1gQRzCxMGXFrSW3NEM1M9T6KCY9eA7HhyEA", ];
for key_did in test_keys {
let original_key = identify_key(key_did)?;
let jwk = generate(&original_key)?;
let converted_key = to_key_data(&jwk)?;
assert_eq!(*original_key.key_type(), *converted_key.key_type());
assert_eq!(original_key.bytes(), converted_key.bytes());
let original_did = format!("{}", original_key);
let converted_did = format!("{}", converted_key);
assert_eq!(original_did, converted_did);
}
Ok(())
}
#[test]
fn test_to_key_data_metadata_preservation() -> Result<()> {
let test_keys = [
(generate_key(KeyType::P256Private)?, "ES256", "P-256"),
(generate_key(KeyType::P384Private)?, "ES384", "P-384"),
(generate_key(KeyType::K256Private)?, "ES256K", "secp256k1"),
];
for (key, expected_alg, expected_crv) in test_keys {
let jwk = generate(&key)?;
assert_eq!(jwk.alg, Some(expected_alg.to_string()));
assert_eq!(jwk._use, Some("sig".to_string()));
assert_eq!(jwk.jwk.crv(), expected_crv);
assert!(jwk.kid.is_some());
let converted_key = to_key_data(&jwk)?;
assert_eq!(key.bytes(), converted_key.bytes());
}
Ok(())
}
#[test]
fn test_to_key_data_performance_stress() -> Result<()> {
use std::time::Instant;
let start = Instant::now();
for _ in 0..100 {
let p256_key = generate_key(KeyType::P256Private)?;
let p256_jwk = generate(&p256_key)?;
let p256_converted = to_key_data(&p256_jwk)?;
assert_eq!(p256_key.bytes(), p256_converted.bytes());
let p384_key = generate_key(KeyType::P384Private)?;
let p384_jwk = generate(&p384_key)?;
let p384_converted = to_key_data(&p384_jwk)?;
assert_eq!(p384_key.bytes(), p384_converted.bytes());
let k256_key = generate_key(KeyType::K256Private)?;
let k256_jwk = generate(&k256_key)?;
let k256_converted = to_key_data(&k256_jwk)?;
assert_eq!(k256_key.bytes(), k256_converted.bytes());
}
let duration = start.elapsed();
println!("300 round-trip conversions completed in: {:?}", duration);
assert!(
duration.as_millis() < 10000,
"Performance test took too long: {:?}",
duration
);
Ok(())
}
#[test]
fn test_to_key_data_serialization_consistency() -> Result<()> {
let test_keys = [
generate_key(KeyType::P256Private)?,
generate_key(KeyType::P384Private)?,
generate_key(KeyType::K256Private)?,
];
for original_key in test_keys {
let jwk = generate(&original_key)?;
let json_string = serde_json::to_string(&jwk)?;
let deserialized_jwk: WrappedJsonWebKey = serde_json::from_str(&json_string)?;
let converted_from_original = to_key_data(&jwk)?;
let converted_from_deserialized = to_key_data(&deserialized_jwk)?;
assert_eq!(
*converted_from_original.key_type(),
*converted_from_deserialized.key_type()
);
assert_eq!(
converted_from_original.bytes(),
converted_from_deserialized.bytes()
);
assert_eq!(original_key.bytes(), converted_from_original.bytes());
}
Ok(())
}
#[test]
fn test_to_key_data_comprehensive_workflow() -> Result<()> {
println!("\n=== WrappedJsonWebKey to KeyData Comprehensive Test ===");
let test_cases = [
("P-256 private", KeyType::P256Private),
("P-384 private", KeyType::P384Private),
("K-256 private", KeyType::K256Private),
];
for (description, key_type) in test_cases {
println!("Testing {}", description);
let original_private = generate_key(key_type)?;
let original_public = to_public(&original_private)?;
let private_jwk = generate(&original_private)?;
let public_jwk = generate(&original_public)?;
let converted_private = to_key_data(&private_jwk)?;
let converted_public = to_key_data(&public_jwk)?;
assert_eq!(original_private.bytes(), converted_private.bytes());
assert_eq!(original_public.bytes(), converted_public.bytes());
let test_message = format!("Test data for {}", description);
let test_data = test_message.as_bytes();
let signature_original = sign(&original_private, test_data)?;
let signature_converted = sign(&converted_private, test_data)?;
validate(&original_public, &signature_original, test_data)?;
validate(&converted_public, &signature_original, test_data)?;
validate(&original_public, &signature_converted, test_data)?;
validate(&converted_public, &signature_converted, test_data)?;
assert_eq!(
format!("{}", original_private),
format!("{}", converted_private)
);
assert_eq!(
format!("{}", original_public),
format!("{}", converted_public)
);
println!(" ✓ {} passed all tests", description);
}
println!("=== All comprehensive tests completed successfully! ===\n");
Ok(())
}
#[test]
fn test_try_from_owned_p256_private() -> Result<()> {
let original_key = generate_key(KeyType::P256Private)?;
let wrapped_jwk = generate(&original_key)?;
let converted_key: KeyData = wrapped_jwk.try_into()?;
assert_eq!(*converted_key.key_type(), KeyType::P256Private);
assert_eq!(original_key.bytes(), converted_key.bytes());
Ok(())
}
#[test]
fn test_try_from_reference_p256_private() -> Result<()> {
let original_key = generate_key(KeyType::P256Private)?;
let wrapped_jwk = generate(&original_key)?;
let converted_key: KeyData = (&wrapped_jwk).try_into()?;
assert_eq!(*converted_key.key_type(), KeyType::P256Private);
assert_eq!(original_key.bytes(), converted_key.bytes());
Ok(())
}
#[test]
fn test_try_from_explicit_p256_private() -> Result<()> {
let original_key = generate_key(KeyType::P256Private)?;
let wrapped_jwk = generate(&original_key)?;
let converted_owned = KeyData::try_from(wrapped_jwk.clone())?;
let converted_ref = KeyData::try_from(&wrapped_jwk)?;
assert_eq!(*converted_owned.key_type(), KeyType::P256Private);
assert_eq!(*converted_ref.key_type(), KeyType::P256Private);
assert_eq!(original_key.bytes(), converted_owned.bytes());
assert_eq!(original_key.bytes(), converted_ref.bytes());
assert_eq!(converted_owned.bytes(), converted_ref.bytes());
Ok(())
}
#[test]
fn test_try_into_vs_to_key_data_consistency() -> Result<()> {
let test_keys = [
generate_key(KeyType::P256Private)?,
generate_key(KeyType::P384Private)?,
generate_key(KeyType::K256Private)?,
];
for original_key in test_keys {
let public_key = to_public(&original_key)?;
for key in [&original_key, &public_key] {
let wrapped_jwk = generate(key)?;
let from_to_key_data = to_key_data(&wrapped_jwk)?;
let from_try_from_owned: KeyData = wrapped_jwk.clone().try_into()?;
let from_try_from_ref: KeyData = (&wrapped_jwk).try_into()?;
let from_explicit_owned = KeyData::try_from(wrapped_jwk.clone())?;
let from_explicit_ref = KeyData::try_from(&wrapped_jwk)?;
assert_eq!(from_to_key_data.key_type(), from_try_from_owned.key_type());
assert_eq!(from_to_key_data.key_type(), from_try_from_ref.key_type());
assert_eq!(from_to_key_data.key_type(), from_explicit_owned.key_type());
assert_eq!(from_to_key_data.key_type(), from_explicit_ref.key_type());
assert_eq!(from_to_key_data.bytes(), from_try_from_owned.bytes());
assert_eq!(from_to_key_data.bytes(), from_try_from_ref.bytes());
assert_eq!(from_to_key_data.bytes(), from_explicit_owned.bytes());
assert_eq!(from_to_key_data.bytes(), from_explicit_ref.bytes());
}
}
Ok(())
}
#[test]
fn test_trait_implementations_all_curves() -> Result<()> {
let test_cases = [
(KeyType::P256Private, "P-256 private"),
(KeyType::P384Private, "P-384 private"),
(KeyType::K256Private, "K-256 private"),
];
for (key_type, description) in test_cases {
let private_key = generate_key(key_type)?;
let private_jwk = generate(&private_key)?;
let converted_private_owned: KeyData = private_jwk.clone().try_into()?;
let converted_private_ref: KeyData = (&private_jwk).try_into()?;
assert_eq!(
private_key.bytes(),
converted_private_owned.bytes(),
"Owned conversion failed for {}",
description
);
assert_eq!(
private_key.bytes(),
converted_private_ref.bytes(),
"Reference conversion failed for {}",
description
);
let public_key = to_public(&private_key)?;
let public_jwk = generate(&public_key)?;
let converted_public_owned: KeyData = public_jwk.clone().try_into()?;
let converted_public_ref: KeyData = (&public_jwk).try_into()?;
assert_eq!(
public_key.bytes(),
converted_public_owned.bytes(),
"Public owned conversion failed for {}",
description
);
assert_eq!(
public_key.bytes(),
converted_public_ref.bytes(),
"Public reference conversion failed for {}",
description
);
let test_data = format!("Trait test for {}", description);
let test_bytes = test_data.as_bytes();
let signature = sign(&converted_private_owned, test_bytes)?;
validate(&converted_public_owned, &signature, test_bytes)?;
validate(&converted_public_ref, &signature, test_bytes)?;
}
Ok(())
}
#[test]
fn test_trait_error_handling() -> Result<()> {
let p256_key = generate_key(KeyType::P256Private)?;
let valid_jwk = generate(&p256_key)?;
let _: KeyData = valid_jwk.clone().try_into()?;
let _: KeyData = (&valid_jwk).try_into()?;
let _ = KeyData::try_from(valid_jwk.clone())?;
let _ = KeyData::try_from(&valid_jwk)?;
Ok(())
}
#[test]
fn test_trait_ownership_semantics() -> Result<()> {
let original_key = generate_key(KeyType::P256Private)?;
let wrapped_jwk = generate(&original_key)?;
let cloned_jwk = wrapped_jwk.clone();
let converted_owned: KeyData = cloned_jwk.try_into()?;
let converted_ref: KeyData = (&wrapped_jwk).try_into()?;
let converted_ref2: KeyData = (&wrapped_jwk).try_into()?;
assert_eq!(converted_owned.bytes(), converted_ref.bytes());
assert_eq!(converted_ref.bytes(), converted_ref2.bytes());
assert_eq!(original_key.bytes(), converted_owned.bytes());
Ok(())
}
#[test]
fn test_trait_type_inference() -> Result<()> {
let original_key = generate_key(KeyType::K256Private)?;
let wrapped_jwk = generate(&original_key)?;
let converted1 = KeyData::try_from(wrapped_jwk.clone())?;
let converted2 = KeyData::try_from(&wrapped_jwk)?;
let converted3: Result<KeyData, _> = wrapped_jwk.clone().try_into();
let converted3 = converted3?;
let converted4: Result<KeyData, _> = (&wrapped_jwk).try_into();
let converted4 = converted4?;
assert_eq!(converted1.bytes(), converted2.bytes());
assert_eq!(converted2.bytes(), converted3.bytes());
assert_eq!(converted3.bytes(), converted4.bytes());
assert_eq!(original_key.bytes(), converted1.bytes());
Ok(())
}
#[test]
fn test_trait_comprehensive_workflow() -> Result<()> {
println!("\n=== TryFrom/TryInto Trait Implementation Test ===");
let test_cases = [
("P-256", KeyType::P256Private),
("P-384", KeyType::P384Private),
("K-256", KeyType::K256Private),
];
for (curve_name, key_type) in test_cases {
println!("Testing {} trait implementations", curve_name);
let original_private = generate_key(key_type)?;
let original_public = to_public(&original_private)?;
let private_jwk = generate(&original_private)?;
let public_jwk = generate(&original_public)?;
println!(" Testing TryFrom<WrappedJsonWebKey>");
let private_from_owned = KeyData::try_from(private_jwk.clone())?;
let public_from_owned = KeyData::try_from(public_jwk.clone())?;
println!(" Testing TryFrom<&WrappedJsonWebKey>");
let private_from_ref = KeyData::try_from(&private_jwk)?;
let public_from_ref = KeyData::try_from(&public_jwk)?;
println!(" Testing TryInto<KeyData> for WrappedJsonWebKey");
let private_into_owned: KeyData = private_jwk.clone().try_into()?;
let public_into_owned: KeyData = public_jwk.clone().try_into()?;
println!(" Testing TryInto<KeyData> for &WrappedJsonWebKey");
let private_into_ref: KeyData = (&private_jwk).try_into()?;
let public_into_ref: KeyData = (&public_jwk).try_into()?;
let private_results = [
&private_from_owned,
&private_from_ref,
&private_into_owned,
&private_into_ref,
];
let public_results = [
&public_from_owned,
&public_from_ref,
&public_into_owned,
&public_into_ref,
];
for result in &private_results[1..] {
assert_eq!(private_results[0].bytes(), result.bytes());
assert_eq!(private_results[0].key_type(), result.key_type());
}
for result in &public_results[1..] {
assert_eq!(public_results[0].bytes(), result.bytes());
assert_eq!(public_results[0].key_type(), result.key_type());
}
assert_eq!(original_private.bytes(), private_results[0].bytes());
assert_eq!(original_public.bytes(), public_results[0].bytes());
let test_data = format!("{} trait test", curve_name);
let test_bytes = test_data.as_bytes();
let signature = sign(&private_from_owned, test_bytes)?;
validate(&public_from_owned, &signature, test_bytes)?;
validate(&public_into_ref, &signature, test_bytes)?;
println!(" ✓ {} trait implementations passed all tests", curve_name);
}
println!("=== All trait implementation tests completed successfully! ===\n");
Ok(())
}
#[test]
fn test_trait_usage_examples() -> Result<()> {
let original_key = generate_key(KeyType::P256Private)?;
let wrapped_jwk = generate(&original_key)?;
let converted1: KeyData = wrapped_jwk.clone().try_into()?;
let converted2: KeyData = (&wrapped_jwk).try_into()?;
let converted3 = KeyData::try_from(wrapped_jwk.clone())?;
let converted4 = KeyData::try_from(&wrapped_jwk)?;
let converted5 = to_key_data(&wrapped_jwk)?;
let results = [
&converted1,
&converted2,
&converted3,
&converted4,
&converted5,
];
for result in &results[1..] {
assert_eq!(converted1.bytes(), result.bytes());
assert_eq!(converted1.key_type(), result.key_type());
}
assert_eq!(original_key.bytes(), converted1.bytes());
assert_eq!(*original_key.key_type(), *converted1.key_type());
println!("✓ All trait usage examples work correctly");
Ok(())
}
#[test]
fn test_thumbprint_p256() -> Result<()> {
let key = generate_key(KeyType::P256Private)?;
let wrapped_jwk = generate(&key)?;
let tp = thumbprint(&wrapped_jwk)?;
assert!(!tp.is_empty());
assert!(tp.len() > 20); assert!(!tp.contains('=')); assert!(!tp.contains('+')); assert!(!tp.contains('/'));
Ok(())
}
#[test]
fn test_thumbprint_p384() -> Result<()> {
let key = generate_key(KeyType::P384Private)?;
let wrapped_jwk = generate(&key)?;
let tp = thumbprint(&wrapped_jwk)?;
assert!(!tp.is_empty());
assert!(tp.len() > 20);
assert!(!tp.contains('='));
assert!(!tp.contains('+'));
assert!(!tp.contains('/'));
Ok(())
}
#[test]
fn test_thumbprint_k256() -> Result<()> {
let key = generate_key(KeyType::K256Private)?;
let wrapped_jwk = generate(&key)?;
let tp = thumbprint(&wrapped_jwk)?;
assert!(!tp.is_empty());
assert!(tp.len() > 20);
assert!(!tp.contains('='));
assert!(!tp.contains('+'));
assert!(!tp.contains('/'));
Ok(())
}
#[test]
fn test_thumbprint_consistency() -> Result<()> {
let key = generate_key(KeyType::P256Private)?;
let wrapped_jwk = generate(&key)?;
let tp1 = thumbprint(&wrapped_jwk)?;
let tp2 = thumbprint(&wrapped_jwk)?;
let tp3 = thumbprint(&wrapped_jwk)?;
assert_eq!(tp1, tp2);
assert_eq!(tp2, tp3);
Ok(())
}
#[test]
fn test_thumbprint_different_keys_different_thumbprints() -> Result<()> {
let key1 = generate_key(KeyType::P256Private)?;
let key2 = generate_key(KeyType::P256Private)?;
let jwk1 = generate(&key1)?;
let jwk2 = generate(&key2)?;
let tp1 = thumbprint(&jwk1)?;
let tp2 = thumbprint(&jwk2)?;
assert_ne!(tp1, tp2);
Ok(())
}
#[test]
fn test_thumbprint_private_vs_public_same_thumbprint() -> Result<()> {
let private_key = generate_key(KeyType::P256Private)?;
let public_key = to_public(&private_key)?;
let private_jwk = generate(&private_key)?;
let public_jwk = generate(&public_key)?;
let private_tp = thumbprint(&private_jwk)?;
let public_tp = thumbprint(&public_jwk)?;
assert_eq!(private_tp, public_tp);
Ok(())
}
#[test]
fn test_thumbprint_cross_curve_different() -> Result<()> {
let p256_key = generate_key(KeyType::P256Private)?;
let p384_key = generate_key(KeyType::P384Private)?;
let k256_key = generate_key(KeyType::K256Private)?;
let p256_jwk = generate(&p256_key)?;
let p384_jwk = generate(&p384_key)?;
let k256_jwk = generate(&k256_key)?;
let p256_tp = thumbprint(&p256_jwk)?;
let p384_tp = thumbprint(&p384_jwk)?;
let k256_tp = thumbprint(&k256_jwk)?;
assert_ne!(p256_tp, p384_tp);
assert_ne!(p256_tp, k256_tp);
assert_ne!(p384_tp, k256_tp);
Ok(())
}
#[test]
fn test_thumbprint_deterministic() -> Result<()> {
use atproto_identity::key::identify_key;
let known_key = identify_key("did:key:z42tnbHmmnhF11nwSnp5kQJbcZQw2Vbw5WF3ABDSxPtDgU2o")?;
let wrapped_jwk = generate(&known_key)?;
let tp = thumbprint(&wrapped_jwk)?;
assert!(!tp.is_empty());
assert!(tp.len() == 43);
let tp2 = thumbprint(&wrapped_jwk)?;
assert_eq!(tp, tp2);
Ok(())
}
#[test]
fn test_thumbprint_performance() -> Result<()> {
use std::time::Instant;
let key = generate_key(KeyType::P256Private)?;
let wrapped_jwk = generate(&key)?;
let start = Instant::now();
for _ in 0..1000 {
let _tp = thumbprint(&wrapped_jwk)?;
}
let duration = start.elapsed();
assert!(
duration.as_millis() < 2000,
"Thumbprint performance test took too long: {:?}",
duration
);
Ok(())
}
#[test]
fn test_thumbprint_spec_compliance() -> Result<()> {
let key = generate_key(KeyType::P256Private)?;
let wrapped_jwk = generate(&key)?;
let tp = thumbprint(&wrapped_jwk)?;
assert_eq!(tp.len(), 43);
for c in tp.chars() {
assert!(c.is_alphanumeric() || c == '-' || c == '_');
}
Ok(())
}
#[test]
fn test_thumbprint_with_all_curves() -> Result<()> {
let test_cases = [
(KeyType::P256Private, "P-256"),
(KeyType::P384Private, "P-384"),
(KeyType::K256Private, "K-256"),
];
for (key_type, curve_name) in test_cases {
let private_key = generate_key(key_type)?;
let public_key = to_public(&private_key)?;
let private_jwk = generate(&private_key)?;
let public_jwk = generate(&public_key)?;
let private_tp = thumbprint(&private_jwk)?;
let public_tp = thumbprint(&public_jwk)?;
assert_eq!(
private_tp, public_tp,
"Thumbprint mismatch for {}",
curve_name
);
assert_eq!(
private_tp.len(),
43,
"Invalid thumbprint length for {}",
curve_name
);
assert!(
!private_tp.contains('='),
"Thumbprint contains padding for {}",
curve_name
);
}
Ok(())
}
#[test]
fn test_thumbprint_comprehensive() -> Result<()> {
let curves = [
(KeyType::P256Private, "P-256"),
(KeyType::P384Private, "P-384"),
(KeyType::K256Private, "K-256"),
];
for (key_type, curve_name) in curves {
let keys: Vec<_> = (0..5)
.map(|_| generate_key(key_type.clone()))
.collect::<Result<Vec<_>, _>>()?;
let mut thumbprints = Vec::new();
for (i, key) in keys.iter().enumerate() {
let private_jwk = generate(key)?;
let public_jwk = generate(&to_public(key)?)?;
let private_tp = thumbprint(&private_jwk)?;
let public_tp = thumbprint(&public_jwk)?;
assert_eq!(
private_tp, public_tp,
"Thumbprint mismatch for {} key {}",
curve_name, i
);
assert!(
!thumbprints.contains(&private_tp),
"Duplicate thumbprint for {} key {}",
curve_name,
i
);
thumbprints.push(private_tp);
}
assert_eq!(
thumbprints.len(),
5,
"Not all thumbprints are unique for {}",
curve_name
);
for tp in &thumbprints {
assert_eq!(tp.len(), 43, "Invalid length for {} thumbprint", curve_name);
assert!(
!tp.contains(&['=', '+', '/'][..]),
"Invalid characters in {} thumbprint",
curve_name
);
}
}
Ok(())
}
}