Working pairing
This commit is contained in:
parent
1871dc9a5d
commit
836f6cf900
198
src/api.rs
198
src/api.rs
@ -20,10 +20,9 @@ use anyhow::Error as AnyhowError;
|
|||||||
use anyhow::Result as AnyhowResult;
|
use anyhow::Result as AnyhowResult;
|
||||||
use sdk_common::aes_gcm::aead::{Aead, Payload};
|
use sdk_common::aes_gcm::aead::{Aead, Payload};
|
||||||
use sdk_common::crypto::{
|
use sdk_common::crypto::{
|
||||||
AeadCore, Aes256Decryption, Aes256Encryption, Aes256Gcm, AnkSharedSecret, AnkSharedSecretHash,
|
encrypt_with_key, AeadCore, Aes256Gcm, AnkSharedSecretHash, KeyInit, AAD
|
||||||
KeyInit, Purpose, AAD,
|
|
||||||
};
|
};
|
||||||
use sdk_common::process::Process;
|
use sdk_common::process::{lock_processes, Process, ProcessState};
|
||||||
use sdk_common::signature::{AnkHash, AnkValidationNoHash, AnkValidationYesHash, Proof};
|
use sdk_common::signature::{AnkHash, AnkValidationNoHash, AnkValidationYesHash, Proof};
|
||||||
use sdk_common::sp_client::bitcoin::blockdata::fee_rate;
|
use sdk_common::sp_client::bitcoin::blockdata::fee_rate;
|
||||||
use sdk_common::sp_client::bitcoin::consensus::{deserialize, serialize};
|
use sdk_common::sp_client::bitcoin::consensus::{deserialize, serialize};
|
||||||
@ -50,7 +49,6 @@ use sdk_common::sp_client::silentpayments::{
|
|||||||
utils::{Network as SpNetwork, SilentPaymentAddress},
|
utils::{Network as SpNetwork, SilentPaymentAddress},
|
||||||
Error as SpError,
|
Error as SpError,
|
||||||
};
|
};
|
||||||
use sdk_common::uuid::Uuid;
|
|
||||||
use sdk_common::{signature, MAX_PRD_PAYLOAD_SIZE};
|
use sdk_common::{signature, MAX_PRD_PAYLOAD_SIZE};
|
||||||
use serde_json::{Error as SerdeJsonError, Map, Value};
|
use serde_json::{Error as SerdeJsonError, Map, Value};
|
||||||
|
|
||||||
@ -77,7 +75,7 @@ use sdk_common::sp_client::spclient::{SpWallet, SpendKey};
|
|||||||
use crate::user::{lock_local_device, set_new_device, LOCAL_DEVICE};
|
use crate::user::{lock_local_device, set_new_device, LOCAL_DEVICE};
|
||||||
use crate::wallet::{generate_sp_wallet, lock_freezed_utxos};
|
use crate::wallet::{generate_sp_wallet, lock_freezed_utxos};
|
||||||
use crate::{
|
use crate::{
|
||||||
lock_messages, lock_processes, ProcessState, RelevantProcess, CACHEDMESSAGES, CACHEDPROCESSES,
|
lock_messages, CACHEDMESSAGES,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Tsify, Serialize, Deserialize, Default)]
|
#[derive(Debug, PartialEq, Tsify, Serialize, Deserialize, Default)]
|
||||||
@ -85,7 +83,7 @@ use crate::{
|
|||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub struct ApiReturn {
|
pub struct ApiReturn {
|
||||||
pub updated_cached_msg: Vec<CachedMessage>,
|
pub updated_cached_msg: Vec<CachedMessage>,
|
||||||
pub updated_process: Option<(String, RelevantProcess)>,
|
pub updated_process: Option<(String, Process)>,
|
||||||
pub new_tx_to_send: Option<Transaction>,
|
pub new_tx_to_send: Option<Transaction>,
|
||||||
pub ciphers_to_send: Vec<String>,
|
pub ciphers_to_send: Vec<String>,
|
||||||
pub commit_to_send: Option<CommitMessage>,
|
pub commit_to_send: Option<CommitMessage>,
|
||||||
@ -263,6 +261,15 @@ pub fn pair_device(commitment_tx: String, mut sp_addresses: Vec<String>) -> ApiR
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn unpair_device() -> ApiResult<()> {
|
||||||
|
let mut local_device = lock_local_device()?;
|
||||||
|
|
||||||
|
local_device.unpair();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Tsify, Serialize, Deserialize)]
|
#[derive(Debug, Tsify, Serialize, Deserialize)]
|
||||||
#[tsify(from_wasm_abi, into_wasm_abi)]
|
#[tsify(from_wasm_abi, into_wasm_abi)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
@ -324,7 +331,7 @@ pub fn dump_process_cache() -> ApiResult<String> {
|
|||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn set_process_cache(processes: String) -> ApiResult<()> {
|
pub fn set_process_cache(processes: String) -> ApiResult<()> {
|
||||||
let processes: HashMap<OutPoint, RelevantProcess> = serde_json::from_str(&processes)?;
|
let processes: HashMap<OutPoint, Process> = serde_json::from_str(&processes)?;
|
||||||
|
|
||||||
let mut cached_processes = lock_processes()?;
|
let mut cached_processes = lock_processes()?;
|
||||||
|
|
||||||
@ -433,7 +440,7 @@ fn handle_transaction(
|
|||||||
&tweak_data,
|
&tweak_data,
|
||||||
&sp_wallet.get_client().get_scan_key(),
|
&sp_wallet.get_client().get_scan_key(),
|
||||||
);
|
);
|
||||||
let shared_secret = AnkSharedSecret::new(shared_point);
|
let shared_secret = AnkSharedSecretHash::from_shared_point(shared_point);
|
||||||
|
|
||||||
let mut plaintext: Vec<u8> = vec![];
|
let mut plaintext: Vec<u8> = vec![];
|
||||||
if let Some(message) = messages.iter_mut().find(|m| {
|
if let Some(message) = messages.iter_mut().find(|m| {
|
||||||
@ -469,23 +476,20 @@ fn handle_transaction(
|
|||||||
|
|
||||||
let outpoint = OutPoint::from_str(&prd.root_commitment)?;
|
let outpoint = OutPoint::from_str(&prd.root_commitment)?;
|
||||||
|
|
||||||
let updated_process: RelevantProcess;
|
let updated_process: Process;
|
||||||
if let Some(process) = lock_processes()?.get_mut(&outpoint) {
|
if let Some(process) = lock_processes()?.get_mut(&outpoint) {
|
||||||
process.shared_secrets.insert(
|
process.insert_shared_secret(
|
||||||
actual_sender,
|
SilentPaymentAddress::try_from(actual_sender.as_str()).unwrap(),
|
||||||
shared_secret.to_byte_array().to_lower_hex_string(),
|
shared_secret,
|
||||||
);
|
);
|
||||||
updated_process = process.clone();
|
updated_process = process.clone();
|
||||||
} else {
|
} else {
|
||||||
let mut shared_secrets = HashMap::new();
|
let mut shared_secrets = HashMap::new();
|
||||||
shared_secrets.insert(
|
shared_secrets.insert(
|
||||||
actual_sender,
|
SilentPaymentAddress::try_from(actual_sender.as_str()).unwrap(),
|
||||||
shared_secret.to_byte_array().to_lower_hex_string(),
|
shared_secret,
|
||||||
);
|
);
|
||||||
let new_process = RelevantProcess {
|
let new_process = Process::new(vec![], shared_secrets, vec![]);
|
||||||
shared_secrets,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
lock_processes()?.insert(outpoint, new_process.clone());
|
lock_processes()?.insert(outpoint, new_process.clone());
|
||||||
updated_process = new_process;
|
updated_process = new_process;
|
||||||
}
|
}
|
||||||
@ -575,18 +579,13 @@ pub fn parse_new_tx(new_tx_msg: String, block_height: u32, fee_rate: u32) -> Api
|
|||||||
|
|
||||||
fn try_decrypt_with_processes(
|
fn try_decrypt_with_processes(
|
||||||
cipher: &[u8],
|
cipher: &[u8],
|
||||||
processes: MutexGuard<HashMap<OutPoint, RelevantProcess>>,
|
processes: MutexGuard<HashMap<OutPoint, Process>>,
|
||||||
) -> Option<(Vec<u8>, SilentPaymentAddress, OutPoint)> {
|
) -> Option<(Vec<u8>, SilentPaymentAddress, OutPoint)> {
|
||||||
let nonce = Nonce::from_slice(&cipher[..12]);
|
let nonce = Nonce::from_slice(&cipher[..12]);
|
||||||
|
|
||||||
for (outpoint, process) in processes.iter() {
|
for (outpoint, process) in processes.iter() {
|
||||||
for (address, secret) in &process.shared_secrets {
|
for (address, secret) in process.get_all_secrets() {
|
||||||
let aes_key = match AnkSharedSecretHash::from_str(secret) {
|
let engine = Aes256Gcm::new(&secret.to_byte_array().into());
|
||||||
Ok(key) => key,
|
|
||||||
Err(_) => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
let engine = Aes256Gcm::new(aes_key.as_byte_array().into());
|
|
||||||
if let Ok(plain) = engine.decrypt(
|
if let Ok(plain) = engine.decrypt(
|
||||||
&nonce,
|
&nonce,
|
||||||
Payload {
|
Payload {
|
||||||
@ -596,7 +595,7 @@ fn try_decrypt_with_processes(
|
|||||||
) {
|
) {
|
||||||
return Some((
|
return Some((
|
||||||
plain,
|
plain,
|
||||||
SilentPaymentAddress::try_from(address.as_str()).unwrap(),
|
address,
|
||||||
*outpoint,
|
*outpoint,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -655,7 +654,7 @@ pub fn response_prd(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm_prd(prd: Prd, shared_secret: &str) -> AnyhowResult<String> {
|
fn confirm_prd(prd: Prd, shared_secret: &AnkSharedSecretHash) -> AnyhowResult<String> {
|
||||||
match prd.prd_type {
|
match prd.prd_type {
|
||||||
PrdType::Confirm | PrdType::Response | PrdType::List => {
|
PrdType::Confirm | PrdType::Response | PrdType::List => {
|
||||||
return Err(AnyhowError::msg("Invalid prd type"));
|
return Err(AnyhowError::msg("Invalid prd type"));
|
||||||
@ -690,16 +689,16 @@ fn confirm_prd(prd: Prd, shared_secret: &str) -> AnyhowResult<String> {
|
|||||||
|
|
||||||
let prd_msg = prd_confirm.to_network_msg(local_device.get_wallet())?;
|
let prd_msg = prd_confirm.to_network_msg(local_device.get_wallet())?;
|
||||||
|
|
||||||
Ok(encrypt_with_key(prd_msg, shared_secret.to_owned()).unwrap())
|
Ok(encrypt_with_key(shared_secret.as_byte_array(), prd_msg.as_bytes())?.to_lower_hex_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_data(prd: &Prd, shared_secret: &str) -> AnyhowResult<ApiReturn> {
|
fn send_data(prd: &Prd, shared_secret: &AnkSharedSecretHash) -> AnyhowResult<ApiReturn> {
|
||||||
let pcd = &prd.payload;
|
let pcd = &prd.payload;
|
||||||
|
|
||||||
let cipher = encrypt_with_key(pcd.clone(), shared_secret.to_owned()).unwrap();
|
let cipher = encrypt_with_key(shared_secret.as_byte_array(), pcd.as_bytes())?;
|
||||||
|
|
||||||
Ok(ApiReturn {
|
Ok(ApiReturn {
|
||||||
ciphers_to_send: vec![cipher],
|
ciphers_to_send: vec![cipher.to_lower_hex_string()],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -767,17 +766,9 @@ fn decrypt_with_known_processes(cipher: &[u8]) -> anyhow::Result<Option<(Vec<u8>
|
|||||||
let nonce = Nonce::from_slice(&cipher[..12]);
|
let nonce = Nonce::from_slice(&cipher[..12]);
|
||||||
|
|
||||||
for (outpoint, process) in processes.iter() {
|
for (outpoint, process) in processes.iter() {
|
||||||
for (address, secret) in &process.shared_secrets {
|
for (address, secret) in process.get_all_secrets() {
|
||||||
debug!("Attempting decryption with key {} for {}", secret, address);
|
debug!("Attempting decryption with key {} for {}", secret, address);
|
||||||
let aes_key = match AnkSharedSecretHash::from_str(secret) {
|
let engine = Aes256Gcm::new(secret.as_byte_array().into());
|
||||||
Ok(key) => key,
|
|
||||||
Err(_) => {
|
|
||||||
debug!("Invalid shared secret for process {}: {}", outpoint, secret);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let engine = Aes256Gcm::new(aes_key.as_byte_array().into());
|
|
||||||
|
|
||||||
if let Ok(plain) = engine.decrypt(
|
if let Ok(plain) = engine.decrypt(
|
||||||
&nonce,
|
&nonce,
|
||||||
@ -832,13 +823,10 @@ fn handle_prd(
|
|||||||
.ok_or_else(|| anyhow::Error::msg("Missing shared secret for new process"))?;
|
.ok_or_else(|| anyhow::Error::msg("Missing shared secret for new process"))?;
|
||||||
let mut shared_secrets = HashMap::new();
|
let mut shared_secrets = HashMap::new();
|
||||||
shared_secrets.insert(
|
shared_secrets.insert(
|
||||||
sp_address.to_string(),
|
sp_address,
|
||||||
shared_secret.to_byte_array().to_lower_hex_string(),
|
shared_secret,
|
||||||
);
|
);
|
||||||
entry.insert(RelevantProcess {
|
entry.insert(Process::new(vec![], shared_secrets, vec![]))
|
||||||
shared_secrets,
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -848,8 +836,8 @@ fn handle_prd(
|
|||||||
// We send the whole data in a pcd
|
// We send the whole data in a pcd
|
||||||
debug!("Received confirm prd {:#?}", prd);
|
debug!("Received confirm prd {:#?}", prd);
|
||||||
let original_request = relevant_process
|
let original_request = relevant_process
|
||||||
.impending_requests
|
.get_impending_requests()
|
||||||
.iter()
|
.into_iter()
|
||||||
.find(|r| {
|
.find(|r| {
|
||||||
if r.prd_type != PrdType::Update {
|
if r.prd_type != PrdType::Update {
|
||||||
return false;
|
return false;
|
||||||
@ -859,27 +847,25 @@ fn handle_prd(
|
|||||||
})
|
})
|
||||||
.ok_or(anyhow::Error::msg("Original request not found"))?;
|
.ok_or(anyhow::Error::msg("Original request not found"))?;
|
||||||
let shared_secret = relevant_process
|
let shared_secret = relevant_process
|
||||||
.shared_secrets
|
.get_shared_secret_for_address(&sp_address)
|
||||||
.get(&sp_address.to_string())
|
|
||||||
.ok_or(anyhow::Error::msg(
|
.ok_or(anyhow::Error::msg(
|
||||||
"Missing shared secret for address in original request",
|
"Missing shared secret for address in original request",
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
return send_data(original_request, shared_secret);
|
return send_data(original_request, &shared_secret);
|
||||||
}
|
}
|
||||||
PrdType::Update | PrdType::TxProposal | PrdType::Message => {
|
PrdType::Update | PrdType::TxProposal | PrdType::Message => {
|
||||||
// Those all have some new data we don't know about yet
|
// Those all have some new data we don't know about yet
|
||||||
// We send a Confirm to get the pcd
|
// We send a Confirm to get the pcd
|
||||||
// Add the prd to our list of actions for this process
|
// Add the prd to our list of actions for this process
|
||||||
relevant_process.impending_requests.push(prd.clone());
|
relevant_process.insert_impending_request(prd.clone());
|
||||||
let shared_secret = relevant_process
|
let shared_secret = relevant_process
|
||||||
.shared_secrets
|
.get_shared_secret_for_address(&sp_address)
|
||||||
.get(&sp_address.to_string())
|
|
||||||
.ok_or(anyhow::Error::msg(
|
.ok_or(anyhow::Error::msg(
|
||||||
"Missing shared secret for address in original request",
|
"Missing shared secret for address in original request",
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
let cipher = confirm_prd(prd, shared_secret)?;
|
let cipher = confirm_prd(prd, &shared_secret)?;
|
||||||
|
|
||||||
return Ok(ApiReturn {
|
return Ok(ApiReturn {
|
||||||
ciphers_to_send: vec![cipher],
|
ciphers_to_send: vec![cipher],
|
||||||
@ -890,8 +876,8 @@ fn handle_prd(
|
|||||||
PrdType::Response => {
|
PrdType::Response => {
|
||||||
// We must know of a prd update that the response answers to
|
// We must know of a prd update that the response answers to
|
||||||
let original_request = relevant_process
|
let original_request = relevant_process
|
||||||
.impending_requests
|
.get_impending_requests()
|
||||||
.iter()
|
.into_iter()
|
||||||
.find(|r| {
|
.find(|r| {
|
||||||
if r.prd_type != PrdType::Update {
|
if r.prd_type != PrdType::Update {
|
||||||
return false;
|
return false;
|
||||||
@ -919,8 +905,8 @@ fn handle_pcd(plain: Vec<u8>, root_commitment: OutPoint) -> AnyhowResult<ApiRetu
|
|||||||
|
|
||||||
// We match the pcd with a prd and act accordingly
|
// We match the pcd with a prd and act accordingly
|
||||||
let prd = relevant_process
|
let prd = relevant_process
|
||||||
.impending_requests
|
.get_impending_requests_mut()
|
||||||
.iter_mut()
|
.into_iter()
|
||||||
.find(|r| *r.payload == pcd_commitment.to_string())
|
.find(|r| *r.payload == pcd_commitment.to_string())
|
||||||
.ok_or(AnyhowError::msg("Failed to retrieve the matching prd"))?;
|
.ok_or(AnyhowError::msg("Failed to retrieve the matching prd"))?;
|
||||||
|
|
||||||
@ -1023,7 +1009,7 @@ fn handle_decrypted_message(
|
|||||||
|
|
||||||
// let mut processes = lock_processes()?;
|
// let mut processes = lock_processes()?;
|
||||||
|
|
||||||
// let updated_process: RelevantProcess;
|
// let updated_process: Process;
|
||||||
// if let Some(process) = processes.get_mut(&root_outpoint) {
|
// if let Some(process) = processes.get_mut(&root_outpoint) {
|
||||||
// // we're actually replacing the shared_secret for that process and that sender if it exists
|
// // we're actually replacing the shared_secret for that process and that sender if it exists
|
||||||
// process.shared_secrets.insert(
|
// process.shared_secrets.insert(
|
||||||
@ -1037,7 +1023,7 @@ fn handle_decrypted_message(
|
|||||||
// actual_sender,
|
// actual_sender,
|
||||||
// Vec::from_hex(shared_secret)?.to_lower_hex_string(),
|
// Vec::from_hex(shared_secret)?.to_lower_hex_string(),
|
||||||
// );
|
// );
|
||||||
// let new_process = RelevantProcess {
|
// let new_process = Process {
|
||||||
// shared_secrets,
|
// shared_secrets,
|
||||||
// ..Default::default()
|
// ..Default::default()
|
||||||
// };
|
// };
|
||||||
@ -1181,14 +1167,14 @@ pub fn create_update_transaction(
|
|||||||
let mut processes = lock_processes()?;
|
let mut processes = lock_processes()?;
|
||||||
|
|
||||||
let commitment_outpoint: OutPoint;
|
let commitment_outpoint: OutPoint;
|
||||||
let relevant_process: &mut RelevantProcess;
|
let relevant_process: &mut Process;
|
||||||
if let Some(s) = init_commitment {
|
if let Some(s) = init_commitment {
|
||||||
// We're updating an existing contract
|
// We're updating an existing contract
|
||||||
let outpoint = OutPoint::from_str(&s)?;
|
let outpoint = OutPoint::from_str(&s)?;
|
||||||
|
|
||||||
if let Some(p) = processes.get_mut(&outpoint) {
|
if let Some(p) = processes.get_mut(&outpoint) {
|
||||||
// compare the provided new_state with the process defined template
|
// compare the provided new_state with the process defined template
|
||||||
let previous_state = &p.states.first().unwrap().encrypted_pcd;
|
let previous_state = &p.get_status_at(0).unwrap().encrypted_pcd;
|
||||||
if !compare_maps(previous_state.as_object().unwrap(), pcd_map) {
|
if !compare_maps(previous_state.as_object().unwrap(), pcd_map) {
|
||||||
return Err(ApiError::new(
|
return Err(ApiError::new(
|
||||||
"Provided updated state is not consistent with the process template".to_owned(),
|
"Provided updated state is not consistent with the process template".to_owned(),
|
||||||
@ -1198,7 +1184,7 @@ pub fn create_update_transaction(
|
|||||||
commitment_outpoint = outpoint;
|
commitment_outpoint = outpoint;
|
||||||
} else {
|
} else {
|
||||||
// This is a process we don't know about, so we insert a new entry
|
// This is a process we don't know about, so we insert a new entry
|
||||||
processes.insert(outpoint, RelevantProcess::default());
|
processes.insert(outpoint, Process::default());
|
||||||
relevant_process = processes.get_mut(&outpoint).unwrap();
|
relevant_process = processes.get_mut(&outpoint).unwrap();
|
||||||
commitment_outpoint = outpoint;
|
commitment_outpoint = outpoint;
|
||||||
}
|
}
|
||||||
@ -1210,7 +1196,7 @@ pub fn create_update_transaction(
|
|||||||
|
|
||||||
let dummy_outpoint = OutPoint::new(Txid::from_slice(dummy.as_byte_array())?, u32::MAX);
|
let dummy_outpoint = OutPoint::new(Txid::from_slice(dummy.as_byte_array())?, u32::MAX);
|
||||||
|
|
||||||
processes.insert(dummy_outpoint, RelevantProcess::default());
|
processes.insert(dummy_outpoint, Process::default());
|
||||||
|
|
||||||
relevant_process = processes.get_mut(&dummy_outpoint).unwrap();
|
relevant_process = processes.get_mut(&dummy_outpoint).unwrap();
|
||||||
commitment_outpoint = dummy_outpoint;
|
commitment_outpoint = dummy_outpoint;
|
||||||
@ -1305,7 +1291,6 @@ pub fn create_update_transaction(
|
|||||||
let final_tx = signed_psbt.extract_tx()?;
|
let final_tx = signed_psbt.extract_tx()?;
|
||||||
|
|
||||||
let mut ciphers = vec![];
|
let mut ciphers = vec![];
|
||||||
let mut shared_secrets = HashMap::new();
|
|
||||||
for (member, visible_fields) in all_members {
|
for (member, visible_fields) in all_members {
|
||||||
let mut prd = full_prd.clone();
|
let mut prd = full_prd.clone();
|
||||||
prd.filter_keys(visible_fields);
|
prd.filter_keys(visible_fields);
|
||||||
@ -1323,18 +1308,15 @@ pub fn create_update_transaction(
|
|||||||
&partial_secret,
|
&partial_secret,
|
||||||
);
|
);
|
||||||
|
|
||||||
let shared_secret = AnkSharedSecret::new(shared_point)
|
let shared_secret = AnkSharedSecretHash::from_shared_point(shared_point);
|
||||||
.to_byte_array()
|
|
||||||
.to_lower_hex_string();
|
|
||||||
|
|
||||||
let cipher = encrypt_with_key(prd_msg.clone(), shared_secret.clone())?;
|
let cipher = encrypt_with_key(shared_secret.as_byte_array(), prd_msg.as_bytes())?;
|
||||||
ciphers.push(cipher);
|
ciphers.push(cipher.to_lower_hex_string());
|
||||||
shared_secrets.insert(sp_address, shared_secret);
|
relevant_process.insert_shared_secret(SilentPaymentAddress::try_from(sp_address)?, shared_secret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
relevant_process.impending_requests.push(full_prd);
|
relevant_process.insert_impending_request(full_prd);
|
||||||
relevant_process.shared_secrets.extend(shared_secrets);
|
relevant_process.insert_state(ProcessState {
|
||||||
relevant_process.states.push(ProcessState {
|
|
||||||
commited_in: OutPoint::null(),
|
commited_in: OutPoint::null(),
|
||||||
encrypted_pcd: Value::Object(fields2cipher),
|
encrypted_pcd: Value::Object(fields2cipher),
|
||||||
keys: fields2keys,
|
keys: fields2keys,
|
||||||
@ -1357,64 +1339,6 @@ pub struct encryptWithNewKeyResult {
|
|||||||
pub key: String,
|
pub key: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub fn encrypt_with_key(plaintext: String, key: String) -> ApiResult<String> {
|
|
||||||
let nonce = Aes256Gcm::generate_nonce(&mut rand::thread_rng());
|
|
||||||
|
|
||||||
let mut aes_key = [0u8; 32];
|
|
||||||
aes_key.copy_from_slice(&Vec::from_hex(&key)?);
|
|
||||||
|
|
||||||
// encrypt
|
|
||||||
let aes_enc = Aes256Encryption::import_key(
|
|
||||||
Purpose::Arbitrary,
|
|
||||||
plaintext.into_bytes(),
|
|
||||||
aes_key,
|
|
||||||
nonce.into(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let cipher = aes_enc.encrypt_with_aes_key()?;
|
|
||||||
|
|
||||||
Ok(cipher.to_lower_hex_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub fn encrypt_with_new_key(plaintext: String) -> ApiResult<encryptWithNewKeyResult> {
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
|
|
||||||
// generate new key
|
|
||||||
let aes_key = Aes256Gcm::generate_key(&mut rng);
|
|
||||||
let nonce = Aes256Gcm::generate_nonce(&mut rng);
|
|
||||||
|
|
||||||
// encrypt
|
|
||||||
let aes_enc = Aes256Encryption::import_key(
|
|
||||||
Purpose::Arbitrary,
|
|
||||||
plaintext.into_bytes(),
|
|
||||||
aes_key.into(),
|
|
||||||
nonce.into(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let cipher = aes_enc.encrypt_with_aes_key()?;
|
|
||||||
|
|
||||||
Ok(encryptWithNewKeyResult {
|
|
||||||
cipher: cipher.to_lower_hex_string(),
|
|
||||||
key: aes_key.to_lower_hex_string(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub fn try_decrypt_with_key(cipher: String, key: String) -> ApiResult<String> {
|
|
||||||
let key_bin = Vec::from_hex(&key)?;
|
|
||||||
if key_bin.len() != 32 {
|
|
||||||
return Err(ApiError::new("key of invalid lenght".to_owned()));
|
|
||||||
}
|
|
||||||
let mut aes_key = [0u8; 32];
|
|
||||||
aes_key.copy_from_slice(&Vec::from_hex(&key)?);
|
|
||||||
let aes_dec = Aes256Decryption::new(Purpose::Arbitrary, Vec::from_hex(&cipher)?, aes_key)?;
|
|
||||||
|
|
||||||
let plain = String::from_utf8(aes_dec.decrypt_with_key()?)?;
|
|
||||||
Ok(plain)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn create_faucet_msg() -> ApiResult<String> {
|
pub fn create_faucet_msg() -> ApiResult<String> {
|
||||||
let sp_address = lock_local_device()?
|
let sp_address = lock_local_device()?
|
||||||
@ -1442,8 +1366,8 @@ pub fn get_update_proposals(process_outpoint: String) -> ApiResult<Vec<String>>
|
|||||||
.ok_or(ApiError::new("process not found".to_owned()))?;
|
.ok_or(ApiError::new("process not found".to_owned()))?;
|
||||||
|
|
||||||
let update_proposals: Vec<&Prd> = relevant_process
|
let update_proposals: Vec<&Prd> = relevant_process
|
||||||
.impending_requests
|
.get_impending_requests()
|
||||||
.iter()
|
.into_iter()
|
||||||
.filter(|r| r.prd_type == PrdType::Update)
|
.filter(|r| r.prd_type == PrdType::Update)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
51
src/lib.rs
51
src/lib.rs
@ -1,21 +1,8 @@
|
|||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use sdk_common::crypto::AnkSharedSecret;
|
|
||||||
use sdk_common::network::CachedMessage;
|
use sdk_common::network::CachedMessage;
|
||||||
use sdk_common::pcd::AnkPcdHash;
|
|
||||||
use sdk_common::prd::Prd;
|
|
||||||
use sdk_common::process::Process;
|
|
||||||
use sdk_common::signature::Proof;
|
|
||||||
use sdk_common::sp_client::bitcoin::OutPoint;
|
|
||||||
use sdk_common::uuid::Uuid;
|
|
||||||
use sdk_common::MutexExt;
|
use sdk_common::MutexExt;
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use serde_json::{Map, Value};
|
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
use std::fmt::Debug;
|
|
||||||
use std::ops::Index;
|
|
||||||
use std::sync::{Mutex, MutexGuard, OnceLock};
|
use std::sync::{Mutex, MutexGuard, OnceLock};
|
||||||
use tsify::Tsify;
|
|
||||||
|
|
||||||
pub mod api;
|
pub mod api;
|
||||||
mod peers;
|
mod peers;
|
||||||
@ -29,41 +16,3 @@ pub fn lock_messages() -> Result<MutexGuard<'static, Vec<CachedMessage>>, Error>
|
|||||||
.get_or_init(|| Mutex::new(vec![]))
|
.get_or_init(|| Mutex::new(vec![]))
|
||||||
.lock_anyhow()
|
.lock_anyhow()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO move to sdk-common
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct ProcessState {
|
|
||||||
pub commited_in: OutPoint,
|
|
||||||
pub encrypted_pcd: Value,
|
|
||||||
pub keys: Map<String, Value>, // We may not always have all the keys
|
|
||||||
pub validation_token: Vec<Proof>, // This signs the encrypted pcd
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct RelevantProcess {
|
|
||||||
states: Vec<ProcessState>,
|
|
||||||
shared_secrets: HashMap<String, String>,
|
|
||||||
impending_requests: Vec<Prd>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RelevantProcess {
|
|
||||||
pub fn get_status_at(&self, index: usize) -> Option<ProcessState> {
|
|
||||||
self.states.get(index).cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_latest_state(&self) -> Option<ProcessState> {
|
|
||||||
self.states.last().cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_impending_requests(&self) -> Vec<Prd> {
|
|
||||||
self.impending_requests.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub static CACHEDPROCESSES: OnceLock<Mutex<HashMap<OutPoint, RelevantProcess>>> = OnceLock::new();
|
|
||||||
|
|
||||||
pub fn lock_processes() -> Result<MutexGuard<'static, HashMap<OutPoint, RelevantProcess>>, Error> {
|
|
||||||
CACHEDPROCESSES
|
|
||||||
.get_or_init(|| Mutex::new(HashMap::new()))
|
|
||||||
.lock_anyhow()
|
|
||||||
}
|
|
||||||
|
@ -9,7 +9,6 @@ use sdk_common::sp_client::bitcoin::{
|
|||||||
Network, OutPoint, ScriptBuf, Transaction, Txid, XOnlyPublicKey,
|
Network, OutPoint, ScriptBuf, Transaction, Txid, XOnlyPublicKey,
|
||||||
};
|
};
|
||||||
use sdk_common::sp_client::spclient::SpClient;
|
use sdk_common::sp_client::spclient::SpClient;
|
||||||
use sdk_common::uuid::Uuid;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use tsify::Tsify;
|
use tsify::Tsify;
|
||||||
@ -31,9 +30,7 @@ use sdk_common::sp_client::spclient::{OutputList, SpWallet, SpendKey};
|
|||||||
use crate::peers::Peer;
|
use crate::peers::Peer;
|
||||||
use crate::wallet::generate_sp_wallet;
|
use crate::wallet::generate_sp_wallet;
|
||||||
use crate::MutexExt;
|
use crate::MutexExt;
|
||||||
use sdk_common::crypto::{
|
use sdk_common::crypto::{AeadCore, Aes256Gcm, KeyInit};
|
||||||
AeadCore, Aes256Decryption, Aes256Encryption, Aes256Gcm, HalfKey, KeyInit, Purpose,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub static LOCAL_DEVICE: OnceLock<Mutex<Device>> = OnceLock::new();
|
pub static LOCAL_DEVICE: OnceLock<Mutex<Device>> = OnceLock::new();
|
||||||
|
|
||||||
|
@ -57,12 +57,12 @@ fn test_pairing() {
|
|||||||
"validation_rules":
|
"validation_rules":
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"quorum": 0.0,
|
"quorum": 1.0,
|
||||||
"fields": [
|
"fields": [
|
||||||
"roles",
|
"roles",
|
||||||
"pairing_tx"
|
"pairing_tx"
|
||||||
],
|
],
|
||||||
"min_sig_member": 0.0
|
"min_sig_member": 1.0
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -114,7 +114,6 @@ fn test_pairing() {
|
|||||||
// TODO unpair device
|
// TODO unpair device
|
||||||
|
|
||||||
// We can produce the prd response now even if we can't use it yet
|
// We can produce the prd response now even if we can't use it yet
|
||||||
// TODO pass the process as argument
|
|
||||||
let alice_prd_response = response_prd(
|
let alice_prd_response = response_prd(
|
||||||
root_outpoint,
|
root_outpoint,
|
||||||
alice_init_process
|
alice_init_process
|
||||||
@ -130,6 +129,8 @@ fn test_pairing() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
|
// We can also create the first login transaction and sign it
|
||||||
|
|
||||||
// this is only for testing, as we're playing both parts
|
// this is only for testing, as we're playing both parts
|
||||||
let alice_device = dump_device().unwrap();
|
let alice_device = dump_device().unwrap();
|
||||||
let alice_processes = dump_process_cache().unwrap();
|
let alice_processes = dump_process_cache().unwrap();
|
||||||
@ -263,6 +264,15 @@ fn test_pairing() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// To make the pairing effective, alice and bob must now creates a new transaction where they both control one output
|
// To make the pairing effective, alice and bob must now creates a new transaction where they both control one output
|
||||||
|
|
||||||
|
// login logic: user must have access to both devices to login
|
||||||
|
// user must still have access to both devices in case an action needs both devices (as defined in the roles)
|
||||||
|
// process can define that acting on some fields of the state only needs a fraction of the devices to sign
|
||||||
|
|
||||||
|
// Problem: we need both devices to sign the next login transaction.
|
||||||
|
// Simplest solution: device A creates the transaction with both inputs and outputs, signs its input and sends to device B
|
||||||
|
// device B notify user that a login is underway, user either accepts (sign the transaction and broadcast), or refuses (actually we should think of some revokation step from here)
|
||||||
|
|
||||||
// login();
|
// login();
|
||||||
|
|
||||||
// Once we know this tx id, we can commit to the relay
|
// Once we know this tx id, we can commit to the relay
|
||||||
|
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user