382 lines
13 KiB
Rust
Raw Normal View History

2025-05-07 16:52:08 -03:00
use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit};
2025-04-16 16:17:53 +03:00
use common::merkle_tree_public::TreeHashType;
2024-10-30 12:32:36 +02:00
use constants_types::{CipherText, Nonce};
2025-05-07 16:37:03 -03:00
use elliptic_curve::point::AffineCoordinates;
2024-10-30 12:32:36 +02:00
use ephemeral_key_holder::EphemeralKeyHolder;
use k256::{ecdsa::SigningKey, AffinePoint, FieldBytes};
use log::info;
use rand::{rngs::OsRng, RngCore};
2024-10-30 12:32:36 +02:00
use secret_holders::{SeedHolder, TopSecretKeyHolder, UTXOSecretKeyHolder};
use serde::{Deserialize, Serialize};
2024-10-25 09:41:43 +03:00
2024-11-25 07:26:16 +02:00
use crate::account_core::PublicKey;
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 constants_types;
pub mod ephemeral_key_holder;
pub mod secret_holders;
2024-10-25 09:41:43 +03:00
#[derive(Serialize, Deserialize, Clone)]
2024-10-25 09:41:43 +03:00
///Entrypoint to key management
pub struct AddressKeyHolder {
2024-10-30 12:32:36 +02:00
//Will be useful in future
#[allow(dead_code)]
top_secret_key_holder: TopSecretKeyHolder,
2024-12-22 16:14:52 +02:00
pub utxo_secret_key_holder: UTXOSecretKeyHolder,
2025-07-16 10:04:23 -03:00
pub_account_signing_key: PublicAccountSigningKey,
2024-10-25 09:41:43 +03:00
pub address: TreeHashType,
2024-11-25 07:26:16 +02:00
pub nullifer_public_key: PublicKey,
pub viewing_public_key: PublicKey,
2024-10-25 09:41:43 +03:00
}
impl AddressKeyHolder {
pub fn new_os_random() -> Self {
2024-10-30 12:32:36 +02: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();
let top_secret_key_holder = seed_holder.produce_top_secret_key_holder();
let utxo_secret_key_holder = top_secret_key_holder.produce_utxo_secret_holder();
let address = utxo_secret_key_holder.generate_address();
let nullifer_public_key = utxo_secret_key_holder.generate_nullifier_public_key();
let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key();
2025-07-17 08:36:46 -03:00
let pub_account_signing_key = {
let mut bytes = [0; 32];
OsRng.fill_bytes(&mut bytes);
bytes
};
2024-10-25 09:41:43 +03:00
Self {
2024-10-30 12:32:36 +02:00
top_secret_key_holder,
2024-10-25 09:41:43 +03:00
utxo_secret_key_holder,
address,
nullifer_public_key,
viewing_public_key,
2025-07-17 08:36:46 -03:00
pub_account_signing_key,
2024-10-25 09:41:43 +03:00
}
}
/// Returns the signing key for public transaction signatures
2025-07-16 10:04:23 -03:00
pub fn get_pub_account_signing_key(&self) -> SigningKey {
let field_bytes = FieldBytes::from_slice(&self.pub_account_signing_key);
// TODO: remove unwrap
SigningKey::from_bytes(&field_bytes).unwrap()
}
2024-10-25 09:41:43 +03:00
pub fn calculate_shared_secret_receiver(
&self,
ephemeral_public_key_sender: AffinePoint,
) -> AffinePoint {
(ephemeral_public_key_sender * self.utxo_secret_key_holder.viewing_secret_key).into()
}
2024-10-30 12:32:36 +02:00
pub fn decrypt_data(
&self,
ephemeral_public_key_sender: AffinePoint,
ciphertext: CipherText,
nonce: Nonce,
2024-12-30 09:10:04 +02:00
) -> Result<Vec<u8>, aes_gcm::Error> {
2025-05-07 16:34:52 -03:00
let shared_secret = self.calculate_shared_secret_receiver(ephemeral_public_key_sender);
let cipher = Aes256Gcm::new(&shared_secret.x());
2024-11-02 01:40:44 +01:00
2024-12-30 09:10:04 +02:00
cipher.decrypt(&nonce, ciphertext.as_slice())
2024-10-30 12:32:36 +02:00
}
pub fn log(&self) {
2024-12-30 09:10:04 +02:00
info!(
2025-01-03 08:13:59 +02:00
"Secret spending key is {:?}",
2025-04-04 15:23:19 -04:00
hex::encode(
serde_json::to_vec(&self.top_secret_key_holder.secret_spending_key).unwrap()
),
2024-12-30 09:10:04 +02:00
);
info!(
2025-01-03 08:13:59 +02:00
"Nulifier secret key is {:?}",
2025-04-04 15:23:19 -04:00
hex::encode(
serde_json::to_vec(&self.utxo_secret_key_holder.nullifier_secret_key).unwrap()
),
2024-12-30 09:10:04 +02:00
);
info!(
2025-01-03 08:13:59 +02:00
"Viewing secret key is {:?}",
2025-04-04 15:23:19 -04:00
hex::encode(
serde_json::to_vec(&self.utxo_secret_key_holder.viewing_secret_key).unwrap()
),
2024-12-30 09:10:04 +02:00
);
info!(
2025-01-03 08:13:59 +02:00
"Nullifier public key is {:?}",
2025-04-04 14:55:50 -04:00
hex::encode(serde_json::to_vec(&self.nullifer_public_key).unwrap()),
2025-01-03 08:13:59 +02:00
);
info!(
"Viewing public key is {:?}",
2025-04-04 14:55:50 -04:00
hex::encode(serde_json::to_vec(&self.viewing_public_key).unwrap()),
2024-12-30 09:10:04 +02:00
);
}
2024-10-25 09:41:43 +03:00
}
2024-10-25 14:15:00 +03:00
#[cfg(test)]
mod tests {
2024-11-02 01:40:44 +01:00
use aes_gcm::{
aead::{Aead, KeyInit, OsRng},
Aes256Gcm,
};
use constants_types::{CipherText, Nonce};
2025-04-18 08:17:40 -04:00
use constants_types::{NULLIFIER_SECRET_CONST, VIEWING_SECRET_CONST};
2025-05-07 16:52:08 -03:00
use elliptic_curve::ff::Field;
2024-11-02 01:40:44 +01:00
use elliptic_curve::group::prime::PrimeCurveAffine;
2025-05-07 16:34:52 -03:00
use elliptic_curve::point::AffineCoordinates;
2025-05-07 16:37:03 -03:00
use k256::{AffinePoint, ProjectivePoint, Scalar};
2024-10-30 12:32:36 +02:00
use crate::key_management::ephemeral_key_holder::EphemeralKeyHolder;
2024-10-25 14:15:00 +03:00
use super::*;
2024-11-02 01:34:04 +01:00
#[test]
fn test_new_os_random() {
// Ensure that a new AddressKeyHolder instance can be created without errors.
let address_key_holder = AddressKeyHolder::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
2024-11-02 01:40:44 +01:00
assert!(!Into::<bool>::into(
address_key_holder.nullifer_public_key.is_identity()
));
assert!(!Into::<bool>::into(
address_key_holder.viewing_public_key.is_identity()
));
2024-11-02 01:34:04 +01:00
}
#[test]
fn test_calculate_shared_secret_receiver() {
let address_key_holder = AddressKeyHolder::new_os_random();
// Generate a random ephemeral public key sender
let scalar = Scalar::random(&mut OsRng);
let ephemeral_public_key_sender = (ProjectivePoint::GENERATOR * scalar).to_affine();
// Calculate shared secret
2024-11-02 01:40:44 +01:00
let shared_secret =
address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender);
// Ensure the shared secret is not an identity point (suggesting non-zero output)
assert!(!Into::<bool>::into(shared_secret.is_identity()));
}
2024-11-02 01:35:00 +01:00
#[test]
fn test_decrypt_data() {
let address_key_holder = AddressKeyHolder::new_os_random();
// Generate an ephemeral key and shared secret
let ephemeral_public_key_sender =
EphemeralKeyHolder::new_os_random().generate_ephemeral_public_key();
2024-11-02 01:40:44 +01:00
let shared_secret =
address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender);
2024-11-02 01:35:00 +01:00
// Encrypt sample data
2025-05-07 16:34:52 -03:00
let cipher = Aes256Gcm::new(&shared_secret.x());
2024-11-02 01:35:00 +01:00
let nonce = Nonce::from_slice(b"unique nonce");
let plaintext = b"Sensitive data";
2024-11-02 01:40:44 +01:00
let ciphertext = cipher
.encrypt(nonce, plaintext.as_ref())
.expect("encryption failure");
2024-11-02 01:35:00 +01:00
// Attempt decryption
2024-12-30 09:10:04 +02:00
let decrypted_data: Vec<u8> = address_key_holder
.decrypt_data(
ephemeral_public_key_sender,
CipherText::from(ciphertext),
nonce.clone(),
)
.unwrap();
2024-11-02 01:35:00 +01:00
// Verify decryption is successful and matches original plaintext
assert_eq!(decrypted_data, plaintext);
}
2024-11-02 01:36:10 +01:00
#[test]
fn test_new_os_random_initialization() {
// Ensure that AddressKeyHolder is initialized correctly
let address_key_holder = AddressKeyHolder::new_os_random();
// Check that key holder fields are initialized with expected types and values
2024-11-02 01:40:44 +01:00
assert!(!Into::<bool>::into(
address_key_holder.nullifer_public_key.is_identity()
));
assert!(!Into::<bool>::into(
address_key_holder.viewing_public_key.is_identity()
));
2024-11-02 01:36:10 +01:00
assert!(address_key_holder.address.as_slice().len() > 0); // Assume TreeHashType has non-zero length for a valid address
}
#[test]
fn test_calculate_shared_secret_with_identity_point() {
let address_key_holder = AddressKeyHolder::new_os_random();
// Use identity point as ephemeral public key
let identity_point = AffinePoint::identity();
// Calculate shared secret
let shared_secret = address_key_holder.calculate_shared_secret_receiver(identity_point);
// The shared secret with the identity point should also result in the identity point
assert!(Into::<bool>::into(shared_secret.is_identity()));
}
#[test]
#[should_panic]
fn test_decrypt_data_with_incorrect_nonce() {
let address_key_holder = AddressKeyHolder::new_os_random();
// Generate ephemeral public key and shared secret
let scalar = Scalar::random(OsRng);
2025-05-07 16:36:30 -03:00
let ephemeral_public_key_sender = (ProjectivePoint::GENERATOR * scalar).to_affine();
2024-11-02 01:40:44 +01:00
let shared_secret =
address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender);
// Encrypt sample data with a specific nonce
2025-05-07 16:52:08 -03:00
let cipher = Aes256Gcm::new(&shared_secret.x());
let nonce = Nonce::from_slice(b"unique nonce");
let plaintext = b"Sensitive data";
2024-11-02 01:40:44 +01:00
let ciphertext = cipher
.encrypt(nonce, plaintext.as_ref())
.expect("encryption failure");
// Attempt decryption with an incorrect nonce
let incorrect_nonce = Nonce::from_slice(b"wrong nonce");
2024-12-30 09:10:04 +02:00
let decrypted_data = address_key_holder
.decrypt_data(
ephemeral_public_key_sender,
CipherText::from(ciphertext.clone()),
incorrect_nonce.clone(),
)
.unwrap();
// The decryption should fail or produce incorrect output due to nonce mismatch
assert_ne!(decrypted_data, plaintext);
}
#[test]
#[should_panic]
fn test_decrypt_data_with_incorrect_ciphertext() {
let address_key_holder = AddressKeyHolder::new_os_random();
// Generate ephemeral public key and shared secret
let scalar = Scalar::random(OsRng);
2025-05-07 16:36:30 -03:00
let ephemeral_public_key_sender = (ProjectivePoint::GENERATOR * scalar).to_affine();
2024-11-02 01:40:44 +01:00
let shared_secret =
address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender);
// Encrypt sample data
2025-05-07 16:52:08 -03:00
let cipher = Aes256Gcm::new(&shared_secret.x());
let nonce = Nonce::from_slice(b"unique nonce");
let plaintext = b"Sensitive data";
2024-11-02 01:40:44 +01:00
let ciphertext = cipher
.encrypt(nonce, plaintext.as_ref())
.expect("encryption failure");
// Tamper with the ciphertext to simulate corruption
let mut corrupted_ciphertext = ciphertext.clone();
corrupted_ciphertext[0] ^= 1; // Flip a bit in the ciphertext
// Attempt decryption
2024-12-30 09:10:04 +02:00
let result = address_key_holder
.decrypt_data(
ephemeral_public_key_sender,
CipherText::from(corrupted_ciphertext),
nonce.clone(),
)
.unwrap();
// The decryption should fail or produce incorrect output due to tampered ciphertext
assert_ne!(result, plaintext);
}
#[test]
fn test_encryption_decryption_round_trip() {
let address_key_holder = AddressKeyHolder::new_os_random();
// Generate ephemeral key and shared secret
let scalar = Scalar::random(OsRng);
2025-05-07 16:36:30 -03:00
let ephemeral_public_key_sender = (ProjectivePoint::GENERATOR * scalar).to_affine();
// Encrypt sample data
let plaintext = b"Round-trip test data";
let nonce = Nonce::from_slice(b"unique nonce");
2024-11-02 01:40:44 +01:00
let shared_secret =
address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender);
2025-05-07 16:34:52 -03:00
let cipher = Aes256Gcm::new(&shared_secret.x());
2024-11-02 01:40:44 +01:00
let ciphertext = cipher
.encrypt(nonce, plaintext.as_ref())
.expect("encryption failure");
// Decrypt the data using the `AddressKeyHolder` instance
2024-12-30 09:10:04 +02:00
let decrypted_data = address_key_holder
.decrypt_data(
ephemeral_public_key_sender,
CipherText::from(ciphertext),
nonce.clone(),
)
.unwrap();
// Verify the decrypted data matches the original plaintext
assert_eq!(decrypted_data, plaintext);
}
2025-07-16 11:43:40 -03:00
#[test]
fn test_get_public_account_signing_key() {
let address_key_holder = AddressKeyHolder::new_os_random();
let signing_key = address_key_holder.get_pub_account_signing_key();
assert_eq!(
signing_key.to_bytes().as_slice(),
address_key_holder.pub_account_signing_key
);
}
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();
let utxo_secret_key_holder = top_secret_key_holder.produce_utxo_secret_holder();
let address = utxo_secret_key_holder.generate_address();
let nullifer_public_key = utxo_secret_key_holder.generate_nullifier_public_key();
let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key();
println!("======Prerequisites======");
println!();
2024-10-25 14:19:42 +03:00
println!(
"Group generator {:?}",
2025-04-04 14:55:50 -04:00
hex::encode(serde_json::to_vec(&AffinePoint::GENERATOR).unwrap())
2024-10-25 14:19:42 +03:00
);
println!(
"Nullifier constant {:?}",
2025-04-18 08:17:40 -04:00
hex::encode(*NULLIFIER_SECRET_CONST)
2024-10-25 14:19:42 +03:00
);
2025-04-18 08:17:40 -04:00
println!("Viewing constatnt {:?}", hex::encode(*VIEWING_SECRET_CONST));
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!("Address{:?}", hex::encode(address));
2024-10-25 14:19:42 +03:00
println!(
"Nulifier public key {:?}",
2025-04-04 14:55:50 -04:00
hex::encode(serde_json::to_vec(&nullifer_public_key).unwrap())
2024-10-25 14:19:42 +03:00
);
println!(
"Viewing public key {:?}",
2025-04-04 14:55:50 -04:00
hex::encode(serde_json::to_vec(&viewing_public_key).unwrap())
2024-10-25 14:19:42 +03:00
);
2024-10-25 14:15:00 +03:00
}
}