use crate::Error;
use crate::{
did::*,
multihash::{canonicalize_then_double_hash_then_encode, canonicalize_then_hash_then_encode},
secp256k1::KeyPair,
Delta, Patch, SuffixData,
};
use serde::{ser::SerializeMap, Serialize};
#[derive(Debug, Clone)]
pub enum Operation {
Create(SuffixData, Delta),
}
#[derive(Serialize, Debug, Clone, Default)]
pub struct OperationInput {
signing_key: Option<PublicKey>,
update_key: Option<JsonWebKey>,
recovery_key: Option<JsonWebKey>,
}
#[derive(Serialize, Debug, Clone)]
pub struct OperationOutput {
operation_request: Operation,
did_suffix: String,
update_key: JsonWebKey,
recovery_key: JsonWebKey,
signing_key: PublicKey,
}
impl Serialize for Operation {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut map = serializer.serialize_map(None)?;
match self {
Operation::Create(suffix_data, delta) => {
map.serialize_entry("type", "create")?;
map.serialize_entry("suffixData", suffix_data)?;
map.serialize_entry("delta", delta)?;
}
}
map.end()
}
}
pub fn create() -> Result<OperationOutput, Error> {
let update_key = KeyPair::random();
let recovery_key = KeyPair::random();
let signing_key = KeyPair::random();
let signing_key_public = signing_key.to_public_key("key-1".into(), Some(Purpose::all()));
let document = Document {
public_keys: vec![signing_key_public.clone()],
services: vec![],
};
let patches = vec![Patch::Replace(document)];
let mut update_key_public: JsonWebKey = (&update_key).into();
update_key_public.d = None;
let delta = Delta {
update_commitment: canonicalize_then_double_hash_then_encode(&update_key_public).unwrap(),
patches,
};
let delta_hash = canonicalize_then_hash_then_encode(&delta, crate::multihash::HashAlgorithm::Sha256);
let mut recovery_key_public: JsonWebKey = (&recovery_key).into();
recovery_key_public.d = None;
let suffix_data = SuffixData {
delta_hash,
recovery_commitment: canonicalize_then_double_hash_then_encode(&recovery_key_public).unwrap(),
data_type: None,
};
let did_suffix = compute_unique_suffix(&suffix_data);
let operation = Operation::Create(suffix_data, delta);
Ok(OperationOutput {
update_key: (&update_key).into(),
recovery_key: (&recovery_key).into(),
signing_key: signing_key_public,
operation_request: operation,
did_suffix,
})
}
#[cfg(test)]
mod test {
use super::{create, Operation};
#[test]
fn generate_create_operation() {
let result = create().unwrap();
let json = serde_json::to_string_pretty(&result.operation_request);
assert!(matches!(json, Result::Ok(_)));
assert!(matches!(result.operation_request, Operation::Create(_, _)));
assert!(result.did_suffix.len() > 0);
println!("did:ion:{}", result.did_suffix);
println!("{}", json.unwrap());
}
}