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
19pub fn write_byte<W: Write>(byte: &u8, w: &mut W) -> io::Result<()> {
23 w.write_all(&[*byte])
24}
25
26pub fn write_scalar<W: Write>(scalar: &Scalar, w: &mut W) -> io::Result<()> {
28 w.write_all(&scalar.to_bytes())
29}
30
31pub fn write_point<W: Write>(point: &EdwardsPoint, w: &mut W) -> io::Result<()> {
33 CompressedPoint(point.compress().to_bytes()).write(w)
34}
35
36pub 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
48pub 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
58pub 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
65pub fn read_byte<R: Read>(r: &mut R) -> io::Result<u8> {
67 Ok(read_bytes::<_, 1>(r)?[0])
68}
69
70pub fn read_u16<R: Read>(r: &mut R) -> io::Result<u16> {
72 read_bytes(r).map(u16::from_le_bytes)
73}
74
75pub fn read_u32<R: Read>(r: &mut R) -> io::Result<u32> {
77 read_bytes(r).map(u32::from_le_bytes)
78}
79
80pub fn read_u64<R: Read>(r: &mut R) -> io::Result<u64> {
82 read_bytes(r).map(u64::from_le_bytes)
83}
84
85pub 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
94pub 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
102pub 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
115pub 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
127pub 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}