use super::acquire_certificate::{base64_decode, base64_encode};
use super::*;
use crate::wallet::error::WalletError;
use crate::wallet::interfaces::*;
use std::collections::HashMap;
pub fn serialize_certificate(cert: &Certificate) -> Result<Vec<u8>, WalletError> {
serialize_to_vec(|w| {
write_raw_bytes(w, cert.cert_type.bytes())?;
write_raw_bytes(w, &cert.serial_number.0)?;
write_public_key(w, &cert.subject)?;
write_public_key(w, &cert.certifier)?;
if let Some(ref outpoint) = cert.revocation_outpoint {
write_outpoint(w, outpoint)?;
} else {
write_raw_bytes(w, &[0u8; 32])?;
write_varint(w, 0)?;
}
let fields = cert.fields.clone().unwrap_or_default();
let mut keys: Vec<&String> = fields.keys().collect();
keys.sort();
write_varint(w, keys.len() as u64)?;
for key in keys {
write_bytes(w, key.as_bytes())?;
write_bytes(w, fields[key].as_bytes())?;
}
if let Some(ref sig) = cert.signature {
write_raw_bytes(w, sig)?;
}
Ok(())
})
}
pub fn deserialize_certificate(data: &[u8]) -> Result<Certificate, WalletError> {
let mut r = std::io::Cursor::new(data);
let mut type_bytes = [0u8; 32];
let tb = read_raw_bytes(&mut r, SIZE_TYPE)?;
type_bytes.copy_from_slice(&tb);
let cert_type = CertificateType(type_bytes);
let mut sn_bytes = [0u8; 32];
let sb = read_raw_bytes(&mut r, SIZE_SERIAL)?;
sn_bytes.copy_from_slice(&sb);
let serial_number = SerialNumber(sn_bytes);
let subject = read_public_key(&mut r)?;
let certifier = read_public_key(&mut r)?;
let revocation_outpoint = Some(read_outpoint(&mut r)?);
let fields_len = read_varint(&mut r)?;
let mut fields = HashMap::with_capacity(fields_len as usize);
for _ in 0..fields_len {
let key = String::from_utf8(read_bytes(&mut r)?)
.map_err(|e| WalletError::Internal(e.to_string()))?;
let value = String::from_utf8(read_bytes(&mut r)?)
.map_err(|e| WalletError::Internal(e.to_string()))?;
fields.insert(key, value);
}
let pos = r.position() as usize;
let remaining = &data[pos..];
let signature = if remaining.is_empty() {
None
} else {
Some(remaining.to_vec())
};
Ok(Certificate {
cert_type,
serial_number,
subject,
certifier,
revocation_outpoint,
fields: if fields.is_empty() {
None
} else {
Some(fields)
},
signature,
})
}
pub fn serialize_identity_certificate(cert: &IdentityCertificate) -> Result<Vec<u8>, WalletError> {
serialize_to_vec(|w| {
let cert_bytes = serialize_certificate(&cert.certificate)?;
write_bytes(w, &cert_bytes)?;
write_string(w, &cert.certifier_info.name)?;
write_string(w, &cert.certifier_info.icon_url)?;
write_string(w, &cert.certifier_info.description)?;
write_byte(w, cert.certifier_info.trust)?;
let mut keys: Vec<&String> = cert.publicly_revealed_keyring.keys().collect();
keys.sort();
write_varint(w, keys.len() as u64)?;
for key in keys {
write_string(w, key)?;
let value_bytes = base64_decode(&cert.publicly_revealed_keyring[key])?;
write_bytes(w, &value_bytes)?;
}
write_string_map(w, &cert.decrypted_fields)?;
Ok(())
})
}
pub fn deserialize_identity_certificate(
reader: &mut impl std::io::Read,
) -> Result<IdentityCertificate, WalletError> {
let cert_bytes = read_bytes(reader)?;
let certificate = deserialize_certificate(&cert_bytes)?;
let name = read_string(reader)?;
let icon_url = read_string(reader)?;
let description = read_string(reader)?;
let trust = read_byte(reader)?;
let keyring_len = read_varint(reader)?;
let mut publicly_revealed_keyring = HashMap::with_capacity(keyring_len as usize);
for _ in 0..keyring_len {
let key = read_string(reader)?;
let value_bytes = read_bytes(reader)?;
publicly_revealed_keyring.insert(key, base64_encode(&value_bytes));
}
let decrypted_fields = read_string_map(reader)?;
Ok(IdentityCertificate {
certificate,
certifier_info: IdentityCertifier {
name,
icon_url,
description,
trust,
},
publicly_revealed_keyring,
decrypted_fields,
})
}