update_meeting

This commit is contained in:
Sosthene00 2024-04-24 12:10:10 +02:00
parent 9a34a02063
commit b1bfe0ba22
4 changed files with 180 additions and 49 deletions

View File

@ -1,12 +1,11 @@
use std::collections::HashMap; use std::collections::HashMap;
use anyhow::{Error, Result}; use anyhow::{Error, Result};
use serde::{Deserialize, Serialize};
use sp_client::{ use sp_client::{
bitcoin::{ bitcoin::{
consensus::serde::hex,
hex::DisplayHex,
key::constants::SECRET_KEY_SIZE, key::constants::SECRET_KEY_SIZE,
secp256k1::{ecdh::SharedSecret, PublicKey, SecretKey}, secp256k1::{ecdh::SharedSecret, PublicKey},
Txid, Txid,
}, },
silentpayments::{ silentpayments::{
@ -14,9 +13,7 @@ use sp_client::{
sending::SilentPaymentAddress, sending::SilentPaymentAddress,
}, },
}; };
use tsify::Tsify;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use aes_gcm::{ use aes_gcm::{
aead::{Aead, AeadInPlace, Nonce}, aead::{Aead, AeadInPlace, Nonce},
@ -36,38 +33,45 @@ const HALFKEYSIZE: usize = SECRET_KEY_SIZE / 2;
const THIRTYTWO: usize = 32; const THIRTYTWO: usize = 32;
type SharedPublicKey = PublicKey;
#[derive(Debug)] #[derive(Debug)]
pub struct AnkSharedSecret(SharedSecret); pub struct SharedPoint([u8; 64]);
impl SharedPoint {
pub fn as_inner(&self) -> &[u8; 64] {
&self.0
}
}
#[derive(Debug, Serialize, Deserialize, Tsify, Clone)]
#[tsify(from_wasm_abi, into_wasm_abi)]
pub struct AnkSharedSecret {
secret: [u8; 32],
pub trusted: bool,
}
impl AnkSharedSecret { impl AnkSharedSecret {
pub fn new_from_public_key(public_key: SharedPublicKey) -> Self { pub fn new(shared_point: [u8; 64], trusted: bool) -> Self {
let t_hash = SharedPublicKeyHash::from_shared_pubkey(public_key); let secret = AnkSharedSecretHash::from_shared_point(shared_point).to_byte_array();
Self(SharedSecret::from_bytes(t_hash.to_byte_array())) Self { secret, trusted }
} }
pub fn to_byte_array(&self) -> [u8; SECRET_KEY_SIZE] { pub fn to_byte_array(&self) -> [u8; 32] {
self.0.secret_bytes() self.secret
}
pub fn to_string(&self) -> String {
format!("{}", self.0.display_secret())
} }
} }
sha256t_hash_newtype! { sha256t_hash_newtype! {
pub struct SharedPublicKeyTag = hash_str("4nk/SharedPublicKey"); pub struct AnkSharedSecretTag = hash_str("4nk/AnkSharedSecret");
#[hash_newtype(forward)] #[hash_newtype(forward)]
pub struct SharedPublicKeyHash(_); pub struct AnkSharedSecretHash(_);
} }
impl SharedPublicKeyHash { impl AnkSharedSecretHash {
pub fn from_shared_pubkey(shared_pubkey: SharedPublicKey) -> Self { pub fn from_shared_point(shared_point: [u8; 64]) -> Self {
let mut eng = SharedPublicKeyHash::engine(); let mut eng = AnkSharedSecretHash::engine();
eng.input(&shared_pubkey.serialize()); eng.input(&shared_point);
SharedPublicKeyHash::from_engine(eng) AnkSharedSecretHash::from_engine(eng)
} }
} }
@ -214,7 +218,7 @@ pub struct Aes256Encryption {
plaintext: Vec<u8>, plaintext: Vec<u8>,
aes_key: [u8; 32], aes_key: [u8; 32],
nonce: [u8; 12], nonce: [u8; 12],
shared_secrets: HashMap<Txid, HashMap<SilentPaymentAddress, SharedSecret>>, shared_secrets: HashMap<Txid, HashMap<SilentPaymentAddress, AnkSharedSecret>>,
} }
impl Aes256Encryption { impl Aes256Encryption {
@ -227,7 +231,7 @@ impl Aes256Encryption {
pub fn set_shared_secret( pub fn set_shared_secret(
&mut self, &mut self,
shared_secrets: HashMap<Txid, HashMap<SilentPaymentAddress, SharedSecret>>, shared_secrets: HashMap<Txid, HashMap<SilentPaymentAddress, AnkSharedSecret>>,
) { ) {
self.shared_secrets = shared_secrets; self.shared_secrets = shared_secrets;
} }
@ -240,7 +244,7 @@ impl Aes256Encryption {
for (_, sp_address2shared_secret) in self.shared_secrets.iter() { for (_, sp_address2shared_secret) in self.shared_secrets.iter() {
for (sp_address, shared_secret) in sp_address2shared_secret { for (sp_address, shared_secret) in sp_address2shared_secret {
let cipher = Aes256Gcm::new_from_slice(shared_secret.as_ref()) let cipher = Aes256Gcm::new_from_slice(&shared_secret.secret)
.map_err(|e| Error::msg(format!("{}", e)))?; .map_err(|e| Error::msg(format!("{}", e)))?;
let nonce = Aes256Gcm::generate_nonce(&mut rng); let nonce = Aes256Gcm::generate_nonce(&mut rng);
let encrypted_key = cipher let encrypted_key = cipher
@ -327,6 +331,8 @@ impl Aes256Encryption {
mod tests { mod tests {
use std::str::FromStr; use std::str::FromStr;
use sp_client::bitcoin::hex::FromHex;
use super::*; use super::*;
const ALICE_SP_ADDRESS: &str = "tsp1qqw3lqr6xravz9nf8ntazgwwl0fqv47kfjdxsnxs6eutavqfwyv5q6qk97mmyf6dtkdyzqlu2zv6h9j2ggclk7vn705q5u2phglpq7yw3dg5rwpdz"; const ALICE_SP_ADDRESS: &str = "tsp1qqw3lqr6xravz9nf8ntazgwwl0fqv47kfjdxsnxs6eutavqfwyv5q6qk97mmyf6dtkdyzqlu2zv6h9j2ggclk7vn705q5u2phglpq7yw3dg5rwpdz";
@ -399,11 +405,14 @@ mod tests {
let mut aes_enc = Aes256Encryption::new(Purpose::Login, plaintext.to_vec()).unwrap(); let mut aes_enc = Aes256Encryption::new(Purpose::Login, plaintext.to_vec()).unwrap();
let mut shared_secrets: HashMap<Txid, _> = HashMap::new(); let mut shared_secrets: HashMap<Txid, _> = HashMap::new();
let mut sp_address2shared_secrets: HashMap<SilentPaymentAddress, SharedSecret> = let mut sp_address2shared_secrets: HashMap<SilentPaymentAddress, AnkSharedSecret> =
HashMap::new(); HashMap::new();
let alice_secret = Vec::from_hex(ALICE_SHARED_SECRET).unwrap();
let mut buf = [0u8;32];
buf.copy_from_slice(&alice_secret);
sp_address2shared_secrets.insert( sp_address2shared_secrets.insert(
ALICE_SP_ADDRESS.try_into().unwrap(), ALICE_SP_ADDRESS.try_into().unwrap(),
SharedSecret::from_str(ALICE_SHARED_SECRET).unwrap(), AnkSharedSecret { secret: buf, trusted: true }
); );
shared_secrets.insert( shared_secrets.insert(
Txid::from_str(TRANSACTION).unwrap(), Txid::from_str(TRANSACTION).unwrap(),
@ -448,15 +457,21 @@ mod tests {
Aes256Encryption::new(Purpose::ThirtyTwoBytes, plaintext.to_vec()).unwrap(); Aes256Encryption::new(Purpose::ThirtyTwoBytes, plaintext.to_vec()).unwrap();
let mut shared_secrets: HashMap<Txid, _> = HashMap::new(); let mut shared_secrets: HashMap<Txid, _> = HashMap::new();
let mut sp_address2shared_secrets: HashMap<SilentPaymentAddress, SharedSecret> = let mut sp_address2shared_secrets: HashMap<SilentPaymentAddress, AnkSharedSecret> =
HashMap::new(); HashMap::new();
let alice_secret = Vec::from_hex(ALICE_SHARED_SECRET).unwrap();
let mut buf = [0u8;32];
buf.copy_from_slice(&alice_secret);
sp_address2shared_secrets.insert( sp_address2shared_secrets.insert(
ALICE_SP_ADDRESS.try_into().unwrap(), ALICE_SP_ADDRESS.try_into().unwrap(),
SharedSecret::from_str(ALICE_SHARED_SECRET).unwrap(), AnkSharedSecret { secret: buf, trusted: true }
); );
let bob_secret = Vec::from_hex(BOB_SHARED_SECRET).unwrap();
let mut buf = [0u8;32];
buf.copy_from_slice(&bob_secret);
sp_address2shared_secrets.insert( sp_address2shared_secrets.insert(
BOB_SP_ADDRESS.try_into().unwrap(), BOB_SP_ADDRESS.try_into().unwrap(),
SharedSecret::from_str(BOB_SHARED_SECRET).unwrap(), AnkSharedSecret { secret: buf, trusted: true }
); );
shared_secrets.insert( shared_secrets.insert(
Txid::from_str(TRANSACTION).unwrap(), Txid::from_str(TRANSACTION).unwrap(),

View File

@ -1,2 +1,3 @@
pub mod crypto; pub mod crypto;
pub mod network; pub mod network;
pub mod silentpayments;

View File

@ -138,17 +138,19 @@ impl Envelope {
pub enum AnkFlag { pub enum AnkFlag {
NewTx, NewTx,
Faucet, Faucet,
Prd,
Error, Error,
Unknown, Unknown,
} }
impl From<&str> for AnkFlag { impl From<&str> for AnkFlag {
fn from(value: &str) -> Self { fn from(value: &str) -> Self {
match value { match value {
"NewTx" => Self::NewTx, "NewTx" => Self::NewTx,
"Faucet" => Self::Faucet, "Faucet" => Self::Faucet,
"Prd" => Self::Prd,
"Error" => Self::Error, "Error" => Self::Error,
_ => Self::Unknown _ => Self::Unknown,
} }
} }
} }
@ -164,8 +166,9 @@ impl AnkFlag {
match byte { match byte {
0 => Self::NewTx, 0 => Self::NewTx,
1 => Self::Faucet, 1 => Self::Faucet,
2 => Self::Error, 2 => Self::Prd,
_ => Self::Unknown 9 => Self::Error,
_ => Self::Unknown,
} }
} }
@ -173,8 +176,9 @@ impl AnkFlag {
match self { match self {
Self::NewTx => "new_tx", Self::NewTx => "new_tx",
Self::Faucet => "faucet", Self::Faucet => "faucet",
Self::Prd => "prd",
Self::Error => "error", Self::Error => "error",
Self::Unknown => "unknown" Self::Unknown => "unknown",
} }
} }
} }
@ -187,9 +191,7 @@ pub struct FaucetMessage {
impl FaucetMessage { impl FaucetMessage {
pub fn new(sp_address: String) -> Self { pub fn new(sp_address: String) -> Self {
Self { Self { sp_address }
sp_address
}
} }
} }
@ -197,14 +199,14 @@ impl FaucetMessage {
#[tsify(into_wasm_abi, from_wasm_abi)] #[tsify(into_wasm_abi, from_wasm_abi)]
pub struct NewTxMessage { pub struct NewTxMessage {
pub transaction: String, pub transaction: String,
pub tweak_data: Option<String> pub tweak_data: Option<String>,
} }
impl NewTxMessage { impl NewTxMessage {
pub fn new(transaction: String, tweak_data: Option<String>) -> Self { pub fn new(transaction: String, tweak_data: Option<String>) -> Self {
Self { Self {
transaction, transaction,
tweak_data tweak_data,
} }
} }
} }
@ -220,17 +222,17 @@ pub struct AnkNetworkMsg {
// type Error = anyhow::Error; // type Error = anyhow::Error;
// fn try_from(value: &str) -> std::prelude::v1::Result<Self, Self::Error> { // fn try_from(value: &str) -> std::prelude::v1::Result<Self, Self::Error> {
// let parsed: Value = serde_json::from_str(value)?; // let parsed: Value = serde_json::from_str(value)?;
// let flag = parsed // let flag = parsed
// .get("flag") // .get("flag")
// .ok_or(Error::msg("Invalid AnkNetworkMsg"))? // .ok_or(Error::msg("Invalid AnkNetworkMsg"))?
// .as_str() // .as_str()
// .ok_or(Error::msg("Invalid AnkNetworkMsg"))?; // .ok_or(Error::msg("Invalid AnkNetworkMsg"))?;
// let content = parsed // let content = parsed
// .get("content") // .get("content")
// .ok_or(Error::msg("Invalid AnkNetworkMsg"))? // .ok_or(Error::msg("Invalid AnkNetworkMsg"))?
// .as_str() // .as_str()
// .ok_or(Error::msg("Invalid AnkNetworkMsg"))?; // .ok_or(Error::msg("Invalid AnkNetworkMsg"))?;
// Ok(Self { flag: flag.into(), content: content.into() }) // Ok(Self { flag: flag.into(), content: content.into() })
// } // }
// } // }
@ -238,7 +240,7 @@ impl AnkNetworkMsg {
pub fn new(flag: AnkFlag, raw: &str) -> Self { pub fn new(flag: AnkFlag, raw: &str) -> Self {
Self { Self {
flag, flag,
content: raw.into() content: raw.into(),
} }
} }
} }

113
src/silentpayments.rs Normal file
View File

@ -0,0 +1,113 @@
use std::collections::HashMap;
use anyhow::{Error, Result};
use rand::Rng;
use serde::{Deserialize, Serialize};
use sp_client::bitcoin::secp256k1::ecdh::shared_secret_point;
use sp_client::bitcoin::{secp256k1::PublicKey, Transaction};
use sp_client::bitcoin::{Amount, OutPoint, Txid};
use sp_client::silentpayments::sending::SilentPaymentAddress;
use sp_client::spclient::{OwnedOutput, Recipient, SpClient, SpWallet};
use tsify::Tsify;
use crate::crypto::AnkSharedSecret;
// #[derive(Debug, Serialize, Deserialize, Tsify)]
// #[tsify(into_wasm_abi, from_wasm_abi)]
// pub struct ScannedTransaction(HashMap<Txid, Vec<AnkSharedSecret>>);
// impl ScannedTransaction {
// pub fn new() -> Self {
// Self(HashMap::new())
// }
// pub fn get(&self) -> &HashMap<Txid, Vec<AnkSharedSecret>> {
// &self.0
// }
// pub fn get_mut(&mut self) -> &mut HashMap<Txid, Vec<AnkSharedSecret>> {
// &mut self.0
// }
// pub fn to_inner(&self) -> HashMap<Txid, Vec<AnkSharedSecret>> {
// self.0.clone()
// }
// }
pub fn create_transaction_for_address_with_shared_secret(
sp_address: SilentPaymentAddress,
sp_wallet: &SpWallet,
message: String,
fee_rate: Amount,
) -> Result<(Transaction, AnkSharedSecret)> {
let available_outpoints = sp_wallet.get_outputs().to_spendable_list();
// Here we need to add more heuristics about which outpoint we spend
// For now let's keep it simple
let mut inputs: HashMap<OutPoint, OwnedOutput> = HashMap::new();
let mut total_available = Amount::from_sat(0);
for (outpoint, output) in available_outpoints {
total_available += output.amount;
inputs.insert(outpoint, output);
if total_available > Amount::from_sat(1000) {
break;
}
}
if total_available < Amount::from_sat(1000) {
return Err(Error::msg("Not enough available funds"));
}
let recipient = Recipient {
address: sp_address.into(),
amount: Amount::from_sat(1000),
nb_outputs: 1,
};
let mut new_psbt = sp_wallet.get_client().create_new_psbt(
inputs,
vec![recipient],
Some(message.as_bytes()),
)?;
let change_addr = sp_wallet.get_client().sp_receiver.get_change_address();
SpClient::set_fees(&mut new_psbt, fee_rate, change_addr)?;
let partial_secret = sp_wallet
.get_client()
.get_partial_secret_from_psbt(&new_psbt)?;
// This wouldn't work with many recipients in the same transaction
// each address (or more precisely each scan public key) would have its own point
let shared_point = shared_secret_point(&sp_address.get_scan_key(), &partial_secret);
sp_wallet
.get_client()
.fill_sp_outputs(&mut new_psbt, partial_secret)?;
let mut aux_rand = [0u8; 32];
rand::thread_rng().fill(&mut aux_rand);
let mut signed = sp_wallet.get_client().sign_psbt(new_psbt, &aux_rand)?;
SpClient::finalize_psbt(&mut signed)?;
let final_tx = signed.extract_tx()?;
Ok((final_tx, AnkSharedSecret::new(shared_point, true)))
}
// This need to go
pub fn check_transaction(
tx: &Transaction,
sp_wallet: &mut SpWallet,
blockheight: u32,
tweak_data: PublicKey,
) -> Result<String> {
let txid = tx.txid().to_string();
if sp_wallet.update_wallet_with_transaction(tx, blockheight, tweak_data)? > 0 {
return Ok(txid);
}
return Err(Error::msg("No new outputs found"));
}