update_meeting
This commit is contained in:
parent
9a34a02063
commit
b1bfe0ba22
@ -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(),
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
pub mod crypto;
|
pub mod crypto;
|
||||||
pub mod network;
|
pub mod network;
|
||||||
|
pub mod silentpayments;
|
||||||
|
@ -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
113
src/silentpayments.rs
Normal 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"));
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user