diff --git a/Cargo.lock b/Cargo.lock index 066222a..ea291ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,6 +6,7 @@ version = 4 name = "accounts" version = "0.1.0" dependencies = [ + "aes-gcm", "anyhow", "elliptic-curve", "env_logger", @@ -17,6 +18,7 @@ dependencies = [ "serde_json", "sha2 0.10.8", "storage", + "utxo", ] [[package]] @@ -248,6 +250,41 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array 0.14.7", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if 1.0.0", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle 2.6.1", +] + [[package]] name = "ahash" version = "0.3.8" @@ -511,6 +548,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clang-sys" version = "1.8.1" @@ -596,6 +643,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array 0.14.7", + "rand_core 0.6.4", "typenum", ] @@ -609,6 +657,15 @@ dependencies = [ "subtle 1.0.0", ] +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + [[package]] name = "der" version = "0.7.9" @@ -885,6 +942,16 @@ dependencies = [ "wasi 0.11.0+wasi-snapshot-preview1", ] +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug 0.3.1", + "polyval", +] + [[package]] name = "gimli" version = "0.31.0" @@ -1028,6 +1095,15 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array 0.14.7", +] + [[package]] name = "is-terminal" version = "0.4.13" @@ -1441,6 +1517,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "parking_lot" version = "0.12.3" @@ -1529,6 +1611,18 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "opaque-debug 0.3.1", + "universal-hash", +] + [[package]] name = "portable-atomic" version = "1.9.0" @@ -1909,7 +2003,7 @@ dependencies = [ "block-buffer 0.7.3", "digest 0.8.1", "fake-simd", - "opaque-debug", + "opaque-debug 0.2.3", ] [[package]] @@ -1933,7 +2027,7 @@ dependencies = [ "byte-tools", "digest 0.8.1", "keccak", - "opaque-debug", + "opaque-debug 0.2.3", ] [[package]] @@ -2198,6 +2292,16 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle 2.6.1", +] + [[package]] name = "url" version = "2.5.2" diff --git a/Cargo.toml b/Cargo.toml index 003f145..0cc1d20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ rs_merkle = "1.4" sha2 = "0.10.8" monotree = "0.1.5" hex = "0.4.3" +aes-gcm = "0.10.3" rocksdb = { version = "0.21.0", default-features = false, features = ["snappy"] } diff --git a/accounts/Cargo.toml b/accounts/Cargo.toml index 9f48799..1c36560 100644 --- a/accounts/Cargo.toml +++ b/accounts/Cargo.toml @@ -14,6 +14,10 @@ sha2.workspace = true rand.workspace = true elliptic-curve.workspace = true hex.workspace = true +aes-gcm.workspace = true [dependencies.storage] -path = "../storage" \ No newline at end of file +path = "../storage" + +[dependencies.utxo] +path = "../utxo" \ No newline at end of file diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs new file mode 100644 index 0000000..6adb899 --- /dev/null +++ b/accounts/src/account_core/mod.rs @@ -0,0 +1,101 @@ +use std::collections::HashMap; + +use anyhow::Result; +use k256::AffinePoint; +use serde::Serialize; +use storage::{merkle_tree_public::TreeHashType, nullifier::UTXONullifier}; +use utxo::{ + utxo_core::{UTXOPayload, UTXO}, + utxo_tree::UTXOSparseMerkleTree, +}; + +use crate::key_management::{ + constants_types::{CipherText, Nonce}, + ephemeral_key_holder::EphemeralKeyHolder, + AddressKeyHolder, +}; + +pub struct Account { + pub key_holder: AddressKeyHolder, + pub address: TreeHashType, + pub balance: u64, + pub utxo_tree: UTXOSparseMerkleTree, +} + +impl Account { + pub fn new() -> Self { + let key_holder = AddressKeyHolder::new_os_random(); + let address = key_holder.address; + let balance = 0; + let utxo_tree = UTXOSparseMerkleTree::new(); + + Self { + key_holder, + address, + balance, + utxo_tree, + } + } + + pub fn produce_ephemeral_key_holder(&self) -> EphemeralKeyHolder { + self.key_holder.produce_ephemeral_key_holder() + } + + pub fn encrypt_data( + ephemeral_key_holder: &EphemeralKeyHolder, + viewing_public_key_receiver: AffinePoint, + data: &[u8], + ) -> (CipherText, Nonce) { + ephemeral_key_holder.encrypt_data(viewing_public_key_receiver, data) + } + + pub fn decrypt_data( + &self, + ephemeral_public_key_sender: AffinePoint, + ciphertext: CipherText, + nonce: Nonce, + ) -> Vec { + self.key_holder + .decrypt_data(ephemeral_public_key_sender, ciphertext, nonce) + } + + pub fn mark_spent_utxo( + &mut self, + utxo_nullifier_map: HashMap, + ) -> Result<()> { + for (hash, nullifier) in utxo_nullifier_map { + if let Some(utxo_entry) = self.utxo_tree.store.get_mut(&hash) { + utxo_entry.consume_utxo(nullifier)?; + } + } + + Ok(()) + } + + pub fn add_new_utxo_outputs(&mut self, utxos: Vec) -> Result<()> { + Ok(self.utxo_tree.insert_items(utxos)?) + } + + pub fn update_public_balance(&mut self, new_balance: u64) { + self.balance = new_balance; + } + + pub fn add_asset(&mut self, asset: Asset) -> Result<()> { + let payload_with_asset = UTXOPayload { + owner: self.address, + asset: serde_json::to_vec(&asset)?, + }; + + let asset_utxo = UTXO::create_utxo_from_payload(payload_with_asset); + + self.utxo_tree.insert_item(asset_utxo)?; + + Ok(()) + } +} + +impl Default for Account { + fn default() -> Self { + Self::new() + } +} diff --git a/accounts/src/key_management/constants_types.rs b/accounts/src/key_management/constants_types.rs new file mode 100644 index 0000000..b139874 --- /dev/null +++ b/accounts/src/key_management/constants_types.rs @@ -0,0 +1,17 @@ +use elliptic_curve::{ + consts::{B0, B1}, + generic_array::GenericArray, +}; +use sha2::digest::typenum::{UInt, UTerm}; + +pub const NULLIFIER_SECRET_CONST: [u8; 32] = [ + 38, 29, 97, 210, 148, 172, 75, 220, 36, 249, 27, 111, 73, 14, 250, 38, 55, 87, 164, 169, 95, + 101, 135, 28, 212, 241, 107, 46, 162, 60, 59, 93, +]; +pub const VIEVING_SECRET_CONST: [u8; 32] = [ + 97, 23, 175, 117, 11, 48, 215, 162, 150, 103, 46, 195, 179, 178, 93, 52, 137, 190, 202, 60, + 254, 87, 112, 250, 57, 242, 117, 206, 195, 149, 213, 206, +]; + +pub type CipherText = Vec; +pub type Nonce = GenericArray, B1>, B0>, B0>>; diff --git a/accounts/src/key_management/ephemeral_key_holder.rs b/accounts/src/key_management/ephemeral_key_holder.rs new file mode 100644 index 0000000..4ae3229 --- /dev/null +++ b/accounts/src/key_management/ephemeral_key_holder.rs @@ -0,0 +1,53 @@ +use aes_gcm::{aead::Aead, AeadCore, Aes256Gcm, Key, KeyInit}; +use elliptic_curve::group::GroupEncoding; +use elliptic_curve::PrimeField; +use k256::{AffinePoint, FieldBytes, Scalar}; +use rand::{rngs::OsRng, RngCore}; + +use super::constants_types::{CipherText, Nonce}; + +#[derive(Debug)] +///Ephemeral secret key holder. Non-clonable as intended for one-time use. Produces ephemeral public keys. Can produce shared secret for sender. +pub struct EphemeralKeyHolder { + ephemeral_secret_key: Scalar, +} + +impl EphemeralKeyHolder { + pub fn new_os_random() -> Self { + let mut bytes = FieldBytes::default(); + + OsRng.fill_bytes(&mut bytes); + + Self { + ephemeral_secret_key: Scalar::from_repr(bytes).unwrap(), + } + } + + pub fn generate_ephemeral_public_key(&self) -> AffinePoint { + (AffinePoint::GENERATOR * self.ephemeral_secret_key).into() + } + + pub fn calculate_shared_secret_sender( + &self, + viewing_public_key_receiver: AffinePoint, + ) -> AffinePoint { + (viewing_public_key_receiver * self.ephemeral_secret_key).into() + } + + pub fn encrypt_data( + &self, + viewing_public_key_receiver: AffinePoint, + data: &[u8], + ) -> (CipherText, Nonce) { + let key_point = self.calculate_shared_secret_sender(viewing_public_key_receiver); + let key_raw = key_point.to_bytes(); + let key_raw_adjust: [u8; 32] = key_raw.as_slice().try_into().unwrap(); + + let key: Key = key_raw_adjust.into(); + + let cipher = Aes256Gcm::new(&key); + let nonce = Aes256Gcm::generate_nonce(&mut OsRng); + + (cipher.encrypt(&nonce, data).unwrap(), nonce) + } +} diff --git a/accounts/src/key_management/mod.rs b/accounts/src/key_management/mod.rs index 131f3a8..42988a2 100644 --- a/accounts/src/key_management/mod.rs +++ b/accounts/src/key_management/mod.rs @@ -1,161 +1,21 @@ -use k256::elliptic_curve::group::GroupEncoding; -use k256::{elliptic_curve::PrimeField, AffinePoint, FieldBytes, Scalar}; -use rand::{rngs::OsRng, RngCore}; -use sha2::{digest::FixedOutput, Digest}; +use aes_gcm::{aead::Aead, Aes256Gcm, Key, KeyInit}; +use constants_types::{CipherText, Nonce}; +use elliptic_curve::group::GroupEncoding; +use ephemeral_key_holder::EphemeralKeyHolder; +use k256::AffinePoint; +use secret_holders::{SeedHolder, TopSecretKeyHolder, UTXOSecretKeyHolder}; use storage::merkle_tree_public::TreeHashType; -pub const NULLIFIER_SECRET_CONST: [u8; 32] = [ - 38, 29, 97, 210, 148, 172, 75, 220, 36, 249, 27, 111, 73, 14, 250, 38, 55, 87, 164, 169, 95, - 101, 135, 28, 212, 241, 107, 46, 162, 60, 59, 93, -]; -pub const VIEVING_SECRET_CONST: [u8; 32] = [ - 97, 23, 175, 117, 11, 48, 215, 162, 150, 103, 46, 195, 179, 178, 93, 52, 137, 190, 202, 60, - 254, 87, 112, 250, 57, 242, 117, 206, 195, 149, 213, 206, -]; - -#[derive(Debug)] -///Seed holder. Non-clonable to ensure that different holders use different seeds. -/// Produces `TopSecretKeyHolder` objects. -pub struct SeedHolder { - seed: Scalar, -} - -#[derive(Debug, Clone)] -///Secret spending key holder. Produces `UTXOSecretKeyHolder` objects. -pub struct TopSecretKeyHolder { - secret_spending_key: Scalar, -} - -#[derive(Debug, Clone)] -///Nullifier secret key and viewing secret key holder. Produces public keys. Can produce address. Can produce shared secret for recepient. -pub struct UTXOSecretKeyHolder { - nullifier_secret_key: Scalar, - viewing_secret_key: Scalar, -} - -impl SeedHolder { - pub fn new_os_random() -> Self { - let mut bytes = FieldBytes::default(); - - OsRng.fill_bytes(&mut bytes); - - Self { - seed: Scalar::from_repr(bytes).unwrap(), - } - } - - pub fn generate_secret_spending_key_hash(&self) -> TreeHashType { - let mut hasher = sha2::Sha256::new(); - - hasher.update(self.seed.to_bytes()); - - ::from(hasher.finalize_fixed()) - } - - pub fn generate_secret_spending_key_scalar(&self) -> Scalar { - let hash = self.generate_secret_spending_key_hash(); - - Scalar::from_repr(hash.into()).unwrap() - } - - pub fn produce_top_secret_key_holder(&self) -> TopSecretKeyHolder { - TopSecretKeyHolder { - secret_spending_key: self.generate_secret_spending_key_scalar(), - } - } -} - -impl TopSecretKeyHolder { - pub fn generate_nullifier_secret_key(&self) -> Scalar { - let mut hasher = sha2::Sha256::new(); - - hasher.update(self.secret_spending_key.to_bytes()); - hasher.update(NULLIFIER_SECRET_CONST); - - let hash = ::from(hasher.finalize_fixed()); - - Scalar::from_repr(hash.into()).unwrap() - } - - pub fn generate_viewing_secret_key(&self) -> Scalar { - let mut hasher = sha2::Sha256::new(); - - hasher.update(self.secret_spending_key.to_bytes()); - hasher.update(VIEVING_SECRET_CONST); - - let hash = ::from(hasher.finalize_fixed()); - - Scalar::from_repr(hash.into()).unwrap() - } - - pub fn produce_utxo_secret_holder(&self) -> UTXOSecretKeyHolder { - UTXOSecretKeyHolder { - nullifier_secret_key: self.generate_nullifier_secret_key(), - viewing_secret_key: self.generate_viewing_secret_key(), - } - } -} - -impl UTXOSecretKeyHolder { - pub fn generate_nullifier_public_key(&self) -> AffinePoint { - (AffinePoint::GENERATOR * self.nullifier_secret_key).into() - } - - pub fn generate_viewing_public_key(&self) -> AffinePoint { - (AffinePoint::GENERATOR * self.viewing_secret_key).into() - } - - pub fn generate_address(&self) -> TreeHashType { - let npk = self.generate_nullifier_public_key(); - let vpk = self.generate_viewing_public_key(); - - let mut hasher = sha2::Sha256::new(); - - hasher.update(npk.to_bytes()); - hasher.update(vpk.to_bytes()); - - ::from(hasher.finalize_fixed()) - } -} - -#[derive(Debug)] -///Ephemeral secret key holder. Non-clonable as intended for one-time use. Produces ephemeral public keys. Can produce shared secret for sender. -pub struct EphemeralKeyHolder { - ephemeral_secret_key: Scalar, -} - -impl EphemeralKeyHolder { - pub fn new_os_random() -> Self { - let mut bytes = FieldBytes::default(); - - OsRng.fill_bytes(&mut bytes); - - Self { - ephemeral_secret_key: Scalar::from_repr(bytes).unwrap(), - } - } - - pub fn generate_ephemeral_public_key(&self) -> AffinePoint { - (AffinePoint::GENERATOR * self.ephemeral_secret_key).into() - } - - pub fn calculate_shared_secret_sender( - &self, - viewing_public_key_receiver: AffinePoint, - ) -> AffinePoint { - (viewing_public_key_receiver * self.ephemeral_secret_key).into() - } - - pub fn encrypt_data(&self) { - //ToDo: Implement that - //Need clarification on exact symmetric encoding, which we want to use for ECIES - todo!() - } -} +pub mod constants_types; +pub mod ephemeral_key_holder; +pub mod secret_holders; #[derive(Debug)] ///Entrypoint to key management pub struct AddressKeyHolder { + //Will be useful in future + #[allow(dead_code)] + top_secret_key_holder: TopSecretKeyHolder, utxo_secret_key_holder: UTXOSecretKeyHolder, pub address: TreeHashType, pub nullifer_public_key: AffinePoint, @@ -164,8 +24,8 @@ pub struct AddressKeyHolder { impl AddressKeyHolder { pub fn new_os_random() -> Self { - //Currently dropping SeedHolder and TopSecretKeyHolder at the end of initialization. - //Now entirely sure if we need them in the future. + //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(); @@ -176,6 +36,7 @@ impl AddressKeyHolder { let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key(); Self { + top_secret_key_holder, utxo_secret_key_holder, address, nullifer_public_key, @@ -193,10 +54,30 @@ impl AddressKeyHolder { pub fn produce_ephemeral_key_holder(&self) -> EphemeralKeyHolder { EphemeralKeyHolder::new_os_random() } + + pub fn decrypt_data( + &self, + ephemeral_public_key_sender: AffinePoint, + ciphertext: CipherText, + nonce: Nonce, + ) -> Vec { + let key_point = self.calculate_shared_secret_receiver(ephemeral_public_key_sender); + let key_raw = key_point.to_bytes(); + let key_raw_adjust: [u8; 32] = key_raw.as_slice().try_into().unwrap(); + + let key: Key = key_raw_adjust.into(); + + let cipher = Aes256Gcm::new(&key); + + cipher.decrypt(&nonce, ciphertext.as_slice()).unwrap() + } } #[cfg(test)] mod tests { + use constants_types::{NULLIFIER_SECRET_CONST, VIEVING_SECRET_CONST}; + use elliptic_curve::group::GroupEncoding; + use super::*; #[test] diff --git a/accounts/src/key_management/secret_holders.rs b/accounts/src/key_management/secret_holders.rs new file mode 100644 index 0000000..25e1d86 --- /dev/null +++ b/accounts/src/key_management/secret_holders.rs @@ -0,0 +1,113 @@ +use elliptic_curve::group::GroupEncoding; +use elliptic_curve::PrimeField; +use k256::{AffinePoint, FieldBytes, Scalar}; +use rand::{rngs::OsRng, RngCore}; +use sha2::{digest::FixedOutput, Digest}; +use storage::merkle_tree_public::TreeHashType; + +use super::constants_types::{NULLIFIER_SECRET_CONST, VIEVING_SECRET_CONST}; + +#[derive(Debug)] +///Seed holder. Non-clonable to ensure that different holders use different seeds. +/// Produces `TopSecretKeyHolder` objects. +pub struct SeedHolder { + seed: Scalar, +} + +#[derive(Debug, Clone)] +///Secret spending key holder. Produces `UTXOSecretKeyHolder` objects. +pub struct TopSecretKeyHolder { + secret_spending_key: Scalar, +} + +#[derive(Debug, Clone)] +///Nullifier secret key and viewing secret key holder. Produces public keys. Can produce address. Can produce shared secret for recepient. +pub struct UTXOSecretKeyHolder { + pub nullifier_secret_key: Scalar, + pub viewing_secret_key: Scalar, +} + +impl SeedHolder { + pub fn new_os_random() -> Self { + let mut bytes = FieldBytes::default(); + + OsRng.fill_bytes(&mut bytes); + + Self { + seed: Scalar::from_repr(bytes).unwrap(), + } + } + + pub fn generate_secret_spending_key_hash(&self) -> TreeHashType { + let mut hasher = sha2::Sha256::new(); + + hasher.update(self.seed.to_bytes()); + + ::from(hasher.finalize_fixed()) + } + + pub fn generate_secret_spending_key_scalar(&self) -> Scalar { + let hash = self.generate_secret_spending_key_hash(); + + Scalar::from_repr(hash.into()).unwrap() + } + + pub fn produce_top_secret_key_holder(&self) -> TopSecretKeyHolder { + TopSecretKeyHolder { + secret_spending_key: self.generate_secret_spending_key_scalar(), + } + } +} + +impl TopSecretKeyHolder { + pub fn generate_nullifier_secret_key(&self) -> Scalar { + let mut hasher = sha2::Sha256::new(); + + hasher.update(self.secret_spending_key.to_bytes()); + hasher.update(NULLIFIER_SECRET_CONST); + + let hash = ::from(hasher.finalize_fixed()); + + Scalar::from_repr(hash.into()).unwrap() + } + + pub fn generate_viewing_secret_key(&self) -> Scalar { + let mut hasher = sha2::Sha256::new(); + + hasher.update(self.secret_spending_key.to_bytes()); + hasher.update(VIEVING_SECRET_CONST); + + let hash = ::from(hasher.finalize_fixed()); + + Scalar::from_repr(hash.into()).unwrap() + } + + pub fn produce_utxo_secret_holder(&self) -> UTXOSecretKeyHolder { + UTXOSecretKeyHolder { + nullifier_secret_key: self.generate_nullifier_secret_key(), + viewing_secret_key: self.generate_viewing_secret_key(), + } + } +} + +impl UTXOSecretKeyHolder { + pub fn generate_nullifier_public_key(&self) -> AffinePoint { + (AffinePoint::GENERATOR * self.nullifier_secret_key).into() + } + + pub fn generate_viewing_public_key(&self) -> AffinePoint { + (AffinePoint::GENERATOR * self.viewing_secret_key).into() + } + + pub fn generate_address(&self) -> TreeHashType { + let npk = self.generate_nullifier_public_key(); + let vpk = self.generate_viewing_public_key(); + + let mut hasher = sha2::Sha256::new(); + + hasher.update(npk.to_bytes()); + hasher.update(vpk.to_bytes()); + + ::from(hasher.finalize_fixed()) + } +} diff --git a/accounts/src/lib.rs b/accounts/src/lib.rs index a98b67c..998d3ec 100644 --- a/accounts/src/lib.rs +++ b/accounts/src/lib.rs @@ -1 +1,2 @@ +pub mod account_core; pub mod key_management;