From 76dd12aaac9ac9d83a6ce870d138fb46f26cece3 Mon Sep 17 00:00:00 2001 From: Sosthene00 <674694@protonmail.ch> Date: Wed, 17 Apr 2024 08:27:16 +0200 Subject: [PATCH] Add network --- Cargo.toml | 2 + src/lib.rs | 1 + src/network.rs | 248 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 251 insertions(+) create mode 100644 src/network.rs diff --git a/Cargo.toml b/Cargo.toml index 1737a6a..6128ce2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,5 @@ sp_backend = { git = "https://github.com/Sosthene00/sp-backend.git", branch = "s uuid = { version = "1.6.1", features = ["serde", "v4"] } aes-gcm = "0.10.3" rand = "0.8.5" +tsify = { git = "https://github.com/Sosthene00/tsify", branch = "next" } +wasm-bindgen = "0.2.91" diff --git a/src/lib.rs b/src/lib.rs index 274f0ed..a688c6e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,2 @@ pub mod crypto; +pub mod network; diff --git a/src/network.rs b/src/network.rs new file mode 100644 index 0000000..274ab04 --- /dev/null +++ b/src/network.rs @@ -0,0 +1,248 @@ +use std::str::FromStr; + +use anyhow::{Error, Result}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use sp_backend::bitcoin::key::constants::ZERO; +use sp_backend::bitcoin::{consensus::deserialize, hashes, secp256k1::PublicKey, Transaction}; +use sp_backend::bitcoin::{OutPoint, Txid}; +use sp_backend::silentpayments::bitcoin_hashes::{sha256t_hash_newtype, Hash, HashEngine}; +use tsify::Tsify; + +use crate::crypto::CipherText; + +const RAWTXTOPIC: &'static str = "rawtx"; +const RAWBLOCKTOPIC: &'static str = "rawblock"; +const ANKMAGIC: [u8; 4] = [0x34, 0x6E, 0x6B, 0x30]; + +#[derive(Debug, Serialize, Deserialize)] +pub enum BitcoinTopic { + RawTx, + RawBlock, +} + +impl BitcoinTopic { + pub fn as_str(&self) -> &str { + match self { + Self::RawTx => RAWTXTOPIC, + Self::RawBlock => RAWBLOCKTOPIC, + } + } +} + +#[derive(Debug, Serialize, Deserialize, Tsify)] +#[tsify(from_wasm_abi, into_wasm_abi)] +pub struct BitcoinNetworkMsg<'a> { + pub topic: BitcoinTopic, + pub data: &'a [u8], + pub sequence: &'a [u8], + pub addon: &'a [u8], +} + +impl<'a> BitcoinNetworkMsg<'a> { + pub fn new(raw_msg: &'a [u8]) -> Result { + let topic: BitcoinTopic; + let data: &[u8]; + let sequence: &[u8]; + let addon: &[u8]; + let addon_len: usize; + let raw_msg_len = raw_msg.len(); + + if raw_msg.starts_with(RAWTXTOPIC.as_bytes()) { + topic = BitcoinTopic::RawTx; + addon_len = 33; + } else if raw_msg.starts_with(RAWBLOCKTOPIC.as_bytes()) { + topic = BitcoinTopic::RawBlock; + addon_len = 0; + } else { + return Err(Error::msg("Unknown prefix")); + } + + data = &raw_msg[topic.as_str().as_bytes().len()..raw_msg_len - 4 - addon_len]; + sequence = &raw_msg[raw_msg_len - 4 - addon_len..]; + addon = &raw_msg[raw_msg_len - addon_len..]; + + Ok(Self { + topic, + data, + sequence, + addon, + }) + } +} + +sha256t_hash_newtype! { + pub struct PcdTag = hash_str("4nk/PCD"); + + #[hash_newtype(forward)] + pub struct PcdHash(_); + + pub struct PrdTag = hash_str("4nk/PRD"); + + #[hash_newtype(forward)] + pub struct PrdHash(_); +} + +impl PcdHash { + pub fn from_pcd(pcd: Pcd) -> Result { + let mut eng = PcdHash::engine(); + eng.input(&serde_json::to_string(&pcd)?.into_bytes()); + Ok(PcdHash::from_engine(eng)) + } +} + +impl PrdHash { + pub fn from_prd(prd: Prd) -> Result { + let mut eng = PrdHash::engine(); + eng.input(&serde_json::to_string(&prd)?.into_bytes()); + Ok(PrdHash::from_engine(eng)) + } +} + +type Item = String; // Is either a stringified json or the hex representation of its cipher + +#[derive(Debug, Serialize, Deserialize)] +pub struct Pcd { + name: String, + items: Item, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Prd { + name: String, + seal: Option, + key: Option>, // encrypted key used to decrypt the linked pcd + pcd: PcdHash, +} + +impl Default for Prd { + fn default() -> Self { + Self { + name: "".to_owned(), + seal: None, + key: None, + pcd: PcdHash::from_byte_array(ZERO), + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Envelope { + encrypted_prd: CipherText, +} + +impl Envelope { + pub fn new(encrypted_prd: Vec) -> Result { + Ok(Self { encrypted_prd }) + } +} + +#[derive(Debug, Serialize, Deserialize, Tsify)] +#[tsify(into_wasm_abi, from_wasm_abi)] +pub enum AnkFlag { + NewTx, + Faucet, + Error, + Unknown, +} + +impl From<&str> for AnkFlag { + fn from(value: &str) -> Self { + match value { + "NewTx" => Self::NewTx, + "Faucet" => Self::Faucet, + "Error" => Self::Error, + _ => Self::Unknown + } + } +} + +impl From for AnkFlag { + fn from(value: String) -> Self { + (&value[..]).into() + } +} + +impl AnkFlag { + pub fn new_from_byte(byte: u8) -> Self { + match byte { + 0 => Self::NewTx, + 1 => Self::Faucet, + 2 => Self::Error, + _ => Self::Unknown + } + } + + pub fn as_str(&self) -> &str { + match self { + Self::NewTx => "new_tx", + Self::Faucet => "faucet", + Self::Error => "error", + Self::Unknown => "unknown" + } + } +} + +#[derive(Debug, Serialize, Deserialize, Tsify)] +#[tsify(into_wasm_abi, from_wasm_abi)] +pub struct FaucetMessage { + pub sp_address: String, +} + +impl FaucetMessage { + pub fn new(sp_address: String) -> Self { + Self { + sp_address + } + } +} + +#[derive(Debug, Serialize, Deserialize, Tsify)] +#[tsify(into_wasm_abi, from_wasm_abi)] +pub struct NewTxMessage { + pub transaction: String, + pub tweak_data: Option +} + +impl NewTxMessage { + pub fn new(transaction: String, tweak_data: Option) -> Self { + Self { + transaction, + tweak_data + } + } +} + +#[derive(Debug, Serialize, Deserialize, Tsify)] +#[tsify(into_wasm_abi, from_wasm_abi)] +pub struct AnkNetworkMsg { + pub flag: AnkFlag, + pub content: String, +} + +// impl TryFrom<&str> for AnkNetworkMsg { +// type Error = anyhow::Error; +// fn try_from(value: &str) -> std::prelude::v1::Result { +// let parsed: Value = serde_json::from_str(value)?; +// let flag = parsed +// .get("flag") +// .ok_or(Error::msg("Invalid AnkNetworkMsg"))? +// .as_str() +// .ok_or(Error::msg("Invalid AnkNetworkMsg"))?; +// let content = parsed +// .get("content") +// .ok_or(Error::msg("Invalid AnkNetworkMsg"))? +// .as_str() +// .ok_or(Error::msg("Invalid AnkNetworkMsg"))?; +// Ok(Self { flag: flag.into(), content: content.into() }) +// } +// } + +impl AnkNetworkMsg { + pub fn new(flag: AnkFlag, raw: &str) -> Self { + Self { + flag, + content: raw.into() + } + } +}