v0.2.6-pre.015
This commit is contained in:
141
crates/ksp-wallet-lib/src/transcript_v2.rs
Normal file
141
crates/ksp-wallet-lib/src/transcript_v2.rs
Normal file
@@ -0,0 +1,141 @@
|
||||
// file: crates/ksp-wallet-lib/src/transcript_v2.rs
|
||||
// version: 1
|
||||
|
||||
//! Deterministic `.kspwallet` V2 state-transcript and AEAD-AAD encoding.
|
||||
|
||||
const TAG_COMPARTMENT_ALGORITHM: u16 = 0x0202;
|
||||
const TAG_COMPARTMENT_CIPHERTEXT: u16 = 0x0204;
|
||||
const TAG_COMPARTMENT_KIND: u16 = 0x0200;
|
||||
const TAG_COMPARTMENT_NONCE: u16 = 0x0203;
|
||||
const TAG_COMPARTMENT_VERSION: u16 = 0x0201;
|
||||
const TAG_FORMAT_VERSION: u16 = 0x0002;
|
||||
const TAG_KDF_ALGORITHM: u16 = 0x0102;
|
||||
const TAG_KDF_ITERATIONS: u16 = 0x0105;
|
||||
const TAG_KDF_MEMORY_KIB: u16 = 0x0104;
|
||||
const TAG_KDF_PARALLELISM: u16 = 0x0106;
|
||||
const TAG_KDF_SALT: u16 = 0x0107;
|
||||
const TAG_KDF_VERSION: u16 = 0x0103;
|
||||
const TAG_MAGIC: u16 = 0x0001;
|
||||
const TAG_OWNER_AUTH_PUBLIC_KEY: u16 = 0x0003;
|
||||
const TAG_SLOT_ID: u16 = 0x0100;
|
||||
const TAG_SLOT_ROLE: u16 = 0x0101;
|
||||
const TAG_STATE_SIGNATURE_ALGORITHM: u16 = 0x0500;
|
||||
const TAG_VIEW_ENABLED: u16 = 0x0010;
|
||||
const TAG_VIEW_ROLE: u16 = 0x0011;
|
||||
const TAG_VIEW_SLOT_ID: u16 = 0x0012;
|
||||
const TAG_WRAP_ALGORITHM: u16 = 0x0108;
|
||||
const TAG_WRAP_CIPHERTEXT: u16 = 0x010A;
|
||||
const TAG_WRAP_NONCE: u16 = 0x0109;
|
||||
|
||||
/// Builds the normative OWNER state-signature transcript for one validated V2 envelope.
|
||||
pub(crate) fn state_transcript_v2(envelope: &crate::KspWalletEnvelopeV2) -> std::vec::Vec<u8> {
|
||||
let mut output = start(crate::KSPWALLET_V2_STATE_TRANSCRIPT_DOMAIN);
|
||||
push_common(&mut output, envelope);
|
||||
push_bool(&mut output, TAG_VIEW_ENABLED, envelope.view_descriptor().enabled());
|
||||
push_u8(&mut output, TAG_VIEW_ROLE, crate::WalletKeySlotRoleV2::View.wire_id());
|
||||
match envelope.view_descriptor().slot_id() {
|
||||
std::option::Option::Some(slot_id) => push_bytes(&mut output, TAG_VIEW_SLOT_ID, slot_id),
|
||||
std::option::Option::None => push_bytes(&mut output, TAG_VIEW_SLOT_ID, &[]),
|
||||
}
|
||||
push_slot(&mut output, envelope.owner_slot(), true);
|
||||
push_compartment(&mut output, envelope.owner_control(), true);
|
||||
push_compartment(&mut output, envelope.metadata(), true);
|
||||
push_compartment(&mut output, envelope.secret(), true);
|
||||
push_u8(&mut output, TAG_STATE_SIGNATURE_ALGORITHM, envelope.state_signature().algorithm().wire_id());
|
||||
return output;
|
||||
}
|
||||
|
||||
/// Builds the normative wrapping AAD for one validated V2 OWNER or VIEW key slot.
|
||||
pub(crate) fn slot_aad_v2(envelope: &crate::KspWalletEnvelopeV2, slot: &crate::WalletKeySlotV2) -> std::vec::Vec<u8> {
|
||||
let domain = match slot.role() {
|
||||
crate::WalletKeySlotRoleV2::Owner => crate::KSPWALLET_V2_OWNER_SLOT_AAD_DOMAIN,
|
||||
crate::WalletKeySlotRoleV2::View => crate::KSPWALLET_V2_VIEW_SLOT_AAD_DOMAIN,
|
||||
};
|
||||
let mut output = start(domain);
|
||||
push_common(&mut output, envelope);
|
||||
push_slot(&mut output, slot, false);
|
||||
return output;
|
||||
}
|
||||
|
||||
/// Builds the normative AEAD AAD for one validated V2 encrypted compartment.
|
||||
pub(crate) fn compartment_aad_v2(envelope: &crate::KspWalletEnvelopeV2, compartment: &crate::WalletEncryptedCompartmentV2) -> std::vec::Vec<u8> {
|
||||
let domain = match compartment.kind() {
|
||||
crate::WalletCompartmentKindV2::OwnerControl => crate::KSPWALLET_V2_OWNER_CONTROL_AAD_DOMAIN,
|
||||
crate::WalletCompartmentKindV2::Metadata => crate::KSPWALLET_V2_METADATA_AAD_DOMAIN,
|
||||
crate::WalletCompartmentKindV2::Secret => crate::KSPWALLET_V2_SECRET_AAD_DOMAIN,
|
||||
};
|
||||
let mut output = start(domain);
|
||||
push_common(&mut output, envelope);
|
||||
push_compartment(&mut output, compartment, false);
|
||||
return output;
|
||||
}
|
||||
|
||||
fn start(domain: &[u8]) -> std::vec::Vec<u8> {
|
||||
let mut output = std::vec::Vec::with_capacity(512);
|
||||
output.extend_from_slice(domain);
|
||||
output.push(0);
|
||||
return output;
|
||||
}
|
||||
|
||||
fn push_bool(output: &mut std::vec::Vec<u8>, tag: u16, value: bool) {
|
||||
let byte = if value { 1_u8 } else { 0_u8 };
|
||||
push_bytes(output, tag, &[byte]);
|
||||
return;
|
||||
}
|
||||
|
||||
fn push_bytes(output: &mut std::vec::Vec<u8>, tag: u16, value: &[u8]) {
|
||||
output.extend_from_slice(tag.to_be_bytes().as_slice());
|
||||
let length = value.len() as u64;
|
||||
output.extend_from_slice(length.to_be_bytes().as_slice());
|
||||
output.extend_from_slice(value);
|
||||
return;
|
||||
}
|
||||
|
||||
fn push_common(output: &mut std::vec::Vec<u8>, envelope: &crate::KspWalletEnvelopeV2) {
|
||||
push_bytes(output, TAG_MAGIC, crate::KSPWALLET_MAGIC.as_bytes());
|
||||
push_u32(output, TAG_FORMAT_VERSION, envelope.format_version());
|
||||
push_bytes(output, TAG_OWNER_AUTH_PUBLIC_KEY, envelope.owner_auth_public_key());
|
||||
return;
|
||||
}
|
||||
|
||||
fn push_compartment(output: &mut std::vec::Vec<u8>, compartment: &crate::WalletEncryptedCompartmentV2, include_ciphertext: bool) {
|
||||
push_u8(output, TAG_COMPARTMENT_KIND, compartment.kind().wire_id());
|
||||
push_u32(output, TAG_COMPARTMENT_VERSION, compartment.payload_version());
|
||||
push_u8(output, TAG_COMPARTMENT_ALGORITHM, compartment.algorithm().wire_id());
|
||||
if include_ciphertext {
|
||||
push_bytes(output, TAG_COMPARTMENT_NONCE, compartment.nonce());
|
||||
push_bytes(output, TAG_COMPARTMENT_CIPHERTEXT, compartment.ciphertext());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
fn push_slot(output: &mut std::vec::Vec<u8>, slot: &crate::WalletKeySlotV2, include_wrap_payload: bool) {
|
||||
push_bytes(output, TAG_SLOT_ID, slot.slot_id());
|
||||
push_u8(output, TAG_SLOT_ROLE, slot.role().wire_id());
|
||||
push_u8(output, TAG_KDF_ALGORITHM, slot.kdf().algorithm().wire_id());
|
||||
push_u32(output, TAG_KDF_VERSION, slot.kdf().version());
|
||||
push_u32(output, TAG_KDF_MEMORY_KIB, slot.kdf().memory_kib());
|
||||
push_u32(output, TAG_KDF_ITERATIONS, slot.kdf().iterations());
|
||||
push_u32(output, TAG_KDF_PARALLELISM, slot.kdf().parallelism());
|
||||
push_bytes(output, TAG_KDF_SALT, slot.kdf().salt());
|
||||
push_u8(output, TAG_WRAP_ALGORITHM, slot.wrap().algorithm().wire_id());
|
||||
if include_wrap_payload {
|
||||
push_bytes(output, TAG_WRAP_NONCE, slot.wrap().nonce());
|
||||
push_bytes(output, TAG_WRAP_CIPHERTEXT, slot.wrap().ciphertext());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
fn push_u32(output: &mut std::vec::Vec<u8>, tag: u16, value: u32) {
|
||||
push_bytes(output, tag, value.to_be_bytes().as_slice());
|
||||
return;
|
||||
}
|
||||
|
||||
fn push_u8(output: &mut std::vec::Vec<u8>, tag: u16, value: u8) {
|
||||
push_bytes(output, tag, &[value]);
|
||||
return;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/transcript_v2.rs"]
|
||||
mod tests;
|
||||
Reference in New Issue
Block a user