From 030cc0231a084cb727e0954c1eada1316f325d16 Mon Sep 17 00:00:00 2001 From: Sosthene00 <674694@protonmail.ch> Date: Tue, 2 Apr 2024 14:19:25 +0200 Subject: [PATCH] User creation + login --- crates/sp_client/src/Prd_list.rs | 56 ++++----- crates/sp_client/src/api.rs | 45 ++++++- crates/sp_client/src/lib.rs | 8 +- crates/sp_client/src/peers.rs | 9 ++ crates/sp_client/src/user.rs | 209 ++++++++----------------------- 5 files changed, 128 insertions(+), 199 deletions(-) create mode 100644 crates/sp_client/src/peers.rs diff --git a/crates/sp_client/src/Prd_list.rs b/crates/sp_client/src/Prd_list.rs index dc0867d..e8e8185 100644 --- a/crates/sp_client/src/Prd_list.rs +++ b/crates/sp_client/src/Prd_list.rs @@ -1,14 +1,12 @@ -use sp_backend::bitcoin::PublicKey; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; +use sp_backend::bitcoin::PublicKey; //use sp_backend::silentpayments::sending::SilentPaymentAddress; +use std::marker::Copy; use tsify::Tsify; use wasm_bindgen::prelude::*; -use std::marker::Copy; - #[wasm_bindgen] - #[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq, Copy)] pub enum Role { Manager, @@ -18,27 +16,26 @@ pub enum Role { #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] pub struct SilentPaymentAddress { - version : u8, - scan_pubkey : PublicKey, - m_pubkey : PublicKey, - is_testnet : bool, + version: u8, + scan_pubkey: PublicKey, + m_pubkey: PublicKey, + is_testnet: bool, } - #[derive(Debug, Copy, Clone)] pub struct ItemMember { - pub role : Role, - pub sp_address: SilentPaymentAddress, + pub role: Role, + pub sp_address: SilentPaymentAddress, //pre_id: hash(password, part1) //shard, //priv_key_mainnet_spend, (enc) - //priv_key_mainnet_scan, - //priv_key_signet_scan, + //priv_key_mainnet_scan, + //priv_key_signet_scan, } impl ItemMember { pub fn new(role: Role, sp_address: SilentPaymentAddress) -> Self { - ItemMember {role, sp_address} + ItemMember { role, sp_address } } } @@ -46,38 +43,31 @@ impl ItemMember { pub struct Prdlist { //pub id: String, //pub version: String, - pub gestionnaires: Vec, - // pub gestionnaires: Box>, + pub gestionnaires: Vec, + // pub gestionnaires: Box>, } - - - #[derive(Serialize)] #[wasm_bindgen] struct RequestBody { message: String, } -pub fn send_PrdRequest(prdlist: &Prdlist) -> Result<(), JsValue> { - let managers: Vec<&ItemMember> = prdlist.gestionnaires.iter().filter(|m| m.role == Role::Manager).collect(); +pub fn send_PrdRequest(prdlist: &Prdlist) -> Result<(), JsValue> { + let managers: Vec<&ItemMember> = prdlist + .gestionnaires + .iter() + .filter(|m| m.role == Role::Manager) + .collect(); for manager in managers { let request_body = RequestBody { message: "Asking for the Prd list".to_string(), }; - - let json_body = serde_json::to_string(&request_body).map_err(|e| JsValue::from_str(&format!("Failed to serialize request body: {:?}", e)))?; + + let json_body = serde_json::to_string(&request_body).map_err(|e| { + JsValue::from_str(&format!("Failed to serialize request body: {:?}", e)) + })?; println!("Sending request to manager {:?}", manager.sp_address); } Ok(()) } - - - - - - - - - - diff --git a/crates/sp_client/src/api.rs b/crates/sp_client/src/api.rs index 145dccf..ae4752c 100644 --- a/crates/sp_client/src/api.rs +++ b/crates/sp_client/src/api.rs @@ -128,20 +128,21 @@ pub fn get_receiving_address(sp_client: String) -> String { #[wasm_bindgen] pub fn create_user( - password: String, + password: String, // Attention à la conversion depuis le js label: Option, - birthday: u32, + birthday_main: u32, + birthday_signet: u32, process: String, ) -> ApiResult { let mut output_list: Vec = Vec::new(); //recover - let sp_wallet_recover = generate_sp_wallet(label.clone(), birthday, true)?; + let sp_wallet_recover = generate_sp_wallet(label.clone(), birthday_signet, true)?; output_list.push(sp_wallet_recover.sp_outputs); //revoke - let sp_wallet_revoke = generate_sp_wallet(label.clone(), birthday, true)?; + let sp_wallet_revoke = generate_sp_wallet(label.clone(), birthday_signet, true)?; output_list.push(sp_wallet_revoke.sp_outputs); //mainet - let sp_wallet_main = generate_sp_wallet(label, birthday, false)?; + let sp_wallet_main = generate_sp_wallet(label, birthday_main, false)?; output_list.push(sp_wallet_main.sp_outputs); let user_keys = UserKeys::new( @@ -195,3 +196,37 @@ pub fn get_processes() -> ApiResult { data_process.push(process3); Ok(get_process_return(data_process)) } + +#[derive(Debug, Tsify, Serialize, Deserialize)] +#[tsify(from_wasm_abi)] +#[allow(non_camel_case_types)] +pub struct recover_data(Vec); + +impl recover_data { + fn as_inner(&self) -> &[u8] { + &self.0 + } +} + +#[derive(Debug, Tsify, Serialize, Deserialize)] +#[tsify(from_wasm_abi)] +#[allow(non_camel_case_types)] +pub struct shamir_shares(Vec>); + +impl shamir_shares { + fn as_inner(&self) -> &[Vec] { + &self.0 + } +} + +#[wasm_bindgen] +pub fn login_user( + user_password: String, + pre_id: String, + recover: recover_data, + shares: shamir_shares, +) -> ApiResult<()> { + let res = User::login(pre_id, user_password, recover.as_inner(), shares.as_inner())?; + + Ok(res) +} diff --git a/crates/sp_client/src/lib.rs b/crates/sp_client/src/lib.rs index 4f1409e..bceda87 100644 --- a/crates/sp_client/src/lib.rs +++ b/crates/sp_client/src/lib.rs @@ -1,8 +1,8 @@ #![allow(warnings)] +mod Prd_list; +mod aesgcm; pub mod api; mod injecteurhtml; -mod user; -mod aesgcm; -mod Prd_list; +mod peers; mod process; - +mod user; diff --git a/crates/sp_client/src/peers.rs b/crates/sp_client/src/peers.rs new file mode 100644 index 0000000..5f7d207 --- /dev/null +++ b/crates/sp_client/src/peers.rs @@ -0,0 +1,9 @@ +use std::net::SocketAddr; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Peer { + pub addr: SocketAddr, + pub processes: Vec, +} diff --git a/crates/sp_client/src/user.rs b/crates/sp_client/src/user.rs index 852327c..50ee132 100644 --- a/crates/sp_client/src/user.rs +++ b/crates/sp_client/src/user.rs @@ -16,7 +16,6 @@ use sp_backend::bitcoin::secp256k1::ThirtyTwoByteHash; use tsify::Tsify; use wasm_bindgen::prelude::*; -use bytes::Bytes; use shamir::SecretData; use std::collections::HashMap; use std::fs::File; @@ -37,10 +36,14 @@ use img_parts::{ImageEXIF, ImageICC}; use crate::aesgcm::Aes256Decryption; use crate::aesgcm::HalfKey; use crate::aesgcm::{Aes256Encryption, Purpose}; +use crate::peers::Peer; use crate::user; type PreId = String; +const MANAGERS_NUMBER: u8 = 10; +const QUORUM_SHARD: f32 = 0.8; + pub static CONNECTED_USERS: OnceLock>> = OnceLock::new(); #[derive(Debug, Clone, Serialize, Deserialize)] @@ -67,11 +70,12 @@ impl UserKeys { #[derive(Debug, Serialize, Deserialize, Clone, Tsify)] #[tsify(into_wasm_abi, from_wasm_abi)] pub struct User { - pub pre_id: String, - pub process: String, + pub pre_id: PreId, + pub processes: Vec, + pub peers: Vec, recover_data: Vec, revoke_data: Option>, - sharding: Sharding, + shares: Vec>, } impl User { @@ -143,7 +147,18 @@ impl User { let cipher_recover_part2 = part2_encryption.encrypt_with_aes_key()?; //create shardings - let sharding = Sharding::new(&cipher_recover_part2.to_lower_hex_string(), 10u8); //nMembers = 10 for testing, need to recover nmember elsewhere + let threshold = (MANAGERS_NUMBER as f32 * QUORUM_SHARD).floor(); + debug_assert!(threshold > 0.0 && threshold <= u8::MAX as f32); + let sharding = shamir::SecretData::with_secret( + &cipher_recover_part2.to_lower_hex_string(), + threshold as u8, + ); + + let shares: Vec> = (1..MANAGERS_NUMBER) + .map(|x| { + sharding.get_share(x).unwrap() // Let's trust it for now + }) + .collect(); //scan key: let mut engine = sha256::HashEngine::default(); @@ -171,10 +186,11 @@ impl User { Ok(User { pre_id: pre_id.to_string(), - process, + processes: vec![process], + peers: vec![], recover_data, revoke_data: Some(revoke_data), - sharding, + shares, }) } @@ -182,7 +198,7 @@ impl User { pre_id: PreId, user_password: String, recover_data: &[u8], - sharding: Sharding, + shares: &[Vec], ) -> Result<()> { let mut retrieved_spend_key = [0u8; 32]; let mut retrieved_scan_key = [0u8; 32]; @@ -228,13 +244,10 @@ impl User { part1_ciphertext.to_vec(), )?); - //@todo: get shardings from member managers! - let shardings = sharding.shares_vec.clone(); // temporary - retrieved_spend_key[16..].copy_from_slice(&Self::recover_part2( &user_password, &entropy2, - shardings, + shares, )?); retrieved_scan_key.copy_from_slice(&Self::recover_key_slice( @@ -309,17 +322,17 @@ impl User { aes_dec.decrypt_with_key() } - fn recover_part2(password: &str, entropy: &[u8], shares_vec: Vec>) -> Result> { + fn recover_part2(password: &str, entropy: &[u8], shares: &[Vec]) -> Result> { let mut engine = sha256::HashEngine::default(); engine.write_all(&password.as_bytes()); engine.write_all(&entropy); let hash = sha256::Hash::from_engine(engine); - let shares_total: f32 = u8::try_from(shares_vec.len())?.try_into()?; - let quorum_sharding: u8 = (Sharding::QUORUM_SHARD * shares_total).round() as u8; + let threshold = (MANAGERS_NUMBER as f32 * QUORUM_SHARD).floor(); + debug_assert!(threshold > 0.0 && threshold <= u8::MAX as f32); let part2_key_enc = Vec::from_hex( - &SecretData::recover_secret(quorum_sharding, shares_vec) + &SecretData::recover_secret(threshold as u8, shares.to_vec()) .ok_or_else(|| anyhow::Error::msg("Failed to retrieve the sharded secret"))?, )?; @@ -356,141 +369,27 @@ impl User { // sha_256(&password_hash) // } - // Test sharing JS side - pub fn get_shares(&self) -> Vec { - self.sharding.shares_format_str.clone() - } + // // Test sharing JS side + // pub fn get_shares(&self) -> Vec { + // self.sharding.shares_format_str.clone() + // } - //Test sharing Js side - pub fn get_secret(&self, shardings: Vec) -> String { - let mut shares_vec = Vec::new(); + // //Test sharing Js side + // pub fn get_secret(&self, shardings: Vec) -> String { + // let mut shares_vec = Vec::new(); - for s in shardings.iter() { - let bytes_vec: Vec = s - .trim_matches(|c| c == '[' || c == ']') - .split(',') - .filter_map(|s| s.trim().parse().ok()) - .collect(); - shares_vec.push(bytes_vec); - } - self.sharding.recover_secrete(shares_vec.clone()) - } + // for s in shardings.iter() { + // let bytes_vec: Vec = s + // .trim_matches(|c| c == '[' || c == ']') + // .split(',') + // .filter_map(|s| s.trim().parse().ok()) + // .collect(); + // shares_vec.push(bytes_vec); + // } + // self.sharding.recover_secrete(shares_vec.clone()) + // } } -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum BackUpImage { - Recover(Vec), - Revoke(Vec), -} - -impl BackUpImage { - pub fn new_recover(image: &[u8], data: &[u8]) -> Result { - let img = write_exif(image, data)?; - Ok(Self::Recover(img)) - } - - pub fn new_revoke(image: &[u8], data: &[u8]) -> Result { - let img = write_exif(image, data)?; - Ok(Self::Revoke(img)) - } -} - -#[derive(Debug, Serialize, Deserialize, Default, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct Sharding { - shares_vec: Vec>, - shares_format_str: Vec, -} - -impl Sharding { - const QUORUM_SHARD: f32 = 0.80_f32; - pub fn new(part2_key_enc: &str, number_members: u8) -> Self { - let secret_data = SecretData::with_secret(part2_key_enc, number_members); - let mut shares_format_str: Vec = Vec::new(); - let shares_vec = (1..=number_members) - .map(|i| match secret_data.get_share(i) { - Ok(share) => { - let string = format!( - "[{}]", - share - .clone() - .iter() - .map(|b| format!("{}", b)) - .collect::>() - .join(",") - ); - shares_format_str.push(string.clone()); - share - } - Err(_) => panic!("Not able to recover the shares!"), - }) - .collect::>(); - - Sharding { - shares_vec, - shares_format_str, - } - } - - pub fn recover_secrete(&self, shares: Vec>) -> String { - let quorum_sharding = (Self::QUORUM_SHARD * f32::from(shares.len() as u8)).round() as u8; - SecretData::recover_secret(quorum_sharding, shares).unwrap() - } -} - -pub fn write_exif(image_to_recover: &[u8], data: &[u8]) -> Result> { - let mut jpeg = Jpeg::from_bytes(Bytes::from(image_to_recover.to_vec()))?; - let data_bytes = Bytes::from(data.to_owned()); - jpeg.set_exif(Some(data_bytes)); - let output_image_bytes = jpeg.encoder().bytes(); - let output_image = output_image_bytes.to_vec(); - Ok(output_image) -} - -pub fn read_exif(image: &[u8]) -> Result, String> { - let image_bytes = Bytes::from(image.to_vec()); - let jpeg = Jpeg::from_bytes(image_bytes).unwrap(); - - //exif out - let mut exif_image = Bytes::new(); - if let Some(ref meta) = jpeg.exif() { - exif_image = meta.clone(); - } else { - return Err("No exif data".to_string()); - } - let exif_bytes = exif_image.as_ref(); - Ok(exif_bytes.to_vec()) -} - -// //change for return Result? -// pub fn from_hex_to_b58(hex_string: &str) -> String { -// let decoded_data = hex::decode(hex_string).expect("Failed to decode hex string"); -// let base58_string = bs58::encode(decoded_data).into_string(); -// base58_string -// } -// //change for return Result? -// pub fn from_b58_to_hex(base58_string: &str) -> String { -// let decoded_data = bs58::decode(base58_string.to_owned()).into_vec().unwrap(); -// let hex_string = decoded_data -// .iter() -// .map(|b| format!("{:02x}", b)) -// .collect::(); -// hex_string -// } - -// fn from_b64_to_hex(base64_string: &str) -> String { -// let decoded_data = base64::decode(base64_string).unwrap(); -// let hex_string = decoded_data -// .iter() -// .map(|b| format!("{:02x}", b)) -// .collect::(); -// hex_string -// } -// fn from_hex_to_b64(hex_string: &str) -> String { -// let decoded_data = hex::decode(hex_string).expect("Failed to decode hex string"); -// let base64_string = base64::encode(decoded_data); -// base64_string -// } - #[cfg(test)] mod tests { use super::*; // Import everything from the outer module @@ -550,22 +449,18 @@ mod tests { let user_keys = helper_create_user_keys(); let user = User::new(user_keys, USER_PASSWORD.to_owned(), PROCESS.to_owned()).unwrap(); - let pre_id = user.pre_id; - let recover_data = user.recover_data; - let sharding = user.sharding; - - let retrieved_recover_spend = User::login( - pre_id.clone(), + let res = User::login( + user.pre_id.clone(), USER_PASSWORD.to_owned(), - &recover_data, - sharding, + &user.recover_data, + &user.shares, ); - assert!(retrieved_recover_spend.is_ok()); + assert!(res.is_ok()); let connected = CONNECTED_USERS.get().unwrap().lock().unwrap(); - let recover = &connected.get(&pre_id).unwrap().recover; + let recover = &connected.get(&user.pre_id).unwrap().recover; assert!( format!(