use std::{collections::{HashMap, HashSet}, str::FromStr}; use anyhow::{Result, Error}; use aes_gcm::{aead::{Aead, Payload}, AeadCore, Aes256Gcm, KeyInit}; use log::debug; use rand::thread_rng; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; use sp_client::{bitcoin::{hashes::{sha256t_hash_newtype, Hash, HashEngine}, hex::{DisplayHex, FromHex}, Txid}, silentpayments::utils::SilentPaymentAddress}; use tsify::Tsify; use crate::crypto::AAD; #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Tsify)] #[tsify(into_wasm_abi, from_wasm_abi)] pub struct Member { sp_addresses: Vec } impl Member { pub fn new( sp_addresses: Vec, ) -> Result { if sp_addresses.is_empty() { return Err(Error::msg("empty address set")); } let mut seen = HashSet::new(); for s in sp_addresses.iter() { if !seen.insert(s.clone()) { return Err(Error::msg("Duplicate addresses found")); } } let res: Vec = sp_addresses.iter() .map(|a| Into::::into(*a)) .collect(); Ok(Self { sp_addresses: res }) } pub fn get_addresses(&self) -> Vec { self.sp_addresses.clone() } } sha256t_hash_newtype! { pub struct AnkPcdTag = hash_str("4nk/Pcd"); #[hash_newtype(forward)] pub struct AnkPcdHash(_); } impl AnkPcdHash { pub fn from_value(value: &Value) -> Self { let mut eng = AnkPcdHash::engine(); eng.input(value.to_string().as_bytes()); AnkPcdHash::from_engine(eng) } pub fn from_map(map: &Map) -> Self { let value = Value::Object(map.clone()); let mut eng = AnkPcdHash::engine(); eng.input(value.to_string().as_bytes()); AnkPcdHash::from_engine(eng) } } pub trait Pcd<'a>: Serialize + Deserialize<'a> { fn hash(&self) -> AnkPcdHash { AnkPcdHash::from_value(&self.to_value()) } fn encrypt_fields(&self, fields2keys: &mut Map, fields2cipher: &mut Map) -> Result<()> { let as_value = self.to_value(); let as_map = as_value.as_object().unwrap(); let mut rng = thread_rng(); for (key, value) in as_map { let aes_key: [u8; 32] = Aes256Gcm::generate_key(&mut rng).into(); let nonce: [u8; 12] = Aes256Gcm::generate_nonce(&mut rng).into(); fields2keys.insert(key.to_owned(), Value::String(aes_key.to_lower_hex_string())); let encryption = Aes256Gcm::new(&aes_key.into()); let value_string = value.to_string(); let payload = Payload { msg: value_string.as_bytes(), aad: AAD, }; let cipher = encryption.encrypt(&nonce.into(), payload) .map_err(|e| Error::msg(format!("{}", e)))?; let mut res = Vec::with_capacity(nonce.len() + cipher.len()); res.extend_from_slice(&nonce); res.extend_from_slice(&cipher); fields2cipher.insert(key.to_owned(), Value::String(res.to_lower_hex_string())); } Ok(()) } fn decrypt_fields(&mut self, fields2keys: &Map) -> Result<()> { let as_value = self.to_value(); let as_map = as_value.as_object().unwrap(); for (key, value) in as_map { if let Some(aes_key) = fields2keys.get(key) { let mut nonce = [0u8; 12]; let mut key_buf = [0u8; 32]; key_buf.copy_from_slice(&Vec::from_hex(&aes_key.to_string().trim_matches('\"'))?); let decrypt = Aes256Gcm::new(&key_buf.into()); let raw_cipher = Vec::from_hex(&value.to_string().trim_matches('\"'))?; nonce.copy_from_slice(&raw_cipher[..12]); let payload = Payload { msg: &raw_cipher[12..], aad: AAD, }; let plain = decrypt.decrypt(&nonce.into(), payload) .map_err(|_| Error::msg(format!("Failed to decrypt field {}", key)))?; self.to_value() .as_object_mut() .unwrap() .insert(key.to_owned(), Value::String(plain.to_lower_hex_string())); } else { continue; } } Ok(()) } fn to_value(&self) -> Value { Value::from_str(&serde_json::to_string(&self).unwrap()).unwrap() } } impl Pcd<'_> for Value {} #[derive(Debug, Clone, Serialize, Deserialize, Tsify)] #[tsify(into_wasm_abi, from_wasm_abi)] pub struct ValidationRule { quorum: f32, // Must be >= 0.0, <= 1.0, 0.0 means reading right pub fields: Vec, // Which fields are concerned by this rule min_sig_member: f32, // Must be >= 0.0, <= 1.0, does each member need to sign with all it's devices? } impl ValidationRule { pub fn new(quorum: f32, fields: Vec, min_sig_member: f32) -> Result { if quorum < 0.0 || quorum > 1.0 { return Err(Error::msg("quorum must be 0.0 < quorum <= 1.0")); } if min_sig_member < 0.0 || min_sig_member > 1.0 { return Err(Error::msg("min_signatures_member must be 0.0 < min_signatures_member <= 1.0")); } if fields.is_empty() { return Err(Error::msg("Fields can't be empty")); } let res = Self { quorum, fields, min_sig_member, }; Ok(res) } } #[derive(Debug, Clone, Serialize, Deserialize, Tsify)] #[tsify(into_wasm_abi, from_wasm_abi)] pub struct RoleDefinition { pub members: Vec, pub validation_rules: Vec, } // #[derive(Debug, Clone, Serialize, Deserialize, Tsify)] // #[tsify(into_wasm_abi, from_wasm_abi)] // pub struct Roles { // pub roles: HashMap // }