mirror of
https://github.com/mimblewimble/grin-wallet.git
synced 2025-01-20 19:11:09 +03:00
Slatepack Pt. 3 - The Packening (SlatepackAddress implementation) (#413)
* addition of SlatepackAddress type * complete conversion of ed25519 keys to x25519 and isolate conversion within libwallet * refactor packing/unpacking of slates logic into libwallet and out of slate adapters * println
This commit is contained in:
parent
038dafcc25
commit
03cb1097e0
14 changed files with 519 additions and 248 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -1444,6 +1444,7 @@ version = "4.0.0-alpha.1"
|
|||
dependencies = [
|
||||
"chrono",
|
||||
"easy-jsonrpc-mw",
|
||||
"ed25519-dalek",
|
||||
"failure",
|
||||
"failure_derive",
|
||||
"futures 0.3.5",
|
||||
|
@ -1465,7 +1466,6 @@ dependencies = [
|
|||
"tokio",
|
||||
"url 1.7.2",
|
||||
"uuid",
|
||||
"x25519-dalek",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1509,6 +1509,7 @@ version = "4.0.0-alpha.1"
|
|||
dependencies = [
|
||||
"age",
|
||||
"base64 0.9.3",
|
||||
"bech32",
|
||||
"blake2-rfc",
|
||||
"bs58",
|
||||
"byteorder",
|
||||
|
|
|
@ -38,4 +38,4 @@ grin_wallet_libwallet = { path = "../libwallet", version = "4.0.0-alpha.1" }
|
|||
grin_wallet_config = { path = "../config", version = "4.0.0-alpha.1" }
|
||||
|
||||
[dev-dependencies]
|
||||
x25519-dalek = "0.6"
|
||||
ed25519-dalek = "1.0.0-pre.1"
|
||||
|
|
|
@ -22,17 +22,18 @@ use grin_wallet_util::grin_core as core;
|
|||
use grin_wallet_util::OnionV3Address;
|
||||
|
||||
use impls::test_framework::{self, LocalWalletClient};
|
||||
use impls::{
|
||||
PathToSlatepack, PathToSlatepackArmored, SlateGetter as _, SlatePutter as _, SlatepackArgs,
|
||||
};
|
||||
use impls::{PathToSlatepack, SlatePutter as _};
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use grin_wallet_libwallet::{InitTxArgs, IssueInvoiceTxArgs, Slate, Slatepack};
|
||||
use grin_wallet_libwallet::{
|
||||
InitTxArgs, IssueInvoiceTxArgs, Slate, Slatepack, SlatepackAddress, Slatepacker,
|
||||
SlatepackerArgs,
|
||||
};
|
||||
|
||||
use x25519_dalek::PublicKey as xDalekPublicKey;
|
||||
use x25519_dalek::StaticSecret;
|
||||
use ed25519_dalek::PublicKey as edDalekPublicKey;
|
||||
use ed25519_dalek::SecretKey as edDalekSecretKey;
|
||||
|
||||
#[macro_use]
|
||||
mod common;
|
||||
|
@ -43,54 +44,37 @@ fn output_slatepack(
|
|||
file: &str,
|
||||
armored: bool,
|
||||
use_bin: bool,
|
||||
sender: Option<xDalekPublicKey>,
|
||||
recipients: Vec<xDalekPublicKey>,
|
||||
sender: Option<SlatepackAddress>,
|
||||
recipients: Vec<SlatepackAddress>,
|
||||
) -> Result<(), libwallet::Error> {
|
||||
let packer = Slatepacker::new(SlatepackerArgs {
|
||||
sender,
|
||||
recipients,
|
||||
dec_key: None,
|
||||
});
|
||||
let mut file = file.into();
|
||||
if armored {
|
||||
let file = format!("{}.armored", file);
|
||||
let args = SlatepackArgs {
|
||||
pathbuf: file.into(),
|
||||
sender,
|
||||
recipients,
|
||||
dec_key: None,
|
||||
};
|
||||
PathToSlatepackArmored::new(args).put_tx(&slate, use_bin)
|
||||
} else {
|
||||
let args = SlatepackArgs {
|
||||
pathbuf: file.into(),
|
||||
sender,
|
||||
recipients,
|
||||
dec_key: None,
|
||||
};
|
||||
PathToSlatepack::new(args).put_tx(&slate, use_bin)
|
||||
file = format!("{}.armored", file);
|
||||
}
|
||||
PathToSlatepack::new(file.into(), &packer, armored).put_tx(&slate, use_bin)
|
||||
}
|
||||
|
||||
fn slate_from_packed(
|
||||
file: &str,
|
||||
armored: bool,
|
||||
dec_key: Option<&StaticSecret>,
|
||||
dec_key: Option<&edDalekSecretKey>,
|
||||
) -> Result<(Slatepack, Slate), libwallet::Error> {
|
||||
let packer = Slatepacker::new(SlatepackerArgs {
|
||||
sender: None,
|
||||
recipients: vec![],
|
||||
dec_key,
|
||||
});
|
||||
let mut file = file.into();
|
||||
if armored {
|
||||
let file = format!("{}.armored", file);
|
||||
let args = SlatepackArgs {
|
||||
pathbuf: file.into(),
|
||||
sender: None,
|
||||
recipients: vec![],
|
||||
dec_key,
|
||||
};
|
||||
let pts = PathToSlatepackArmored::new(args);
|
||||
Ok((pts.get_slatepack()?, pts.get_tx()?.0))
|
||||
} else {
|
||||
let args = SlatepackArgs {
|
||||
pathbuf: file.into(),
|
||||
sender: None,
|
||||
recipients: vec![],
|
||||
dec_key,
|
||||
};
|
||||
let pts = PathToSlatepack::new(args);
|
||||
Ok((pts.get_slatepack()?, pts.get_tx()?.0))
|
||||
file = format!("{}.armored", file);
|
||||
}
|
||||
let slatepack = PathToSlatepack::new(file.into(), &packer, armored).get_slatepack()?;
|
||||
Ok((slatepack.clone(), packer.get_slate(&slatepack)?))
|
||||
}
|
||||
|
||||
/// self send impl
|
||||
|
@ -165,34 +149,38 @@ fn slatepack_exchange_test_impl(
|
|||
|
||||
let (recipients_1, dec_key_1, sender_1) = match use_encryption {
|
||||
true => {
|
||||
let mut rec_address = xDalekPublicKey::from([0u8; 32]);
|
||||
let mut sec_key = StaticSecret::from([0u8; 32]);
|
||||
let mut rec_address = SlatepackAddress::random();
|
||||
let mut sec_key = edDalekSecretKey::from_bytes(&[0u8; 32]).unwrap();
|
||||
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
|
||||
let ed25519_sec_key = api.get_secret_key(m, 0)?;
|
||||
let mut b = [0u8; 32];
|
||||
b.copy_from_slice(&ed25519_sec_key.as_ref()[0..32]);
|
||||
sec_key = StaticSecret::from(b);
|
||||
rec_address = xDalekPublicKey::from(&sec_key);
|
||||
sec_key = api.get_secret_key(m, 0)?;
|
||||
let pub_key = edDalekPublicKey::from(&sec_key);
|
||||
rec_address = SlatepackAddress::new(&pub_key);
|
||||
Ok(())
|
||||
})?;
|
||||
(vec![rec_address], Some(sec_key), Some(rec_address.clone()))
|
||||
(
|
||||
vec![rec_address.clone()],
|
||||
Some(sec_key),
|
||||
Some(rec_address.clone()),
|
||||
)
|
||||
}
|
||||
false => (vec![], None, None),
|
||||
};
|
||||
|
||||
let (recipients_2, dec_key_2, sender_2) = match use_encryption {
|
||||
true => {
|
||||
let mut rec_address = xDalekPublicKey::from([0u8; 32]);
|
||||
let mut sec_key = StaticSecret::from([0u8; 32]);
|
||||
let mut rec_address = SlatepackAddress::random();
|
||||
let mut sec_key = edDalekSecretKey::from_bytes(&[0u8; 32]).unwrap();
|
||||
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
|
||||
let ed25519_sec_key = api.get_secret_key(m, 0)?;
|
||||
let mut b = [0u8; 32];
|
||||
b.copy_from_slice(&ed25519_sec_key.as_ref()[0..32]);
|
||||
sec_key = StaticSecret::from(b);
|
||||
rec_address = xDalekPublicKey::from(&sec_key);
|
||||
sec_key = api.get_secret_key(m, 0)?;
|
||||
let pub_key = edDalekPublicKey::from(&sec_key);
|
||||
rec_address = SlatepackAddress::new(&pub_key);
|
||||
Ok(())
|
||||
})?;
|
||||
(vec![rec_address], Some(sec_key), Some(rec_address.clone()))
|
||||
(
|
||||
vec![rec_address.clone()],
|
||||
Some(sec_key),
|
||||
Some(rec_address.clone()),
|
||||
)
|
||||
}
|
||||
false => (vec![], None, None),
|
||||
};
|
||||
|
@ -232,7 +220,7 @@ fn slatepack_exchange_test_impl(
|
|||
&send_file,
|
||||
use_armored,
|
||||
use_bin,
|
||||
sender_1,
|
||||
sender_1.clone(),
|
||||
recipients_2.clone(),
|
||||
)?;
|
||||
api.tx_lock_outputs(m, &slate)?;
|
||||
|
@ -257,8 +245,8 @@ fn slatepack_exchange_test_impl(
|
|||
use_armored,
|
||||
use_bin,
|
||||
// re-encrypt for sender!
|
||||
sender_2,
|
||||
match slatepack.sender {
|
||||
sender_2.clone(),
|
||||
match slatepack.sender.clone() {
|
||||
Some(s) => vec![s.clone()],
|
||||
None => vec![],
|
||||
},
|
||||
|
@ -326,7 +314,7 @@ fn slatepack_exchange_test_impl(
|
|||
&send_file,
|
||||
use_armored,
|
||||
use_bin,
|
||||
sender_2,
|
||||
sender_2.clone(),
|
||||
recipients_1.clone(),
|
||||
)?;
|
||||
Ok(())
|
||||
|
@ -352,8 +340,8 @@ fn slatepack_exchange_test_impl(
|
|||
&receive_file,
|
||||
use_armored,
|
||||
use_bin,
|
||||
sender_1,
|
||||
match slatepack.sender {
|
||||
sender_1.clone(),
|
||||
match slatepack.sender.clone() {
|
||||
Some(s) => vec![s.clone()],
|
||||
None => vec![],
|
||||
},
|
||||
|
|
|
@ -20,7 +20,7 @@ mod slatepack;
|
|||
pub use self::file::PathToSlate;
|
||||
pub use self::http::{HttpSlateSender, SchemeNotHttp};
|
||||
pub use self::keybase::{KeybaseAllChannels, KeybaseChannel};
|
||||
pub use self::slatepack::{PathToSlatepack, PathToSlatepackArmored, SlatepackArgs};
|
||||
pub use self::slatepack::PathToSlatepack;
|
||||
|
||||
use crate::config::{TorConfig, WalletConfig};
|
||||
use crate::libwallet::{Error, ErrorKind, Slate};
|
||||
|
|
|
@ -12,90 +12,59 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::convert::TryFrom;
|
||||
/// Slatepack Output 'plugin' implementation
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use x25519_dalek::PublicKey as xDalekPublicKey;
|
||||
use x25519_dalek::StaticSecret;
|
||||
|
||||
use crate::libwallet::{
|
||||
Error, ErrorKind, Slate, SlateVersion, Slatepack, SlatepackArmor, SlatepackBin,
|
||||
VersionedBinSlate, VersionedSlate,
|
||||
};
|
||||
use crate::libwallet::{Error, ErrorKind, Slate, Slatepack, SlatepackBin, Slatepacker};
|
||||
use crate::{SlateGetter, SlatePutter};
|
||||
use grin_wallet_util::byte_ser;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SlatepackArgs<'a> {
|
||||
// And Slate putter impls to output to files
|
||||
pub struct PathToSlatepack<'a> {
|
||||
pub pathbuf: PathBuf,
|
||||
pub sender: Option<xDalekPublicKey>,
|
||||
pub recipients: Vec<xDalekPublicKey>,
|
||||
pub dec_key: Option<&'a StaticSecret>,
|
||||
pub packer: &'a Slatepacker<'a>,
|
||||
pub armor_output: bool,
|
||||
}
|
||||
|
||||
pub struct PathToSlatepack<'a>(SlatepackArgs<'a>);
|
||||
|
||||
impl<'a> PathToSlatepack<'a> {
|
||||
/// Create with pathbuf and recipients
|
||||
pub fn new(args: SlatepackArgs<'a>) -> Self {
|
||||
Self(args)
|
||||
pub fn new(pathbuf: PathBuf, packer: &'a Slatepacker<'a>, armor_output: bool) -> Self {
|
||||
Self {
|
||||
pathbuf,
|
||||
packer,
|
||||
armor_output,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_slatepack_file_contents(&self) -> Result<Vec<u8>, Error> {
|
||||
let mut pub_tx_f = File::open(&self.0.pathbuf)?;
|
||||
let mut pub_tx_f = File::open(&self.pathbuf)?;
|
||||
let mut data = Vec::new();
|
||||
pub_tx_f.read_to_end(&mut data)?;
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
// return slatepack itself
|
||||
pub fn deser_slatepack(&self, data: Vec<u8>) -> Result<Slatepack, Error> {
|
||||
// try as bin first, then as json
|
||||
let bin_res = byte_ser::from_bytes::<SlatepackBin>(&data);
|
||||
match bin_res {
|
||||
Err(e) => debug!("Not a valid binary slatepack: {} - Will try JSON", e),
|
||||
Ok(s) => return Ok(s.0),
|
||||
}
|
||||
// Otherwise try json
|
||||
let content = String::from_utf8(data).map_err(|_| ErrorKind::SlatepackDeser)?;
|
||||
let slatepack: Slatepack = serde_json::from_str(&content).map_err(|e| {
|
||||
error!("Error reading JSON Slatepack: {}", e);
|
||||
ErrorKind::SlatepackDeser
|
||||
})?;
|
||||
slatepack.ver_check_warn();
|
||||
Ok(slatepack)
|
||||
}
|
||||
|
||||
pub fn get_slatepack(&self) -> Result<Slatepack, Error> {
|
||||
let data = self.get_slatepack_file_contents()?;
|
||||
self.deser_slatepack(data)
|
||||
}
|
||||
|
||||
// Create slatepack from slate and args
|
||||
pub fn create_slatepack(&self, slate: &Slate) -> Result<Slatepack, Error> {
|
||||
let out_slate = VersionedSlate::into_version(slate.clone(), SlateVersion::V4)?;
|
||||
let bin_slate =
|
||||
VersionedBinSlate::try_from(out_slate).map_err(|_| ErrorKind::SlatepackSer)?;
|
||||
let mut slatepack = Slatepack::default();
|
||||
slatepack.payload = byte_ser::to_bytes(&bin_slate).map_err(|_| ErrorKind::SlatepackSer)?;
|
||||
slatepack.sender = self.0.sender;
|
||||
slatepack.try_encrypt_payload(self.0.recipients.clone())?;
|
||||
Ok(slatepack)
|
||||
self.packer.deser_slatepack(data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SlatePutter for PathToSlatepack<'a> {
|
||||
fn put_tx(&self, slate: &Slate, as_bin: bool) -> Result<(), Error> {
|
||||
let slatepack = self.create_slatepack(slate)?;
|
||||
let mut pub_tx = File::create(&self.0.pathbuf)?;
|
||||
let slatepack = self.packer.create_slatepack(slate)?;
|
||||
let mut pub_tx = File::create(&self.pathbuf)?;
|
||||
if as_bin {
|
||||
pub_tx.write_all(
|
||||
&byte_ser::to_bytes(&SlatepackBin(slatepack))
|
||||
.map_err(|_| ErrorKind::SlatepackSer)?,
|
||||
)?;
|
||||
if self.armor_output {
|
||||
let armored = self.packer.armor_slatepack(&slatepack)?;
|
||||
pub_tx.write_all(armored.as_bytes())?;
|
||||
} else {
|
||||
pub_tx.write_all(
|
||||
&byte_ser::to_bytes(&SlatepackBin(slatepack))
|
||||
.map_err(|_| ErrorKind::SlatepackSer)?,
|
||||
)?;
|
||||
}
|
||||
} else {
|
||||
pub_tx.write_all(
|
||||
serde_json::to_string_pretty(&slatepack)
|
||||
|
@ -111,59 +80,7 @@ impl<'a> SlatePutter for PathToSlatepack<'a> {
|
|||
impl<'a> SlateGetter for PathToSlatepack<'a> {
|
||||
fn get_tx(&self) -> Result<(Slate, bool), Error> {
|
||||
let data = self.get_slatepack_file_contents()?;
|
||||
let mut slatepack = self.deser_slatepack(data)?;
|
||||
slatepack.try_decrypt_payload(self.0.dec_key)?;
|
||||
let slate = byte_ser::from_bytes::<VersionedBinSlate>(&slatepack.payload)
|
||||
.map_err(|_| ErrorKind::SlatepackSer)?;
|
||||
Ok((Slate::upgrade(slate.into())?, true))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PathToSlatepackArmored<'a>(SlatepackArgs<'a>);
|
||||
|
||||
impl<'a> PathToSlatepackArmored<'a> {
|
||||
/// Create with pathbuf and recipients
|
||||
pub fn new(args: SlatepackArgs<'a>) -> Self {
|
||||
Self(args)
|
||||
}
|
||||
|
||||
/// decode armor
|
||||
pub fn decode_armored_file(&self) -> Result<Vec<u8>, Error> {
|
||||
let mut pub_sp_armored = File::open(&self.0.pathbuf)?;
|
||||
let mut data = Vec::new();
|
||||
pub_sp_armored.read_to_end(&mut data)?;
|
||||
SlatepackArmor::decode(&String::from_utf8(data).unwrap())
|
||||
}
|
||||
|
||||
// return slatepack
|
||||
pub fn get_slatepack(&self) -> Result<Slatepack, Error> {
|
||||
let data = self.decode_armored_file()?;
|
||||
let pts = PathToSlatepack::new(self.0.clone());
|
||||
pts.deser_slatepack(data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SlatePutter for PathToSlatepackArmored<'a> {
|
||||
fn put_tx(&self, slate: &Slate, _as_bin: bool) -> Result<(), Error> {
|
||||
let pts = PathToSlatepack::new(self.0.clone());
|
||||
let slatepack = pts.create_slatepack(slate)?;
|
||||
let armored = SlatepackArmor::encode(&slatepack, 3)?;
|
||||
let mut pub_tx = File::create(&self.0.pathbuf)?;
|
||||
pub_tx.write_all(armored.as_bytes())?;
|
||||
pub_tx.sync_all()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SlateGetter for PathToSlatepackArmored<'a> {
|
||||
fn get_tx(&self) -> Result<(Slate, bool), Error> {
|
||||
let mut slatepack = self.get_slatepack()?;
|
||||
slatepack.try_decrypt_payload(self.0.dec_key)?;
|
||||
let slate_bin =
|
||||
byte_ser::from_bytes::<VersionedBinSlate>(&slatepack.payload).map_err(|e| {
|
||||
error!("Error reading slate from armored slatepack: {}", e);
|
||||
ErrorKind::SlatepackDeser
|
||||
})?;
|
||||
Ok((Slate::upgrade(slate_bin.into())?, true))
|
||||
let slatepack = self.packer.deser_slatepack(data)?;
|
||||
Ok((self.packer.get_slate(&slatepack)?, true))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,8 +45,7 @@ pub mod tor;
|
|||
|
||||
pub use crate::adapters::{
|
||||
create_sender, HttpSlateSender, KeybaseAllChannels, KeybaseChannel, PathToSlate,
|
||||
PathToSlatepack, PathToSlatepackArmored, SlateGetter, SlatePutter, SlateReceiver, SlateSender,
|
||||
SlatepackArgs,
|
||||
PathToSlatepack, SlateGetter, SlatePutter, SlateReceiver, SlateSender,
|
||||
};
|
||||
pub use crate::backends::{wallet_db_exists, LMDBBackend};
|
||||
pub use crate::error::{Error, ErrorKind};
|
||||
|
|
|
@ -34,6 +34,7 @@ bs58 = "0.3"
|
|||
age = "0.4"
|
||||
curve25519-dalek = "2.0.0"
|
||||
secrecy = "0.6"
|
||||
bech32 = "0.7"
|
||||
|
||||
grin_wallet_util = { path = "../util", version = "4.0.0-alpha.1" }
|
||||
grin_wallet_config = { path = "../config", version = "4.0.0-alpha.1" }
|
||||
|
|
|
@ -207,8 +207,8 @@ pub enum ErrorKind {
|
|||
SlatepackSer,
|
||||
|
||||
/// Can't deserialize slate
|
||||
#[fail(display = "Can't Deserialize slatepack")]
|
||||
SlatepackDeser,
|
||||
#[fail(display = "Can't Deserialize slatepack: {}", _0)]
|
||||
SlatepackDeser(String),
|
||||
|
||||
/// Unknown slate version
|
||||
#[fail(display = "Unknown Slate Version: {}", _0)]
|
||||
|
@ -290,6 +290,10 @@ pub enum ErrorKind {
|
|||
#[fail(display = "Age error: {}", _0)]
|
||||
Age(String),
|
||||
|
||||
/// Slatepack address parsing error
|
||||
#[fail(display = "SlatepackAddress error: {}", _0)]
|
||||
SlatepackAddress(String),
|
||||
|
||||
/// Other
|
||||
#[fail(display = "Generic error: {}", _0)]
|
||||
GenericError(String),
|
||||
|
@ -426,3 +430,11 @@ impl From<age::Error> for Error {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bech32::Error> for Error {
|
||||
fn from(error: bech32::Error) -> Error {
|
||||
Error {
|
||||
inner: Context::new(ErrorKind::SlatepackAddress(format!("{}", error))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,9 @@ pub use crate::slate_versions::{
|
|||
SlateVersion, VersionedBinSlate, VersionedCoinbase, VersionedSlate, CURRENT_SLATE_VERSION,
|
||||
GRIN_BLOCK_HEADER_VERSION,
|
||||
};
|
||||
pub use crate::slatepack::{Slatepack, SlatepackArmor, SlatepackBin};
|
||||
pub use crate::slatepack::{
|
||||
Slatepack, SlatepackAddress, SlatepackArmor, SlatepackBin, Slatepacker, SlatepackerArgs,
|
||||
};
|
||||
pub use api_impl::owner_updater::StatusMessage;
|
||||
pub use api_impl::types::{
|
||||
BlockFees, InitTxArgs, InitTxSendArgs, IssueInvoiceTxArgs, NodeHeightResult,
|
||||
|
|
248
libwallet/src/slatepack/address.rs
Normal file
248
libwallet/src/slatepack/address.rs
Normal file
|
@ -0,0 +1,248 @@
|
|||
// Copyright 2020 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use bech32::{self, FromBase32, ToBase32};
|
||||
/// Slatepack Address definition
|
||||
use ed25519_dalek::PublicKey as edDalekPublicKey;
|
||||
use ed25519_dalek::SecretKey as edDalekSecretKey;
|
||||
use rand::{thread_rng, Rng};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use x25519_dalek::PublicKey as xDalekPublicKey;
|
||||
|
||||
use crate::grin_core::ser::{self, Readable, Reader, Writeable, Writer};
|
||||
use crate::util::OnionV3Address;
|
||||
use crate::{Error, ErrorKind};
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
/// Definition of a Slatepack address
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct SlatepackAddress {
|
||||
/// Human-readable prefix
|
||||
pub hrp: String,
|
||||
/// ed25519 Public key, to be bech32 encoded,
|
||||
/// interpreted as tor address or converted
|
||||
/// to an X25519 public key for encrypting
|
||||
/// slatepacks
|
||||
pub pub_key: edDalekPublicKey,
|
||||
}
|
||||
|
||||
impl SlatepackAddress {
|
||||
/// new with default hrp
|
||||
pub fn new(pub_key: &edDalekPublicKey) -> Self {
|
||||
Self {
|
||||
hrp: String::from("slatepack"),
|
||||
pub_key: pub_key.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// new with a random key
|
||||
pub fn random() -> Self {
|
||||
let bytes: [u8; 32] = thread_rng().gen();
|
||||
let pub_key = edDalekPublicKey::from(&edDalekSecretKey::from_bytes(&bytes).unwrap());
|
||||
SlatepackAddress::new(&pub_key)
|
||||
}
|
||||
|
||||
/// calculate encoded length
|
||||
pub fn encoded_len(&self) -> Result<usize, Error> {
|
||||
let encoded = String::try_from(self)?;
|
||||
// add length byte
|
||||
Ok(encoded.as_bytes().len() + 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for SlatepackAddress {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str(&String::try_from(self).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for SlatepackAddress {
|
||||
type Error = Error;
|
||||
fn try_from(encoded: &str) -> Result<Self, Self::Error> {
|
||||
let (hrp, data) = bech32::decode(&encoded)?;
|
||||
let bytes = Vec::<u8>::from_base32(&data)?;
|
||||
let pub_key = match edDalekPublicKey::from_bytes(&bytes) {
|
||||
Ok(k) => k,
|
||||
Err(e) => {
|
||||
return Err(ErrorKind::ED25519Key(format!("{}", e)).into());
|
||||
}
|
||||
};
|
||||
Ok(SlatepackAddress { hrp, pub_key })
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&SlatepackAddress> for String {
|
||||
type Error = Error;
|
||||
fn try_from(addr: &SlatepackAddress) -> Result<Self, Self::Error> {
|
||||
let encoded = bech32::encode(&addr.hrp, addr.pub_key.to_bytes().to_base32())?;
|
||||
Ok(encoded.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&SlatepackAddress> for OnionV3Address {
|
||||
fn from(addr: &SlatepackAddress) -> Self {
|
||||
OnionV3Address::from_bytes(addr.pub_key.to_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&SlatepackAddress> for xDalekPublicKey {
|
||||
type Error = Error;
|
||||
fn try_from(addr: &SlatepackAddress) -> Result<Self, Self::Error> {
|
||||
let cep =
|
||||
curve25519_dalek::edwards::CompressedEdwardsY::from_slice(addr.pub_key.as_bytes());
|
||||
let ep = match cep.decompress() {
|
||||
Some(p) => p,
|
||||
None => {
|
||||
return Err(
|
||||
ErrorKind::ED25519Key("Can't decompress ed25519 Edwards Point".into()).into(),
|
||||
);
|
||||
}
|
||||
};
|
||||
let res = xDalekPublicKey::from(ep.to_montgomery().to_bytes());
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
/// Serializes a SlatepackAddress to a bech32 string
|
||||
impl Serialize for SlatepackAddress {
|
||||
///
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
serializer.serialize_str(
|
||||
&String::try_from(self).map_err(|err| serde::ser::Error::custom(err.to_string()))?,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize from a bech32 string
|
||||
impl<'de> Deserialize<'de> for SlatepackAddress {
|
||||
fn deserialize<D>(deserializer: D) -> Result<SlatepackAddress, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
struct SlatepackAddressVisitor;
|
||||
|
||||
impl<'de> serde::de::Visitor<'de> for SlatepackAddressVisitor {
|
||||
type Value = SlatepackAddress;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(formatter, "a SlatepackAddress")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<SlatepackAddress, E>
|
||||
where
|
||||
E: serde::de::Error,
|
||||
{
|
||||
let s = SlatepackAddress::try_from(value)
|
||||
.map_err(|err| serde::de::Error::custom(err.to_string()))?;
|
||||
Ok(s)
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_str(SlatepackAddressVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
/// write binary trait
|
||||
impl Writeable for SlatepackAddress {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
||||
// We're actually going to encode the bech32 address as opposed to
|
||||
// the binary serialization
|
||||
let encoded = match String::try_from(self) {
|
||||
Ok(e) => e,
|
||||
Err(e) => {
|
||||
error!("Cannot parse Slatepack address: {:?}, {}", self, e);
|
||||
return Err(ser::Error::CorruptedData);
|
||||
}
|
||||
};
|
||||
// write length, max 255
|
||||
let bytes = encoded.as_bytes();
|
||||
if bytes.len() > 255 {
|
||||
error!(
|
||||
"Cannot encode Slatepackaddress: {:?}, Too Long (Max 255)",
|
||||
self
|
||||
);
|
||||
return Err(ser::Error::CorruptedData);
|
||||
}
|
||||
writer.write_u8(bytes.len() as u8)?;
|
||||
writer.write_fixed_bytes(&bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl Readable for SlatepackAddress {
|
||||
fn read<R: Reader>(reader: &mut R) -> Result<SlatepackAddress, ser::Error> {
|
||||
// read length as u8
|
||||
let len = reader.read_u8()?;
|
||||
// and bech32 string
|
||||
let encoded = match String::from_utf8(reader.read_fixed_bytes(len as usize)?) {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
error!("Cannot parse Slatepack address from utf8: {}", e);
|
||||
return Err(ser::Error::CorruptedData);
|
||||
}
|
||||
};
|
||||
let parsed_addr = match SlatepackAddress::try_from(encoded.as_str()) {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
error!("Cannot parse Slatepack address: {}, {}", encoded, e);
|
||||
return Err(ser::Error::CorruptedData);
|
||||
}
|
||||
};
|
||||
Ok(parsed_addr)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slatepack_address() -> Result<(), Error> {
|
||||
use rand::{thread_rng, Rng};
|
||||
let sec_key_bytes: [u8; 32] = thread_rng().gen();
|
||||
|
||||
let ed_sec_key = edDalekSecretKey::from_bytes(&sec_key_bytes).unwrap();
|
||||
let ed_pub_key = edDalekPublicKey::from(&ed_sec_key);
|
||||
let addr = SlatepackAddress::new(&ed_pub_key);
|
||||
let x_pub_key = xDalekPublicKey::try_from(&addr)?;
|
||||
|
||||
let x_dec_secret = x25519_dalek::StaticSecret::from(sec_key_bytes);
|
||||
let x_pub_key_direct = xDalekPublicKey::from(&x_dec_secret);
|
||||
|
||||
println!("ed sec key: {:?}", ed_sec_key);
|
||||
println!("ed pub key: {:?}", ed_pub_key);
|
||||
println!("x pub key from addr: {:?}", x_pub_key);
|
||||
println!("x pub key direct: {:?}", x_pub_key_direct);
|
||||
|
||||
let encoded = String::try_from(&addr).unwrap();
|
||||
println!("Encoded bech32: {}", encoded);
|
||||
let parsed_addr = SlatepackAddress::try_from(encoded.as_str()).unwrap();
|
||||
assert_eq!(addr, parsed_addr);
|
||||
|
||||
// ensure ed25519 pub keys and x25519 pubkeys are equivalent on decryption
|
||||
let mut slatepack = super::Slatepack::default();
|
||||
let mut payload: Vec<u8> = Vec::with_capacity(243);
|
||||
for _ in 0..payload.capacity() {
|
||||
payload.push(rand::random());
|
||||
}
|
||||
slatepack.payload = payload;
|
||||
let orig_sp = slatepack.clone();
|
||||
|
||||
slatepack.try_encrypt_payload(vec![addr.clone()])?;
|
||||
slatepack.try_decrypt_payload(Some(&ed_sec_key))?;
|
||||
|
||||
assert_eq!(orig_sp.payload, slatepack.payload);
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -29,7 +29,7 @@ use std::str;
|
|||
use super::types::{Slatepack, SlatepackBin};
|
||||
|
||||
// Framing and formatting for slate armor
|
||||
static HEADER: &str = "BEGINSLATEPACK. ";
|
||||
pub static HEADER: &str = "BEGINSLATEPACK. ";
|
||||
static FOOTER: &str = ". ENDSLATEPACK.";
|
||||
const WORD_LENGTH: usize = 15;
|
||||
|
||||
|
|
|
@ -12,8 +12,12 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
mod address;
|
||||
mod armor;
|
||||
mod packer;
|
||||
mod types;
|
||||
|
||||
pub use self::address::SlatepackAddress;
|
||||
pub use self::armor::SlatepackArmor;
|
||||
pub use self::packer::{Slatepacker, SlatepackerArgs};
|
||||
pub use self::types::{Slatepack, SlatepackBin};
|
||||
|
|
120
libwallet/src/slatepack/packer.rs
Normal file
120
libwallet/src/slatepack/packer.rs
Normal file
|
@ -0,0 +1,120 @@
|
|||
// Copyright 2020 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::iter::FromIterator;
|
||||
|
||||
use crate::{Error, ErrorKind};
|
||||
use crate::{
|
||||
Slate, SlateVersion, Slatepack, SlatepackAddress, SlatepackArmor, SlatepackBin,
|
||||
VersionedBinSlate, VersionedSlate,
|
||||
};
|
||||
|
||||
use grin_wallet_util::byte_ser;
|
||||
|
||||
use ed25519_dalek::SecretKey as edSecretKey;
|
||||
|
||||
#[derive(Clone)]
|
||||
/// Arguments, mostly for encrypting decrypting a slatepack
|
||||
pub struct SlatepackerArgs<'a> {
|
||||
/// Optional sender to include in slatepack
|
||||
pub sender: Option<SlatepackAddress>,
|
||||
/// Optional list of recipients, for encryption
|
||||
pub recipients: Vec<SlatepackAddress>,
|
||||
/// Optional decryption key
|
||||
pub dec_key: Option<&'a edSecretKey>,
|
||||
}
|
||||
|
||||
/// Helper struct to pack and unpack slatepacks
|
||||
#[derive(Clone)]
|
||||
pub struct Slatepacker<'a>(SlatepackerArgs<'a>);
|
||||
|
||||
impl<'a> Slatepacker<'a> {
|
||||
/// Create with pathbuf and recipients
|
||||
pub fn new(args: SlatepackerArgs<'a>) -> Self {
|
||||
Self(args)
|
||||
}
|
||||
|
||||
/// return slatepack
|
||||
pub fn deser_slatepack(&self, data: Vec<u8>) -> Result<Slatepack, Error> {
|
||||
// check if data is armored, if so, remove and continue
|
||||
let test_header = Vec::from_iter(data[0..super::armor::HEADER.len()].iter().cloned());
|
||||
let data = match String::from_utf8(test_header) {
|
||||
Ok(s) => {
|
||||
if s.as_str() == super::armor::HEADER {
|
||||
SlatepackArmor::decode(
|
||||
String::from_utf8(data)
|
||||
.map_err(|e| {
|
||||
let msg = format!("{}", e);
|
||||
error!("Error decoding slatepack armor: {}", msg);
|
||||
ErrorKind::SlatepackDeser(msg)
|
||||
})?
|
||||
.as_str(),
|
||||
)?
|
||||
} else {
|
||||
data
|
||||
}
|
||||
}
|
||||
Err(_) => data,
|
||||
};
|
||||
|
||||
// try as bin first, then as json
|
||||
let mut slatepack = match byte_ser::from_bytes::<SlatepackBin>(&data) {
|
||||
Ok(s) => s.0,
|
||||
Err(e) => {
|
||||
debug!("Not a valid binary slatepack: {} - Will try JSON", e);
|
||||
let content = String::from_utf8(data).map_err(|e| {
|
||||
let msg = format!("{}", e);
|
||||
ErrorKind::SlatepackDeser(msg)
|
||||
})?;
|
||||
serde_json::from_str(&content).map_err(|e| {
|
||||
let msg = format!("Error reading JSON slatepack: {}", e);
|
||||
ErrorKind::SlatepackDeser(msg)
|
||||
})?
|
||||
}
|
||||
};
|
||||
|
||||
slatepack.ver_check_warn();
|
||||
slatepack.try_decrypt_payload(self.0.dec_key)?;
|
||||
Ok(slatepack)
|
||||
}
|
||||
|
||||
/// Create slatepack from slate and args
|
||||
pub fn create_slatepack(&self, slate: &Slate) -> Result<Slatepack, Error> {
|
||||
let out_slate = VersionedSlate::into_version(slate.clone(), SlateVersion::V4)?;
|
||||
let bin_slate =
|
||||
VersionedBinSlate::try_from(out_slate).map_err(|_| ErrorKind::SlatepackSer)?;
|
||||
let mut slatepack = Slatepack::default();
|
||||
slatepack.payload = byte_ser::to_bytes(&bin_slate).map_err(|_| ErrorKind::SlatepackSer)?;
|
||||
slatepack.sender = self.0.sender.clone();
|
||||
slatepack.try_encrypt_payload(self.0.recipients.clone())?;
|
||||
Ok(slatepack)
|
||||
}
|
||||
|
||||
/// Armor a slatepack
|
||||
pub fn armor_slatepack(&self, slatepack: &Slatepack) -> Result<String, Error> {
|
||||
SlatepackArmor::encode(&slatepack, 3)
|
||||
}
|
||||
|
||||
/// Return/upgrade slate from slatepack
|
||||
pub fn get_slate(&self, slatepack: &Slatepack) -> Result<Slate, Error> {
|
||||
let slate_bin =
|
||||
byte_ser::from_bytes::<VersionedBinSlate>(&slatepack.payload).map_err(|e| {
|
||||
error!("Error reading slate from armored slatepack: {}", e);
|
||||
let msg = format!("{}", e);
|
||||
ErrorKind::SlatepackDeser(msg)
|
||||
})?;
|
||||
Ok(Slate::upgrade(slate_bin.into())?)
|
||||
}
|
||||
}
|
|
@ -13,20 +13,24 @@
|
|||
// limitations under the License.
|
||||
|
||||
/// Slatepack Types + Serialization implementation
|
||||
use x25519_dalek::PublicKey as xDalekPublicKey;
|
||||
use ed25519_dalek::SecretKey as edSecretKey;
|
||||
use sha2::{Digest, Sha512};
|
||||
use x25519_dalek::StaticSecret;
|
||||
|
||||
use crate::dalek_ser;
|
||||
use crate::grin_core::ser::{self, Readable, Reader, Writeable, Writer};
|
||||
use crate::Error;
|
||||
|
||||
use super::SlatepackAddress;
|
||||
|
||||
use std::convert::TryInto;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
pub const SLATEPACK_MAJOR_VERSION: u8 = 1;
|
||||
pub const SLATEPACK_MINOR_VERSION: u8 = 0;
|
||||
|
||||
/// Basic Slatepack definition
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Slatepack {
|
||||
// Required Fields
|
||||
/// Versioning info
|
||||
|
@ -38,9 +42,8 @@ pub struct Slatepack {
|
|||
// Optional Fields
|
||||
/// Optional Sender address
|
||||
#[serde(default = "default_sender_none")]
|
||||
#[serde(with = "dalek_ser::option_xdalek_pubkey_serde")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sender: Option<xDalekPublicKey>,
|
||||
pub sender: Option<SlatepackAddress>,
|
||||
|
||||
// Payload
|
||||
/// Binary payload, can be encrypted or plaintext
|
||||
|
@ -51,7 +54,7 @@ pub struct Slatepack {
|
|||
pub payload: Vec<u8>,
|
||||
}
|
||||
|
||||
fn default_sender_none() -> Option<xDalekPublicKey> {
|
||||
fn default_sender_none() -> Option<SlatepackAddress> {
|
||||
None
|
||||
}
|
||||
|
||||
|
@ -73,21 +76,21 @@ impl Slatepack {
|
|||
/// return length of optional fields
|
||||
pub fn opt_fields_len(&self) -> Result<usize, ser::Error> {
|
||||
let mut retval = 0;
|
||||
if self.sender.is_some() {
|
||||
retval += 32;
|
||||
if let Some(s) = self.sender.as_ref() {
|
||||
retval += s.encoded_len().unwrap();
|
||||
}
|
||||
Ok(retval)
|
||||
}
|
||||
|
||||
/// age encrypt the payload with the given public key
|
||||
pub fn try_encrypt_payload(&mut self, recipients: Vec<xDalekPublicKey>) -> Result<(), Error> {
|
||||
pub fn try_encrypt_payload(&mut self, recipients: Vec<SlatepackAddress>) -> Result<(), Error> {
|
||||
if recipients.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let rec_keys: Result<Vec<_>, _> = recipients
|
||||
.into_iter()
|
||||
.map(|pk| {
|
||||
let key = age::keys::RecipientKey::X25519(pk);
|
||||
.map(|addr| {
|
||||
let key = age::keys::RecipientKey::X25519((&addr).try_into()?);
|
||||
Ok(key)
|
||||
})
|
||||
.collect();
|
||||
|
@ -108,7 +111,7 @@ impl Slatepack {
|
|||
}
|
||||
|
||||
/// As above, decrypt if needed
|
||||
pub fn try_decrypt_payload(&mut self, dec_key: Option<&StaticSecret>) -> Result<(), Error> {
|
||||
pub fn try_decrypt_payload(&mut self, dec_key: Option<&edSecretKey>) -> Result<(), Error> {
|
||||
if self.mode == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -116,7 +119,16 @@ impl Slatepack {
|
|||
Some(k) => k,
|
||||
None => return Ok(()),
|
||||
};
|
||||
let key = age::keys::SecretKey::X25519(dec_key.clone());
|
||||
let mut b = [0u8; 32];
|
||||
b.copy_from_slice(&dec_key.as_bytes()[0..32]);
|
||||
let mut hasher = Sha512::new();
|
||||
hasher.input(b);
|
||||
let result = hasher.result();
|
||||
b.copy_from_slice(&result[0..32]);
|
||||
|
||||
let x_dec_secret = StaticSecret::from(b);
|
||||
let key = age::keys::SecretKey::X25519(x_dec_secret);
|
||||
|
||||
let decryptor = match age::Decryptor::new(&self.payload[..])? {
|
||||
age::Decryptor::Recipients(d) => d,
|
||||
_ => unreachable!(),
|
||||
|
@ -213,7 +225,7 @@ impl Writeable for SlatepackBin {
|
|||
|
||||
// write optional fields
|
||||
if let Some(s) = sp.sender {
|
||||
writer.write_fixed_bytes(s.as_bytes())?;
|
||||
s.write(writer)?;
|
||||
};
|
||||
|
||||
// Now write payload (length prefixed)
|
||||
|
@ -240,11 +252,16 @@ impl Readable for SlatepackBin {
|
|||
let mut bytes_to_payload = reader.read_u32()?;
|
||||
|
||||
let sender = if opt_flags & 0x01 > 0 {
|
||||
bytes_to_payload -= 32;
|
||||
let bytes = reader.read_fixed_bytes(32)?;
|
||||
let mut b = [0u8; 32];
|
||||
b.copy_from_slice(&bytes[0..32]);
|
||||
Some(xDalekPublicKey::from(b))
|
||||
let addr = SlatepackAddress::read(reader)?;
|
||||
let len = match addr.encoded_len() {
|
||||
Ok(e) => e as u32,
|
||||
Err(e) => {
|
||||
error!("Cannot parse Slatepack address: {}", e);
|
||||
return Err(ser::Error::CorruptedData);
|
||||
}
|
||||
};
|
||||
bytes_to_payload -= len;
|
||||
Some(addr)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -328,30 +345,6 @@ pub mod slatepack_version {
|
|||
}
|
||||
}
|
||||
|
||||
/// Header struct definition
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct RecipientListEntry {
|
||||
#[serde(with = "dalek_ser::dalek_xpubkey_serde")]
|
||||
/// Public Address
|
||||
pub pub_address: xDalekPublicKey,
|
||||
}
|
||||
|
||||
impl Writeable for RecipientListEntry {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
||||
writer.write_fixed_bytes(self.pub_address.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl Readable for RecipientListEntry {
|
||||
fn read<R: Reader>(reader: &mut R) -> Result<RecipientListEntry, ser::Error> {
|
||||
let bytes = reader.read_fixed_bytes(32)?;
|
||||
let mut b = [0u8; 32];
|
||||
b.copy_from_slice(&bytes[0..32]);
|
||||
let pub_address = xDalekPublicKey::from(b);
|
||||
Ok(RecipientListEntry { pub_address })
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slatepack_bin_basic_ser() -> Result<(), grin_wallet_util::byte_ser::Error> {
|
||||
use grin_wallet_util::byte_ser;
|
||||
|
@ -377,7 +370,6 @@ fn slatepack_bin_basic_ser() -> Result<(), grin_wallet_util::byte_ser::Error> {
|
|||
#[test]
|
||||
fn slatepack_bin_opt_fields_ser() -> Result<(), grin_wallet_util::byte_ser::Error> {
|
||||
use grin_wallet_util::byte_ser;
|
||||
use rand::{thread_rng, Rng};
|
||||
let slatepack = SlatepackVersion { major: 1, minor: 0 };
|
||||
let mut payload: Vec<u8> = Vec::with_capacity(243);
|
||||
for _ in 0..payload.capacity() {
|
||||
|
@ -385,9 +377,7 @@ fn slatepack_bin_opt_fields_ser() -> Result<(), grin_wallet_util::byte_ser::Erro
|
|||
}
|
||||
|
||||
// includes optional fields
|
||||
let bytes: [u8; 32] = thread_rng().gen();
|
||||
let sender_secret = StaticSecret::from(bytes);
|
||||
let sender = Some(xDalekPublicKey::from(&sender_secret));
|
||||
let sender = Some(SlatepackAddress::random());
|
||||
let sp = Slatepack {
|
||||
slatepack,
|
||||
mode: 1,
|
||||
|
@ -396,12 +386,7 @@ fn slatepack_bin_opt_fields_ser() -> Result<(), grin_wallet_util::byte_ser::Erro
|
|||
};
|
||||
let ser = byte_ser::to_bytes(&SlatepackBin(sp.clone()))?;
|
||||
let deser = byte_ser::from_bytes::<SlatepackBin>(&ser)?.0;
|
||||
assert_eq!(sp.slatepack, deser.slatepack);
|
||||
assert_eq!(sp.mode, deser.mode);
|
||||
assert_eq!(
|
||||
sp.sender.unwrap().as_bytes(),
|
||||
deser.sender.unwrap().as_bytes()
|
||||
);
|
||||
assert_eq!(sp, deser);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -413,19 +398,18 @@ fn slatepack_bin_future() -> Result<(), grin_wallet_util::byte_ser::Error> {
|
|||
use grin_wallet_util::byte_ser;
|
||||
use rand::{thread_rng, Rng};
|
||||
use std::io::Cursor;
|
||||
|
||||
let slatepack = SlatepackVersion { major: 1, minor: 0 };
|
||||
let payload_size = 1234;
|
||||
let mut payload: Vec<u8> = Vec::with_capacity(payload_size);
|
||||
for _ in 0..payload.capacity() {
|
||||
payload.push(rand::random());
|
||||
}
|
||||
let sender = Some(SlatepackAddress::random());
|
||||
|
||||
let bytes: [u8; 32] = thread_rng().gen();
|
||||
let sender_secret = StaticSecret::from(bytes);
|
||||
let sender = Some(xDalekPublicKey::from(&sender_secret));
|
||||
println!(
|
||||
"sender key len: {}",
|
||||
sender.as_ref().unwrap().as_bytes().len()
|
||||
"sender len: {}",
|
||||
sender.as_ref().unwrap().encoded_len().unwrap()
|
||||
);
|
||||
|
||||
let sp = Slatepack {
|
||||
|
@ -445,14 +429,14 @@ fn slatepack_bin_future() -> Result<(), grin_wallet_util::byte_ser::Error> {
|
|||
// opt fields len (bytes to payload) 4
|
||||
// bytes 5-8 are opt fields len
|
||||
|
||||
// sender 32
|
||||
// sender 68
|
||||
|
||||
let mut opt_fields_len_bytes = [0u8; 4];
|
||||
opt_fields_len_bytes.copy_from_slice(&ser[5..9]);
|
||||
let mut rdr = Cursor::new(opt_fields_len_bytes.to_vec());
|
||||
let opt_fields_len = rdr.read_u32::<BigEndian>().unwrap();
|
||||
// check this matches what we expect below
|
||||
assert_eq!(opt_fields_len, 32);
|
||||
assert_eq!(opt_fields_len, 69);
|
||||
|
||||
let end_head_pos = opt_fields_len as usize + 8 + 1;
|
||||
|
||||
|
@ -481,11 +465,6 @@ fn slatepack_bin_future() -> Result<(), grin_wallet_util::byte_ser::Error> {
|
|||
}
|
||||
|
||||
let deser = byte_ser::from_bytes::<SlatepackBin>(&new_bytes)?.0;
|
||||
assert_eq!(sp.slatepack, deser.slatepack);
|
||||
assert_eq!(sp.mode, deser.mode);
|
||||
assert_eq!(
|
||||
sp.sender.unwrap().as_bytes(),
|
||||
deser.sender.unwrap().as_bytes()
|
||||
);
|
||||
assert_eq!(sp, deser);
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue