//! The committed reference vectors (`vectors.json`) as the tests' source of //! truth, so the file and the derivations cannot drift apart. Language ports //! and FFI bindings pin the same operations against the same file without //! regenerating anything from the reference stack. use serde::Deserialize; use crate::crypto::KEY_LEN; #[derive(Deserialize)] pub struct Vectors { /// The master every derivation below starts from, hex-encoded. pub master_hex: String, /// `identity_seed(master, n)` per rotation index, base32. pub identity_seeds_b32: std::collections::BTreeMap, /// `Identity::from_seed(seed_n).pk()` per rotation index, base32. pub identity_pks_b32: std::collections::BTreeMap, /// The X25519 half per rotation index, base32. pub identity_xprivs_b32: std::collections::BTreeMap, pub accept_key_b32: String, /// `Account::new(master, 0).token_for(pk_1)`, base32. pub accept_token_for_pk1_b32: String, pub rotation_cert: RotationCertVector, pub accept_mac: AcceptMacVector, pub envelope: EnvelopeVector, pub hkdf_rfc5869_case1: HkdfVector, pub hmac_rfc4231_case1: HmacVector, /// `ed25519_to_x25519(pk_0)`, base32 — libsodium's pk_to_curve25519. pub ed25519_to_x25519_pk0_b32: String, pub rns_bind: RnsBindVector, } #[derive(Deserialize)] pub struct RotationCertVector { pub username: String, pub old_index: u32, pub new_index: u32, pub when: i64, pub cert_hex: String, } #[derive(Deserialize)] pub struct AcceptMacVector { /// The token is `token_for(pk_1)` over this message id, base32. pub message_id_b32: String, pub mac_hex: String, } #[derive(Deserialize)] pub struct EnvelopeVector { pub sender_index: u32, pub recipient_index: u32, pub when: i64, /// The fixed ephemeral scalar the reference client used, hex. pub ephemeral_hex: String, pub padded_b32: String, pub unpadded_b32: String, pub message_id_hex: String, pub body: String, pub sender_pk_b32: String, } #[derive(Deserialize)] pub struct HkdfVector { pub ikm_hex: String, pub salt_hex: String, pub info_hex: String, /// The first 32 bytes of the 42-byte OKM. pub okm_hex_32: String, } #[derive(Deserialize)] pub struct HmacVector { pub key_hex: String, pub data: String, pub mac_hex: String, } #[derive(Deserialize)] pub struct RnsBindVector { pub destination_hex: String, pub link_id_hex: String, pub h_hex: String, pub server_static_hex: String, } pub fn load() -> Vectors { serde_json::from_str(include_str!("../vectors.json")).expect("vectors.json parses") } fn b32_at(map: &std::collections::BTreeMap, n: u32) -> &str { map.get(&n.to_string()).expect("vectors.json has the index") } impl Vectors { pub fn master(&self) -> [u8; KEY_LEN] { data_encoding::HEXLOWER .decode(self.master_hex.as_bytes()) .expect("master_hex decodes") .try_into() .expect("master is 32 bytes") } pub fn seed_b32(&self, n: u32) -> &str { b32_at(&self.identity_seeds_b32, n) } pub fn pk_b32(&self, n: u32) -> &str { b32_at(&self.identity_pks_b32, n) } pub fn xpriv_b32(&self, n: u32) -> &str { b32_at(&self.identity_xprivs_b32, n) } pub fn hex(&self, hex: &str) -> Vec { data_encoding::HEXLOWER.decode(hex.as_bytes()).expect("hex decodes") } }