mirror of
https://github.com/serai-dex/serai.git
synced 2024-11-17 09:27:36 +00:00
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:
parent
7508106650
commit
7b0b8a20ec
12 changed files with 219 additions and 186 deletions
|
@ -1,7 +1,7 @@
|
|||
use std::io;
|
||||
use std::io::{self, Write};
|
||||
|
||||
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;
|
||||
while {
|
||||
let mut b = u8::try_from(varint & u64::from(!VARINT_CONTINUATION_MASK)).unwrap();
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::io::{self, Read, Write};
|
||||
|
||||
use crate::{serialize::*, transaction::Transaction};
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
|
@ -10,7 +12,7 @@ pub struct 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.minor_version, w)?;
|
||||
write_varint(&self.timestamp, w)?;
|
||||
|
@ -18,7 +20,13 @@ impl BlockHeader {
|
|||
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 {
|
||||
major_version: read_varint(r)?,
|
||||
minor_version: read_varint(r)?,
|
||||
|
@ -37,9 +45,9 @@ pub struct Block {
|
|||
}
|
||||
|
||||
impl Block {
|
||||
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
|
||||
self.header.serialize(w)?;
|
||||
self.miner_tx.serialize(w)?;
|
||||
pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
self.header.write(w)?;
|
||||
self.miner_tx.write(w)?;
|
||||
write_varint(&self.txs.len().try_into().unwrap(), w)?;
|
||||
for tx in &self.txs {
|
||||
w.write_all(tx)?;
|
||||
|
@ -47,10 +55,16 @@ impl Block {
|
|||
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 {
|
||||
header: BlockHeader::deserialize(r)?,
|
||||
miner_tx: Transaction::deserialize(r)?,
|
||||
header: BlockHeader::read(r)?,
|
||||
miner_tx: Transaction::read(r)?,
|
||||
txs: (0 .. read_varint(r)?).map(|_| read_bytes(r)).collect::<Result<_, _>>()?,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#![allow(non_snake_case)]
|
||||
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
|
||||
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,
|
||||
w: &mut W,
|
||||
specific_write_vec: F,
|
||||
) -> std::io::Result<()> {
|
||||
) -> io::Result<()> {
|
||||
match self {
|
||||
Bulletproofs::Original(bp) => {
|
||||
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<()> {
|
||||
self.serialize_core(w, |points, w| write_raw_vec(write_point, points, w))
|
||||
pub(crate) fn signature_write<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
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<()> {
|
||||
self.serialize_core(w, |points, w| write_vec(write_point, points, w))
|
||||
pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
self.write_core(w, |points, w| write_vec(write_point, points, w))
|
||||
}
|
||||
|
||||
/// Deserialize non-plus Bulletproofs.
|
||||
pub fn deserialize<R: std::io::Read>(r: &mut R) -> std::io::Result<Bulletproofs> {
|
||||
pub fn serialize(&self) -> Vec<u8> {
|
||||
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 {
|
||||
A: read_point(r)?,
|
||||
S: read_point(r)?,
|
||||
|
@ -151,8 +159,8 @@ impl Bulletproofs {
|
|||
}))
|
||||
}
|
||||
|
||||
/// Deserialize Bulletproofs+.
|
||||
pub fn deserialize_plus<R: std::io::Read>(r: &mut R) -> std::io::Result<Bulletproofs> {
|
||||
/// Read Bulletproofs+.
|
||||
pub fn read_plus<R: Read>(r: &mut R) -> io::Result<Bulletproofs> {
|
||||
Ok(Bulletproofs::Plus(PlusStruct {
|
||||
A: read_point(r)?,
|
||||
A1: read_point(r)?,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#![allow(non_snake_case)]
|
||||
|
||||
use core::ops::Deref;
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use thiserror::Error;
|
||||
|
@ -313,13 +314,13 @@ impl Clsag {
|
|||
(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)?;
|
||||
w.write_all(&self.c1.to_bytes())?;
|
||||
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)? })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,18 +41,17 @@ impl ClsagInput {
|
|||
// Doesn't domain separate as this is considered part of the larger CLSAG proof
|
||||
|
||||
// Ring index
|
||||
transcript.append_message(b"ring_index", [self.decoys.i]);
|
||||
transcript.append_message(b"real_spend", [self.decoys.i]);
|
||||
|
||||
// Ring
|
||||
let mut ring = vec![];
|
||||
for pair in &self.decoys.ring {
|
||||
for (i, pair) in self.decoys.ring.iter().enumerate() {
|
||||
// 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
|
||||
// if in use
|
||||
ring.extend(pair[0].compress().to_bytes());
|
||||
ring.extend(pair[1].compress().to_bytes());
|
||||
transcript.append_message(b"member", [u8::try_from(i).expect("ring size exceeded 255")]);
|
||||
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
|
||||
// The only potential malleability would be if the G/H relationship is known breaking the
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use core::ops::Deref;
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
|
@ -35,7 +36,7 @@ impl RctBase {
|
|||
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])?;
|
||||
match rct_type {
|
||||
0 => Ok(()),
|
||||
|
@ -50,10 +51,7 @@ impl RctBase {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn deserialize<R: std::io::Read>(
|
||||
outputs: usize,
|
||||
r: &mut R,
|
||||
) -> std::io::Result<(RctBase, u8)> {
|
||||
pub fn read<R: Read>(outputs: usize, r: &mut R) -> io::Result<(RctBase, u8)> {
|
||||
let rct_type = read_byte(r)?;
|
||||
Ok((
|
||||
if rct_type == 0 {
|
||||
|
@ -96,46 +94,43 @@ impl RctPrunable {
|
|||
(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 {
|
||||
RctPrunable::Null => Ok(()),
|
||||
RctPrunable::Clsag { bulletproofs, clsags, pseudo_outs, .. } => {
|
||||
write_vec(Bulletproofs::serialize, bulletproofs, w)?;
|
||||
write_raw_vec(Clsag::serialize, clsags, w)?;
|
||||
write_vec(Bulletproofs::write, bulletproofs, w)?;
|
||||
write_raw_vec(Clsag::write, clsags, w)?;
|
||||
write_raw_vec(write_point, pseudo_outs, w)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize<R: std::io::Read>(
|
||||
rct_type: u8,
|
||||
decoys: &[usize],
|
||||
r: &mut R,
|
||||
) -> std::io::Result<RctPrunable> {
|
||||
pub fn serialize(&self) -> Vec<u8> {
|
||||
let mut serialized = vec![];
|
||||
self.write(&mut serialized).unwrap();
|
||||
serialized
|
||||
}
|
||||
|
||||
pub fn read<R: Read>(rct_type: u8, decoys: &[usize], r: &mut R) -> io::Result<RctPrunable> {
|
||||
Ok(match rct_type {
|
||||
0 => RctPrunable::Null,
|
||||
5 | 6 => RctPrunable::Clsag {
|
||||
bulletproofs: read_vec(
|
||||
if rct_type == 5 { Bulletproofs::deserialize } else { Bulletproofs::deserialize_plus },
|
||||
if rct_type == 5 { Bulletproofs::read } else { Bulletproofs::read_plus },
|
||||
r,
|
||||
)?,
|
||||
clsags: (0 .. decoys.len())
|
||||
.map(|o| Clsag::deserialize(decoys[o], r))
|
||||
.collect::<Result<_, _>>()?,
|
||||
clsags: (0 .. decoys.len()).map(|o| Clsag::read(decoys[o], r)).collect::<Result<_, _>>()?,
|
||||
pseudo_outs: read_raw_vec(read_point, decoys.len(), r)?,
|
||||
},
|
||||
_ => Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"Tried to deserialize unknown RCT type",
|
||||
))?,
|
||||
_ => Err(io::Error::new(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 {
|
||||
RctPrunable::Null => panic!("Serializing RctPrunable::Null for a signature"),
|
||||
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)
|
||||
}
|
||||
|
||||
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
|
||||
self.base.serialize(w, self.prunable.rct_type())?;
|
||||
self.prunable.serialize(w)
|
||||
pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
self.base.write(w, self.prunable.rct_type())?;
|
||||
self.prunable.write(w)
|
||||
}
|
||||
|
||||
pub fn deserialize<R: std::io::Read>(
|
||||
decoys: Vec<usize>,
|
||||
outputs: usize,
|
||||
r: &mut R,
|
||||
) -> std::io::Result<RctSignatures> {
|
||||
let base = RctBase::deserialize(outputs, r)?;
|
||||
Ok(RctSignatures { base: base.0, prunable: RctPrunable::deserialize(base.1, &decoys, r)? })
|
||||
pub fn serialize(&self) -> Vec<u8> {
|
||||
let mut serialized = vec![];
|
||||
self.write(&mut serialized).unwrap();
|
||||
serialized
|
||||
}
|
||||
|
||||
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)? })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -249,7 +249,7 @@ impl Rpc {
|
|||
.txs
|
||||
.iter()
|
||||
.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 })?
|
||||
.as_ref(),
|
||||
)
|
||||
|
@ -312,8 +312,7 @@ impl Rpc {
|
|||
let res: BlockResponse =
|
||||
self.json_rpc_call("get_block", Some(json!({ "hash": hex::encode(hash) }))).await?;
|
||||
|
||||
Block::deserialize::<&[u8]>(&mut rpc_hex(&res.blob)?.as_ref())
|
||||
.map_err(|_| RpcError::InvalidNode)
|
||||
Block::read::<&[u8]>(&mut rpc_hex(&res.blob)?.as_ref()).map_err(|_| RpcError::InvalidNode)
|
||||
}
|
||||
|
||||
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);
|
||||
tx.serialize(&mut buf).unwrap();
|
||||
tx.write(&mut buf).unwrap();
|
||||
let res: SendRawResponse = self
|
||||
.rpc_call("send_raw_transaction", Some(json!({ "tx_as_hex": hex::encode(&buf) })))
|
||||
.await?;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::io;
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
use curve25519_dalek::{
|
||||
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
|
||||
}
|
||||
|
||||
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])
|
||||
}
|
||||
|
||||
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;
|
||||
while {
|
||||
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(())
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
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,
|
||||
values: &[T],
|
||||
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(())
|
||||
}
|
||||
|
||||
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,
|
||||
values: &[T],
|
||||
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)
|
||||
}
|
||||
|
||||
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];
|
||||
r.read_exact(&mut 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])
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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 res = 0;
|
||||
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
|
||||
// https://github.com/monero-project/monero/issues/8438, where some scalars had an archaic
|
||||
// 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)?)
|
||||
.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)?;
|
||||
CompressedEdwardsY(bytes)
|
||||
.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"))
|
||||
}
|
||||
|
||||
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)
|
||||
.ok()
|
||||
.filter(|point| point.is_torsion_free())
|
||||
.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,
|
||||
len: usize,
|
||||
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)
|
||||
}
|
||||
|
||||
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,
|
||||
r: &mut R,
|
||||
) -> io::Result<Vec<T>> {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use core::cmp::Ordering;
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
use zeroize::Zeroize;
|
||||
|
||||
|
@ -27,7 +28,7 @@ impl Input {
|
|||
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 {
|
||||
Input::Gen(height) => {
|
||||
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)? {
|
||||
255 => Input::Gen(read_varint(r)?),
|
||||
2 => Input::ToKey {
|
||||
|
@ -51,10 +52,9 @@ impl Input {
|
|||
key_offsets: read_vec(read_varint, r)?,
|
||||
key_image: read_torsion_free_point(r)?,
|
||||
},
|
||||
_ => Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
"Tried to deserialize unknown/unused input type",
|
||||
))?,
|
||||
_ => {
|
||||
Err(io::Error::new(io::ErrorKind::Other, "Tried to deserialize unknown/unused input type"))?
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ impl Output {
|
|||
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)?;
|
||||
w.write_all(&[2 + u8::from(self.view_tag.is_some())])?;
|
||||
w.write_all(&self.key.to_bytes())?;
|
||||
|
@ -82,13 +82,13 @@ impl Output {
|
|||
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 view_tag = match read_byte(r)? {
|
||||
2 => false,
|
||||
3 => true,
|
||||
_ => Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
_ => Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"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(
|
||||
&match self {
|
||||
Timelock::None => 0,
|
||||
|
@ -163,21 +163,21 @@ impl TransactionPrefix {
|
|||
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)?;
|
||||
self.timelock.serialize(w)?;
|
||||
write_vec(Input::serialize, &self.inputs, w)?;
|
||||
write_vec(Output::serialize, &self.outputs, w)?;
|
||||
self.timelock.write(w)?;
|
||||
write_vec(Input::write, &self.inputs, w)?;
|
||||
write_vec(Output::write, &self.outputs, w)?;
|
||||
write_varint(&self.extra.len().try_into().unwrap(), w)?;
|
||||
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 {
|
||||
version: read_varint(r)?,
|
||||
timelock: Timelock::from_raw(read_varint(r)?),
|
||||
inputs: read_vec(Input::deserialize, r)?,
|
||||
outputs: read_vec(Output::deserialize, r)?,
|
||||
inputs: read_vec(Input::read, r)?,
|
||||
outputs: read_vec(Output::read, r)?,
|
||||
extra: vec![],
|
||||
};
|
||||
prefix.extra = read_vec(read_byte, r)?;
|
||||
|
@ -204,8 +204,8 @@ impl Transaction {
|
|||
RctSignatures::fee_weight(protocol, inputs, outputs)
|
||||
}
|
||||
|
||||
pub fn serialize<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
|
||||
self.prefix.serialize(w)?;
|
||||
pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
self.prefix.write(w)?;
|
||||
if self.prefix.version == 1 {
|
||||
for sig in &self.signatures {
|
||||
write_scalar(&sig.0, w)?;
|
||||
|
@ -213,14 +213,14 @@ impl Transaction {
|
|||
}
|
||||
Ok(())
|
||||
} else if self.prefix.version == 2 {
|
||||
self.rct_signatures.serialize(w)
|
||||
self.rct_signatures.write(w)
|
||||
} else {
|
||||
panic!("Serializing a transaction with an unknown version");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize<R: std::io::Read>(r: &mut R) -> std::io::Result<Transaction> {
|
||||
let prefix = TransactionPrefix::deserialize(r)?;
|
||||
pub fn read<R: Read>(r: &mut R) -> io::Result<Transaction> {
|
||||
let prefix = TransactionPrefix::read(r)?;
|
||||
let mut signatures = vec![];
|
||||
let mut rct_signatures = RctSignatures {
|
||||
base: RctBase { fee: 0, ecdh_info: vec![], commitments: vec![] },
|
||||
|
@ -241,7 +241,7 @@ impl Transaction {
|
|||
.sum::<u64>()
|
||||
.saturating_sub(prefix.outputs.iter().map(|output| output.amount).sum());
|
||||
} else if prefix.version == 2 {
|
||||
rct_signatures = RctSignatures::deserialize(
|
||||
rct_signatures = RctSignatures::read(
|
||||
prefix
|
||||
.inputs
|
||||
.iter()
|
||||
|
@ -254,64 +254,56 @@ impl Transaction {
|
|||
r,
|
||||
)?;
|
||||
} 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 })
|
||||
}
|
||||
|
||||
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 {
|
||||
self.serialize(&mut serialized).unwrap();
|
||||
hash(&serialized)
|
||||
self.write(&mut buf).unwrap();
|
||||
hash(&buf)
|
||||
} else {
|
||||
let mut sig_hash = Vec::with_capacity(96);
|
||||
let mut hashes = Vec::with_capacity(96);
|
||||
|
||||
self.prefix.serialize(&mut serialized).unwrap();
|
||||
sig_hash.extend(hash(&serialized));
|
||||
serialized.clear();
|
||||
self.prefix.write(&mut buf).unwrap();
|
||||
hashes.extend(hash(&buf));
|
||||
buf.clear();
|
||||
|
||||
self
|
||||
.rct_signatures
|
||||
.base
|
||||
.serialize(&mut serialized, self.rct_signatures.prunable.rct_type())
|
||||
.unwrap();
|
||||
sig_hash.extend(hash(&serialized));
|
||||
serialized.clear();
|
||||
self.rct_signatures.base.write(&mut buf, self.rct_signatures.prunable.rct_type()).unwrap();
|
||||
hashes.extend(hash(&buf));
|
||||
buf.clear();
|
||||
|
||||
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();
|
||||
serialized = hash(&serialized).to_vec();
|
||||
self.rct_signatures.prunable.write(&mut buf).unwrap();
|
||||
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.
|
||||
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);
|
||||
|
||||
self.prefix.serialize(&mut serialized).unwrap();
|
||||
sig_hash.extend(hash(&serialized));
|
||||
serialized.clear();
|
||||
self.prefix.write(&mut buf).unwrap();
|
||||
sig_hash.extend(hash(&buf));
|
||||
buf.clear();
|
||||
|
||||
self
|
||||
.rct_signatures
|
||||
.base
|
||||
.serialize(&mut serialized, self.rct_signatures.prunable.rct_type())
|
||||
.unwrap();
|
||||
sig_hash.extend(hash(&serialized));
|
||||
serialized.clear();
|
||||
self.rct_signatures.base.write(&mut buf, self.rct_signatures.prunable.rct_type()).unwrap();
|
||||
sig_hash.extend(hash(&buf));
|
||||
buf.clear();
|
||||
|
||||
self.rct_signatures.prunable.signature_serialize(&mut serialized).unwrap();
|
||||
sig_hash.extend(hash(&serialized));
|
||||
self.rct_signatures.prunable.signature_write(&mut buf).unwrap();
|
||||
sig_hash.extend(hash(&buf));
|
||||
|
||||
hash(&sig_hash)
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ impl BitXor<[u8; 8]> for 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 {
|
||||
PaymentId::Unencrypted(id) => {
|
||||
w.write_all(&[0])?;
|
||||
|
@ -46,7 +46,7 @@ impl PaymentId {
|
|||
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)? {
|
||||
0 => PaymentId::Unencrypted(read_bytes(r)?),
|
||||
1 => PaymentId::Encrypted(read_bytes(r)?),
|
||||
|
@ -65,7 +65,7 @@ pub(crate) enum 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 {
|
||||
ExtraField::PublicKey(key) => {
|
||||
w.write_all(&[1])?;
|
||||
|
@ -88,7 +88,7 @@ impl ExtraField {
|
|||
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)? {
|
||||
1 => ExtraField::PublicKey(read_point(r)?),
|
||||
2 => ExtraField::Nonce({
|
||||
|
@ -127,7 +127,7 @@ impl Extra {
|
|||
pub(crate) fn payment_id(&self) -> Option<PaymentId> {
|
||||
for field in &self.0 {
|
||||
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
|
||||
|
@ -176,18 +176,18 @@ impl Extra {
|
|||
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 {
|
||||
field.serialize(w)?;
|
||||
field.write(w)?;
|
||||
}
|
||||
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 field;
|
||||
while {
|
||||
field = ExtraField::deserialize(r);
|
||||
field = ExtraField::read(r);
|
||||
field.is_ok()
|
||||
} {
|
||||
res.0.push(field.unwrap());
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::io;
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
|
@ -24,14 +24,18 @@ pub struct AbsoluteId {
|
|||
}
|
||||
|
||||
impl AbsoluteId {
|
||||
pub fn serialize(&self) -> Vec<u8> {
|
||||
let mut res = Vec::with_capacity(32 + 1);
|
||||
res.extend(self.tx);
|
||||
res.push(self.o);
|
||||
res
|
||||
pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
w.write_all(&self.tx)?;
|
||||
w.write_all(&[self.o])
|
||||
}
|
||||
|
||||
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)? })
|
||||
}
|
||||
}
|
||||
|
@ -46,16 +50,20 @@ pub struct OutputData {
|
|||
}
|
||||
|
||||
impl OutputData {
|
||||
pub fn serialize(&self) -> Vec<u8> {
|
||||
let mut res = Vec::with_capacity(32 + 32 + 40);
|
||||
res.extend(self.key.compress().to_bytes());
|
||||
res.extend(self.key_offset.to_bytes());
|
||||
res.extend(self.commitment.mask.to_bytes());
|
||||
res.extend(self.commitment.amount.to_le_bytes());
|
||||
res
|
||||
pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
w.write_all(&self.key.compress().to_bytes())?;
|
||||
w.write_all(&self.key_offset.to_bytes())?;
|
||||
w.write_all(&self.commitment.mask.to_bytes())?;
|
||||
w.write_all(&self.commitment.amount.to_le_bytes())
|
||||
}
|
||||
|
||||
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 {
|
||||
key: read_point(r)?,
|
||||
key_offset: read_scalar(r)?,
|
||||
|
@ -79,26 +87,31 @@ pub struct Metadata {
|
|||
}
|
||||
|
||||
impl Metadata {
|
||||
pub fn serialize(&self) -> Vec<u8> {
|
||||
let mut res = Vec::with_capacity(4 + 4 + 8 + 1);
|
||||
pub fn write<W: Write>(&self, w: &mut W) -> io::Result<()> {
|
||||
if let Some(subaddress) = self.subaddress {
|
||||
res.push(1);
|
||||
res.extend(subaddress.account().to_le_bytes());
|
||||
res.extend(subaddress.address().to_le_bytes());
|
||||
w.write_all(&[1])?;
|
||||
w.write_all(&subaddress.account().to_le_bytes())?;
|
||||
w.write_all(&subaddress.address().to_le_bytes())?;
|
||||
} 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 {
|
||||
res.extend([u8::try_from(part.len()).unwrap()]);
|
||||
res.extend(part);
|
||||
w.write_all(&[u8::try_from(part.len()).unwrap()])?;
|
||||
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 {
|
||||
Some(
|
||||
SubaddressIndex::new(read_u32(r)?, read_u32(r)?)
|
||||
|
@ -148,14 +161,19 @@ impl ReceivedOutput {
|
|||
&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> {
|
||||
let mut serialized = self.absolute.serialize();
|
||||
serialized.extend(&self.data.serialize());
|
||||
serialized.extend(&self.metadata.serialize());
|
||||
let mut serialized = vec![];
|
||||
self.write(&mut serialized).unwrap();
|
||||
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 {
|
||||
absolute: AbsoluteId::read(r)?,
|
||||
data: OutputData::read(r)?,
|
||||
|
@ -200,14 +218,19 @@ impl SpendableOutput {
|
|||
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> {
|
||||
let mut serialized = self.output.serialize();
|
||||
serialized.extend(self.global_index.to_le_bytes());
|
||||
let mut serialized = vec![];
|
||||
self.write(&mut serialized).unwrap();
|
||||
serialized
|
||||
}
|
||||
|
||||
pub fn read<R: io::Read>(r: &mut R) -> io::Result<SpendableOutput> {
|
||||
Ok(SpendableOutput { output: ReceivedOutput::deserialize(r)?, global_index: read_u64(r)? })
|
||||
pub fn read<R: Read>(r: &mut R) -> io::Result<SpendableOutput> {
|
||||
Ok(SpendableOutput { output: ReceivedOutput::read(r)?, global_index: read_u64(r)? })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -248,7 +271,7 @@ impl<O: Clone + Zeroize> Timelocked<O> {
|
|||
impl Scanner {
|
||||
/// Scan a transaction to discover the received outputs.
|
||||
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 extra = if let Ok(extra) = extra {
|
||||
keys = extra.keys();
|
||||
|
|
|
@ -311,7 +311,7 @@ impl SignableTransaction {
|
|||
let mut extra = Extra::new(outputs.iter().map(|output| output.R).collect());
|
||||
|
||||
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));
|
||||
|
||||
// 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()));
|
||||
extra.serialize(&mut serialized).unwrap();
|
||||
extra.write(&mut serialized).unwrap();
|
||||
serialized
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue