zcash_encoding/
lib.rs

1//! *Zcash binary encodings.*
2//!
3//! `zcash_encoding` is a library that provides common encoding and decoding operations
4//! for stable binary encodings used throughout the Zcash ecosystem.
5
6#![no_std]
7// Catch documentation errors caused by code changes.
8#![deny(rustdoc::broken_intra_doc_links)]
9#![deny(missing_docs)]
10#![deny(unsafe_code)]
11
12#[cfg_attr(test, macro_use)]
13extern crate alloc;
14
15use alloc::vec::Vec;
16
17use core::iter::FromIterator;
18use core2::io::{self, Read, Write};
19
20use nonempty::NonEmpty;
21
22/// The maximum allowed value representable as a `[CompactSize]`
23pub const MAX_COMPACT_SIZE: u32 = 0x02000000;
24
25/// Namespace for functions for compact encoding of integers.
26///
27/// This codec requires integers to be in the range `0x0..=0x02000000`, for compatibility
28/// with Zcash consensus rules.
29pub struct CompactSize;
30
31impl CompactSize {
32    /// Reads an integer encoded in compact form.
33    pub fn read<R: Read>(mut reader: R) -> io::Result<u64> {
34        let mut flag_bytes = [0; 1];
35        reader.read_exact(&mut flag_bytes)?;
36        let flag = flag_bytes[0];
37
38        let result = if flag < 253 {
39            Ok(flag as u64)
40        } else if flag == 253 {
41            let mut bytes = [0; 2];
42            reader.read_exact(&mut bytes)?;
43            match u16::from_le_bytes(bytes) {
44                n if n < 253 => Err(io::Error::new(
45                    io::ErrorKind::InvalidInput,
46                    "non-canonical CompactSize",
47                )),
48                n => Ok(n as u64),
49            }
50        } else if flag == 254 {
51            let mut bytes = [0; 4];
52            reader.read_exact(&mut bytes)?;
53            match u32::from_le_bytes(bytes) {
54                n if n < 0x10000 => Err(io::Error::new(
55                    io::ErrorKind::InvalidInput,
56                    "non-canonical CompactSize",
57                )),
58                n => Ok(n as u64),
59            }
60        } else {
61            let mut bytes = [0; 8];
62            reader.read_exact(&mut bytes)?;
63            match u64::from_le_bytes(bytes) {
64                n if n < 0x100000000 => Err(io::Error::new(
65                    io::ErrorKind::InvalidInput,
66                    "non-canonical CompactSize",
67                )),
68                n => Ok(n),
69            }
70        }?;
71
72        match result {
73            s if s > <u64>::from(MAX_COMPACT_SIZE) => Err(io::Error::new(
74                io::ErrorKind::InvalidInput,
75                "CompactSize too large",
76            )),
77            s => Ok(s),
78        }
79    }
80
81    /// Reads an integer encoded in contact form and performs checked conversion
82    /// to the target type.
83    pub fn read_t<R: Read, T: TryFrom<u64>>(mut reader: R) -> io::Result<T> {
84        let n = Self::read(&mut reader)?;
85        <T>::try_from(n).map_err(|_| {
86            io::Error::new(
87                io::ErrorKind::InvalidInput,
88                "CompactSize value exceeds range of target type.",
89            )
90        })
91    }
92
93    /// Writes the provided `usize` value to the provided Writer in compact form.
94    pub fn write<W: Write>(mut writer: W, size: usize) -> io::Result<()> {
95        match size {
96            s if s < 253 => writer.write_all(&[s as u8]),
97            s if s <= 0xFFFF => {
98                writer.write_all(&[253])?;
99                writer.write_all(&(s as u16).to_le_bytes())
100            }
101            s if s <= 0xFFFFFFFF => {
102                writer.write_all(&[254])?;
103                writer.write_all(&(s as u32).to_le_bytes())
104            }
105            s => {
106                writer.write_all(&[255])?;
107                writer.write_all(&(s as u64).to_le_bytes())
108            }
109        }
110    }
111
112    /// Returns the number of bytes needed to encode the given size in compact form.
113    pub fn serialized_size(size: usize) -> usize {
114        match size {
115            s if s < 253 => 1,
116            s if s <= 0xFFFF => 3,
117            s if s <= 0xFFFFFFFF => 5,
118            _ => 9,
119        }
120    }
121}
122
123/// Namespace for functions that perform encoding of vectors.
124///
125/// The length of a vector is restricted to at most `0x02000000`, for compatibility with
126/// the Zcash consensus rules.
127pub struct Vector;
128
129impl Vector {
130    /// Reads a vector, assuming the encoding written by [`Vector::write`], using the provided
131    /// function to decode each element of the vector.
132    pub fn read<R: Read, E, F>(reader: R, func: F) -> io::Result<Vec<E>>
133    where
134        F: Fn(&mut R) -> io::Result<E>,
135    {
136        Self::read_collected(reader, func)
137    }
138
139    /// Reads a CompactSize-prefixed series of elements into a collection, assuming the encoding
140    /// written by [`Vector::write`], using the provided function to decode each element.
141    pub fn read_collected<R: Read, E, F, O: FromIterator<E>>(reader: R, func: F) -> io::Result<O>
142    where
143        F: Fn(&mut R) -> io::Result<E>,
144    {
145        Self::read_collected_mut(reader, func)
146    }
147
148    /// Reads a CompactSize-prefixed series of elements into a collection, assuming the encoding
149    /// written by [`Vector::write`], using the provided function to decode each element.
150    pub fn read_collected_mut<R: Read, E, F, O: FromIterator<E>>(
151        mut reader: R,
152        func: F,
153    ) -> io::Result<O>
154    where
155        F: FnMut(&mut R) -> io::Result<E>,
156    {
157        let count: usize = CompactSize::read_t(&mut reader)?;
158        Array::read_collected_mut(reader, count, func)
159    }
160
161    /// Writes a slice of values by writing [`CompactSize`]-encoded integer specifying the length
162    /// of the slice to the stream, followed by the encoding of each element of the slice as
163    /// performed by the provided function.
164    pub fn write<W: Write, E, F>(writer: W, vec: &[E], func: F) -> io::Result<()>
165    where
166        F: Fn(&mut W, &E) -> io::Result<()>,
167    {
168        Self::write_sized(writer, vec.iter(), func)
169    }
170
171    /// Writes a NonEmpty container of values to the stream using the same encoding as
172    /// `[Vector::write]`
173    pub fn write_nonempty<W: Write, E, F>(
174        mut writer: W,
175        vec: &NonEmpty<E>,
176        func: F,
177    ) -> io::Result<()>
178    where
179        F: Fn(&mut W, &E) -> io::Result<()>,
180    {
181        CompactSize::write(&mut writer, vec.len())?;
182        vec.iter().try_for_each(|e| func(&mut writer, e))
183    }
184
185    /// Writes an iterator of values by writing [`CompactSize`]-encoded integer specifying
186    /// the length of the iterator to the stream, followed by the encoding of each element
187    /// of the iterator as performed by the provided function.
188    pub fn write_sized<W: Write, E, F, I: Iterator<Item = E> + ExactSizeIterator>(
189        mut writer: W,
190        mut items: I,
191        func: F,
192    ) -> io::Result<()>
193    where
194        F: Fn(&mut W, E) -> io::Result<()>,
195    {
196        CompactSize::write(&mut writer, items.len())?;
197        items.try_for_each(|e| func(&mut writer, e))
198    }
199
200    /// Returns the serialized size of a vector of `u8` as written by `[Vector::write]`.
201    pub fn serialized_size_of_u8_vec(vec: &[u8]) -> usize {
202        let length = vec.len();
203        CompactSize::serialized_size(length) + length
204    }
205}
206
207/// Namespace for functions that perform encoding of array contents.
208///
209/// This is similar to the [`Vector`] encoding except that no length information is
210/// written as part of the encoding, so length must be statically known or obtained from
211/// other parts of the input stream.
212pub struct Array;
213
214impl Array {
215    /// Reads `count` elements from a stream into a vector, assuming the encoding written by
216    /// [`Array::write`], using the provided function to decode each element.
217    pub fn read<R: Read, E, F>(reader: R, count: usize, func: F) -> io::Result<Vec<E>>
218    where
219        F: Fn(&mut R) -> io::Result<E>,
220    {
221        Self::read_collected(reader, count, func)
222    }
223
224    /// Reads `count` elements into a collection, assuming the encoding written by
225    /// [`Array::write`], using the provided function to decode each element.
226    pub fn read_collected<R: Read, E, F, O: FromIterator<E>>(
227        reader: R,
228        count: usize,
229        func: F,
230    ) -> io::Result<O>
231    where
232        F: Fn(&mut R) -> io::Result<E>,
233    {
234        Self::read_collected_mut(reader, count, func)
235    }
236
237    /// Reads `count` elements into a collection, assuming the encoding written by
238    /// [`Array::write`], using the provided function to decode each element.
239    pub fn read_collected_mut<R: Read, E, F, O: FromIterator<E>>(
240        mut reader: R,
241        count: usize,
242        mut func: F,
243    ) -> io::Result<O>
244    where
245        F: FnMut(&mut R) -> io::Result<E>,
246    {
247        (0..count).map(|_| func(&mut reader)).collect()
248    }
249
250    /// Writes an iterator full of values to a stream by sequentially
251    /// encoding each element using the provided function.
252    pub fn write<W: Write, E, I: IntoIterator<Item = E>, F>(
253        mut writer: W,
254        vec: I,
255        func: F,
256    ) -> io::Result<()>
257    where
258        F: Fn(&mut W, &E) -> io::Result<()>,
259    {
260        vec.into_iter().try_for_each(|e| func(&mut writer, &e))
261    }
262}
263
264/// Namespace for functions that perform encoding of [`Option`] values.
265pub struct Optional;
266
267impl Optional {
268    /// Reads an optional value, assuming the encoding written by [`Optional::write`], using the
269    /// provided function to decode the contained element if present.
270    pub fn read<R: Read, T, F>(mut reader: R, func: F) -> io::Result<Option<T>>
271    where
272        F: Fn(R) -> io::Result<T>,
273    {
274        let mut bytes = [0; 1];
275        reader.read_exact(&mut bytes)?;
276        match bytes[0] {
277            0 => Ok(None),
278            1 => Ok(Some(func(reader)?)),
279            _ => Err(io::Error::new(
280                io::ErrorKind::InvalidInput,
281                "non-canonical Option<T>",
282            )),
283        }
284    }
285
286    /// Writes an optional value to a stream by writing a flag byte with a value of 0 if no value
287    /// is present, or 1 if there is a value, followed by the encoding of the contents of the
288    /// option as performed by the provided function.
289    pub fn write<W: Write, T, F>(mut writer: W, val: Option<T>, func: F) -> io::Result<()>
290    where
291        F: Fn(W, T) -> io::Result<()>,
292    {
293        match val {
294            None => writer.write_all(&[0]),
295            Some(e) => {
296                writer.write_all(&[1])?;
297                func(writer, e)
298            }
299        }
300    }
301}
302
303#[cfg(test)]
304mod tests {
305    use super::*;
306    use core::fmt::Debug;
307
308    #[test]
309    fn compact_size() {
310        fn eval<T: TryFrom<u64> + TryInto<usize> + Eq + Debug + Copy>(value: T, expected: &[u8])
311        where
312            <T as TryInto<usize>>::Error: Debug,
313        {
314            let mut data = vec![];
315            let value_usize: usize = value.try_into().unwrap();
316            CompactSize::write(&mut data, value_usize).unwrap();
317            assert_eq!(&data[..], expected);
318            let serialized_size = CompactSize::serialized_size(value_usize);
319            assert_eq!(serialized_size, expected.len());
320            let result: io::Result<T> = CompactSize::read_t(&data[..]);
321            match result {
322                Ok(n) => assert_eq!(n, value),
323                Err(e) => panic!("Unexpected error: {:?}", e),
324            }
325        }
326
327        eval(0, &[0]);
328        eval(1, &[1]);
329        eval(252, &[252]);
330        eval(253, &[253, 253, 0]);
331        eval(254, &[253, 254, 0]);
332        eval(255, &[253, 255, 0]);
333        eval(256, &[253, 0, 1]);
334        eval(256, &[253, 0, 1]);
335        eval(65535, &[253, 255, 255]);
336        eval(65536, &[254, 0, 0, 1, 0]);
337        eval(65537, &[254, 1, 0, 1, 0]);
338
339        eval(33554432, &[254, 0, 0, 0, 2]);
340
341        {
342            let value = 33554433;
343            let encoded = &[254, 1, 0, 0, 2][..];
344            let mut data = vec![];
345            CompactSize::write(&mut data, value).unwrap();
346            assert_eq!(&data[..], encoded);
347            let serialized_size = CompactSize::serialized_size(value);
348            assert_eq!(serialized_size, encoded.len());
349            assert!(CompactSize::read(encoded).is_err());
350        }
351    }
352
353    #[allow(clippy::useless_vec)]
354    #[test]
355    fn vector() {
356        macro_rules! eval {
357            ($value:expr, $expected:expr) => {
358                let mut data = vec![];
359                Vector::write(&mut data, &$value, |w, e| w.write_all(&[*e])).unwrap();
360                assert_eq!(&data[..], &$expected[..]);
361                let serialized_size = Vector::serialized_size_of_u8_vec(&$value);
362                assert_eq!(serialized_size, $expected.len());
363                match Vector::read(&data[..], |r| {
364                    let mut bytes = [0; 1];
365                    r.read_exact(&mut bytes).map(|_| bytes[0])
366                }) {
367                    Ok(v) => assert_eq!(v, $value),
368                    Err(e) => panic!("Unexpected error: {:?}", e),
369                }
370            };
371        }
372
373        eval!(vec![], [0]);
374        eval!(vec![0], [1, 0]);
375        eval!(vec![1], [1, 1]);
376        eval!(vec![5; 8], [8, 5, 5, 5, 5, 5, 5, 5, 5]);
377
378        {
379            // expected = [253, 4, 1, 7, 7, 7, ...]
380            let mut expected = vec![7; 263];
381            expected[0] = 253;
382            expected[1] = 4;
383            expected[2] = 1;
384
385            eval!(vec![7; 260], expected);
386        }
387    }
388
389    #[test]
390    fn optional() {
391        macro_rules! eval {
392            ($value:expr, $expected:expr, $write:expr, $read:expr) => {
393                let mut data = vec![];
394                Optional::write(&mut data, $value, $write).unwrap();
395                assert_eq!(&data[..], &$expected[..]);
396                match Optional::read(&data[..], $read) {
397                    Ok(v) => assert_eq!(v, $value),
398                    Err(e) => panic!("Unexpected error: {:?}", e),
399                }
400            };
401        }
402
403        macro_rules! eval_u8 {
404            ($value:expr, $expected:expr) => {
405                eval!($value, $expected, |w, e| w.write_all(&[e]), |mut r| {
406                    let mut bytes = [0; 1];
407                    r.read_exact(&mut bytes).map(|_| bytes[0])
408                })
409            };
410        }
411
412        macro_rules! eval_vec {
413            ($value:expr, $expected:expr) => {
414                eval!(
415                    $value,
416                    $expected,
417                    |w, v| Vector::write(w, &v, |w, e| w.write_all(&[*e])),
418                    |r| Vector::read(r, |r| {
419                        let mut bytes = [0; 1];
420                        r.read_exact(&mut bytes).map(|_| bytes[0])
421                    })
422                )
423            };
424        }
425
426        eval_u8!(None, [0]);
427        eval_u8!(Some(0), [1, 0]);
428        eval_u8!(Some(1), [1, 1]);
429        eval_u8!(Some(5), [1, 5]);
430
431        eval_vec!(None as Option<Vec<_>>, [0]);
432        eval_vec!(Some(vec![]), [1, 0]);
433        eval_vec!(Some(vec![0]), [1, 1, 0]);
434        eval_vec!(Some(vec![1]), [1, 1, 1]);
435        eval_vec!(Some(vec![5; 8]), [1, 8, 5, 5, 5, 5, 5, 5, 5, 5]);
436    }
437}