monero_io/
lib.rs

1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
2#![doc = include_str!("../README.md")]
3#![deny(missing_docs)]
4#![cfg_attr(not(feature = "std"), no_std)]
5
6use core::fmt::Debug;
7#[allow(unused_imports)]
8use std_shims::prelude::*;
9use std_shims::io::{self, Read, Write};
10
11use curve25519_dalek::{scalar::Scalar, edwards::EdwardsPoint};
12
13mod varint;
14pub use varint::*;
15
16mod compressed_point;
17pub use compressed_point::CompressedPoint;
18
19/// Write a byte.
20///
21/// This is used as a building block within generic functions.
22pub fn write_byte<W: Write>(byte: &u8, w: &mut W) -> io::Result<()> {
23  w.write_all(&[*byte])
24}
25
26/// Write a scalar.
27pub fn write_scalar<W: Write>(scalar: &Scalar, w: &mut W) -> io::Result<()> {
28  w.write_all(&scalar.to_bytes())
29}
30
31/// Write a point.
32pub fn write_point<W: Write>(point: &EdwardsPoint, w: &mut W) -> io::Result<()> {
33  CompressedPoint(point.compress().to_bytes()).write(w)
34}
35
36/// Write a list of elements, without length-prefixing.
37pub fn write_raw_vec<T, W: Write, F: FnMut(&T, &mut W) -> io::Result<()>>(
38  mut f: F,
39  values: &[T],
40  w: &mut W,
41) -> io::Result<()> {
42  for value in values {
43    f(value, w)?;
44  }
45  Ok(())
46}
47
48/// Write a list of elements, with length-prefixing.
49pub fn write_vec<T, W: Write, F: FnMut(&T, &mut W) -> io::Result<()>>(
50  f: F,
51  values: &[T],
52  w: &mut W,
53) -> io::Result<()> {
54  VarInt::write(&values.len(), w)?;
55  write_raw_vec(f, values, w)
56}
57
58/// Read a constant amount of bytes.
59pub fn read_bytes<R: Read, const N: usize>(r: &mut R) -> io::Result<[u8; N]> {
60  let mut res = [0; N];
61  r.read_exact(&mut res)?;
62  Ok(res)
63}
64
65/// Read a single byte.
66pub fn read_byte<R: Read>(r: &mut R) -> io::Result<u8> {
67  Ok(read_bytes::<_, 1>(r)?[0])
68}
69
70/// Read a u16, little-endian encoded.
71pub fn read_u16<R: Read>(r: &mut R) -> io::Result<u16> {
72  read_bytes(r).map(u16::from_le_bytes)
73}
74
75/// Read a u32, little-endian encoded.
76pub fn read_u32<R: Read>(r: &mut R) -> io::Result<u32> {
77  read_bytes(r).map(u32::from_le_bytes)
78}
79
80/// Read a u64, little-endian encoded.
81pub fn read_u64<R: Read>(r: &mut R) -> io::Result<u64> {
82  read_bytes(r).map(u64::from_le_bytes)
83}
84
85/// Read a canonically-encoded scalar.
86///
87/// Some scalars within the Monero protocol are not enforced to be canonically encoded. For such
88/// scalars, they should be represented as `[u8; 32]` and later converted to scalars as relevant.
89pub fn read_scalar<R: Read>(r: &mut R) -> io::Result<Scalar> {
90  Option::from(Scalar::from_canonical_bytes(read_bytes(r)?))
91    .ok_or_else(|| io::Error::other("unreduced scalar"))
92}
93
94/// Read a canonically-encoded Ed25519 point.
95///
96/// This internally calls [`CompressedPoint::decompress`] and has the same definition of canonicity.
97/// This function does not check the resulting point is within the prime-order subgroup.
98pub fn read_point<R: Read>(r: &mut R) -> io::Result<EdwardsPoint> {
99  CompressedPoint::read(r)?.decompress().ok_or_else(|| io::Error::other("invalid point"))
100}
101
102/// Read a variable-length list of elements, without length-prefixing.
103pub fn read_raw_vec<R: Read, T, F: FnMut(&mut R) -> io::Result<T>>(
104  mut f: F,
105  len: usize,
106  r: &mut R,
107) -> io::Result<Vec<T>> {
108  let mut res = vec![];
109  for _ in 0 .. len {
110    res.push(f(r)?);
111  }
112  Ok(res)
113}
114
115/// Read a constant-length list of elements.
116pub fn read_array<R: Read, T: Debug, F: FnMut(&mut R) -> io::Result<T>, const N: usize>(
117  f: F,
118  r: &mut R,
119) -> io::Result<[T; N]> {
120  read_raw_vec(f, N, r).map(|vec| {
121    vec.try_into().expect(
122      "read vector of specific length yet couldn't transform to an array of the same length",
123    )
124  })
125}
126
127/// Read a length-prefixed variable-length list of elements.
128///
129/// An optional bound on the length of the result may be provided. If `None`, the returned `Vec`
130/// will be of the length read off the reader, if successfully read. If `Some(_)`, an error will be
131/// raised if the length read off the read is greater than the bound.
132pub fn read_vec<R: Read, T, F: FnMut(&mut R) -> io::Result<T>>(
133  f: F,
134  length_bound: Option<usize>,
135  r: &mut R,
136) -> io::Result<Vec<T>> {
137  let declared_length: usize = VarInt::read(r)?;
138  if let Some(length_bound) = length_bound {
139    if declared_length > length_bound {
140      Err(io::Error::other("vector exceeds bound on length"))?;
141    }
142  }
143  read_raw_vec(f, declared_length, r)
144}