mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-02 13:23: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"
|
||||
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"
|
||||
|
||||
@ -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"] }
|
||||
|
||||
|
||||
@ -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"
|
||||
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 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());
|
||||
|
||||
<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!()
|
||||
}
|
||||
}
|
||||
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<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)]
|
||||
mod tests {
|
||||
use constants_types::{NULLIFIER_SECRET_CONST, VIEVING_SECRET_CONST};
|
||||
use elliptic_curve::group::GroupEncoding;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user