119 lines
3.4 KiB
Rust
119 lines
3.4 KiB
Rust
//! 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<String, String>,
|
|
/// `Identity::from_seed(seed_n).pk()` per rotation index, base32.
|
|
pub identity_pks_b32: std::collections::BTreeMap<String, String>,
|
|
/// The X25519 half per rotation index, base32.
|
|
pub identity_xprivs_b32: std::collections::BTreeMap<String, String>,
|
|
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<String, String>, 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<u8> {
|
|
data_encoding::HEXLOWER.decode(hex.as_bytes()).expect("hex decodes")
|
|
}
|
|
}
|