Standardize serialization within the Monero lib

read for R: Read
write for W: Write
serialize for -> Vec<u8>

Also uses std::io::{self, Read, Write} consistently.
This commit is contained in:
Luke Parker
2023-01-07 05:18:35 -05:00
parent 7508106650
commit 7b0b8a20ec
12 changed files with 219 additions and 186 deletions

View File

@@ -1,7 +1,7 @@
use std::io; use std::io::{self, Write};
const VARINT_CONTINUATION_MASK: u8 = 0b1000_0000; const VARINT_CONTINUATION_MASK: u8 = 0b1000_0000;
pub(crate) fn write_varint<W: io::Write>(varint: &u64, w: &mut W) -> io::Result<()> { pub(crate) fn write_varint<W: Write>(varint: &u64, w: &mut W) -> io::Result<()> {
let mut varint = *varint; let mut varint = *varint;
while { while {
let mut b = u8::try_from(varint & u64::from(!VARINT_CONTINUATION_MASK)).unwrap(); let mut b = u8::try_from(varint & u64::from(!VARINT_CONTINUATION_MASK)).unwrap();

View File

@@ -1,3 +1,5 @@
use std::io::{self, Read, Write};
use crate::{serialize::*, transaction::Transaction}; use crate::{serialize::*, transaction::Transaction};
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
@@ -10,7 +12,7 @@ pub struct BlockHeader {
} }
impl BlockHeader { impl BlockHeader {
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> { pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
write_varint(&self.major_version, w)?; write_varint(&self.major_version, w)?;
write_varint(&self.minor_version, w)?; write_varint(&self.minor_version, w)?;
write_varint(&self.timestamp, w)?; write_varint(&self.timestamp, w)?;
@@ -18,7 +20,13 @@ impl BlockHeader {
w.write_all(&self.nonce.to_le_bytes()) w.write_all(&self.nonce.to_le_bytes())
} }
pub fn deserialize<R: std::io::Read>(r: &mut R) -> std::io::Result<BlockHeader> { pub fn serialize(&self) -> Vec<u8> {
let mut serialized = vec![];
self.write(&mut serialized).unwrap();
serialized
}
pub fn read<R: Read>(r: &mut R) -> io::Result<BlockHeader> {
Ok(BlockHeader { Ok(BlockHeader {
major_version: read_varint(r)?, major_version: read_varint(r)?,
minor_version: read_varint(r)?, minor_version: read_varint(r)?,
@@ -37,9 +45,9 @@ pub struct Block {
} }
impl Block { impl Block {
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> { pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
self.header.serialize(w)?; self.header.write(w)?;
self.miner_tx.serialize(w)?; self.miner_tx.write(w)?;
write_varint(&self.txs.len().try_into().unwrap(), w)?; write_varint(&self.txs.len().try_into().unwrap(), w)?;
for tx in &self.txs { for tx in &self.txs {
w.write_all(tx)?; w.write_all(tx)?;
@@ -47,10 +55,16 @@ impl Block {
Ok(()) Ok(())
} }
pub fn deserialize<R: std::io::Read>(r: &mut R) -> std::io::Result<Block> { pub fn serialize(&self) -> Vec<u8> {
let mut serialized = vec![];
self.write(&mut serialized).unwrap();
serialized
}
pub fn read<R: Read>(r: &mut R) -> io::Result<Block> {
Ok(Block { Ok(Block {
header: BlockHeader::deserialize(r)?, header: BlockHeader::read(r)?,
miner_tx: Transaction::deserialize(r)?, miner_tx: Transaction::read(r)?,
txs: (0 .. read_varint(r)?).map(|_| read_bytes(r)).collect::<Result<_, _>>()?, txs: (0 .. read_varint(r)?).map(|_| read_bytes(r)).collect::<Result<_, _>>()?,
}) })
} }

View File

@@ -1,5 +1,7 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use std::io::{self, Read, Write};
use rand_core::{RngCore, CryptoRng}; use rand_core::{RngCore, CryptoRng};
use zeroize::Zeroize; use zeroize::Zeroize;
@@ -93,11 +95,11 @@ impl Bulletproofs {
} }
} }
fn serialize_core<W: std::io::Write, F: Fn(&[EdwardsPoint], &mut W) -> std::io::Result<()>>( fn write_core<W: Write, F: Fn(&[EdwardsPoint], &mut W) -> io::Result<()>>(
&self, &self,
w: &mut W, w: &mut W,
specific_write_vec: F, specific_write_vec: F,
) -> std::io::Result<()> { ) -> io::Result<()> {
match self { match self {
Bulletproofs::Original(bp) => { Bulletproofs::Original(bp) => {
write_point(&bp.A, w)?; write_point(&bp.A, w)?;
@@ -126,16 +128,22 @@ impl Bulletproofs {
} }
} }
pub(crate) fn signature_serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> { pub(crate) fn signature_write<W: Write>(&self, w: &mut W) -> io::Result<()> {
self.serialize_core(w, |points, w| write_raw_vec(write_point, points, w)) self.write_core(w, |points, w| write_raw_vec(write_point, points, w))
} }
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> { pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
self.serialize_core(w, |points, w| write_vec(write_point, points, w)) self.write_core(w, |points, w| write_vec(write_point, points, w))
} }
/// Deserialize non-plus Bulletproofs. pub fn serialize(&self) -> Vec<u8> {
pub fn deserialize<R: std::io::Read>(r: &mut R) -> std::io::Result<Bulletproofs> { let mut serialized = vec![];
self.write(&mut serialized).unwrap();
serialized
}
/// Read Bulletproofs.
pub fn read<R: Read>(r: &mut R) -> io::Result<Bulletproofs> {
Ok(Bulletproofs::Original(OriginalStruct { Ok(Bulletproofs::Original(OriginalStruct {
A: read_point(r)?, A: read_point(r)?,
S: read_point(r)?, S: read_point(r)?,
@@ -151,8 +159,8 @@ impl Bulletproofs {
})) }))
} }
/// Deserialize Bulletproofs+. /// Read Bulletproofs+.
pub fn deserialize_plus<R: std::io::Read>(r: &mut R) -> std::io::Result<Bulletproofs> { pub fn read_plus<R: Read>(r: &mut R) -> io::Result<Bulletproofs> {
Ok(Bulletproofs::Plus(PlusStruct { Ok(Bulletproofs::Plus(PlusStruct {
A: read_point(r)?, A: read_point(r)?,
A1: read_point(r)?, A1: read_point(r)?,

View File

@@ -1,6 +1,7 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use core::ops::Deref; use core::ops::Deref;
use std::io::{self, Read, Write};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use thiserror::Error; use thiserror::Error;
@@ -313,13 +314,13 @@ impl Clsag {
(ring_len * 32) + 32 + 32 (ring_len * 32) + 32 + 32
} }
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> { pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
write_raw_vec(write_scalar, &self.s, w)?; write_raw_vec(write_scalar, &self.s, w)?;
w.write_all(&self.c1.to_bytes())?; w.write_all(&self.c1.to_bytes())?;
write_point(&self.D, w) write_point(&self.D, w)
} }
pub fn deserialize<R: std::io::Read>(decoys: usize, r: &mut R) -> std::io::Result<Clsag> { pub fn read<R: Read>(decoys: usize, r: &mut R) -> io::Result<Clsag> {
Ok(Clsag { s: read_raw_vec(read_scalar, decoys, r)?, c1: read_scalar(r)?, D: read_point(r)? }) Ok(Clsag { s: read_raw_vec(read_scalar, decoys, r)?, c1: read_scalar(r)?, D: read_point(r)? })
} }
} }

View File

@@ -41,18 +41,17 @@ impl ClsagInput {
// Doesn't domain separate as this is considered part of the larger CLSAG proof // Doesn't domain separate as this is considered part of the larger CLSAG proof
// Ring index // Ring index
transcript.append_message(b"ring_index", [self.decoys.i]); transcript.append_message(b"real_spend", [self.decoys.i]);
// Ring // Ring
let mut ring = vec![]; for (i, pair) in self.decoys.ring.iter().enumerate() {
for pair in &self.decoys.ring {
// Doesn't include global output indexes as CLSAG doesn't care and won't be affected by it // Doesn't include global output indexes as CLSAG doesn't care and won't be affected by it
// They're just a unreliable reference to this data which will be included in the message // They're just a unreliable reference to this data which will be included in the message
// if in use // if in use
ring.extend(pair[0].compress().to_bytes()); transcript.append_message(b"member", [u8::try_from(i).expect("ring size exceeded 255")]);
ring.extend(pair[1].compress().to_bytes()); transcript.append_message(b"key", pair[0].compress().to_bytes());
transcript.append_message(b"commitment", pair[1].compress().to_bytes())
} }
transcript.append_message(b"ring", ring);
// Doesn't include the commitment's parts as the above ring + index includes the commitment // Doesn't include the commitment's parts as the above ring + index includes the commitment
// The only potential malleability would be if the G/H relationship is known breaking the // The only potential malleability would be if the G/H relationship is known breaking the

View File

@@ -1,4 +1,5 @@
use core::ops::Deref; use core::ops::Deref;
use std::io::{self, Read, Write};
use zeroize::Zeroizing; use zeroize::Zeroizing;
@@ -35,7 +36,7 @@ impl RctBase {
1 + 8 + (outputs * (8 + 32)) 1 + 8 + (outputs * (8 + 32))
} }
pub fn serialize<W: std::io::Write>(&self, w: &mut W, rct_type: u8) -> std::io::Result<()> { pub fn write<W: Write>(&self, w: &mut W, rct_type: u8) -> io::Result<()> {
w.write_all(&[rct_type])?; w.write_all(&[rct_type])?;
match rct_type { match rct_type {
0 => Ok(()), 0 => Ok(()),
@@ -50,10 +51,7 @@ impl RctBase {
} }
} }
pub fn deserialize<R: std::io::Read>( pub fn read<R: Read>(outputs: usize, r: &mut R) -> io::Result<(RctBase, u8)> {
outputs: usize,
r: &mut R,
) -> std::io::Result<(RctBase, u8)> {
let rct_type = read_byte(r)?; let rct_type = read_byte(r)?;
Ok(( Ok((
if rct_type == 0 { if rct_type == 0 {
@@ -96,46 +94,43 @@ impl RctPrunable {
(inputs * (Clsag::fee_weight(protocol.ring_len()) + 32)) (inputs * (Clsag::fee_weight(protocol.ring_len()) + 32))
} }
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> { pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
match self { match self {
RctPrunable::Null => Ok(()), RctPrunable::Null => Ok(()),
RctPrunable::Clsag { bulletproofs, clsags, pseudo_outs, .. } => { RctPrunable::Clsag { bulletproofs, clsags, pseudo_outs, .. } => {
write_vec(Bulletproofs::serialize, bulletproofs, w)?; write_vec(Bulletproofs::write, bulletproofs, w)?;
write_raw_vec(Clsag::serialize, clsags, w)?; write_raw_vec(Clsag::write, clsags, w)?;
write_raw_vec(write_point, pseudo_outs, w) write_raw_vec(write_point, pseudo_outs, w)
} }
} }
} }
pub fn deserialize<R: std::io::Read>( pub fn serialize(&self) -> Vec<u8> {
rct_type: u8, let mut serialized = vec![];
decoys: &[usize], self.write(&mut serialized).unwrap();
r: &mut R, serialized
) -> std::io::Result<RctPrunable> { }
pub fn read<R: Read>(rct_type: u8, decoys: &[usize], r: &mut R) -> io::Result<RctPrunable> {
Ok(match rct_type { Ok(match rct_type {
0 => RctPrunable::Null, 0 => RctPrunable::Null,
5 | 6 => RctPrunable::Clsag { 5 | 6 => RctPrunable::Clsag {
bulletproofs: read_vec( bulletproofs: read_vec(
if rct_type == 5 { Bulletproofs::deserialize } else { Bulletproofs::deserialize_plus }, if rct_type == 5 { Bulletproofs::read } else { Bulletproofs::read_plus },
r, r,
)?, )?,
clsags: (0 .. decoys.len()) clsags: (0 .. decoys.len()).map(|o| Clsag::read(decoys[o], r)).collect::<Result<_, _>>()?,
.map(|o| Clsag::deserialize(decoys[o], r))
.collect::<Result<_, _>>()?,
pseudo_outs: read_raw_vec(read_point, decoys.len(), r)?, pseudo_outs: read_raw_vec(read_point, decoys.len(), r)?,
}, },
_ => Err(std::io::Error::new( _ => Err(io::Error::new(io::ErrorKind::Other, "Tried to deserialize unknown RCT type"))?,
std::io::ErrorKind::Other,
"Tried to deserialize unknown RCT type",
))?,
}) })
} }
pub(crate) fn signature_serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> { pub(crate) fn signature_write<W: Write>(&self, w: &mut W) -> io::Result<()> {
match self { match self {
RctPrunable::Null => panic!("Serializing RctPrunable::Null for a signature"), RctPrunable::Null => panic!("Serializing RctPrunable::Null for a signature"),
RctPrunable::Clsag { bulletproofs, .. } => { RctPrunable::Clsag { bulletproofs, .. } => {
bulletproofs.iter().try_for_each(|bp| bp.signature_serialize(w)) bulletproofs.iter().try_for_each(|bp| bp.signature_write(w))
} }
} }
} }
@@ -152,17 +147,19 @@ impl RctSignatures {
RctBase::fee_weight(outputs) + RctPrunable::fee_weight(protocol, inputs, outputs) RctBase::fee_weight(outputs) + RctPrunable::fee_weight(protocol, inputs, outputs)
} }
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> { pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
self.base.serialize(w, self.prunable.rct_type())?; self.base.write(w, self.prunable.rct_type())?;
self.prunable.serialize(w) self.prunable.write(w)
} }
pub fn deserialize<R: std::io::Read>( pub fn serialize(&self) -> Vec<u8> {
decoys: Vec<usize>, let mut serialized = vec![];
outputs: usize, self.write(&mut serialized).unwrap();
r: &mut R, serialized
) -> std::io::Result<RctSignatures> { }
let base = RctBase::deserialize(outputs, r)?;
Ok(RctSignatures { base: base.0, prunable: RctPrunable::deserialize(base.1, &decoys, r)? }) pub fn read<R: Read>(decoys: Vec<usize>, outputs: usize, r: &mut R) -> io::Result<RctSignatures> {
let base = RctBase::read(outputs, r)?;
Ok(RctSignatures { base: base.0, prunable: RctPrunable::read(base.1, &decoys, r)? })
} }
} }

View File

@@ -249,7 +249,7 @@ impl Rpc {
.txs .txs
.iter() .iter()
.map(|res| { .map(|res| {
let tx = Transaction::deserialize::<&[u8]>( let tx = Transaction::read::<&[u8]>(
&mut rpc_hex(if !res.as_hex.is_empty() { &res.as_hex } else { &res.pruned_as_hex })? &mut rpc_hex(if !res.as_hex.is_empty() { &res.as_hex } else { &res.pruned_as_hex })?
.as_ref(), .as_ref(),
) )
@@ -312,8 +312,7 @@ impl Rpc {
let res: BlockResponse = let res: BlockResponse =
self.json_rpc_call("get_block", Some(json!({ "hash": hex::encode(hash) }))).await?; self.json_rpc_call("get_block", Some(json!({ "hash": hex::encode(hash) }))).await?;
Block::deserialize::<&[u8]>(&mut rpc_hex(&res.blob)?.as_ref()) Block::read::<&[u8]>(&mut rpc_hex(&res.blob)?.as_ref()).map_err(|_| RpcError::InvalidNode)
.map_err(|_| RpcError::InvalidNode)
} }
pub async fn get_block_by_number(&self, number: usize) -> Result<Block, RpcError> { pub async fn get_block_by_number(&self, number: usize) -> Result<Block, RpcError> {
@@ -487,7 +486,7 @@ impl Rpc {
} }
let mut buf = Vec::with_capacity(2048); let mut buf = Vec::with_capacity(2048);
tx.serialize(&mut buf).unwrap(); tx.write(&mut buf).unwrap();
let res: SendRawResponse = self let res: SendRawResponse = self
.rpc_call("send_raw_transaction", Some(json!({ "tx_as_hex": hex::encode(&buf) }))) .rpc_call("send_raw_transaction", Some(json!({ "tx_as_hex": hex::encode(&buf) })))
.await?; .await?;

View File

@@ -1,4 +1,4 @@
use std::io; use std::io::{self, Read, Write};
use curve25519_dalek::{ use curve25519_dalek::{
scalar::Scalar, scalar::Scalar,
@@ -11,11 +11,11 @@ pub(crate) fn varint_len(varint: usize) -> usize {
((usize::try_from(usize::BITS - varint.leading_zeros()).unwrap().saturating_sub(1)) / 7) + 1 ((usize::try_from(usize::BITS - varint.leading_zeros()).unwrap().saturating_sub(1)) / 7) + 1
} }
pub(crate) fn write_byte<W: io::Write>(byte: &u8, w: &mut W) -> io::Result<()> { pub(crate) fn write_byte<W: Write>(byte: &u8, w: &mut W) -> io::Result<()> {
w.write_all(&[*byte]) w.write_all(&[*byte])
} }
pub(crate) fn write_varint<W: io::Write>(varint: &u64, w: &mut W) -> io::Result<()> { pub(crate) fn write_varint<W: Write>(varint: &u64, w: &mut W) -> io::Result<()> {
let mut varint = *varint; let mut varint = *varint;
while { while {
let mut b = u8::try_from(varint & u64::from(!VARINT_CONTINUATION_MASK)).unwrap(); let mut b = u8::try_from(varint & u64::from(!VARINT_CONTINUATION_MASK)).unwrap();
@@ -29,15 +29,15 @@ pub(crate) fn write_varint<W: io::Write>(varint: &u64, w: &mut W) -> io::Result<
Ok(()) Ok(())
} }
pub(crate) fn write_scalar<W: io::Write>(scalar: &Scalar, w: &mut W) -> io::Result<()> { pub(crate) fn write_scalar<W: Write>(scalar: &Scalar, w: &mut W) -> io::Result<()> {
w.write_all(&scalar.to_bytes()) w.write_all(&scalar.to_bytes())
} }
pub(crate) fn write_point<W: io::Write>(point: &EdwardsPoint, w: &mut W) -> io::Result<()> { pub(crate) fn write_point<W: Write>(point: &EdwardsPoint, w: &mut W) -> io::Result<()> {
w.write_all(&point.compress().to_bytes()) w.write_all(&point.compress().to_bytes())
} }
pub(crate) fn write_raw_vec<T, W: io::Write, F: Fn(&T, &mut W) -> io::Result<()>>( pub(crate) fn write_raw_vec<T, W: Write, F: Fn(&T, &mut W) -> io::Result<()>>(
f: F, f: F,
values: &[T], values: &[T],
w: &mut W, w: &mut W,
@@ -48,7 +48,7 @@ pub(crate) fn write_raw_vec<T, W: io::Write, F: Fn(&T, &mut W) -> io::Result<()>
Ok(()) Ok(())
} }
pub(crate) fn write_vec<T, W: io::Write, F: Fn(&T, &mut W) -> io::Result<()>>( pub(crate) fn write_vec<T, W: Write, F: Fn(&T, &mut W) -> io::Result<()>>(
f: F, f: F,
values: &[T], values: &[T],
w: &mut W, w: &mut W,
@@ -57,25 +57,25 @@ pub(crate) fn write_vec<T, W: io::Write, F: Fn(&T, &mut W) -> io::Result<()>>(
write_raw_vec(f, values, w) write_raw_vec(f, values, w)
} }
pub(crate) fn read_bytes<R: io::Read, const N: usize>(r: &mut R) -> io::Result<[u8; N]> { pub(crate) fn read_bytes<R: Read, const N: usize>(r: &mut R) -> io::Result<[u8; N]> {
let mut res = [0; N]; let mut res = [0; N];
r.read_exact(&mut res)?; r.read_exact(&mut res)?;
Ok(res) Ok(res)
} }
pub(crate) fn read_byte<R: io::Read>(r: &mut R) -> io::Result<u8> { pub(crate) fn read_byte<R: Read>(r: &mut R) -> io::Result<u8> {
Ok(read_bytes::<_, 1>(r)?[0]) Ok(read_bytes::<_, 1>(r)?[0])
} }
pub(crate) fn read_u64<R: io::Read>(r: &mut R) -> io::Result<u64> { pub(crate) fn read_u64<R: Read>(r: &mut R) -> io::Result<u64> {
read_bytes(r).map(u64::from_le_bytes) read_bytes(r).map(u64::from_le_bytes)
} }
pub(crate) fn read_u32<R: io::Read>(r: &mut R) -> io::Result<u32> { pub(crate) fn read_u32<R: Read>(r: &mut R) -> io::Result<u32> {
read_bytes(r).map(u32::from_le_bytes) read_bytes(r).map(u32::from_le_bytes)
} }
pub(crate) fn read_varint<R: io::Read>(r: &mut R) -> io::Result<u64> { pub(crate) fn read_varint<R: Read>(r: &mut R) -> io::Result<u64> {
let mut bits = 0; let mut bits = 0;
let mut res = 0; let mut res = 0;
while { while {
@@ -100,12 +100,12 @@ pub(crate) fn read_varint<R: io::Read>(r: &mut R) -> io::Result<u64> {
// for now. There's also further edge cases as noted by // for now. There's also further edge cases as noted by
// https://github.com/monero-project/monero/issues/8438, where some scalars had an archaic // https://github.com/monero-project/monero/issues/8438, where some scalars had an archaic
// reduction applied // reduction applied
pub(crate) fn read_scalar<R: io::Read>(r: &mut R) -> io::Result<Scalar> { pub(crate) fn read_scalar<R: Read>(r: &mut R) -> io::Result<Scalar> {
Scalar::from_canonical_bytes(read_bytes(r)?) Scalar::from_canonical_bytes(read_bytes(r)?)
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "unreduced scalar")) .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "unreduced scalar"))
} }
pub(crate) fn read_point<R: io::Read>(r: &mut R) -> io::Result<EdwardsPoint> { pub(crate) fn read_point<R: Read>(r: &mut R) -> io::Result<EdwardsPoint> {
let bytes = read_bytes(r)?; let bytes = read_bytes(r)?;
CompressedEdwardsY(bytes) CompressedEdwardsY(bytes)
.decompress() .decompress()
@@ -114,14 +114,14 @@ pub(crate) fn read_point<R: io::Read>(r: &mut R) -> io::Result<EdwardsPoint> {
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid point")) .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid point"))
} }
pub(crate) fn read_torsion_free_point<R: io::Read>(r: &mut R) -> io::Result<EdwardsPoint> { pub(crate) fn read_torsion_free_point<R: Read>(r: &mut R) -> io::Result<EdwardsPoint> {
read_point(r) read_point(r)
.ok() .ok()
.filter(|point| point.is_torsion_free()) .filter(|point| point.is_torsion_free())
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid point")) .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid point"))
} }
pub(crate) fn read_raw_vec<R: io::Read, T, F: Fn(&mut R) -> io::Result<T>>( pub(crate) fn read_raw_vec<R: Read, T, F: Fn(&mut R) -> io::Result<T>>(
f: F, f: F,
len: usize, len: usize,
r: &mut R, r: &mut R,
@@ -133,7 +133,7 @@ pub(crate) fn read_raw_vec<R: io::Read, T, F: Fn(&mut R) -> io::Result<T>>(
Ok(res) Ok(res)
} }
pub(crate) fn read_vec<R: io::Read, T, F: Fn(&mut R) -> io::Result<T>>( pub(crate) fn read_vec<R: Read, T, F: Fn(&mut R) -> io::Result<T>>(
f: F, f: F,
r: &mut R, r: &mut R,
) -> io::Result<Vec<T>> { ) -> io::Result<Vec<T>> {

View File

@@ -1,4 +1,5 @@
use core::cmp::Ordering; use core::cmp::Ordering;
use std::io::{self, Read, Write};
use zeroize::Zeroize; use zeroize::Zeroize;
@@ -27,7 +28,7 @@ impl Input {
1 + 1 + 1 + (8 * ring_len) + 32 1 + 1 + 1 + (8 * ring_len) + 32
} }
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> { pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
match self { match self {
Input::Gen(height) => { Input::Gen(height) => {
w.write_all(&[255])?; w.write_all(&[255])?;
@@ -43,7 +44,7 @@ impl Input {
} }
} }
pub fn deserialize<R: std::io::Read>(r: &mut R) -> std::io::Result<Input> { pub fn read<R: Read>(r: &mut R) -> io::Result<Input> {
Ok(match read_byte(r)? { Ok(match read_byte(r)? {
255 => Input::Gen(read_varint(r)?), 255 => Input::Gen(read_varint(r)?),
2 => Input::ToKey { 2 => Input::ToKey {
@@ -51,10 +52,9 @@ impl Input {
key_offsets: read_vec(read_varint, r)?, key_offsets: read_vec(read_varint, r)?,
key_image: read_torsion_free_point(r)?, key_image: read_torsion_free_point(r)?,
}, },
_ => Err(std::io::Error::new( _ => {
std::io::ErrorKind::Other, Err(io::Error::new(io::ErrorKind::Other, "Tried to deserialize unknown/unused input type"))?
"Tried to deserialize unknown/unused input type", }
))?,
}) })
} }
} }
@@ -72,7 +72,7 @@ impl Output {
1 + 1 + 32 + 1 1 + 1 + 32 + 1
} }
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> { pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
write_varint(&self.amount, w)?; write_varint(&self.amount, w)?;
w.write_all(&[2 + u8::from(self.view_tag.is_some())])?; w.write_all(&[2 + u8::from(self.view_tag.is_some())])?;
w.write_all(&self.key.to_bytes())?; w.write_all(&self.key.to_bytes())?;
@@ -82,13 +82,13 @@ impl Output {
Ok(()) Ok(())
} }
pub fn deserialize<R: std::io::Read>(r: &mut R) -> std::io::Result<Output> { pub fn read<R: Read>(r: &mut R) -> io::Result<Output> {
let amount = read_varint(r)?; let amount = read_varint(r)?;
let view_tag = match read_byte(r)? { let view_tag = match read_byte(r)? {
2 => false, 2 => false,
3 => true, 3 => true,
_ => Err(std::io::Error::new( _ => Err(io::Error::new(
std::io::ErrorKind::Other, io::ErrorKind::Other,
"Tried to deserialize unknown/unused output type", "Tried to deserialize unknown/unused output type",
))?, ))?,
}; };
@@ -119,7 +119,7 @@ impl Timelock {
} }
} }
fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> { fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
write_varint( write_varint(
&match self { &match self {
Timelock::None => 0, Timelock::None => 0,
@@ -163,21 +163,21 @@ impl TransactionPrefix {
extra extra
} }
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> { pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
write_varint(&self.version, w)?; write_varint(&self.version, w)?;
self.timelock.serialize(w)?; self.timelock.write(w)?;
write_vec(Input::serialize, &self.inputs, w)?; write_vec(Input::write, &self.inputs, w)?;
write_vec(Output::serialize, &self.outputs, w)?; write_vec(Output::write, &self.outputs, w)?;
write_varint(&self.extra.len().try_into().unwrap(), w)?; write_varint(&self.extra.len().try_into().unwrap(), w)?;
w.write_all(&self.extra) w.write_all(&self.extra)
} }
pub fn deserialize<R: std::io::Read>(r: &mut R) -> std::io::Result<TransactionPrefix> { pub fn read<R: Read>(r: &mut R) -> io::Result<TransactionPrefix> {
let mut prefix = TransactionPrefix { let mut prefix = TransactionPrefix {
version: read_varint(r)?, version: read_varint(r)?,
timelock: Timelock::from_raw(read_varint(r)?), timelock: Timelock::from_raw(read_varint(r)?),
inputs: read_vec(Input::deserialize, r)?, inputs: read_vec(Input::read, r)?,
outputs: read_vec(Output::deserialize, r)?, outputs: read_vec(Output::read, r)?,
extra: vec![], extra: vec![],
}; };
prefix.extra = read_vec(read_byte, r)?; prefix.extra = read_vec(read_byte, r)?;
@@ -204,8 +204,8 @@ impl Transaction {
RctSignatures::fee_weight(protocol, inputs, outputs) RctSignatures::fee_weight(protocol, inputs, outputs)
} }
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> { pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
self.prefix.serialize(w)?; self.prefix.write(w)?;
if self.prefix.version == 1 { if self.prefix.version == 1 {
for sig in &self.signatures { for sig in &self.signatures {
write_scalar(&sig.0, w)?; write_scalar(&sig.0, w)?;
@@ -213,14 +213,14 @@ impl Transaction {
} }
Ok(()) Ok(())
} else if self.prefix.version == 2 { } else if self.prefix.version == 2 {
self.rct_signatures.serialize(w) self.rct_signatures.write(w)
} else { } else {
panic!("Serializing a transaction with an unknown version"); panic!("Serializing a transaction with an unknown version");
} }
} }
pub fn deserialize<R: std::io::Read>(r: &mut R) -> std::io::Result<Transaction> { pub fn read<R: Read>(r: &mut R) -> io::Result<Transaction> {
let prefix = TransactionPrefix::deserialize(r)?; let prefix = TransactionPrefix::read(r)?;
let mut signatures = vec![]; let mut signatures = vec![];
let mut rct_signatures = RctSignatures { let mut rct_signatures = RctSignatures {
base: RctBase { fee: 0, ecdh_info: vec![], commitments: vec![] }, base: RctBase { fee: 0, ecdh_info: vec![], commitments: vec![] },
@@ -241,7 +241,7 @@ impl Transaction {
.sum::<u64>() .sum::<u64>()
.saturating_sub(prefix.outputs.iter().map(|output| output.amount).sum()); .saturating_sub(prefix.outputs.iter().map(|output| output.amount).sum());
} else if prefix.version == 2 { } else if prefix.version == 2 {
rct_signatures = RctSignatures::deserialize( rct_signatures = RctSignatures::read(
prefix prefix
.inputs .inputs
.iter() .iter()
@@ -254,64 +254,56 @@ impl Transaction {
r, r,
)?; )?;
} else { } else {
Err(std::io::Error::new(std::io::ErrorKind::Other, "Tried to deserialize unknown version"))?; Err(io::Error::new(io::ErrorKind::Other, "Tried to deserialize unknown version"))?;
} }
Ok(Transaction { prefix, signatures, rct_signatures }) Ok(Transaction { prefix, signatures, rct_signatures })
} }
pub fn hash(&self) -> [u8; 32] { pub fn hash(&self) -> [u8; 32] {
let mut serialized = Vec::with_capacity(2048); let mut buf = Vec::with_capacity(2048);
if self.prefix.version == 1 { if self.prefix.version == 1 {
self.serialize(&mut serialized).unwrap(); self.write(&mut buf).unwrap();
hash(&serialized) hash(&buf)
} else { } else {
let mut sig_hash = Vec::with_capacity(96); let mut hashes = Vec::with_capacity(96);
self.prefix.serialize(&mut serialized).unwrap(); self.prefix.write(&mut buf).unwrap();
sig_hash.extend(hash(&serialized)); hashes.extend(hash(&buf));
serialized.clear(); buf.clear();
self self.rct_signatures.base.write(&mut buf, self.rct_signatures.prunable.rct_type()).unwrap();
.rct_signatures hashes.extend(hash(&buf));
.base buf.clear();
.serialize(&mut serialized, self.rct_signatures.prunable.rct_type())
.unwrap();
sig_hash.extend(hash(&serialized));
serialized.clear();
match self.rct_signatures.prunable { match self.rct_signatures.prunable {
RctPrunable::Null => serialized.resize(32, 0), RctPrunable::Null => buf.resize(32, 0),
_ => { _ => {
self.rct_signatures.prunable.serialize(&mut serialized).unwrap(); self.rct_signatures.prunable.write(&mut buf).unwrap();
serialized = hash(&serialized).to_vec(); buf = hash(&buf).to_vec();
} }
} }
sig_hash.extend(&serialized); hashes.extend(&buf);
hash(&sig_hash) hash(&hashes)
} }
} }
/// Calculate the hash of this transaction as needed for signing it. /// Calculate the hash of this transaction as needed for signing it.
pub fn signature_hash(&self) -> [u8; 32] { pub fn signature_hash(&self) -> [u8; 32] {
let mut serialized = Vec::with_capacity(2048); let mut buf = Vec::with_capacity(2048);
let mut sig_hash = Vec::with_capacity(96); let mut sig_hash = Vec::with_capacity(96);
self.prefix.serialize(&mut serialized).unwrap(); self.prefix.write(&mut buf).unwrap();
sig_hash.extend(hash(&serialized)); sig_hash.extend(hash(&buf));
serialized.clear(); buf.clear();
self self.rct_signatures.base.write(&mut buf, self.rct_signatures.prunable.rct_type()).unwrap();
.rct_signatures sig_hash.extend(hash(&buf));
.base buf.clear();
.serialize(&mut serialized, self.rct_signatures.prunable.rct_type())
.unwrap();
sig_hash.extend(hash(&serialized));
serialized.clear();
self.rct_signatures.prunable.signature_serialize(&mut serialized).unwrap(); self.rct_signatures.prunable.signature_write(&mut buf).unwrap();
sig_hash.extend(hash(&serialized)); sig_hash.extend(hash(&buf));
hash(&sig_hash) hash(&sig_hash)
} }

View File

@@ -32,7 +32,7 @@ impl BitXor<[u8; 8]> for PaymentId {
} }
impl PaymentId { impl PaymentId {
pub(crate) fn serialize<W: Write>(&self, w: &mut W) -> io::Result<()> { pub(crate) fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
match self { match self {
PaymentId::Unencrypted(id) => { PaymentId::Unencrypted(id) => {
w.write_all(&[0])?; w.write_all(&[0])?;
@@ -46,7 +46,7 @@ impl PaymentId {
Ok(()) Ok(())
} }
fn deserialize<R: Read>(r: &mut R) -> io::Result<PaymentId> { fn read<R: Read>(r: &mut R) -> io::Result<PaymentId> {
Ok(match read_byte(r)? { Ok(match read_byte(r)? {
0 => PaymentId::Unencrypted(read_bytes(r)?), 0 => PaymentId::Unencrypted(read_bytes(r)?),
1 => PaymentId::Encrypted(read_bytes(r)?), 1 => PaymentId::Encrypted(read_bytes(r)?),
@@ -65,7 +65,7 @@ pub(crate) enum ExtraField {
} }
impl ExtraField { impl ExtraField {
fn serialize<W: Write>(&self, w: &mut W) -> io::Result<()> { fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
match self { match self {
ExtraField::PublicKey(key) => { ExtraField::PublicKey(key) => {
w.write_all(&[1])?; w.write_all(&[1])?;
@@ -88,7 +88,7 @@ impl ExtraField {
Ok(()) Ok(())
} }
fn deserialize<R: Read>(r: &mut R) -> io::Result<ExtraField> { fn read<R: Read>(r: &mut R) -> io::Result<ExtraField> {
Ok(match read_byte(r)? { Ok(match read_byte(r)? {
1 => ExtraField::PublicKey(read_point(r)?), 1 => ExtraField::PublicKey(read_point(r)?),
2 => ExtraField::Nonce({ 2 => ExtraField::Nonce({
@@ -127,7 +127,7 @@ impl Extra {
pub(crate) fn payment_id(&self) -> Option<PaymentId> { pub(crate) fn payment_id(&self) -> Option<PaymentId> {
for field in &self.0 { for field in &self.0 {
if let ExtraField::Nonce(data) = field { if let ExtraField::Nonce(data) = field {
return PaymentId::deserialize::<&[u8]>(&mut data.as_ref()).ok(); return PaymentId::read::<&[u8]>(&mut data.as_ref()).ok();
} }
} }
None None
@@ -176,18 +176,18 @@ impl Extra {
data.iter().map(|v| 1 + varint_len(v.len()) + v.len()).sum::<usize>() data.iter().map(|v| 1 + varint_len(v.len()) + v.len()).sum::<usize>()
} }
pub(crate) fn serialize<W: Write>(&self, w: &mut W) -> io::Result<()> { pub(crate) fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
for field in &self.0 { for field in &self.0 {
field.serialize(w)?; field.write(w)?;
} }
Ok(()) Ok(())
} }
pub(crate) fn deserialize<R: Read>(r: &mut R) -> io::Result<Extra> { pub(crate) fn read<R: Read>(r: &mut R) -> io::Result<Extra> {
let mut res = Extra(vec![]); let mut res = Extra(vec![]);
let mut field; let mut field;
while { while {
field = ExtraField::deserialize(r); field = ExtraField::read(r);
field.is_ok() field.is_ok()
} { } {
res.0.push(field.unwrap()); res.0.push(field.unwrap());

View File

@@ -1,4 +1,4 @@
use std::io; use std::io::{self, Read, Write};
use zeroize::{Zeroize, ZeroizeOnDrop}; use zeroize::{Zeroize, ZeroizeOnDrop};
@@ -24,14 +24,18 @@ pub struct AbsoluteId {
} }
impl AbsoluteId { impl AbsoluteId {
pub fn serialize(&self) -> Vec<u8> { pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
let mut res = Vec::with_capacity(32 + 1); w.write_all(&self.tx)?;
res.extend(self.tx); w.write_all(&[self.o])
res.push(self.o);
res
} }
pub fn read<R: io::Read>(r: &mut R) -> io::Result<AbsoluteId> { pub fn serialize(&self) -> Vec<u8> {
let mut serialized = Vec::with_capacity(32 + 1);
self.write(&mut serialized).unwrap();
serialized
}
pub fn read<R: Read>(r: &mut R) -> io::Result<AbsoluteId> {
Ok(AbsoluteId { tx: read_bytes(r)?, o: read_byte(r)? }) Ok(AbsoluteId { tx: read_bytes(r)?, o: read_byte(r)? })
} }
} }
@@ -46,16 +50,20 @@ pub struct OutputData {
} }
impl OutputData { impl OutputData {
pub fn serialize(&self) -> Vec<u8> { pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
let mut res = Vec::with_capacity(32 + 32 + 40); w.write_all(&self.key.compress().to_bytes())?;
res.extend(self.key.compress().to_bytes()); w.write_all(&self.key_offset.to_bytes())?;
res.extend(self.key_offset.to_bytes()); w.write_all(&self.commitment.mask.to_bytes())?;
res.extend(self.commitment.mask.to_bytes()); w.write_all(&self.commitment.amount.to_le_bytes())
res.extend(self.commitment.amount.to_le_bytes());
res
} }
pub fn read<R: io::Read>(r: &mut R) -> io::Result<OutputData> { pub fn serialize(&self) -> Vec<u8> {
let mut serialized = Vec::with_capacity(32 + 32 + 32 + 8);
self.write(&mut serialized).unwrap();
serialized
}
pub fn read<R: Read>(r: &mut R) -> io::Result<OutputData> {
Ok(OutputData { Ok(OutputData {
key: read_point(r)?, key: read_point(r)?,
key_offset: read_scalar(r)?, key_offset: read_scalar(r)?,
@@ -79,26 +87,31 @@ pub struct Metadata {
} }
impl Metadata { impl Metadata {
pub fn serialize(&self) -> Vec<u8> { pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
let mut res = Vec::with_capacity(4 + 4 + 8 + 1);
if let Some(subaddress) = self.subaddress { if let Some(subaddress) = self.subaddress {
res.push(1); w.write_all(&[1])?;
res.extend(subaddress.account().to_le_bytes()); w.write_all(&subaddress.account().to_le_bytes())?;
res.extend(subaddress.address().to_le_bytes()); w.write_all(&subaddress.address().to_le_bytes())?;
} else { } else {
res.push(0); w.write_all(&[0])?;
} }
res.extend(self.payment_id); w.write_all(&self.payment_id)?;
res.extend(u32::try_from(self.arbitrary_data.len()).unwrap().to_le_bytes()); w.write_all(&u32::try_from(self.arbitrary_data.len()).unwrap().to_le_bytes())?;
for part in &self.arbitrary_data { for part in &self.arbitrary_data {
res.extend([u8::try_from(part.len()).unwrap()]); w.write_all(&[u8::try_from(part.len()).unwrap()])?;
res.extend(part); w.write_all(part)?;
} }
res Ok(())
} }
pub fn read<R: io::Read>(r: &mut R) -> io::Result<Metadata> { pub fn serialize(&self) -> Vec<u8> {
let mut serialized = Vec::with_capacity(1 + 8 + 1);
self.write(&mut serialized).unwrap();
serialized
}
pub fn read<R: Read>(r: &mut R) -> io::Result<Metadata> {
let subaddress = if read_byte(r)? == 1 { let subaddress = if read_byte(r)? == 1 {
Some( Some(
SubaddressIndex::new(read_u32(r)?, read_u32(r)?) SubaddressIndex::new(read_u32(r)?, read_u32(r)?)
@@ -148,14 +161,19 @@ impl ReceivedOutput {
&self.metadata.arbitrary_data &self.metadata.arbitrary_data
} }
pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
self.absolute.write(w)?;
self.data.write(w)?;
self.metadata.write(w)
}
pub fn serialize(&self) -> Vec<u8> { pub fn serialize(&self) -> Vec<u8> {
let mut serialized = self.absolute.serialize(); let mut serialized = vec![];
serialized.extend(&self.data.serialize()); self.write(&mut serialized).unwrap();
serialized.extend(&self.metadata.serialize());
serialized serialized
} }
pub fn deserialize<R: io::Read>(r: &mut R) -> io::Result<ReceivedOutput> { pub fn read<R: Read>(r: &mut R) -> io::Result<ReceivedOutput> {
Ok(ReceivedOutput { Ok(ReceivedOutput {
absolute: AbsoluteId::read(r)?, absolute: AbsoluteId::read(r)?,
data: OutputData::read(r)?, data: OutputData::read(r)?,
@@ -200,14 +218,19 @@ impl SpendableOutput {
self.output.commitment() self.output.commitment()
} }
pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
self.output.write(w)?;
w.write_all(&self.global_index.to_le_bytes())
}
pub fn serialize(&self) -> Vec<u8> { pub fn serialize(&self) -> Vec<u8> {
let mut serialized = self.output.serialize(); let mut serialized = vec![];
serialized.extend(self.global_index.to_le_bytes()); self.write(&mut serialized).unwrap();
serialized serialized
} }
pub fn read<R: io::Read>(r: &mut R) -> io::Result<SpendableOutput> { pub fn read<R: Read>(r: &mut R) -> io::Result<SpendableOutput> {
Ok(SpendableOutput { output: ReceivedOutput::deserialize(r)?, global_index: read_u64(r)? }) Ok(SpendableOutput { output: ReceivedOutput::read(r)?, global_index: read_u64(r)? })
} }
} }
@@ -248,7 +271,7 @@ impl<O: Clone + Zeroize> Timelocked<O> {
impl Scanner { impl Scanner {
/// Scan a transaction to discover the received outputs. /// Scan a transaction to discover the received outputs.
pub fn scan_transaction(&mut self, tx: &Transaction) -> Timelocked<ReceivedOutput> { pub fn scan_transaction(&mut self, tx: &Transaction) -> Timelocked<ReceivedOutput> {
let extra = Extra::deserialize::<&[u8]>(&mut tx.prefix.extra.as_ref()); let extra = Extra::read::<&[u8]>(&mut tx.prefix.extra.as_ref());
let keys; let keys;
let extra = if let Ok(extra) = extra { let extra = if let Ok(extra) = extra {
keys = extra.keys(); keys = extra.keys();

View File

@@ -311,7 +311,7 @@ impl SignableTransaction {
let mut extra = Extra::new(outputs.iter().map(|output| output.R).collect()); let mut extra = Extra::new(outputs.iter().map(|output| output.R).collect());
let mut id_vec = Vec::with_capacity(1 + 8); let mut id_vec = Vec::with_capacity(1 + 8);
PaymentId::Encrypted(id).serialize(&mut id_vec).unwrap(); PaymentId::Encrypted(id).write(&mut id_vec).unwrap();
extra.push(ExtraField::Nonce(id_vec)); extra.push(ExtraField::Nonce(id_vec));
// Include data if present // Include data if present
@@ -320,7 +320,7 @@ impl SignableTransaction {
} }
let mut serialized = Vec::with_capacity(Extra::fee_weight(outputs.len(), self.data.as_ref())); let mut serialized = Vec::with_capacity(Extra::fee_weight(outputs.len(), self.data.as_ref()));
extra.serialize(&mut serialized).unwrap(); extra.write(&mut serialized).unwrap();
serialized serialized
}; };