use serde::{Deserialize, Serialize};
use crate::sidetree::{json_canonicalization_scheme, DIDSuffix, Delta, PublicKeyJwk, Sidetree};
use super::{jws_decode_verify_inner, PartialVerificationError, SidetreeOperation};
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
pub struct RecoverOperation {
pub did_suffix: DIDSuffix,
pub reveal_value: String,
pub delta: Delta,
pub signed_data: String,
}
impl SidetreeOperation for RecoverOperation {
type PartiallyVerifiedForm = PartiallyVerifiedRecoverOperation;
fn partial_verify<S: Sidetree>(
self,
) -> Result<PartiallyVerifiedRecoverOperation, PartialVerificationError> {
let (header, claims) =
jws_decode_verify_inner(&self.signed_data, |claims: &RecoveryClaims| {
&claims.recovery_key
})?;
if header.algorithm != S::SIGNATURE_ALGORITHM {
return Err(PartialVerificationError::InvalidSignatureAlgorithm);
}
let canonicalized_public_key = json_canonicalization_scheme(&claims.recovery_key).unwrap();
let computed_reveal_value = S::reveal_value(canonicalized_public_key.as_bytes());
if self.reveal_value != computed_reveal_value {
return Err(PartialVerificationError::RevealValueMismatch {
computed: computed_reveal_value,
found: self.reveal_value,
});
}
let delta_string = json_canonicalization_scheme(&self.delta).unwrap();
let delta_hash = S::hash(delta_string.as_bytes());
if claims.delta_hash != delta_hash {
return Err(PartialVerificationError::DeltaHashMismatch);
}
Ok(PartiallyVerifiedRecoverOperation {
reveal_value: self.reveal_value,
signed_delta: self.delta,
signed_recovery_commitment: claims.recovery_commitment,
signed_recovery_key: claims.recovery_key,
signed_anchor_origin: claims.anchor_origin,
})
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct PartiallyVerifiedRecoverOperation {
pub reveal_value: String,
pub signed_delta: Delta,
pub signed_recovery_commitment: String,
pub signed_recovery_key: PublicKeyJwk,
pub signed_anchor_origin: Option<String>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct RecoveryClaims {
pub recovery_commitment: String,
pub recovery_key: PublicKeyJwk,
pub delta_hash: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub anchor_origin: Option<String>,
}