353 lines
9.4 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
2025-07-16 10:04:23 -03:00
pub type PublicAccountSigningKey = [u8; 32];
2024-11-25 07:26:16 +02: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
2025-07-29 14:20:03 +03:00
#[derive(Serialize, Deserialize, Clone, Debug)]
2025-11-26 00:27:20 +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 {
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
}
}
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
}
}
pub fn calculate_shared_secret_receiver(
&self,
2025-09-15 14:04:49 +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),
2025-09-15 14:04:49 +03:00
&ephemeral_public_key_sender,
)
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;
2025-10-23 17:33:25 +03:00
use base58::ToBase58;
2025-11-26 00:27:20 +03:00
use k256::{AffinePoint, elliptic_curve::group::GroupEncoding};
2025-09-17 08:59:14 +03:00
use rand::RngCore;
2024-10-25 14:15:00 +03:00
use super::*;
2026-03-05 15:20:22 +02:00
use crate::key_management::ephemeral_key_holder::EphemeralKeyHolder;
2024-10-25 14:15:00 +03:00
2024-11-02 01:34:04 +01:00
#[test]
fn test_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(),
&[0u8; 32]
);
2024-11-02 01:34:04 +01:00
}
#[test]
fn test_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
.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 {
let key_chain_raw = r#"
{
"secret_spending_key": [
208,
155,
82,
128,
101,
206,
20,
95,
241,
147,
159,
231,
207,
78,
152,
28,
114,
111,
61,
69,
254,
51,
242,
28,
28,
195,
170,
242,
160,
24,
47,
189
],
"private_key_holder": {
"nullifier_secret_key": [
142,
76,
154,
157,
42,
40,
174,
199,
151,
63,
2,
216,
52,
103,
81,
42,
200,
177,
189,
49,
81,
39,
166,
139,
203,
154,
156,
166,
88,
159,
11,
151
],
"viewing_secret_key": [
122,
94,
159,
21,
28,
49,
169,
79,
12,
156,
171,
90,
41,
216,
203,
75,
251,
192,
204,
217,
18,
49,
28,
219,
213,
147,
244,
194,
205,
237,
134,
36
]
},
"nullifer_public_key": [
235,
24,
62,
99,
243,
236,
137,
35,
153,
149,
6,
10,
118,
239,
117,
188,
64,
8,
33,
52,
220,
231,
11,
39,
180,
117,
1,
22,
62,
199,
164,
169
],
"viewing_public_key": [
2,
253,
204,
5,
212,
86,
249,
156,
132,
143,
1,
172,
80,
61,
18,
185,
233,
36,
221,
58,
64,
110,
89,
242,
202,
230,
154,
66,
45,
252,
138,
174,
37
]
}
"#;
serde_json::from_str(key_chain_raw).unwrap()
}
#[test]
fn test_non_trivial_chain_index() {
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(
eph_key_holder.generate_ephemeral_public_key(),
Some(2),
);
assert_eq!(key_sender.0, key_receiver.0);
}
2024-10-25 14:15:00 +03:00
}