RaptorQ fountain codes
This commit is contained in:
parent
ebfb619125
commit
dc573fc9a2
|
@ -68,6 +68,7 @@ rand_chacha = "0.3.1"
|
|||
blake2b_simd = "1.0.0"
|
||||
chacha20poly1305 = "0.9.0"
|
||||
base64 = "^0.13"
|
||||
raptorq = "1.7.0"
|
||||
|
||||
ledger-apdu = { version = "0.9.0", optional = true }
|
||||
hmac = { version = "0.12.1", optional = true }
|
||||
|
|
10
binding.h
10
binding.h
|
@ -64,11 +64,9 @@ void scan_transparent_accounts(uint32_t gap_limit);
|
|||
|
||||
char *prepare_multi_payment(char *recipients_json, bool use_transparent, uint32_t anchor_offset);
|
||||
|
||||
char *sign(char *tx_filename, int64_t port);
|
||||
char *sign(char *tx, int64_t port);
|
||||
|
||||
char *broadcast(char *tx_filename);
|
||||
|
||||
char *broadcast_txhex(char *txhex);
|
||||
char *broadcast_tx(char *tx_str);
|
||||
|
||||
uint32_t get_activation_date(void);
|
||||
|
||||
|
@ -97,3 +95,7 @@ char *generate_random_enc_key(void);
|
|||
char *get_full_backup(char *key);
|
||||
|
||||
char *restore_full_backup(char *key, char *backup);
|
||||
|
||||
char *split_data(uint32_t id, char *data);
|
||||
|
||||
char *merge_data(char *drop);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::coinconfig::{init_coin, CoinConfig};
|
||||
use crate::{broadcast_tx, ChainError, Tx};
|
||||
use crate::FountainCodes;
|
||||
use crate::{ChainError, Tx};
|
||||
use allo_isolate::{ffi, IntoDart};
|
||||
use android_logger::Config;
|
||||
use lazy_static::lazy_static;
|
||||
|
@ -72,21 +73,6 @@ fn log_string(result: anyhow::Result<String>) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
fn encode_tx_result(res: anyhow::Result<Vec<u8>>) -> Vec<u8> {
|
||||
let mut v = vec![];
|
||||
match res {
|
||||
Ok(raw_tx) => {
|
||||
v.push(0x00);
|
||||
v.extend(raw_tx);
|
||||
}
|
||||
Err(e) => {
|
||||
v.push(0x01);
|
||||
v.extend(e.to_string().as_bytes());
|
||||
}
|
||||
}
|
||||
v
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_error() -> bool {
|
||||
IS_ERROR.load(Ordering::Acquire)
|
||||
|
@ -352,13 +338,10 @@ pub async unsafe extern "C" fn prepare_multi_payment(
|
|||
|
||||
#[tokio::main]
|
||||
#[no_mangle]
|
||||
pub async unsafe extern "C" fn sign(tx_filename: *mut c_char, port: i64) -> *mut c_char {
|
||||
from_c_str!(tx_filename);
|
||||
pub async unsafe extern "C" fn sign(tx: *mut c_char, port: i64) -> *mut c_char {
|
||||
from_c_str!(tx);
|
||||
let res = async {
|
||||
let mut file = std::fs::File::open(&tx_filename.to_string())?;
|
||||
let mut s = String::new();
|
||||
file.read_to_string(&mut s)?;
|
||||
let tx: Tx = serde_json::from_str(&s)?;
|
||||
let tx: Tx = serde_json::from_str(&tx)?;
|
||||
let raw_tx = crate::api::payment::sign_only_multi_payment(
|
||||
&tx,
|
||||
Box::new(move |progress| {
|
||||
|
@ -366,33 +349,19 @@ pub async unsafe extern "C" fn sign(tx_filename: *mut c_char, port: i64) -> *mut
|
|||
}),
|
||||
)
|
||||
.await?;
|
||||
Ok(raw_tx)
|
||||
};
|
||||
let tx_hex = hex::encode(encode_tx_result(res.await));
|
||||
to_c_str(tx_hex)
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
#[no_mangle]
|
||||
pub async unsafe extern "C" fn broadcast(tx_filename: *mut c_char) -> *mut c_char {
|
||||
from_c_str!(tx_filename);
|
||||
let res = async {
|
||||
let mut file = std::fs::File::open(&tx_filename.to_string())?;
|
||||
let mut s = String::new();
|
||||
file.read_to_string(&mut s)?;
|
||||
let tx = hex::decode(s.trim_end())?;
|
||||
broadcast_tx(&tx).await
|
||||
let tx_str = base64::encode(&raw_tx);
|
||||
Ok(tx_str)
|
||||
};
|
||||
to_c_str(log_string(res.await))
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
#[no_mangle]
|
||||
pub async unsafe extern "C" fn broadcast_txhex(txhex: *mut c_char) -> *mut c_char {
|
||||
from_c_str!(txhex);
|
||||
pub async unsafe extern "C" fn broadcast_tx(tx_str: *mut c_char) -> *mut c_char {
|
||||
from_c_str!(tx_str);
|
||||
let res = async {
|
||||
let tx = hex::decode(&txhex.to_string())?;
|
||||
broadcast_tx(&tx).await
|
||||
let tx = base64::decode(&*tx_str)?;
|
||||
crate::broadcast_tx(&tx).await
|
||||
};
|
||||
to_c_str(log_string(res.await))
|
||||
}
|
||||
|
@ -523,3 +492,32 @@ pub unsafe extern "C" fn restore_full_backup(key: *mut c_char, backup: *mut c_ch
|
|||
};
|
||||
to_c_str(log_string(res()))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn split_data(id: u32, data: *mut c_char) -> *mut c_char {
|
||||
from_c_str!(data);
|
||||
let res = || {
|
||||
let res = crate::FountainCodes::encode_into_drops(id, &base64::decode(&*data)?)?;
|
||||
let output = serde_json::to_string(&res)?;
|
||||
Ok(output)
|
||||
};
|
||||
to_c_str(log_string(res()))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn merge_data(drop: *mut c_char) -> *mut c_char {
|
||||
from_c_str!(drop);
|
||||
let res = || {
|
||||
let res = crate::put_drop(&*drop)?
|
||||
.map(|d| base64::encode(&d))
|
||||
.unwrap_or(String::new());
|
||||
Ok::<_, anyhow::Error>(res)
|
||||
};
|
||||
match res() {
|
||||
Ok(str) => to_c_str(str),
|
||||
Err(e) => {
|
||||
log::error!("{}", e);
|
||||
to_c_str(String::new()) // do not return error msg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{connect_lightwalletd, CompactTxStreamerClient, DbAdapter, MemPool};
|
||||
use crate::{connect_lightwalletd, CompactTxStreamerClient, DbAdapter, FountainCodes, MemPool};
|
||||
use anyhow::anyhow;
|
||||
use lazy_static::lazy_static;
|
||||
use lazycell::AtomicLazyCell;
|
||||
|
@ -15,6 +15,7 @@ lazy_static! {
|
|||
Mutex::new(CoinConfig::new(1, CoinType::Ycash)),
|
||||
];
|
||||
pub static ref PROVER: AtomicLazyCell<LocalTxProver> = AtomicLazyCell::new();
|
||||
pub static ref RAPTORQ: Mutex<FountainCodes> = Mutex::new(FountainCodes::new());
|
||||
}
|
||||
|
||||
pub static ACTIVE_COIN: AtomicU8 = AtomicU8::new(0);
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
use crate::coinconfig::RAPTORQ;
|
||||
use blake2b_simd::Params;
|
||||
use byteorder::{ReadBytesExt, WriteBytesExt, LE};
|
||||
use raptorq::{Decoder, Encoder, EncodingPacket, ObjectTransmissionInformation};
|
||||
use serde::Serialize;
|
||||
use std::borrow::BorrowMut;
|
||||
use std::convert::TryInto;
|
||||
use std::io::{Cursor, Write};
|
||||
|
||||
pub const QR_DATA_SIZE: u16 = 256;
|
||||
|
||||
pub struct FountainCodes {
|
||||
id: u32,
|
||||
decoder: Option<Decoder>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct RaptorQDrops {
|
||||
drops: Vec<String>,
|
||||
}
|
||||
|
||||
impl FountainCodes {
|
||||
pub fn new() -> Self {
|
||||
FountainCodes {
|
||||
id: 0,
|
||||
decoder: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encode_into_drops(id: u32, data: &[u8]) -> anyhow::Result<RaptorQDrops> {
|
||||
let total_length = data.len() as u32;
|
||||
let encoder = Encoder::with_defaults(data, QR_DATA_SIZE);
|
||||
let drops: Vec<_> = encoder
|
||||
.get_encoded_packets(1)
|
||||
.iter()
|
||||
.map(|p| {
|
||||
let mut result = vec![];
|
||||
let data = p.serialize();
|
||||
let checksum = Self::get_checksum(&data, id, total_length);
|
||||
result.write_u32::<LE>(id).unwrap();
|
||||
result.write_u32::<LE>(total_length as u32).unwrap();
|
||||
result.write_u32::<LE>(checksum).unwrap();
|
||||
result.write_all(&data).unwrap();
|
||||
base64::encode(&result)
|
||||
})
|
||||
.collect();
|
||||
Ok(RaptorQDrops { drops })
|
||||
}
|
||||
|
||||
pub fn put_drop(&mut self, drop: &str) -> anyhow::Result<Option<Vec<u8>>> {
|
||||
let drop = base64::decode(drop)?;
|
||||
if drop.len() < 12 {
|
||||
anyhow::bail!("Not enough data");
|
||||
}
|
||||
let (header, data) = drop.split_at(12);
|
||||
let mut c = Cursor::new(header);
|
||||
let id = c.read_u32::<LE>()?;
|
||||
let total_length = c.read_u32::<LE>()?;
|
||||
let checksum = c.read_u32::<LE>()?;
|
||||
let checksum2 = Self::get_checksum(data, id, total_length);
|
||||
if checksum != checksum2 {
|
||||
anyhow::bail!("Invalid checksum");
|
||||
}
|
||||
|
||||
if self.id != id {
|
||||
self.id = id;
|
||||
let decoder = Decoder::new(ObjectTransmissionInformation::with_defaults(
|
||||
total_length as u64,
|
||||
QR_DATA_SIZE,
|
||||
));
|
||||
self.decoder = Some(decoder);
|
||||
}
|
||||
|
||||
if let Some(ref mut decoder) = self.decoder {
|
||||
let res = decoder.decode(EncodingPacket::deserialize(data));
|
||||
if res.is_some() {
|
||||
self.id = 0;
|
||||
self.decoder = None;
|
||||
}
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn get_checksum(data: &[u8], id: u32, total_length: u32) -> u32 {
|
||||
let hash = Params::new()
|
||||
.personal(b"QR_CHECKSUM")
|
||||
.hash_length(4)
|
||||
.to_state()
|
||||
.update(&id.to_le_bytes())
|
||||
.update(&total_length.to_le_bytes())
|
||||
.update(data)
|
||||
.finalize();
|
||||
let h = u32::from_le_bytes(hash.as_bytes().try_into().unwrap());
|
||||
h
|
||||
}
|
||||
}
|
||||
|
||||
pub fn put_drop(drop: &str) -> anyhow::Result<Option<Vec<u8>>> {
|
||||
let mut fc = RAPTORQ.lock().unwrap();
|
||||
fc.put_drop(drop)
|
||||
}
|
|
@ -25,6 +25,7 @@ mod coinconfig;
|
|||
mod commitment;
|
||||
mod contact;
|
||||
mod db;
|
||||
mod fountain;
|
||||
mod hash;
|
||||
mod key;
|
||||
mod key2;
|
||||
|
@ -69,6 +70,7 @@ pub use crate::coinconfig::{
|
|||
};
|
||||
pub use crate::commitment::{CTree, Witness};
|
||||
pub use crate::db::{AccountRec, DbAdapter, TxRec};
|
||||
pub use crate::fountain::{put_drop, FountainCodes, RaptorQDrops};
|
||||
pub use crate::hash::pedersen_hash;
|
||||
pub use crate::key::{generate_random_enc_key, KeyHelpers};
|
||||
pub use crate::lw_rpc::compact_tx_streamer_client::CompactTxStreamerClient;
|
||||
|
|
|
@ -11,7 +11,7 @@ use std::collections::HashMap;
|
|||
use thiserror::Error;
|
||||
use warp_api_ffi::api::payment::{Recipient, RecipientMemo};
|
||||
use warp_api_ffi::api::payment_uri::PaymentURI;
|
||||
use warp_api_ffi::{AccountRec, CoinConfig, Tx, TxRec};
|
||||
use warp_api_ffi::{AccountRec, CoinConfig, RaptorQDrops, Tx, TxRec};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
|
@ -78,6 +78,8 @@ async fn main() -> anyhow::Result<()> {
|
|||
new_diversified_address,
|
||||
make_payment_uri,
|
||||
parse_payment_uri,
|
||||
split_data,
|
||||
merge_data,
|
||||
],
|
||||
)
|
||||
.attach(AdHoc::config::<Config>())
|
||||
|
@ -267,6 +269,20 @@ pub fn parse_payment_uri(uri: String) -> Result<Json<PaymentURI>, Error> {
|
|||
Ok(Json(payment))
|
||||
}
|
||||
|
||||
#[get("/split?<id>&<data>")]
|
||||
pub fn split_data(id: u32, data: String) -> Result<Json<RaptorQDrops>, Error> {
|
||||
let result = warp_api_ffi::FountainCodes::encode_into_drops(id, &hex::decode(data).unwrap())?;
|
||||
Ok(Json(result))
|
||||
}
|
||||
|
||||
#[post("/merge?<data>")]
|
||||
pub fn merge_data(data: String) -> Result<String, Error> {
|
||||
let result = warp_api_ffi::put_drop(&data)?
|
||||
.map(|data| hex::encode(&data))
|
||||
.unwrap_or(String::new());
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct Config {
|
||||
|
|
|
@ -305,6 +305,7 @@ impl Tx {
|
|||
let chain = get_coin_chain(self.coin_type);
|
||||
let last_height = BlockHeight::from_u32(self.height as u32);
|
||||
let mut builder = Builder::new(*chain.network(), last_height);
|
||||
let efvk = ExtendedFullViewingKey::from(zsk);
|
||||
|
||||
let ovk = hex_to_hash(&self.ovk)?;
|
||||
builder.send_change_to(
|
||||
|
@ -340,6 +341,9 @@ impl Tx {
|
|||
&txin.fvk,
|
||||
)?
|
||||
.unwrap();
|
||||
if fvk != efvk {
|
||||
anyhow::bail!("Incorrect account - Secret key mismatch")
|
||||
}
|
||||
let pa = fvk.fvk.vk.to_payment_address(diversifier).unwrap();
|
||||
let mut rseed_bytes = [0u8; 32];
|
||||
hex::decode_to_slice(&txin.rseed, &mut rseed_bytes)?;
|
||||
|
|
Loading…
Reference in New Issue