mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-04 06:13:10 +00:00
feat: accounts core added
This commit is contained in:
parent
2725e5976a
commit
93ae595596
108
Cargo.lock
generated
108
Cargo.lock
generated
@ -6,6 +6,7 @@ version = 4
|
|||||||
name = "accounts"
|
name = "accounts"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"aes-gcm",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"elliptic-curve",
|
"elliptic-curve",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
@ -17,6 +18,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2 0.10.8",
|
"sha2 0.10.8",
|
||||||
"storage",
|
"storage",
|
||||||
|
"utxo",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -248,6 +250,41 @@ version = "2.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
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]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
version = "0.3.8"
|
version = "0.3.8"
|
||||||
@ -511,6 +548,16 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
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]]
|
[[package]]
|
||||||
name = "clang-sys"
|
name = "clang-sys"
|
||||||
version = "1.8.1"
|
version = "1.8.1"
|
||||||
@ -596,6 +643,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"generic-array 0.14.7",
|
"generic-array 0.14.7",
|
||||||
|
"rand_core 0.6.4",
|
||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -609,6 +657,15 @@ dependencies = [
|
|||||||
"subtle 1.0.0",
|
"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]]
|
[[package]]
|
||||||
name = "der"
|
name = "der"
|
||||||
version = "0.7.9"
|
version = "0.7.9"
|
||||||
@ -885,6 +942,16 @@ dependencies = [
|
|||||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
"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]]
|
[[package]]
|
||||||
name = "gimli"
|
name = "gimli"
|
||||||
version = "0.31.0"
|
version = "0.31.0"
|
||||||
@ -1028,6 +1095,15 @@ dependencies = [
|
|||||||
"hashbrown 0.14.5",
|
"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]]
|
[[package]]
|
||||||
name = "is-terminal"
|
name = "is-terminal"
|
||||||
version = "0.4.13"
|
version = "0.4.13"
|
||||||
@ -1441,6 +1517,12 @@ version = "0.2.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opaque-debug"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.3"
|
version = "0.12.3"
|
||||||
@ -1529,6 +1611,18 @@ version = "0.3.31"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
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]]
|
[[package]]
|
||||||
name = "portable-atomic"
|
name = "portable-atomic"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
@ -1909,7 +2003,7 @@ dependencies = [
|
|||||||
"block-buffer 0.7.3",
|
"block-buffer 0.7.3",
|
||||||
"digest 0.8.1",
|
"digest 0.8.1",
|
||||||
"fake-simd",
|
"fake-simd",
|
||||||
"opaque-debug",
|
"opaque-debug 0.2.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1933,7 +2027,7 @@ dependencies = [
|
|||||||
"byte-tools",
|
"byte-tools",
|
||||||
"digest 0.8.1",
|
"digest 0.8.1",
|
||||||
"keccak",
|
"keccak",
|
||||||
"opaque-debug",
|
"opaque-debug 0.2.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2198,6 +2292,16 @@ dependencies = [
|
|||||||
"tinyvec",
|
"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]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.5.2"
|
version = "2.5.2"
|
||||||
|
|||||||
@ -36,6 +36,7 @@ rs_merkle = "1.4"
|
|||||||
sha2 = "0.10.8"
|
sha2 = "0.10.8"
|
||||||
monotree = "0.1.5"
|
monotree = "0.1.5"
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
|
aes-gcm = "0.10.3"
|
||||||
|
|
||||||
rocksdb = { version = "0.21.0", default-features = false, features = ["snappy"] }
|
rocksdb = { version = "0.21.0", default-features = false, features = ["snappy"] }
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,10 @@ sha2.workspace = true
|
|||||||
rand.workspace = true
|
rand.workspace = true
|
||||||
elliptic-curve.workspace = true
|
elliptic-curve.workspace = true
|
||||||
hex.workspace = true
|
hex.workspace = true
|
||||||
|
aes-gcm.workspace = true
|
||||||
|
|
||||||
[dependencies.storage]
|
[dependencies.storage]
|
||||||
path = "../storage"
|
path = "../storage"
|
||||||
|
|
||||||
|
[dependencies.utxo]
|
||||||
|
path = "../utxo"
|
||||||
101
accounts/src/account_core/mod.rs
Normal file
101
accounts/src/account_core/mod.rs
Normal file
@ -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<u8> {
|
||||||
|
self.key_holder
|
||||||
|
.decrypt_data(ephemeral_public_key_sender, ciphertext, nonce)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mark_spent_utxo(
|
||||||
|
&mut self,
|
||||||
|
utxo_nullifier_map: HashMap<TreeHashType, UTXONullifier>,
|
||||||
|
) -> 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<UTXO>) -> 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<Asset: Serialize>(&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()
|
||||||
|
}
|
||||||
|
}
|
||||||
17
accounts/src/key_management/constants_types.rs
Normal file
17
accounts/src/key_management/constants_types.rs
Normal file
@ -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<u8>;
|
||||||
|
pub type Nonce = GenericArray<u8, UInt<UInt<UInt<UInt<UTerm, B1>, B1>, B0>, B0>>;
|
||||||
53
accounts/src/key_management/ephemeral_key_holder.rs
Normal file
53
accounts/src/key_management/ephemeral_key_holder.rs
Normal file
@ -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<Aes256Gcm> = key_raw_adjust.into();
|
||||||
|
|
||||||
|
let cipher = Aes256Gcm::new(&key);
|
||||||
|
let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
|
||||||
|
|
||||||
|
(cipher.encrypt(&nonce, data).unwrap(), nonce)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,161 +1,21 @@
|
|||||||
use k256::elliptic_curve::group::GroupEncoding;
|
use aes_gcm::{aead::Aead, Aes256Gcm, Key, KeyInit};
|
||||||
use k256::{elliptic_curve::PrimeField, AffinePoint, FieldBytes, Scalar};
|
use constants_types::{CipherText, Nonce};
|
||||||
use rand::{rngs::OsRng, RngCore};
|
use elliptic_curve::group::GroupEncoding;
|
||||||
use sha2::{digest::FixedOutput, Digest};
|
use ephemeral_key_holder::EphemeralKeyHolder;
|
||||||
|
use k256::AffinePoint;
|
||||||
|
use secret_holders::{SeedHolder, TopSecretKeyHolder, UTXOSecretKeyHolder};
|
||||||
use storage::merkle_tree_public::TreeHashType;
|
use storage::merkle_tree_public::TreeHashType;
|
||||||
|
|
||||||
pub const NULLIFIER_SECRET_CONST: [u8; 32] = [
|
pub mod constants_types;
|
||||||
38, 29, 97, 210, 148, 172, 75, 220, 36, 249, 27, 111, 73, 14, 250, 38, 55, 87, 164, 169, 95,
|
pub mod ephemeral_key_holder;
|
||||||
101, 135, 28, 212, 241, 107, 46, 162, 60, 59, 93,
|
pub mod secret_holders;
|
||||||
];
|
|
||||||
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());
|
|
||||||
|
|
||||||
<TreeHashType>::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 = <TreeHashType>::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 = <TreeHashType>::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());
|
|
||||||
|
|
||||||
<TreeHashType>::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!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
///Entrypoint to key management
|
///Entrypoint to key management
|
||||||
pub struct AddressKeyHolder {
|
pub struct AddressKeyHolder {
|
||||||
|
//Will be useful in future
|
||||||
|
#[allow(dead_code)]
|
||||||
|
top_secret_key_holder: TopSecretKeyHolder,
|
||||||
utxo_secret_key_holder: UTXOSecretKeyHolder,
|
utxo_secret_key_holder: UTXOSecretKeyHolder,
|
||||||
pub address: TreeHashType,
|
pub address: TreeHashType,
|
||||||
pub nullifer_public_key: AffinePoint,
|
pub nullifer_public_key: AffinePoint,
|
||||||
@ -164,8 +24,8 @@ pub struct AddressKeyHolder {
|
|||||||
|
|
||||||
impl AddressKeyHolder {
|
impl AddressKeyHolder {
|
||||||
pub fn new_os_random() -> Self {
|
pub fn new_os_random() -> Self {
|
||||||
//Currently dropping SeedHolder and TopSecretKeyHolder at the end of initialization.
|
//Currently dropping SeedHolder at the end of initialization.
|
||||||
//Now entirely sure if we need them in the future.
|
//Now entirely sure if we need it in the future.
|
||||||
let seed_holder = SeedHolder::new_os_random();
|
let seed_holder = SeedHolder::new_os_random();
|
||||||
let top_secret_key_holder = seed_holder.produce_top_secret_key_holder();
|
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();
|
let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
top_secret_key_holder,
|
||||||
utxo_secret_key_holder,
|
utxo_secret_key_holder,
|
||||||
address,
|
address,
|
||||||
nullifer_public_key,
|
nullifer_public_key,
|
||||||
@ -193,10 +54,30 @@ impl AddressKeyHolder {
|
|||||||
pub fn produce_ephemeral_key_holder(&self) -> EphemeralKeyHolder {
|
pub fn produce_ephemeral_key_holder(&self) -> EphemeralKeyHolder {
|
||||||
EphemeralKeyHolder::new_os_random()
|
EphemeralKeyHolder::new_os_random()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn decrypt_data(
|
||||||
|
&self,
|
||||||
|
ephemeral_public_key_sender: AffinePoint,
|
||||||
|
ciphertext: CipherText,
|
||||||
|
nonce: Nonce,
|
||||||
|
) -> Vec<u8> {
|
||||||
|
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<Aes256Gcm> = key_raw_adjust.into();
|
||||||
|
|
||||||
|
let cipher = Aes256Gcm::new(&key);
|
||||||
|
|
||||||
|
cipher.decrypt(&nonce, ciphertext.as_slice()).unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use constants_types::{NULLIFIER_SECRET_CONST, VIEVING_SECRET_CONST};
|
||||||
|
use elliptic_curve::group::GroupEncoding;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
113
accounts/src/key_management/secret_holders.rs
Normal file
113
accounts/src/key_management/secret_holders.rs
Normal file
@ -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());
|
||||||
|
|
||||||
|
<TreeHashType>::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 = <TreeHashType>::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 = <TreeHashType>::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());
|
||||||
|
|
||||||
|
<TreeHashType>::from(hasher.finalize_fixed())
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1 +1,2 @@
|
|||||||
|
pub mod account_core;
|
||||||
pub mod key_management;
|
pub mod key_management;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user