mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-08 16:23:12 +00:00
fix: keys structures updates
This commit is contained in:
parent
324f477b63
commit
33783e06d8
@ -1,11 +1,7 @@
|
|||||||
use aes_gcm::{aead::Aead, AeadCore, Aes256Gcm, KeyInit};
|
|
||||||
use elliptic_curve::point::AffineCoordinates;
|
|
||||||
use elliptic_curve::PrimeField;
|
use elliptic_curve::PrimeField;
|
||||||
use k256::{AffinePoint, FieldBytes, Scalar};
|
use k256::{AffinePoint, Scalar};
|
||||||
use log::info;
|
use log::info;
|
||||||
use rand::{rngs::OsRng, RngCore};
|
use sha2::Digest;
|
||||||
|
|
||||||
use super::types::{CipherText, Nonce};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
///Ephemeral secret key holder. Non-clonable as intended for one-time use. Produces ephemeral public keys. Can produce shared secret for sender.
|
///Ephemeral secret key holder. Non-clonable as intended for one-time use. Produces ephemeral public keys. Can produce shared secret for sender.
|
||||||
@ -14,13 +10,24 @@ pub struct EphemeralKeyHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl EphemeralKeyHolder {
|
impl EphemeralKeyHolder {
|
||||||
pub fn new_os_random() -> Self {
|
pub fn new(
|
||||||
let mut bytes = FieldBytes::default();
|
receiver_nullifier_public_key: [u8; 32],
|
||||||
|
sender_outgoing_viewing_secret_key: Scalar,
|
||||||
|
nonce: u64,
|
||||||
|
) -> Self {
|
||||||
|
let mut hasher = sha2::Sha256::new();
|
||||||
|
hasher.update(receiver_nullifier_public_key);
|
||||||
|
hasher.update(nonce.to_le_bytes());
|
||||||
|
hasher.update([0; 192]);
|
||||||
|
|
||||||
OsRng.fill_bytes(&mut bytes);
|
let hash_recepient = hasher.finalize();
|
||||||
|
|
||||||
|
let mut hasher = sha2::Sha256::new();
|
||||||
|
hasher.update(sender_outgoing_viewing_secret_key.to_bytes());
|
||||||
|
hasher.update(hash_recepient);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
ephemeral_secret_key: Scalar::from_repr(bytes).unwrap(),
|
ephemeral_secret_key: Scalar::from_repr(hasher.finalize()).unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,21 +37,9 @@ impl EphemeralKeyHolder {
|
|||||||
|
|
||||||
pub fn calculate_shared_secret_sender(
|
pub fn calculate_shared_secret_sender(
|
||||||
&self,
|
&self,
|
||||||
viewing_public_key_receiver: AffinePoint,
|
receiver_incoming_viewing_public_key: Scalar,
|
||||||
) -> AffinePoint {
|
) -> Scalar {
|
||||||
(viewing_public_key_receiver * self.ephemeral_secret_key).into()
|
receiver_incoming_viewing_public_key * self.ephemeral_secret_key
|
||||||
}
|
|
||||||
|
|
||||||
pub fn encrypt_data(
|
|
||||||
&self,
|
|
||||||
viewing_public_key_receiver: AffinePoint,
|
|
||||||
data: &[u8],
|
|
||||||
) -> (CipherText, Nonce) {
|
|
||||||
let shared_secret = self.calculate_shared_secret_sender(viewing_public_key_receiver);
|
|
||||||
let cipher = Aes256Gcm::new(&shared_secret.x());
|
|
||||||
let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
|
|
||||||
|
|
||||||
(cipher.encrypt(&nonce, data).unwrap(), nonce)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn log(&self) {
|
pub fn log(&self) {
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit};
|
use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit};
|
||||||
use common::merkle_tree_public::TreeHashType;
|
use common::merkle_tree_public::TreeHashType;
|
||||||
use elliptic_curve::group::GroupEncoding;
|
use elliptic_curve::group::GroupEncoding;
|
||||||
@ -23,8 +21,6 @@ pub mod types;
|
|||||||
pub struct KeyChain {
|
pub struct KeyChain {
|
||||||
top_secret_key_holder: TopSecretKeyHolder,
|
top_secret_key_holder: TopSecretKeyHolder,
|
||||||
pub private_key_holder: PrivateKeyHolder,
|
pub private_key_holder: PrivateKeyHolder,
|
||||||
///Map for all users accounts
|
|
||||||
pub_account_signing_keys: HashMap<nssa::Address, nssa::PrivateKey>,
|
|
||||||
pub nullifer_public_key: [u8; 32],
|
pub nullifer_public_key: [u8; 32],
|
||||||
pub incoming_viewing_public_key: PublicKey,
|
pub incoming_viewing_public_key: PublicKey,
|
||||||
}
|
}
|
||||||
@ -46,61 +42,27 @@ impl KeyChain {
|
|||||||
private_key_holder,
|
private_key_holder,
|
||||||
nullifer_public_key,
|
nullifer_public_key,
|
||||||
incoming_viewing_public_key,
|
incoming_viewing_public_key,
|
||||||
pub_account_signing_keys: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_os_random_with_accounts(accounts: HashMap<nssa::Address, nssa::PrivateKey>) -> Self {
|
|
||||||
//Currently dropping SeedHolder at the end of initialization.
|
|
||||||
//Now entirely sure if we need it in the future.
|
|
||||||
let seed_holder = SeedHolder::new_os_random();
|
|
||||||
let top_secret_key_holder = seed_holder.produce_top_secret_key_holder();
|
|
||||||
|
|
||||||
let private_key_holder = top_secret_key_holder.produce_private_key_holder();
|
|
||||||
|
|
||||||
let nullifer_public_key = private_key_holder.generate_nullifier_public_key();
|
|
||||||
let incoming_viewing_public_key = private_key_holder.generate_incoming_viewing_public_key();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
top_secret_key_holder,
|
|
||||||
private_key_holder,
|
|
||||||
nullifer_public_key,
|
|
||||||
incoming_viewing_public_key,
|
|
||||||
pub_account_signing_keys: accounts,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn produce_user_address(&self) -> [u8; 32] {
|
pub fn produce_user_address(&self) -> [u8; 32] {
|
||||||
let mut hasher = sha2::Sha256::new();
|
let mut hasher = sha2::Sha256::new();
|
||||||
|
|
||||||
hasher.update(&self.nullifer_public_key);
|
hasher.update(self.nullifer_public_key);
|
||||||
hasher.update(&self.incoming_viewing_public_key.to_bytes());
|
hasher.update(self.incoming_viewing_public_key.to_bytes());
|
||||||
|
|
||||||
<TreeHashType>::from(hasher.finalize_fixed())
|
<TreeHashType>::from(hasher.finalize_fixed())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_new_private_key(&mut self) -> nssa::Address {
|
|
||||||
let private_key = nssa::PrivateKey::new_os_random();
|
|
||||||
let address = nssa::Address::from(&nssa::PublicKey::new_from_private_key(&private_key));
|
|
||||||
|
|
||||||
self.pub_account_signing_keys.insert(address, private_key);
|
|
||||||
|
|
||||||
address
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the signing key for public transaction signatures
|
|
||||||
pub fn get_pub_account_signing_key(
|
|
||||||
&self,
|
|
||||||
address: &nssa::Address,
|
|
||||||
) -> Option<&nssa::PrivateKey> {
|
|
||||||
self.pub_account_signing_keys.get(address)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn calculate_shared_secret_receiver(
|
pub fn calculate_shared_secret_receiver(
|
||||||
&self,
|
&self,
|
||||||
ephemeral_public_key_sender: AffinePoint,
|
ephemeral_public_key_sender: AffinePoint,
|
||||||
) -> AffinePoint {
|
) -> AffinePoint {
|
||||||
(ephemeral_public_key_sender * self.utxo_secret_key_holder.viewing_secret_key).into()
|
(ephemeral_public_key_sender
|
||||||
|
* self
|
||||||
|
.top_secret_key_holder
|
||||||
|
.generate_incloming_viewing_secret_key())
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decrypt_data(
|
pub fn decrypt_data(
|
||||||
@ -197,9 +159,19 @@ mod tests {
|
|||||||
fn test_decrypt_data() {
|
fn test_decrypt_data() {
|
||||||
let address_key_holder = KeyChain::new_os_random();
|
let address_key_holder = KeyChain::new_os_random();
|
||||||
|
|
||||||
|
let test_receiver_nullifier_public_key = [42; 32];
|
||||||
|
let sender_outgoing_viewing_key = address_key_holder
|
||||||
|
.top_secret_key_holder
|
||||||
|
.generate_outgoing_viewing_secret_key();
|
||||||
|
let nonce = 0;
|
||||||
|
|
||||||
// Generate an ephemeral key and shared secret
|
// Generate an ephemeral key and shared secret
|
||||||
let ephemeral_public_key_sender =
|
let ephemeral_public_key_sender = EphemeralKeyHolder::new(
|
||||||
EphemeralKeyHolder::new_os_random().generate_ephemeral_public_key();
|
test_receiver_nullifier_public_key,
|
||||||
|
sender_outgoing_viewing_key,
|
||||||
|
nonce,
|
||||||
|
)
|
||||||
|
.generate_ephemeral_public_key();
|
||||||
let shared_secret =
|
let shared_secret =
|
||||||
address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender);
|
address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender);
|
||||||
|
|
||||||
@ -340,19 +312,6 @@ mod tests {
|
|||||||
assert_eq!(decrypted_data, plaintext);
|
assert_eq!(decrypted_data, plaintext);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_get_public_account_signing_key() {
|
|
||||||
let mut address_key_holder = KeyChain::new_os_random();
|
|
||||||
|
|
||||||
let address = address_key_holder.generate_new_private_key();
|
|
||||||
|
|
||||||
let is_private_key_generated = address_key_holder
|
|
||||||
.get_pub_account_signing_key(&address)
|
|
||||||
.is_some();
|
|
||||||
|
|
||||||
assert!(is_private_key_generated);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn key_generation_test() {
|
fn key_generation_test() {
|
||||||
let seed_holder = SeedHolder::new_os_random();
|
let seed_holder = SeedHolder::new_os_random();
|
||||||
|
|||||||
@ -45,7 +45,7 @@ impl SeedHolder {
|
|||||||
let mut hash = hmac_sha512::HMAC::mac(&self.seed, "NSSA_seed");
|
let mut hash = hmac_sha512::HMAC::mac(&self.seed, "NSSA_seed");
|
||||||
|
|
||||||
for _ in 1..2048 {
|
for _ in 1..2048 {
|
||||||
hash = hmac_sha512::HMAC::mac(&hash, "NSSA_seed");
|
hash = hmac_sha512::HMAC::mac(hash, "NSSA_seed");
|
||||||
}
|
}
|
||||||
|
|
||||||
//Safe unwrap
|
//Safe unwrap
|
||||||
@ -64,7 +64,7 @@ impl TopSecretKeyHolder {
|
|||||||
let mut hasher = sha2::Sha256::new();
|
let mut hasher = sha2::Sha256::new();
|
||||||
|
|
||||||
hasher.update("NSSA_keys");
|
hasher.update("NSSA_keys");
|
||||||
hasher.update(&self.secret_spending_key);
|
hasher.update(self.secret_spending_key);
|
||||||
hasher.update([1u8]);
|
hasher.update([1u8]);
|
||||||
hasher.update([0u8; 176]);
|
hasher.update([0u8; 176]);
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ impl TopSecretKeyHolder {
|
|||||||
let mut hasher = sha2::Sha256::new();
|
let mut hasher = sha2::Sha256::new();
|
||||||
|
|
||||||
hasher.update("NSSA_keys");
|
hasher.update("NSSA_keys");
|
||||||
hasher.update(&self.secret_spending_key);
|
hasher.update(self.secret_spending_key);
|
||||||
hasher.update([2u8]);
|
hasher.update([2u8]);
|
||||||
hasher.update([0u8; 176]);
|
hasher.update([0u8; 176]);
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ impl TopSecretKeyHolder {
|
|||||||
let mut hasher = sha2::Sha256::new();
|
let mut hasher = sha2::Sha256::new();
|
||||||
|
|
||||||
hasher.update("NSSA_keys");
|
hasher.update("NSSA_keys");
|
||||||
hasher.update(&self.secret_spending_key);
|
hasher.update(self.secret_spending_key);
|
||||||
hasher.update([3u8]);
|
hasher.update([3u8]);
|
||||||
hasher.update([0u8; 176]);
|
hasher.update([0u8; 176]);
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ impl PrivateKeyHolder {
|
|||||||
let mut hasher = sha2::Sha256::new();
|
let mut hasher = sha2::Sha256::new();
|
||||||
|
|
||||||
hasher.update("NSSA_keys");
|
hasher.update("NSSA_keys");
|
||||||
hasher.update(&self.nullifier_secret_key);
|
hasher.update(self.nullifier_secret_key);
|
||||||
hasher.update([7u8]);
|
hasher.update([7u8]);
|
||||||
hasher.update([0u8; 176]);
|
hasher.update([0u8; 176]);
|
||||||
|
|
||||||
|
|||||||
@ -10,17 +10,14 @@ pub type PublicKey = AffinePoint;
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct NSSAUserData {
|
pub struct NSSAUserData {
|
||||||
pub key_holder: KeyChain,
|
///Map for all user public accounts
|
||||||
|
pub_account_signing_keys: HashMap<nssa::Address, nssa::PrivateKey>,
|
||||||
|
///Map for all user private accounts
|
||||||
|
user_private_accounts: HashMap<nssa::Address, KeyChain>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NSSAUserData {
|
impl NSSAUserData {
|
||||||
pub fn new() -> Self {
|
fn valid_public_key_transaction_pairing_check(
|
||||||
let key_holder = KeyChain::new_os_random();
|
|
||||||
|
|
||||||
Self { key_holder }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn valid_key_transaction_pairing_check(
|
|
||||||
accounts_keys_map: &HashMap<nssa::Address, nssa::PrivateKey>,
|
accounts_keys_map: &HashMap<nssa::Address, nssa::PrivateKey>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut check_res = true;
|
let mut check_res = true;
|
||||||
@ -32,30 +29,78 @@ impl NSSAUserData {
|
|||||||
check_res
|
check_res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn valid_private_key_transaction_pairing_check(
|
||||||
|
accounts_keys_map: &HashMap<nssa::Address, KeyChain>,
|
||||||
|
) -> bool {
|
||||||
|
let mut check_res = true;
|
||||||
|
for (addr, key) in accounts_keys_map {
|
||||||
|
if nssa::Address::new(key.produce_user_address()) != *addr {
|
||||||
|
check_res = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
check_res
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_with_accounts(
|
pub fn new_with_accounts(
|
||||||
accounts_keys: HashMap<nssa::Address, nssa::PrivateKey>,
|
accounts_keys: HashMap<nssa::Address, nssa::PrivateKey>,
|
||||||
|
accounts_key_chains: HashMap<nssa::Address, KeyChain>,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
if !Self::valid_key_transaction_pairing_check(&accounts_keys) {
|
if !Self::valid_public_key_transaction_pairing_check(&accounts_keys) {
|
||||||
anyhow::bail!("Key transaction pairing check not satisfied, there is addresses, which is not derived from keys");
|
anyhow::bail!("Key transaction pairing check not satisfied, there is addresses, which is not derived from keys");
|
||||||
}
|
}
|
||||||
|
|
||||||
let key_holder = KeyChain::new_os_random_with_accounts(accounts_keys);
|
if !Self::valid_private_key_transaction_pairing_check(&accounts_key_chains) {
|
||||||
|
anyhow::bail!("Key transaction pairing check not satisfied, there is addresses, which is not derived from keys");
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Self { key_holder })
|
Ok(Self {
|
||||||
|
pub_account_signing_keys: accounts_keys,
|
||||||
|
user_private_accounts: accounts_key_chains,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_new_account(&mut self) -> nssa::Address {
|
/// Generated new private key for public transaction signatures
|
||||||
self.key_holder.generate_new_private_key()
|
///
|
||||||
|
/// Returns the address of new account
|
||||||
|
pub fn generate_new_public_transaction_private_key(&mut self) -> nssa::Address {
|
||||||
|
let private_key = nssa::PrivateKey::new_os_random();
|
||||||
|
let address = nssa::Address::from(&nssa::PublicKey::new_from_private_key(&private_key));
|
||||||
|
|
||||||
|
self.pub_account_signing_keys.insert(address, private_key);
|
||||||
|
|
||||||
|
address
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_account_signing_key(&self, address: &nssa::Address) -> Option<&nssa::PrivateKey> {
|
/// Returns the signing key for public transaction signatures
|
||||||
self.key_holder.get_pub_account_signing_key(address)
|
pub fn get_pub_account_signing_key(
|
||||||
|
&self,
|
||||||
|
address: &nssa::Address,
|
||||||
|
) -> Option<&nssa::PrivateKey> {
|
||||||
|
self.pub_account_signing_keys.get(address)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generated new private key for privacy preserving transactions
|
||||||
|
///
|
||||||
|
/// Returns the address of new account
|
||||||
|
pub fn generate_new_privacy_preserving_transaction_key_chain(&mut self) -> nssa::Address {
|
||||||
|
let key_chain = KeyChain::new_os_random();
|
||||||
|
let address = nssa::Address::new(key_chain.produce_user_address());
|
||||||
|
|
||||||
|
self.user_private_accounts.insert(address, key_chain);
|
||||||
|
|
||||||
|
address
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the signing key for public transaction signatures
|
||||||
|
pub fn get_private_account_key_chain(&self, address: &nssa::Address) -> Option<&KeyChain> {
|
||||||
|
self.user_private_accounts.get(address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for NSSAUserData {
|
impl Default for NSSAUserData {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
//Safe unwrap as maps are empty
|
||||||
|
Self::new_with_accounts(HashMap::default(), HashMap::default()).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,8 +110,19 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_new_account() {
|
fn test_new_account() {
|
||||||
let mut user_data = NSSAUserData::new();
|
let mut user_data = NSSAUserData::default();
|
||||||
|
|
||||||
let _addr = user_data.generate_new_account();
|
let addr_pub = user_data.generate_new_public_transaction_private_key();
|
||||||
|
let addr_private = user_data.generate_new_privacy_preserving_transaction_key_chain();
|
||||||
|
|
||||||
|
let is_private_key_generated = user_data.get_pub_account_signing_key(&addr_pub).is_some();
|
||||||
|
|
||||||
|
assert!(is_private_key_generated);
|
||||||
|
|
||||||
|
let is_key_chain_generated = user_data
|
||||||
|
.get_private_account_key_chain(&addr_private)
|
||||||
|
.is_some();
|
||||||
|
|
||||||
|
assert!(is_key_chain_generated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,7 @@ impl WalletChainStore {
|
|||||||
let utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]);
|
let utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
user_data: NSSAUserData::new_with_accounts(accounts_keys)?,
|
user_data: NSSAUserData::new_with_accounts(accounts_keys, HashMap::new())?,
|
||||||
utxo_commitments_store,
|
utxo_commitments_store,
|
||||||
wallet_config: config,
|
wallet_config: config,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -41,7 +41,9 @@ impl WalletCore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_new_account(&mut self) -> Address {
|
pub fn create_new_account(&mut self) -> Address {
|
||||||
self.storage.user_data.generate_new_account()
|
self.storage
|
||||||
|
.user_data
|
||||||
|
.generate_new_public_transaction_private_key()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn search_for_initial_account(&self, acc_addr: Address) -> Option<Account> {
|
pub fn search_for_initial_account(&self, acc_addr: Address) -> Option<Account> {
|
||||||
@ -75,7 +77,7 @@ impl WalletCore {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let signing_key = self.storage.user_data.get_account_signing_key(&from);
|
let signing_key = self.storage.user_data.get_pub_account_signing_key(&from);
|
||||||
|
|
||||||
if let Some(signing_key) = signing_key {
|
if let Some(signing_key) = signing_key {
|
||||||
let witness_set =
|
let witness_set =
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user