mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-02 13:23:10 +00:00
feat: private tree
This commit is contained in:
parent
4a430622f4
commit
d9a130cc55
115
key_protocol/src/key_management/key_tree/chain_index.rs
Normal file
115
key_protocol/src/key_management/key_tree/chain_index.rs
Normal file
@ -0,0 +1,115 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize)]
|
||||
pub struct ChainIndex(Vec<u32>);
|
||||
|
||||
impl FromStr for ChainIndex {
|
||||
type Err = hex::FromHexError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if s.is_empty() {
|
||||
return Ok(Self(vec![]));
|
||||
}
|
||||
|
||||
let hex_decoded = hex::decode(s)?;
|
||||
|
||||
if !hex_decoded.len().is_multiple_of(4) {
|
||||
Err(hex::FromHexError::InvalidStringLength)
|
||||
} else {
|
||||
let mut res_vec = vec![];
|
||||
|
||||
for i in 0..(hex_decoded.len() / 4) {
|
||||
res_vec.push(u32::from_le_bytes([
|
||||
hex_decoded[4 * i],
|
||||
hex_decoded[4 * i + 1],
|
||||
hex_decoded[4 * i + 2],
|
||||
hex_decoded[4 * i + 3],
|
||||
]));
|
||||
}
|
||||
|
||||
Ok(Self(res_vec))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::to_string_trait_impl)]
|
||||
impl ToString for ChainIndex {
|
||||
fn to_string(&self) -> String {
|
||||
if self.0.is_empty() {
|
||||
return "".to_string();
|
||||
}
|
||||
|
||||
let mut res_vec = vec![];
|
||||
|
||||
for index in &self.0 {
|
||||
res_vec.extend_from_slice(&index.to_le_bytes());
|
||||
}
|
||||
|
||||
hex::encode(res_vec)
|
||||
}
|
||||
}
|
||||
|
||||
impl ChainIndex {
|
||||
pub fn root() -> Self {
|
||||
ChainIndex::from_str("").unwrap()
|
||||
}
|
||||
|
||||
pub fn chain(&self) -> &[u32] {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub fn next_in_line(&self) -> ChainIndex {
|
||||
let mut chain = self.0.clone();
|
||||
//ToDo: Add overflow check
|
||||
if let Some(last_p) = chain.last_mut() {
|
||||
*last_p += 1
|
||||
}
|
||||
|
||||
ChainIndex(chain)
|
||||
}
|
||||
|
||||
pub fn n_th_child(&self, child_id: u32) -> ChainIndex {
|
||||
let mut chain = self.0.clone();
|
||||
chain.push(child_id);
|
||||
|
||||
ChainIndex(chain)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_chain_id_root_correct() {
|
||||
let chain_id = ChainIndex::root();
|
||||
let chain_id_2 = ChainIndex::from_str("").unwrap();
|
||||
|
||||
assert_eq!(chain_id, chain_id_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chain_id_deser_correct() {
|
||||
let chain_id = ChainIndex::from_str("01010000").unwrap();
|
||||
|
||||
assert_eq!(chain_id.chain(), &[257]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chain_id_next_in_line_correct() {
|
||||
let chain_id = ChainIndex::from_str("01010000").unwrap();
|
||||
let next_in_line = chain_id.next_in_line();
|
||||
|
||||
assert_eq!(next_in_line, ChainIndex::from_str("02010000").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chain_id_child_correct() {
|
||||
let chain_id = ChainIndex::from_str("01010000").unwrap();
|
||||
let child = chain_id.n_th_child(3);
|
||||
|
||||
assert_eq!(child, ChainIndex::from_str("0101000003000000").unwrap());
|
||||
}
|
||||
}
|
||||
201
key_protocol/src/key_management/key_tree/keys_private.rs
Normal file
201
key_protocol/src/key_management/key_tree/keys_private.rs
Normal file
@ -0,0 +1,201 @@
|
||||
use k256::{Scalar, elliptic_curve::PrimeField};
|
||||
use nssa_core::{NullifierPublicKey, NullifierSecretKey, encryption::IncomingViewingPublicKey};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::key_management::{
|
||||
key_tree::traits::KeyNode,
|
||||
secret_holders::{IncomingViewingSecretKey, OutgoingViewingSecretKey, SecretSpendingKey},
|
||||
};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct ChildKeysPrivate {
|
||||
pub ssk: SecretSpendingKey,
|
||||
pub nsk: NullifierSecretKey,
|
||||
pub isk: IncomingViewingSecretKey,
|
||||
pub ovk: OutgoingViewingSecretKey,
|
||||
pub npk: NullifierPublicKey,
|
||||
pub ipk: IncomingViewingPublicKey,
|
||||
pub ccc: [u8; 32],
|
||||
///Can be None if root
|
||||
pub cci: Option<u32>,
|
||||
pub account: nssa::Account,
|
||||
}
|
||||
|
||||
impl KeyNode for ChildKeysPrivate {
|
||||
fn root(seed: [u8; 64]) -> Self {
|
||||
let hash_value = hmac_sha512::HMAC::mac(seed, "NSSA_master_priv");
|
||||
|
||||
let ssk = SecretSpendingKey(*hash_value.first_chunk::<32>().unwrap());
|
||||
let ccc = *hash_value.last_chunk::<32>().unwrap();
|
||||
|
||||
let nsk = ssk.generate_nullifier_secret_key();
|
||||
let isk = ssk.generate_incoming_viewing_secret_key();
|
||||
let ovk = ssk.generate_outgoing_viewing_secret_key();
|
||||
|
||||
let npk = (&nsk).into();
|
||||
let ipk = IncomingViewingPublicKey::from_scalar(isk);
|
||||
|
||||
Self {
|
||||
ssk,
|
||||
nsk,
|
||||
isk,
|
||||
ovk,
|
||||
npk,
|
||||
ipk,
|
||||
ccc,
|
||||
cci: None,
|
||||
account: nssa::Account::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn n_th_child(&self, cci: u32) -> Self {
|
||||
let parent_pt = Scalar::from_repr(self.ovk.into()).unwrap()
|
||||
+ Scalar::from_repr(self.nsk.into()).unwrap()
|
||||
* Scalar::from_repr(self.isk.into()).unwrap();
|
||||
let mut input = vec![];
|
||||
|
||||
input.extend_from_slice(b"NSSA_seed_priv");
|
||||
input.extend_from_slice(&parent_pt.to_bytes());
|
||||
input.extend_from_slice(&cci.to_le_bytes());
|
||||
|
||||
let hash_value = hmac_sha512::HMAC::mac(input, self.ccc);
|
||||
|
||||
let ssk = SecretSpendingKey(*hash_value.first_chunk::<32>().unwrap());
|
||||
let ccc = *hash_value.last_chunk::<32>().unwrap();
|
||||
|
||||
let nsk = ssk.generate_nullifier_secret_key();
|
||||
let isk = ssk.generate_incoming_viewing_secret_key();
|
||||
let ovk = ssk.generate_outgoing_viewing_secret_key();
|
||||
|
||||
let npk = (&nsk).into();
|
||||
let ipk = IncomingViewingPublicKey::from_scalar(isk);
|
||||
|
||||
Self {
|
||||
ssk,
|
||||
nsk,
|
||||
isk,
|
||||
ovk,
|
||||
npk,
|
||||
ipk,
|
||||
ccc,
|
||||
cci: Some(cci),
|
||||
account: nssa::Account::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn chain_code(&self) -> &[u8; 32] {
|
||||
&self.ccc
|
||||
}
|
||||
|
||||
fn child_index(&self) -> &Option<u32> {
|
||||
&self.cci
|
||||
}
|
||||
|
||||
fn address(&self) -> nssa::Address {
|
||||
nssa::Address::from(&self.npk)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_keys_deterministic_generation() {
|
||||
let root_keys = ChildKeysPrivate::root([42; 64]);
|
||||
let child_keys = root_keys.n_th_child(5);
|
||||
|
||||
assert_eq!(root_keys.cci, None);
|
||||
assert_eq!(child_keys.cci, Some(5));
|
||||
|
||||
assert_eq!(
|
||||
root_keys.ssk.0,
|
||||
[
|
||||
249, 83, 253, 32, 174, 204, 185, 44, 253, 167, 61, 92, 128, 5, 152, 4, 220, 21, 88,
|
||||
84, 167, 180, 154, 249, 44, 77, 33, 136, 59, 131, 203, 152
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
child_keys.ssk.0,
|
||||
[
|
||||
16, 242, 229, 242, 252, 158, 153, 210, 234, 120, 70, 85, 83, 196, 5, 53, 28, 26,
|
||||
187, 230, 22, 193, 146, 232, 237, 3, 166, 184, 122, 1, 233, 93
|
||||
]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
root_keys.nsk,
|
||||
[
|
||||
38, 195, 52, 182, 16, 66, 167, 156, 9, 14, 65, 100, 17, 93, 166, 71, 27, 148, 93,
|
||||
85, 116, 109, 130, 8, 195, 222, 159, 214, 141, 41, 124, 57
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
child_keys.nsk,
|
||||
[
|
||||
215, 46, 2, 151, 174, 60, 86, 154, 5, 3, 175, 245, 12, 176, 220, 58, 250, 118, 236,
|
||||
49, 254, 221, 229, 58, 40, 1, 170, 145, 175, 108, 23, 170
|
||||
]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
root_keys.isk,
|
||||
[
|
||||
153, 161, 15, 34, 96, 184, 165, 165, 27, 244, 155, 40, 70, 5, 241, 133, 78, 40, 61,
|
||||
118, 48, 148, 226, 5, 97, 18, 201, 128, 82, 248, 163, 72
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
child_keys.isk,
|
||||
[
|
||||
192, 155, 55, 43, 164, 115, 71, 145, 227, 225, 21, 57, 55, 12, 226, 44, 10, 103,
|
||||
39, 73, 230, 173, 60, 69, 69, 122, 110, 241, 164, 3, 192, 57
|
||||
]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
root_keys.ovk,
|
||||
[
|
||||
205, 87, 71, 129, 90, 242, 217, 200, 140, 252, 124, 46, 207, 7, 33, 156, 83, 166,
|
||||
150, 81, 98, 131, 182, 156, 110, 92, 78, 140, 125, 218, 152, 154
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
child_keys.ovk,
|
||||
[
|
||||
131, 202, 219, 172, 219, 29, 48, 120, 226, 209, 209, 10, 216, 173, 48, 167, 233,
|
||||
17, 35, 155, 30, 217, 176, 120, 72, 146, 250, 226, 165, 178, 255, 90
|
||||
]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
root_keys.npk.0,
|
||||
[
|
||||
65, 176, 149, 243, 192, 45, 216, 177, 169, 56, 229, 7, 28, 66, 204, 87, 109, 83,
|
||||
152, 64, 14, 188, 179, 210, 147, 60, 22, 251, 203, 70, 89, 215
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
child_keys.npk.0,
|
||||
[
|
||||
69, 104, 130, 115, 48, 134, 19, 188, 67, 148, 163, 54, 155, 237, 57, 27, 136, 228,
|
||||
111, 233, 205, 158, 149, 31, 84, 11, 241, 176, 243, 12, 138, 249
|
||||
]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
root_keys.ipk.0,
|
||||
&[
|
||||
3, 174, 56, 136, 244, 179, 18, 122, 38, 220, 36, 50, 200, 41, 104, 167, 70, 18, 60,
|
||||
202, 93, 193, 29, 16, 125, 252, 96, 51, 199, 152, 47, 233, 178
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
child_keys.ipk.0,
|
||||
&[
|
||||
3, 18, 202, 246, 79, 141, 169, 51, 55, 202, 120, 169, 244, 201, 156, 162, 216, 115,
|
||||
126, 53, 46, 94, 235, 125, 114, 178, 215, 81, 171, 93, 93, 88, 117
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
119
key_protocol/src/key_management/key_tree/keys_public.rs
Normal file
119
key_protocol/src/key_management/key_tree/keys_public.rs
Normal file
@ -0,0 +1,119 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::key_management::key_tree::traits::KeyNode;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct ChildKeysPublic {
|
||||
pub csk: nssa::PrivateKey,
|
||||
pub cpk: nssa::PublicKey,
|
||||
pub ccc: [u8; 32],
|
||||
///Can be None if root
|
||||
pub cci: Option<u32>,
|
||||
}
|
||||
|
||||
impl KeyNode for ChildKeysPublic {
|
||||
fn root(seed: [u8; 64]) -> Self {
|
||||
let hash_value = hmac_sha512::HMAC::mac(seed, "NSSA_master_pub");
|
||||
|
||||
let csk = nssa::PrivateKey::try_new(*hash_value.first_chunk::<32>().unwrap()).unwrap();
|
||||
let ccc = *hash_value.last_chunk::<32>().unwrap();
|
||||
let cpk = nssa::PublicKey::new_from_private_key(&csk);
|
||||
|
||||
Self {
|
||||
csk,
|
||||
cpk,
|
||||
ccc,
|
||||
cci: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn n_th_child(&self, cci: u32) -> Self {
|
||||
let mut hash_input = vec![];
|
||||
hash_input.extend_from_slice(self.csk.value());
|
||||
hash_input.extend_from_slice(&cci.to_le_bytes());
|
||||
|
||||
let hash_value = hmac_sha512::HMAC::mac(&hash_input, self.ccc);
|
||||
|
||||
let csk = nssa::PrivateKey::try_new(*hash_value.first_chunk::<32>().unwrap()).unwrap();
|
||||
let ccc = *hash_value.last_chunk::<32>().unwrap();
|
||||
let cpk = nssa::PublicKey::new_from_private_key(&csk);
|
||||
|
||||
Self {
|
||||
csk,
|
||||
cpk,
|
||||
ccc,
|
||||
cci: Some(cci),
|
||||
}
|
||||
}
|
||||
|
||||
fn chain_code(&self) -> &[u8; 32] {
|
||||
&self.ccc
|
||||
}
|
||||
|
||||
fn child_index(&self) -> &Option<u32> {
|
||||
&self.cci
|
||||
}
|
||||
|
||||
fn address(&self) -> nssa::Address {
|
||||
nssa::Address::from(&self.cpk)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_keys_deterministic_generation() {
|
||||
let root_keys = ChildKeysPublic::root([42; 64]);
|
||||
let child_keys = root_keys.n_th_child(5);
|
||||
|
||||
assert_eq!(root_keys.cci, None);
|
||||
assert_eq!(child_keys.cci, Some(5));
|
||||
|
||||
assert_eq!(
|
||||
root_keys.ccc,
|
||||
[
|
||||
61, 30, 91, 26, 133, 91, 236, 192, 231, 53, 186, 139, 11, 221, 202, 11, 178, 215,
|
||||
254, 103, 191, 60, 117, 112, 1, 226, 31, 156, 83, 104, 150, 224
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
child_keys.ccc,
|
||||
[
|
||||
67, 26, 102, 68, 189, 155, 102, 80, 199, 188, 112, 142, 207, 157, 36, 210, 48, 224,
|
||||
35, 6, 112, 180, 11, 190, 135, 218, 9, 14, 84, 231, 58, 98
|
||||
]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
root_keys.csk.value(),
|
||||
&[
|
||||
241, 82, 246, 237, 62, 130, 116, 47, 189, 112, 99, 67, 178, 40, 115, 245, 141, 193,
|
||||
77, 164, 243, 76, 222, 64, 50, 146, 23, 145, 91, 164, 92, 116
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
child_keys.csk.value(),
|
||||
&[
|
||||
11, 151, 27, 212, 167, 26, 77, 234, 103, 145, 53, 191, 184, 25, 240, 191, 156, 25,
|
||||
60, 144, 65, 22, 193, 163, 246, 227, 212, 81, 49, 170, 33, 158
|
||||
]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
root_keys.cpk.value(),
|
||||
&[
|
||||
220, 170, 95, 177, 121, 37, 86, 166, 56, 238, 232, 72, 21, 106, 107, 217, 158, 74,
|
||||
133, 91, 143, 244, 155, 15, 2, 230, 223, 169, 13, 20, 163, 138
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
child_keys.cpk.value(),
|
||||
&[
|
||||
152, 249, 236, 111, 132, 96, 184, 122, 21, 179, 240, 15, 234, 155, 164, 144, 108,
|
||||
110, 120, 74, 176, 147, 196, 168, 243, 186, 203, 79, 97, 17, 194, 52
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,143 +1,35 @@
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
str::FromStr,
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::key_management::{
|
||||
key_tree::{
|
||||
chain_index::ChainIndex, keys_private::ChildKeysPrivate, keys_public::ChildKeysPublic,
|
||||
traits::KeyNode,
|
||||
},
|
||||
secret_holders::SeedHolder,
|
||||
};
|
||||
|
||||
use crate::key_management::secret_holders::SeedHolder;
|
||||
pub mod chain_index;
|
||||
pub mod keys_private;
|
||||
pub mod keys_public;
|
||||
pub mod traits;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
|
||||
pub struct ChainIndex(Vec<u32>);
|
||||
|
||||
impl FromStr for ChainIndex {
|
||||
type Err = hex::FromHexError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if s.is_empty() {
|
||||
return Ok(Self(vec![]));
|
||||
}
|
||||
|
||||
let hex_decoded = hex::decode(s)?;
|
||||
|
||||
if !hex_decoded.len().is_multiple_of(4) {
|
||||
Err(hex::FromHexError::InvalidStringLength)
|
||||
} else {
|
||||
let mut res_vec = vec![];
|
||||
|
||||
for i in 0..(hex_decoded.len() / 4) {
|
||||
res_vec.push(u32::from_le_bytes([
|
||||
hex_decoded[4 * i],
|
||||
hex_decoded[4 * i + 1],
|
||||
hex_decoded[4 * i + 2],
|
||||
hex_decoded[4 * i + 3],
|
||||
]));
|
||||
}
|
||||
|
||||
Ok(Self(res_vec))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::to_string_trait_impl)]
|
||||
impl ToString for ChainIndex {
|
||||
fn to_string(&self) -> String {
|
||||
if self.0.is_empty() {
|
||||
return "".to_string();
|
||||
}
|
||||
|
||||
let mut res_vec = vec![];
|
||||
|
||||
for index in &self.0 {
|
||||
res_vec.extend_from_slice(&index.to_le_bytes());
|
||||
}
|
||||
|
||||
hex::encode(res_vec)
|
||||
}
|
||||
}
|
||||
|
||||
impl ChainIndex {
|
||||
pub fn root() -> Self {
|
||||
ChainIndex::from_str("").unwrap()
|
||||
}
|
||||
|
||||
pub fn chain(&self) -> &[u32] {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub fn next_in_line(&self) -> ChainIndex {
|
||||
let mut chain = self.0.clone();
|
||||
//ToDo: Add overflow check
|
||||
if let Some(last_p) = chain.last_mut() {
|
||||
*last_p += 1
|
||||
}
|
||||
|
||||
ChainIndex(chain)
|
||||
}
|
||||
|
||||
pub fn n_th_child(&self, child_id: u32) -> ChainIndex {
|
||||
let mut chain = self.0.clone();
|
||||
chain.push(child_id);
|
||||
|
||||
ChainIndex(chain)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ChildKeysPublic {
|
||||
pub csk: nssa::PrivateKey,
|
||||
pub cpk: nssa::PublicKey,
|
||||
pub ccc: [u8; 32],
|
||||
///Can be None if root
|
||||
pub cci: Option<u32>,
|
||||
}
|
||||
|
||||
impl ChildKeysPublic {
|
||||
pub fn root(seed: [u8; 64]) -> Self {
|
||||
let hash_value = hmac_sha512::HMAC::mac(seed, "NSSA_master_pub");
|
||||
|
||||
let csk = nssa::PrivateKey::try_new(*hash_value.first_chunk::<32>().unwrap()).unwrap();
|
||||
let ccc = *hash_value.last_chunk::<32>().unwrap();
|
||||
let cpk = nssa::PublicKey::new_from_private_key(&csk);
|
||||
|
||||
Self {
|
||||
csk,
|
||||
cpk,
|
||||
ccc,
|
||||
cci: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn n_th_child(&self, cci: u32) -> Self {
|
||||
let mut hash_input = vec![];
|
||||
hash_input.extend_from_slice(self.csk.value());
|
||||
hash_input.extend_from_slice(&cci.to_le_bytes());
|
||||
|
||||
let hash_value = hmac_sha512::HMAC::mac(&hash_input, self.ccc);
|
||||
|
||||
let csk = nssa::PrivateKey::try_new(*hash_value.first_chunk::<32>().unwrap()).unwrap();
|
||||
let ccc = *hash_value.last_chunk::<32>().unwrap();
|
||||
let cpk = nssa::PublicKey::new_from_private_key(&csk);
|
||||
|
||||
Self {
|
||||
csk,
|
||||
cpk,
|
||||
ccc,
|
||||
cci: Some(cci),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct KeyTreePublic {
|
||||
pub key_map: BTreeMap<ChainIndex, ChildKeysPublic>,
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct KeyTree<Node: KeyNode> {
|
||||
pub key_map: BTreeMap<ChainIndex, Node>,
|
||||
pub addr_map: HashMap<nssa::Address, ChainIndex>,
|
||||
}
|
||||
|
||||
impl KeyTreePublic {
|
||||
pub type KeyTreePublic = KeyTree<ChildKeysPublic>;
|
||||
pub type KeyTreePrivate = KeyTree<ChildKeysPrivate>;
|
||||
|
||||
impl<Node: KeyNode> KeyTree<Node> {
|
||||
pub fn new(seed: &SeedHolder) -> Self {
|
||||
let seed_fit: [u8; 64] = seed.seed.clone().try_into().unwrap();
|
||||
|
||||
let root_keys = ChildKeysPublic::root(seed_fit);
|
||||
let address = nssa::Address::from(&root_keys.cpk);
|
||||
let root_keys = Node::root(seed_fit);
|
||||
let address = root_keys.address();
|
||||
|
||||
let mut key_map = BTreeMap::new();
|
||||
let mut addr_map = HashMap::new();
|
||||
@ -199,7 +91,7 @@ impl KeyTreePublic {
|
||||
|
||||
let child_keys = father_keys.n_th_child(next_child_id);
|
||||
|
||||
let address = nssa::Address::from(&child_keys.cpk);
|
||||
let address = child_keys.address();
|
||||
|
||||
self.key_map.insert(next_cci.clone(), child_keys);
|
||||
self.addr_map.insert(address, next_cci);
|
||||
@ -207,7 +99,7 @@ impl KeyTreePublic {
|
||||
Some(address)
|
||||
}
|
||||
|
||||
pub fn get_pub_keys(&self, addr: nssa::Address) -> Option<&ChildKeysPublic> {
|
||||
pub fn get_pub_keys(&self, addr: nssa::Address) -> Option<&Node> {
|
||||
self.addr_map
|
||||
.get(&addr)
|
||||
.and_then(|chain_id| self.key_map.get(chain_id))
|
||||
@ -216,95 +108,12 @@ impl KeyTreePublic {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::str::FromStr;
|
||||
|
||||
use nssa::Address;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_chain_id_root_correct() {
|
||||
let chain_id = ChainIndex::root();
|
||||
let chain_id_2 = ChainIndex::from_str("").unwrap();
|
||||
|
||||
assert_eq!(chain_id, chain_id_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chain_id_deser_correct() {
|
||||
let chain_id = ChainIndex::from_str("01010000").unwrap();
|
||||
|
||||
assert_eq!(chain_id.chain(), &[257]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chain_id_next_in_line_correct() {
|
||||
let chain_id = ChainIndex::from_str("01010000").unwrap();
|
||||
let next_in_line = chain_id.next_in_line();
|
||||
|
||||
assert_eq!(next_in_line, ChainIndex::from_str("02010000").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chain_id_child_correct() {
|
||||
let chain_id = ChainIndex::from_str("01010000").unwrap();
|
||||
let child = chain_id.n_th_child(3);
|
||||
|
||||
assert_eq!(child, ChainIndex::from_str("0101000003000000").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_keys_deterministic_generation() {
|
||||
let root_keys = ChildKeysPublic::root([42; 64]);
|
||||
let child_keys = root_keys.n_th_child(5);
|
||||
|
||||
assert_eq!(root_keys.cci, None);
|
||||
assert_eq!(child_keys.cci, Some(5));
|
||||
|
||||
assert_eq!(
|
||||
root_keys.ccc,
|
||||
[
|
||||
61, 30, 91, 26, 133, 91, 236, 192, 231, 53, 186, 139, 11, 221, 202, 11, 178, 215,
|
||||
254, 103, 191, 60, 117, 112, 1, 226, 31, 156, 83, 104, 150, 224
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
child_keys.ccc,
|
||||
[
|
||||
67, 26, 102, 68, 189, 155, 102, 80, 199, 188, 112, 142, 207, 157, 36, 210, 48, 224,
|
||||
35, 6, 112, 180, 11, 190, 135, 218, 9, 14, 84, 231, 58, 98
|
||||
]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
root_keys.csk.value(),
|
||||
&[
|
||||
241, 82, 246, 237, 62, 130, 116, 47, 189, 112, 99, 67, 178, 40, 115, 245, 141, 193,
|
||||
77, 164, 243, 76, 222, 64, 50, 146, 23, 145, 91, 164, 92, 116
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
child_keys.csk.value(),
|
||||
&[
|
||||
11, 151, 27, 212, 167, 26, 77, 234, 103, 145, 53, 191, 184, 25, 240, 191, 156, 25,
|
||||
60, 144, 65, 22, 193, 163, 246, 227, 212, 81, 49, 170, 33, 158
|
||||
]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
root_keys.cpk.value(),
|
||||
&[
|
||||
220, 170, 95, 177, 121, 37, 86, 166, 56, 238, 232, 72, 21, 106, 107, 217, 158, 74,
|
||||
133, 91, 143, 244, 155, 15, 2, 230, 223, 169, 13, 20, 163, 138
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
child_keys.cpk.value(),
|
||||
&[
|
||||
152, 249, 236, 111, 132, 96, 184, 122, 21, 179, 240, 15, 234, 155, 164, 144, 108,
|
||||
110, 120, 74, 176, 147, 196, 168, 243, 186, 203, 79, 97, 17, 194, 52
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
fn seed_holder_for_tests() -> SeedHolder {
|
||||
SeedHolder {
|
||||
seed: [42; 64].to_vec(),
|
||||
11
key_protocol/src/key_management/key_tree/traits.rs
Normal file
11
key_protocol/src/key_management/key_tree/traits.rs
Normal file
@ -0,0 +1,11 @@
|
||||
pub trait KeyNode {
|
||||
fn root(seed: [u8; 64]) -> Self;
|
||||
|
||||
fn n_th_child(&self, cci: u32) -> Self;
|
||||
|
||||
fn chain_code(&self) -> &[u8; 32];
|
||||
|
||||
fn child_index(&self) -> &Option<u32>;
|
||||
|
||||
fn address(&self) -> nssa::Address;
|
||||
}
|
||||
@ -45,8 +45,8 @@ impl SeedHolder {
|
||||
}
|
||||
|
||||
pub fn new_mnemonic(passphrase: String) -> Self {
|
||||
let mut enthopy_bytes: [u8; 32] = [0; 32];
|
||||
OsRng.fill_bytes(&mut enthopy_bytes);
|
||||
//Enthropy bytes must be deterministic as well
|
||||
let enthopy_bytes: [u8; 32] = [0; 32];
|
||||
|
||||
let mnemonic = Mnemonic::from_entropy(&enthopy_bytes).unwrap();
|
||||
let seed_wide = mnemonic.to_seed(passphrase);
|
||||
|
||||
@ -4,18 +4,26 @@ use anyhow::Result;
|
||||
use k256::AffinePoint;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::key_management::KeyChain;
|
||||
use crate::key_management::{
|
||||
KeyChain,
|
||||
key_tree::{KeyTreePrivate, KeyTreePublic, chain_index::ChainIndex},
|
||||
};
|
||||
|
||||
pub type PublicKey = AffinePoint;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct NSSAUserData {
|
||||
///Map for all user public accounts
|
||||
pub pub_account_signing_keys: HashMap<nssa::Address, nssa::PrivateKey>,
|
||||
///Map for all user private accounts
|
||||
pub user_private_accounts: HashMap<nssa::Address, (KeyChain, nssa_core::account::Account)>,
|
||||
///Default public accounts
|
||||
pub default_pub_account_signing_keys: HashMap<nssa::Address, nssa::PrivateKey>,
|
||||
///Default private accounts
|
||||
pub default_user_private_accounts:
|
||||
HashMap<nssa::Address, (KeyChain, nssa_core::account::Account)>,
|
||||
///Mnemonic passphrase
|
||||
pub password: String,
|
||||
/// Tree of public keys
|
||||
pub public_key_tree: KeyTreePublic,
|
||||
/// Tree of private keys
|
||||
pub private_key_tree: KeyTreePrivate,
|
||||
}
|
||||
|
||||
impl NSSAUserData {
|
||||
@ -97,13 +105,13 @@ impl NSSAUserData {
|
||||
/// Generated new private key for public transaction signatures
|
||||
///
|
||||
/// 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 generate_new_public_transaction_private_key(
|
||||
&mut self,
|
||||
parent_cci: ChainIndex,
|
||||
) -> nssa::Address {
|
||||
self.public_key_tree
|
||||
.generate_new_pub_keys(parent_cci)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Returns the signing key for public transaction signatures
|
||||
@ -111,7 +119,7 @@ impl NSSAUserData {
|
||||
&self,
|
||||
address: &nssa::Address,
|
||||
) -> Option<&nssa::PrivateKey> {
|
||||
self.pub_account_signing_keys.get(address)
|
||||
self.public_key_tree.get_pub_keys(address)
|
||||
}
|
||||
|
||||
/// Generated new private key for privacy preserving transactions
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
use nssa_core::address::Address;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{PrivateKey, error::NssaError};
|
||||
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct PublicKey([u8; 32]);
|
||||
|
||||
impl PublicKey {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user