Adding helpful utils to simplify Bolt WTPs impl

This commit is contained in:
J. Ayo Akinyele 2019-11-28 03:36:14 -05:00
parent aff41dce68
commit 3881d0c7b2
6 changed files with 286 additions and 6 deletions

View File

@ -22,6 +22,7 @@ serde_bytes = "0.11.2"
time = "*"
secp256k1 = { version = "0.16.0", features = ["rand", "serde"] }
sha2 = { version = "0.8", default-features = false }
hex = "0.4.0"
[lib]
crate-type = ["lib", "cdylib", "staticlib"]

View File

@ -22,7 +22,7 @@ bench:
test:
# runs the unit test suite
cargo +nightly test --release #-- --nocapture
cargo +nightly test --release -- --nocapture
update:
cargo +nightly update

View File

@ -9,6 +9,7 @@ use serde::{Serialize, Deserialize};
use util;
#[derive(Clone, Serialize, Deserialize, Debug)]
#[serde(bound(deserialize = "<E as pairing::Engine>::G1: serde::Deserialize<'de>, <E as pairing::Engine>::G2: serde::Deserialize<'de>"))]
pub struct PublicParams<E: Engine> {
pub g1: E::G1,
pub g2: E::G2,
@ -20,6 +21,17 @@ impl<E: Engine> PartialEq for PublicParams<E> {
}
}
impl<E: Engine> PublicParams<E> {
pub fn from_slice<'de>(ser_g1: &'de [u8], ser_g2: &'de [u8]) -> Self
where <E as pairing::Engine>::G1: serde::Deserialize<'de>,
<E as pairing::Engine>::G2: serde::Deserialize<'de>
{
let g1: E::G1 = serde_json::from_slice(ser_g1).unwrap();
let g2: E::G2 = serde_json::from_slice(ser_g2).unwrap();
return PublicParams { g1, g2 };
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct SecretKey<E: Engine> {
@ -48,6 +60,7 @@ impl<E: Engine> PartialEq for SecretKey<E> {
#[derive(Clone, Serialize, Deserialize, Debug)]
#[serde(bound(deserialize = "<E as pairing::Engine>::G2: serde::Deserialize<'de>"))]
pub struct PublicKey<E: Engine> {
pub X: E::G2,
pub Y: Vec<E::G2>,
@ -72,6 +85,23 @@ impl<E: Engine> PartialEq for PublicKey<E> {
}
}
impl<E: Engine> PublicKey<E> {
pub fn from_slice<'de>(ser_x: &'de [u8], ser_y: &'de [u8], y_len: usize, num_elems: usize) -> Self
where <E as pairing::Engine>::G2: serde::Deserialize<'de>
{
let X: E::G2 = serde_json::from_slice(ser_x).unwrap();
let mut Y: Vec<E::G2> = Vec::new();
let mut start_pos = 0;
let mut end_pos = y_len;
for _ in 0 .. num_elems {
let y = serde_json::from_slice(&ser_y[start_pos .. end_pos]).unwrap();
start_pos = end_pos;
end_pos += y_len;
Y.push(y);
}
return PublicKey { X, Y };
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct BlindPublicKey<E: Engine> {
@ -679,10 +709,10 @@ mod tests {
let blindkeypair = BlindKeyPair::<Bls12>::generate(&mut rng, &mpk, l);
let serialized = serde_json::to_vec(&mpk).unwrap();
//println!("serialized = {:?}", serialized.len());
println!("mpk serialized len = {:?}", serialized.len());
let _mpk_des: PublicParams<Bls12> = serde_json::from_slice(&serialized).unwrap();
//println!("{}", mpk_des);
//println!("{}", _mpk_des);
//println!("SK => {}", &keypair.secret);
let sk_serialized = serde_json::to_vec(&keypair.secret).unwrap();
@ -694,7 +724,7 @@ mod tests {
//println!("PK => {}", &keypair.public);
let pk_serialized = serde_json::to_vec(&keypair.public).unwrap();
//println!("pk_serialized = {:?}", pk_serialized.len());
println!("cl pk_serialized len = {:?}", pk_serialized.len());
let _pk_des: PublicKey<Bls12> = serde_json::from_slice(&pk_serialized).unwrap();
//assert_eq!(pk_des, keypair.public);
@ -716,5 +746,58 @@ mod tests {
assert_eq!(upk_des, unblind_pk);
assert_ne!(upk_des, keypair.public);
}
#[test]
fn test_compact_public_params_deserialize() {
let bin_g1= vec![132, 83, 99, 124, 75, 72, 15, 109, 12, 94, 84, 103, 1, 58, 160, 232, 190, 23, 119, 195, 112, 161, 152, 141, 178, 29, 141, 61, 227, 246, 215, 157, 140, 190, 100, 18, 248, 141, 57, 222, 12, 209, 191, 158, 143, 155, 87, 255];
let bin_g2 = vec![147, 63, 33, 190, 248, 155, 91, 211, 249, 169, 1, 147, 101, 104, 219, 88, 204, 131, 38, 167, 25, 191, 86, 67, 139, 188, 171, 101, 154, 32, 234, 92, 3, 66, 235, 159, 7, 47, 16, 83, 3, 201, 13, 227, 179, 184, 101, 102, 21, 88, 153, 208, 93, 0, 57, 108, 250, 231, 74, 192, 82, 111, 13, 211, 12, 51, 224, 198, 121, 15, 63, 129, 25, 218, 193, 47, 182, 248, 112, 185, 163, 23, 175, 169, 76, 214, 36, 184, 142, 222, 48, 212, 157, 35, 115, 181];
let ser_g1 = util::encode_as_hexstring(&bin_g1);
let ser_g2 = util::encode_as_hexstring(&bin_g2);
let str_g1 = ser_g1.as_bytes();
let str_g2 = ser_g2.as_bytes();
let rec_mpk = PublicParams::<Bls12>::from_slice(&str_g1, &str_g2);
println!("g1: {}", rec_mpk.g1);
println!("g2: {}", rec_mpk.g2);
let rec_g1_str = serde_json::to_string(&rec_mpk.g1).unwrap();
assert_eq!(rec_g1_str, "\"8453637c4b480f6d0c5e5467013aa0e8be1777c370a1988db21d8d3de3f6d79d8cbe6412f88d39de0cd1bf9e8f9b57ff\"");
let rec_g2_str = serde_json::to_string(&rec_mpk.g2).unwrap();
assert_eq!(rec_g2_str, "\"933f21bef89b5bd3f9a901936568db58cc8326a719bf56438bbcab659a20ea5c0342eb9f072f105303c90de3b3b86566155899d05d00396cfae74ac0526f0dd30c33e0c6790f3f8119dac12fb6f870b9a317afa94cd624b88ede30d49d2373b5\"");
}
#[test]
fn test_compact_cl_public_key_deserialize() {
let bin_g2_x = vec![147, 63, 33, 190, 248, 155, 91, 211, 249, 169, 1, 147, 101, 104, 219, 88, 204, 131, 38, 167, 25, 191, 86, 67, 139, 188, 171, 101, 154, 32, 234, 92, 3, 66, 235, 159, 7, 47, 16, 83, 3, 201, 13, 227, 179, 184, 101, 102, 21, 88, 153, 208, 93, 0, 57, 108, 250, 231, 74, 192, 82, 111, 13, 211, 12, 51, 224, 198, 121, 15, 63, 129, 25, 218, 193, 47, 182, 248, 112, 185, 163, 23, 175, 169, 76, 214, 36, 184, 142, 222, 48, 212, 157, 35, 115, 181];
let bin_g2_y1 = vec![143, 76, 112, 7, 35, 99, 254, 7, 255, 225, 69, 13, 99, 32, 92, 186, 234, 175, 230, 0, 202, 144, 1, 216, 187, 248, 152, 76, 229, 74, 156, 94, 4, 16, 132, 119, 157, 172, 231, 164, 207, 88, 41, 6, 234, 78, 73, 58, 19, 104, 236, 127, 5, 231, 248, 150, 53, 197, 85, 194, 110, 93, 1, 73, 24, 96, 149, 133, 109, 194, 16, 190, 244, 184, 254, 192, 52, 21, 205, 109, 18, 83, 189, 175, 208, 147, 74, 32, 181, 126, 224, 136, 250, 126, 224, 186];
let bin_g2_y2 = vec![150, 132, 45, 236, 146, 135, 127, 242, 61, 55, 73, 100, 151, 12, 51, 134, 151, 42, 138, 227, 105, 54, 121, 7, 0, 27, 205, 139, 186, 69, 139, 143, 41, 132, 35, 33, 168, 35, 31, 52, 65, 5, 73, 153, 203, 25, 178, 196, 4, 9, 218, 130, 22, 64, 98, 152, 225, 212, 27, 202, 245, 234, 138, 34, 82, 102, 40, 72, 211, 248, 16, 221, 54, 154, 186, 95, 246, 132, 54, 0, 128, 170, 111, 94, 155, 166, 27, 225, 51, 31, 107, 223, 139, 0, 209, 236];
let ser_g2_x = util::encode_as_hexstring(&bin_g2_x);
let ser_g2_y1 = util::encode_as_hexstring(&bin_g2_y1);
let ser_g2_y2 = util::encode_as_hexstring(&bin_g2_y2);
let str_g2_x = ser_g2_x.as_bytes();
let str_g2_y1 = ser_g2_y1.as_bytes();
let str_g2_y2 = ser_g2_y2.as_bytes();
let mut vec = Vec::new();
vec.extend(str_g2_y1);
vec.extend(str_g2_y2);
let rec_cl_pk = PublicKey::<Bls12>::from_slice(&str_g2_x, &vec.as_slice(), ser_g2_y1.len(), 2);
let rec_x_str = serde_json::to_string(&rec_cl_pk.X).unwrap();
assert_eq!(rec_x_str, "\"933f21bef89b5bd3f9a901936568db58cc8326a719bf56438bbcab659a20ea5c0342eb9f072f105303c90de3b3b86566155899d05d00396cfae74ac0526f0dd30c33e0c6790f3f8119dac12fb6f870b9a317afa94cd624b88ede30d49d2373b5\"");
let rec_y1_str = serde_json::to_string(&rec_cl_pk.Y[0]).unwrap();
assert_eq!(rec_y1_str, "\"8f4c70072363fe07ffe1450d63205cbaeaafe600ca9001d8bbf8984ce54a9c5e041084779dace7a4cf582906ea4e493a1368ec7f05e7f89635c555c26e5d0149186095856dc210bef4b8fec03415cd6d1253bdafd0934a20b57ee088fa7ee0ba\"");
let rec_y2_str = serde_json::to_string(&rec_cl_pk.Y[1]).unwrap();
assert_eq!(rec_y2_str, "\"96842dec92877ff23d374964970c3386972a8ae369367907001bcd8bba458b8f29842321a8231f3441054999cb19b2c40409da8216406298e1d41bcaf5ea8a2252662848d3f810dd369aba5ff684360080aa6f5e9ba61be1331f6bdf8b00d1ec\"");
}
}

View File

@ -31,9 +31,11 @@ extern crate serde;
extern crate serde_with;
extern crate libc;
extern crate hex;
#[cfg(test)]
extern crate core;
extern crate serde_json;
pub mod cl;
pub mod ccs08;
@ -503,6 +505,102 @@ pub mod bidirectional {
}
}
pub mod wtp_utils {
// Useful routines that simplify the Bolt WTP implementation for Zcash
use pairing::bls12_381::Bls12;
use ::{util, BoltResult};
use cl::{PublicKey, PublicParams};
use ped92::CSMultiParams;
pub use channels::ChannelToken;
pub use wallet::Wallet;
const BLS12_381_CHANNEL_TOKEN_LEN: usize = 1074;
const BLS12_381_G1_LEN: usize = 48;
const BLS12_381_G2_LEN: usize = 96;
const SECP256K1_PK_LEN: usize = 33;
pub fn reconstruct_secp_public_key(pk_bytes: &[u8; SECP256K1_PK_LEN]) -> secp256k1::PublicKey {
return secp256k1::PublicKey::from_slice(pk_bytes).unwrap();
}
pub fn reconstruct_wallet_bls12(channel_token: &ChannelToken<Bls12>, wpk: &secp256k1::PublicKey, cust_bal: u32, merch_bal: u32) -> Wallet<Bls12> {
let channelId = channel_token.compute_channel_id();
let wpk_h = util::hash_pubkey_to_fr::<Bls12>(&wpk);
return Wallet {
channelId, wpk: wpk_h, bc: cust_bal as i64, bm: merch_bal as i64, close: None
}
}
pub fn reconstruct_channel_token_bls12(channel_token: &Vec<u8>) -> BoltResult<ChannelToken<Bls12>>
{
// parse pkc, pkm, pkM, mpk and comParams
if channel_token.len() != BLS12_381_CHANNEL_TOKEN_LEN {
return Err(String::from("could not reconstruct the channel token!"));
}
let num_y_elems = 5;
let num_com_params= 6;
let mut cur_index = 0;
let mut end_index = SECP256K1_PK_LEN;
let pkc = secp256k1::PublicKey::from_slice(&channel_token[cur_index .. end_index]).unwrap();
cur_index = end_index;
end_index += SECP256K1_PK_LEN;
let pkm = secp256k1::PublicKey::from_slice(&channel_token[cur_index .. end_index]).unwrap();
cur_index = end_index;
end_index += BLS12_381_G2_LEN; // pk_M => (X, Y)
let ser_cl_x = channel_token[cur_index .. end_index].to_vec();
let str_cl_x = util::encode_as_hexstring(&ser_cl_x);
let X = str_cl_x.as_bytes();
let mut Y = Vec::new();
for _ in 0 .. num_y_elems {
cur_index = end_index;
end_index += BLS12_381_G2_LEN;
let cl_y = channel_token[cur_index .. end_index].to_vec();
let ser_cl_y = util::encode_as_hexstring(&cl_y);
let str_cl_y = ser_cl_y.as_bytes();
Y.extend(str_cl_y);
}
let cl_pk= PublicKey::<Bls12>::from_slice(&X, &Y.as_slice(), str_cl_x.len(), num_y_elems);
cur_index = end_index;
end_index += BLS12_381_G1_LEN;
let g1 = channel_token[cur_index .. end_index].to_vec();
let ser_mpk_g1 = util::encode_as_hexstring(&g1);
cur_index = end_index;
end_index += BLS12_381_G2_LEN;
let g2 = channel_token[cur_index .. end_index].to_vec();
let ser_mpk_g2 = util::encode_as_hexstring(&g2);
let ser_g1 = ser_mpk_g1.as_bytes();
let ser_g2 = ser_mpk_g2.as_bytes();
let mpk = PublicParams::<Bls12>::from_slice(&ser_g1, &ser_g2);
let mut comparams = Vec::new();
for _ in 0 .. num_com_params {
cur_index = end_index;
end_index += BLS12_381_G1_LEN;
let com = channel_token[cur_index .. end_index].to_vec();
let ser_com = util::encode_as_hexstring(&com);
let str_com = ser_com.as_bytes();
comparams.extend(str_com);
}
let com_params = CSMultiParams::<Bls12>::from_slice(&comparams.as_slice(), ser_mpk_g1.len(), num_com_params);
Ok(Some(ChannelToken {
pk_c: Some(pkc), pk_m: pkm, cl_pk_m: cl_pk, mpk: mpk, comParams: com_params
}))
}
}
#[cfg(all(test, feature = "unstable"))]
mod benches {
use rand::{Rng, thread_rng};
@ -895,4 +993,44 @@ mod tests {
let _des_cw: bidirectional::CustomerState<Bls12> = serde_json::from_str(&serialized_cw).unwrap();
}
#[test]
fn test_reconstruct_channel_token() {
let _ser_channel_token = "024c252c7e36d0c30ae7c67dabea2168f41b36b85c14d3e180b423fa1a5df0e7ac027df0457901953b9b776f4999d5a1e78\
049c0afa4f741d0d3bb7d9711a0f8c0038f4c70072363fe07ffe1450d63205cbaeaafe600ca9001d8bbf8984ce54a9c5e041084779dace7a4cf582906ea4e\
493a1368ec7f05e7f89635c555c26e5d0149186095856dc210bef4b8fec03415cd6d1253bdafd0934a20b57ee088fa7ee0bab0668b1aa84c30e856dd685ce\
e2a95844cb68504e82fd9dd874cbf6f7ee58155245e97c52625b53f4ca969f48b33c59f0009adc70d1472a303a35ace0d96149c8cdb96f29b6f476b8f4a10\
bd430c4658d4e0b5873fcb946a76aa861c6c4c601ab8fb0b9c88d2e8861de2f0dae2bb2a8492db2978ce8f2e509328efbf12384ae2db5c17021d222724a3b\
c4b621bf4f32601d555ff2cfc2171adeb2f1bd42c484c1c0a1e5d7d2853c102080680cefc925808b6e3d71b29a93f7e8f5c2eeeeef944b3740feddb24ec2c\
17e3db22ee6a7af77e32a9d186bdcc150dd59b0cd92b92b6656cb588dec9d1d07be5e2a319bf37f1120b7c656f78dc6c4064f8d63f590f70cdc0c1746fde6\
035eeb9aa90b69ea666ad71b27078ab61573aec60bab80a4e6a8e4d8ce02204f5b7e0131bf24d5df1428e9e571891c6feb1c0a52ba789136b244f13f510c4\
f1f0eb4b0a7e675f105f8102c672461da340ebcae1eddd49a009bcf3b199eb2006fab6cf0ccf102b5c6dd45722dc0c27d4b9697f627f1bcbe44f6d96842de\
c92877ff23d374964970c3386972a8ae369367907001bcd8bba458b8f29842321a8231f3441054999cb19b2c40409da8216406298e1d41bcaf5ea8a225266\
2848d3f810dd369aba5ff684360080aa6f5e9ba61be1331f6bdf8b00d1ec8453637c4b480f6d0c5e5467013aa0e8be1777c370a1988db21d8d3de3f6d79d8\
cbe6412f88d39de0cd1bf9e8f9b57ff933f21bef89b5bd3f9a901936568db58cc8326a719bf56438bbcab659a20ea5c0342eb9f072f105303c90de3b3b865\
66155899d05d00396cfae74ac0526f0dd30c33e0c6790f3f8119dac12fb6f870b9a317afa94cd624b88ede30d49d2373b58453637c4b480f6d0c5e5467013\
aa0e8be1777c370a1988db21d8d3de3f6d79d8cbe6412f88d39de0cd1bf9e8f9b57ffa397625c859a63e2c6e42486c4f76f306d484cce151f8614f87506e9\
9c871521dd244bfeb380481aed8df823a507c7a3ad367c1797fc6efa089f929729e7d48bfa9c60860fbb212918bb91d8c6aa523046bdf208c95fa5a0fb86a\
1e46f92e0e5893e136b74d38e106fa990590598932a4e2458034cea22337c6f365bcb5cab59ceea03d7a9f7821ea432e262877ef0128cb73d8733c3961762\
26acb6b3de132c803be39a4e803cbc5a4670cb6169583fa899146fab0227dc2ae167393f96f3b8b31e015af1c305de3a07f52408e9c52495c2458ea05c7a3\
71dc14f3b1d6a646ed7cc0ca9417d8bde6efc1ac300d8e28f";
let ser_channel_token = hex::decode(_ser_channel_token).unwrap();
let option_ct = wtp_utils::reconstruct_channel_token_bls12(&ser_channel_token);
let channel_token = match option_ct {
Ok(n) => n.unwrap(),
Err(e) => panic!("Error reconstructing compact rep of channel token: {}", e)
};
let channelId = channel_token.compute_channel_id();
let original_channelId = "[\"7523dfcf61afce756b79e44c09c5537a8384a43e059d72e3539ffcdda9566c3f\"]";
let computed_channelId = serde_json::to_string(&channelId).unwrap();
println!("channel ID: {}", channelId);
println!("pkc: {:?}", channel_token.pk_c.unwrap());
println!("pkm: {:?}", channel_token.pk_m);
assert_eq!(original_channelId, computed_channelId);
}
}

View File

@ -1,5 +1,5 @@
// ped92.rs
use rand::Rng;
use rand::{Rng, AsByteSliceMut};
use pairing::{Engine, CurveProjective};
use ff::{Rand, Field, PrimeField};
use std::fmt;
@ -40,6 +40,24 @@ impl<E: Engine> PartialEq for CSMultiParams<E> {
}
}
impl<E: Engine> CSMultiParams<E> {
pub fn from_slice<'de>(ser_gs: &'de [u8], g_len: usize, num_elems: usize) -> Self
where <E as pairing::Engine>::G1: serde::Deserialize<'de>
{
let mut pub_bases: Vec<E::G1> = Vec::new();
let mut start_pos = 0;
let mut end_pos = g_len;
for _ in 0 .. num_elems {
let g: E::G1 = serde_json::from_slice(&ser_gs[start_pos .. end_pos]).unwrap();
start_pos = end_pos;
end_pos += g_len;
pub_bases.push(g);
}
return CSMultiParams { pub_bases};
}
}
impl<E: Engine> fmt::Display for CSMultiParams<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@ -369,5 +387,39 @@ mod tests {
assert_eq!(proof.verify_proof(&comParams, &com.c, &challenge, None), true);
}
// add tests for extend/remove commits dynamically
#[test]
fn test_cs_multiparam_serialization() {
let mut vec: Vec<u8> = Vec::new();
let bin_g1= vec![132, 83, 99, 124, 75, 72, 15, 109, 12, 94, 84, 103, 1, 58, 160, 232, 190, 23, 119, 195, 112, 161, 152, 141, 178, 29, 141, 61, 227, 246, 215, 157, 140, 190, 100, 18, 248, 141, 57, 222, 12, 209, 191, 158, 143, 155, 87, 255];
let bin_g2 = vec![140, 16, 244, 244, 135, 28, 18, 94, 46, 64, 233, 195, 218, 147, 238, 170, 46, 164, 50, 92, 234, 117, 61, 158, 64, 226, 153, 38, 127, 168, 49, 125, 177, 183, 74, 164, 138, 128, 168, 84, 137, 67, 21, 179, 124, 88, 194, 239];
let bin_g3 = vec![147, 174, 242, 238, 231, 127, 9, 120, 16, 9, 191, 238, 60, 57, 106, 34, 198, 62, 28, 183, 77, 170, 27, 116, 36, 75, 242, 26, 242, 23, 213, 31, 186, 21, 141, 219, 59, 104, 247, 118, 56, 95, 183, 124, 103, 83, 93, 154];
let ser_g1 = util::encode_as_hexstring(&bin_g1);
let ser_g2 = util::encode_as_hexstring(&bin_g2);
let ser_g3 = util::encode_as_hexstring(&bin_g3);
let str_g1 = ser_g1.as_bytes();
let str_g2 = ser_g2.as_bytes();
let str_g3 = ser_g3.as_bytes();
vec.extend(str_g1);
vec.extend(str_g2);
vec.extend(str_g3);
let rec_csparams = CSMultiParams::<Bls12>::from_slice(&vec.as_slice(), str_g1.len(), 3);
println!("CS params: {:?}", rec_csparams.pub_bases);
let ser_cs = serde_json::to_string(&rec_csparams).unwrap();
println!("Serialized: {:}", ser_cs);
let rec_g1_str = serde_json::to_string(&rec_csparams.pub_bases[0]).unwrap();
assert_eq!(rec_g1_str, "\"8453637c4b480f6d0c5e5467013aa0e8be1777c370a1988db21d8d3de3f6d79d8cbe6412f88d39de0cd1bf9e8f9b57ff\"");
let rec_g2_str = serde_json::to_string(&rec_csparams.pub_bases[1]).unwrap();
assert_eq!(rec_g2_str, "\"8c10f4f4871c125e2e40e9c3da93eeaa2ea4325cea753d9e40e299267fa8317db1b74aa48a80a854894315b37c58c2ef\"");
let rec_g3_str = serde_json::to_string(&rec_csparams.pub_bases[2]).unwrap();
assert_eq!(rec_g3_str, "\"93aef2eee77f09781009bfee3c396a22c63e1cb74daa1b74244bf21af217d51fba158ddb3b68f776385fb77c67535d9a\"");
}
}

View File

@ -24,6 +24,12 @@ pub fn is_vec_g2_equal<E: Engine>(a: &Vec<E::G2>, b: &Vec<E::G2>) -> bool {
.all(|(a, b)| a == b)
}
pub fn encode_as_hexstring(bytes: &Vec<u8>) -> String {
let mut ser_hex = hex::encode(bytes);
ser_hex.insert(0, '"');
ser_hex.push('"');
return ser_hex;
}
pub fn hash_g1_to_fr<E: Engine>(x: &Vec<E::G1>) -> E::Fr {
let mut x_vec: Vec<u8> = Vec::new();