use crate::domain::value_objects::{
constants::{EDDSA_KEY_DOMAIN, KEY_DOMAIN, NULLIFIER_KEY_DOMAIN, VIEWING_KEY_DOMAIN},
EdDSAKey, NullifierKey, ViewingKey,
};
use sha2::{Digest, Sha256};
pub fn derive_encryption_key(viewing_key: &[u8; 32], commitment: &[u8; 32]) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(viewing_key);
hasher.update(commitment);
hasher.update(KEY_DOMAIN);
hasher.finalize().into()
}
pub fn derive_viewing_key_from_spending(spending_key: &[u8; 32]) -> ViewingKey {
let mut hasher = Sha256::new();
hasher.update(spending_key);
hasher.update(VIEWING_KEY_DOMAIN);
ViewingKey(hasher.finalize().into())
}
pub fn derive_nullifier_key_from_spending(spending_key: &[u8; 32]) -> NullifierKey {
let mut hasher = Sha256::new();
hasher.update(spending_key);
hasher.update(NULLIFIER_KEY_DOMAIN);
NullifierKey(hasher.finalize().into())
}
pub fn derive_eddsa_key_from_spending(spending_key: &[u8; 32]) -> EdDSAKey {
let mut hasher = Sha256::new();
hasher.update(spending_key);
hasher.update(EDDSA_KEY_DOMAIN);
EdDSAKey(hasher.finalize().into())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_derive_encryption_key_basic() {
let key = derive_encryption_key(&[1u8; 32], &[2u8; 32]);
assert_ne!(key, [0u8; 32]);
}
#[test]
fn test_derive_encryption_key_deterministic() {
let k1 = derive_encryption_key(&[42u8; 32], &[99u8; 32]);
let k2 = derive_encryption_key(&[42u8; 32], &[99u8; 32]);
assert_eq!(k1, k2);
}
#[test]
fn test_derive_encryption_key_different_commitments() {
let vk = [1u8; 32];
assert_ne!(
derive_encryption_key(&vk, &[2u8; 32]),
derive_encryption_key(&vk, &[3u8; 32])
);
}
#[test]
fn test_derive_encryption_key_different_viewing_keys() {
let comm = [3u8; 32];
assert_ne!(
derive_encryption_key(&[1u8; 32], &comm),
derive_encryption_key(&[2u8; 32], &comm)
);
}
#[test]
fn test_derive_viewing_key_basic() {
let vk = derive_viewing_key_from_spending(&[1u8; 32]);
assert_ne!(vk.0, [0u8; 32]);
}
#[test]
fn test_derive_viewing_key_deterministic() {
assert_eq!(
derive_viewing_key_from_spending(&[42u8; 32]),
derive_viewing_key_from_spending(&[42u8; 32]),
);
}
#[test]
fn test_derive_viewing_key_different_inputs() {
assert_ne!(
derive_viewing_key_from_spending(&[1u8; 32]),
derive_viewing_key_from_spending(&[2u8; 32]),
);
}
#[test]
fn test_derive_nullifier_key_basic() {
let nk = derive_nullifier_key_from_spending(&[1u8; 32]);
assert_ne!(nk.0, [0u8; 32]);
}
#[test]
fn test_derive_nullifier_key_deterministic() {
assert_eq!(
derive_nullifier_key_from_spending(&[42u8; 32]),
derive_nullifier_key_from_spending(&[42u8; 32]),
);
}
#[test]
fn test_derive_eddsa_key_basic() {
let ek = derive_eddsa_key_from_spending(&[1u8; 32]);
assert_ne!(ek.0, [0u8; 32]);
}
#[test]
fn test_derive_eddsa_key_deterministic() {
assert_eq!(
derive_eddsa_key_from_spending(&[42u8; 32]),
derive_eddsa_key_from_spending(&[42u8; 32]),
);
}
#[test]
fn test_domain_separation_all_keys_unique() {
let sk = [99u8; 32];
let vk = derive_viewing_key_from_spending(&sk);
let nk = derive_nullifier_key_from_spending(&sk);
let ek = derive_eddsa_key_from_spending(&sk);
assert_ne!(vk.0, nk.0);
assert_ne!(vk.0, ek.0);
assert_ne!(nk.0, ek.0);
}
#[test]
fn test_full_derivation_chain() {
let sk = [42u8; 32];
let vk = derive_viewing_key_from_spending(&sk);
let nk = derive_nullifier_key_from_spending(&sk);
let ek = derive_eddsa_key_from_spending(&sk);
let enc = derive_encryption_key(vk.as_bytes(), &[99u8; 32]);
assert_ne!(enc, [0u8; 32]);
assert_ne!(enc, vk.0);
assert_ne!(vk.0, nk.0);
assert_ne!(vk.0, ek.0);
}
#[test]
fn test_zero_spending_key_produces_non_zero_keys() {
let sk = [0u8; 32];
assert_ne!(derive_viewing_key_from_spending(&sk).0, [0u8; 32]);
assert_ne!(derive_nullifier_key_from_spending(&sk).0, [0u8; 32]);
assert_ne!(derive_eddsa_key_from_spending(&sk).0, [0u8; 32]);
}
#[test]
fn test_derive_nullifier_key_different_inputs() {
assert_ne!(
derive_nullifier_key_from_spending(&[1u8; 32]),
derive_nullifier_key_from_spending(&[2u8; 32]),
);
}
#[test]
fn test_derive_eddsa_key_different_inputs() {
assert_ne!(
derive_eddsa_key_from_spending(&[1u8; 32]),
derive_eddsa_key_from_spending(&[2u8; 32]),
);
}
#[test]
fn test_all_derived_keys_differ_from_spending_key() {
let sk = [42u8; 32];
assert_ne!(derive_viewing_key_from_spending(&sk).0, sk);
assert_ne!(derive_nullifier_key_from_spending(&sk).0, sk);
assert_ne!(derive_eddsa_key_from_spending(&sk).0, sk);
}
#[test]
fn test_derive_encryption_key_all_zero_inputs_non_zero() {
let result = derive_encryption_key(&[0u8; 32], &[0u8; 32]);
assert_ne!(result, [0u8; 32]);
}
#[test]
fn test_derive_encryption_key_output_length() {
let key = derive_encryption_key(&[1u8; 32], &[2u8; 32]);
assert_eq!(key.len(), 32);
}
}