197 lines
6.2 KiB
Rust
Raw Normal View History

2025-09-15 14:04:49 +03:00
use nssa_core::{
NullifierPublicKey, SharedSecretKey,
2026-01-21 17:27:23 -05:00
encryption::{EphemeralPublicKey, ViewingPublicKey},
2025-09-15 14:04:49 +03:00
};
use secret_holders::{PrivateKeyHolder, SecretSpendingKey, SeedHolder};
use serde::{Deserialize, Serialize};
2024-10-25 09:41:43 +03:00
2024-10-30 12:32:36 +02:00
pub mod ephemeral_key_holder;
2025-11-05 15:15:29 +02:00
pub mod key_tree;
2024-10-30 12:32:36 +02:00
pub mod secret_holders;
2024-10-25 09:41:43 +03:00
2026-03-04 18:42:33 +03:00
pub type PublicAccountSigningKey = [u8; 32];
2025-07-29 14:20:03 +03:00
#[derive(Serialize, Deserialize, Clone, Debug)]
2026-03-10 00:17:43 +03:00
/// Entrypoint to key management.
2025-08-15 14:27:36 +03:00
pub struct KeyChain {
2025-11-10 16:29:33 +02:00
pub secret_spending_key: SecretSpendingKey,
2025-09-05 14:47:58 +03:00
pub private_key_holder: PrivateKeyHolder,
2025-09-15 14:04:49 +03:00
pub nullifer_public_key: NullifierPublicKey,
2026-01-21 17:27:23 -05:00
pub viewing_public_key: ViewingPublicKey,
2024-10-25 09:41:43 +03:00
}
2025-08-15 14:27:36 +03:00
impl KeyChain {
2026-03-03 23:21:08 +03:00
#[must_use]
2024-10-25 09:41:43 +03:00
pub fn new_os_random() -> Self {
2025-11-26 00:27:20 +03:00
// Currently dropping SeedHolder at the end of initialization.
// Now entirely sure if we need it in the future.
2024-10-25 09:41:43 +03:00
let seed_holder = SeedHolder::new_os_random();
2025-09-15 14:04:49 +03:00
let secret_spending_key = seed_holder.produce_top_secret_key_holder();
2024-10-25 09:41:43 +03:00
2026-01-27 16:00:42 -05:00
let private_key_holder = secret_spending_key.produce_private_key_holder(None);
2024-10-25 09:41:43 +03:00
2025-09-05 14:47:58 +03:00
let nullifer_public_key = private_key_holder.generate_nullifier_public_key();
2026-01-21 17:27:23 -05:00
let viewing_public_key = private_key_holder.generate_viewing_public_key();
2025-11-04 16:09:04 +02:00
Self {
secret_spending_key,
private_key_holder,
nullifer_public_key,
2026-01-21 17:27:23 -05:00
viewing_public_key,
2025-11-04 16:09:04 +02:00
}
}
2026-03-03 23:21:08 +03:00
#[must_use]
2025-11-04 16:09:04 +02:00
pub fn new_mnemonic(passphrase: String) -> Self {
// Currently dropping SeedHolder at the end of initialization.
// Not entirely sure if we need it in the future.
2025-11-04 16:09:04 +02:00
let seed_holder = SeedHolder::new_mnemonic(passphrase);
let secret_spending_key = seed_holder.produce_top_secret_key_holder();
2026-01-27 16:00:42 -05:00
let private_key_holder = secret_spending_key.produce_private_key_holder(None);
2025-11-04 16:09:04 +02:00
let nullifer_public_key = private_key_holder.generate_nullifier_public_key();
2026-01-21 17:27:23 -05:00
let viewing_public_key = private_key_holder.generate_viewing_public_key();
2024-10-25 09:41:43 +03:00
2025-08-18 16:15:25 +03:00
Self {
2025-09-15 14:04:49 +03:00
secret_spending_key,
2025-09-05 14:47:58 +03:00
private_key_holder,
2025-08-18 16:15:25 +03:00
nullifer_public_key,
2026-01-21 17:27:23 -05:00
viewing_public_key,
2024-10-25 09:41:43 +03:00
}
}
2026-03-03 23:21:08 +03:00
#[must_use]
2024-10-25 09:41:43 +03:00
pub fn calculate_shared_secret_receiver(
&self,
2026-03-03 23:21:08 +03:00
ephemeral_public_key_sender: &EphemeralPublicKey,
2026-03-05 12:35:18 +02:00
index: Option<u32>,
2025-09-15 14:04:49 +03:00
) -> SharedSecretKey {
SharedSecretKey::new(
2026-03-05 12:35:18 +02:00
&self.secret_spending_key.generate_viewing_secret_key(index),
2026-03-03 23:21:08 +03:00
ephemeral_public_key_sender,
2025-09-15 14:04:49 +03:00
)
2024-10-30 12:32:36 +02:00
}
2024-10-25 09:41:43 +03:00
}
2024-10-25 14:15:00 +03:00
#[cfg(test)]
mod tests {
2025-09-15 14:04:49 +03:00
use aes_gcm::aead::OsRng;
2026-03-04 18:42:33 +03:00
use base58::ToBase58 as _;
use k256::{AffinePoint, elliptic_curve::group::GroupEncoding as _};
use rand::RngCore as _;
2024-10-25 14:15:00 +03:00
use super::*;
2026-03-05 17:25:53 +02:00
use crate::key_management::{
ephemeral_key_holder::EphemeralKeyHolder, key_tree::KeyTreePrivate,
};
2024-10-25 14:15:00 +03:00
2024-11-02 01:34:04 +01:00
#[test]
2026-03-04 18:42:33 +03:00
fn new_os_random() {
2025-08-15 14:27:36 +03:00
// Ensure that a new KeyChain instance can be created without errors.
let account_id_key_holder = KeyChain::new_os_random();
2024-11-02 01:40:44 +01:00
2024-11-02 01:34:04 +01:00
// Check that key holder fields are initialized with expected types
assert_ne!(
account_id_key_holder.nullifer_public_key.as_ref(),
2026-03-04 18:42:33 +03:00
&[0_u8; 32]
);
2024-11-02 01:34:04 +01:00
}
#[test]
2026-03-04 18:42:33 +03:00
fn calculate_shared_secret_receiver() {
let account_id_key_holder = KeyChain::new_os_random();
// Generate a random ephemeral public key sender
2025-09-17 08:59:14 +03:00
let mut scalar = [0; 32];
OsRng.fill_bytes(&mut scalar);
2025-09-15 14:04:49 +03:00
let ephemeral_public_key_sender = EphemeralPublicKey::from_scalar(scalar);
// Calculate shared secret
2026-03-05 12:35:18 +02:00
let _shared_secret = account_id_key_holder
2026-03-03 23:21:08 +03:00
.calculate_shared_secret_receiver(&ephemeral_public_key_sender, None);
}
2024-10-25 14:15:00 +03:00
#[test]
fn key_generation_test() {
let seed_holder = SeedHolder::new_os_random();
let top_secret_key_holder = seed_holder.produce_top_secret_key_holder();
2026-01-27 16:00:42 -05:00
let utxo_secret_key_holder = top_secret_key_holder.produce_private_key_holder(None);
2024-10-25 14:15:00 +03:00
let nullifer_public_key = utxo_secret_key_holder.generate_nullifier_public_key();
2026-01-21 17:27:23 -05:00
let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key();
2024-10-25 14:15:00 +03:00
2025-08-18 16:15:25 +03:00
let pub_account_signing_key = nssa::PrivateKey::new_os_random();
2025-07-29 14:20:03 +03:00
2025-08-13 01:33:11 -03:00
let public_key = nssa::PublicKey::new_from_private_key(&pub_account_signing_key);
2025-07-29 14:20:03 +03:00
let account = nssa::AccountId::from(&public_key);
2025-07-29 14:20:03 +03:00
2024-10-25 14:15:00 +03:00
println!("======Prerequisites======");
println!();
2024-10-25 14:19:42 +03:00
println!(
"Group generator {:?}",
2025-09-25 11:53:42 +03:00
hex::encode(AffinePoint::GENERATOR.to_bytes())
2024-10-25 14:19:42 +03:00
);
2024-10-25 14:15:00 +03:00
println!();
println!("======Holders======");
println!();
println!("{seed_holder:?}");
println!("{top_secret_key_holder:?}");
println!("{utxo_secret_key_holder:?}");
println!();
println!("======Public data======");
println!();
println!("Account {:?}", account.value().to_base58());
2024-10-25 14:19:42 +03:00
println!(
"Nulifier public key {:?}",
2025-09-25 11:53:42 +03:00
hex::encode(nullifer_public_key.to_byte_array())
2024-10-25 14:19:42 +03:00
);
println!(
"Viewing public key {:?}",
2025-09-25 11:53:42 +03:00
hex::encode(viewing_public_key.to_bytes())
2024-10-25 14:19:42 +03:00
);
2024-10-25 14:15:00 +03:00
}
2026-03-05 15:20:22 +02:00
fn account_with_chain_index_2_for_tests() -> KeyChain {
2026-03-05 17:25:53 +02:00
let seed = SeedHolder::new_os_random();
let mut key_tree_private = KeyTreePrivate::new(&seed);
// /0
key_tree_private.generate_new_node_layered().unwrap();
// /1
key_tree_private.generate_new_node_layered().unwrap();
// /0/0
key_tree_private.generate_new_node_layered().unwrap();
// /2
let (second_child_id, _) = key_tree_private.generate_new_node_layered().unwrap();
key_tree_private
.get_node(second_child_id)
.unwrap()
.value
.0
.clone()
2026-03-05 15:20:22 +02:00
}
#[test]
2026-03-04 18:42:33 +03:00
fn non_trivial_chain_index() {
2026-03-05 15:20:22 +02:00
let keys = account_with_chain_index_2_for_tests();
let eph_key_holder = EphemeralKeyHolder::new(&keys.nullifer_public_key);
let key_sender = eph_key_holder.calculate_shared_secret_sender(&keys.viewing_public_key);
let key_receiver = keys.calculate_shared_secret_receiver(
2026-03-03 23:21:08 +03:00
&eph_key_holder.generate_ephemeral_public_key(),
2026-03-05 15:20:22 +02:00
Some(2),
);
assert_eq!(key_sender.0, key_receiver.0);
}
2024-10-25 14:15:00 +03:00
}