1use crate::poly::Polynomial;
2use ff::PrimeField;
3use halo2curves::{serde::SerdeObject, CurveAffine};
4use std::io;
56/// This enum specifies how various types are serialized and deserialized.
7#[derive(Clone, Copy, Debug)]
8pub enum SerdeFormat {
9/// Curve elements are serialized in compressed form.
10 /// Field elements are serialized in standard form, with endianness specified by the
11 /// `PrimeField` implementation.
12Processed,
13/// Curve elements are serialized in uncompressed form. Field elements are serialized
14 /// in their internal Montgomery representation.
15 /// When deserializing, checks are performed to ensure curve elements indeed lie on the curve and field elements
16 /// are less than modulus.
17RawBytes,
18/// Serialization is the same as `RawBytes`, but no checks are performed.
19RawBytesUnchecked,
20}
2122// Keep this trait for compatibility with IPA serialization
23pub(crate) trait CurveRead: CurveAffine {
24/// Reads a compressed element from the buffer and attempts to parse it
25 /// using `from_bytes`.
26fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
27let mut compressed = Self::Repr::default();
28 reader.read_exact(compressed.as_mut())?;
29 Option::from(Self::from_bytes(&compressed))
30 .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Invalid point encoding in proof"))
31 }
32}
33impl<C: CurveAffine> CurveRead for C {}
3435pub trait SerdeCurveAffine: CurveAffine + SerdeObject {
36/// Reads an element from the buffer and parses it according to the `format`:
37 /// - `Processed`: Reads a compressed curve element and decompress it
38 /// - `RawBytes`: Reads an uncompressed curve element with coordinates in Montgomery form.
39 /// Checks that field elements are less than modulus, and then checks that the point is on the curve.
40 /// - `RawBytesUnchecked`: Reads an uncompressed curve element with coordinates in Montgomery form;
41 /// does not perform any checks
42fn read<R: io::Read>(reader: &mut R, format: SerdeFormat) -> io::Result<Self> {
43match format {
44 SerdeFormat::Processed => <Self as CurveRead>::read(reader),
45 SerdeFormat::RawBytes => <Self as SerdeObject>::read_raw(reader),
46 SerdeFormat::RawBytesUnchecked => Ok(<Self as SerdeObject>::read_raw_unchecked(reader)),
47 }
48 }
49/// Writes a curve element according to `format`:
50 /// - `Processed`: Writes a compressed curve element
51 /// - Otherwise: Writes an uncompressed curve element with coordinates in Montgomery form
52fn write<W: io::Write>(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()> {
53match format {
54 SerdeFormat::Processed => writer.write_all(self.to_bytes().as_ref()),
55_ => self.write_raw(writer),
56 }
57 }
58}
59impl<C: CurveAffine + SerdeObject> SerdeCurveAffine for C {}
6061pub trait SerdePrimeField: PrimeField + SerdeObject {
62/// Reads a field element as bytes from the buffer according to the `format`:
63 /// - `Processed`: Reads a field element in standard form, with endianness specified by the
64 /// `PrimeField` implementation, and checks that the element is less than the modulus.
65 /// - `RawBytes`: Reads a field element from raw bytes in its internal Montgomery representations,
66 /// and checks that the element is less than the modulus.
67 /// - `RawBytesUnchecked`: Reads a field element in Montgomery form and performs no checks.
68fn read<R: io::Read>(reader: &mut R, format: SerdeFormat) -> io::Result<Self> {
69match format {
70 SerdeFormat::Processed => {
71let mut compressed = Self::Repr::default();
72 reader.read_exact(compressed.as_mut()).unwrap();
73 Option::from(Self::from_repr(compressed)).ok_or_else(|| {
74 io::Error::new(io::ErrorKind::Other, "Invalid prime field point encoding")
75 })
76 }
77 SerdeFormat::RawBytes => <Self as SerdeObject>::read_raw(reader),
78 SerdeFormat::RawBytesUnchecked => Ok(<Self as SerdeObject>::read_raw_unchecked(reader)),
79 }
80 }
8182/// Writes a field element as bytes to the buffer according to the `format`:
83 /// - `Processed`: Writes a field element in standard form, with endianness specified by the
84 /// `PrimeField` implementation.
85 /// - Otherwise: Writes a field element into raw bytes in its internal Montgomery representation,
86 /// WITHOUT performing the expensive Montgomery reduction.
87fn write<W: io::Write>(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()> {
88match format {
89 SerdeFormat::Processed => writer.write_all(self.to_repr().as_ref()),
90_ => self.write_raw(writer),
91 }
92 }
93}
94impl<F: PrimeField + SerdeObject> SerdePrimeField for F {}
9596/// Convert a slice of `bool` into a `u8`.
97///
98/// Panics if the slice has length greater than 8.
99pub fn pack(bits: &[bool]) -> u8 {
100let mut value = 0u8;
101assert!(bits.len() <= 8);
102for (bit_index, bit) in bits.iter().enumerate() {
103 value |= (*bit as u8) << bit_index;
104 }
105 value
106}
107108/// Writes the first `bits.len()` bits of a `u8` into `bits`.
109pub fn unpack(byte: u8, bits: &mut [bool]) {
110for (bit_index, bit) in bits.iter_mut().enumerate() {
111*bit = (byte >> bit_index) & 1 == 1;
112 }
113}
114115/// Reads a vector of polynomials from buffer
116pub(crate) fn read_polynomial_vec<R: io::Read, F: SerdePrimeField, B>(
117 reader: &mut R,
118 format: SerdeFormat,
119) -> Vec<Polynomial<F, B>> {
120let mut len = [0u8; 4];
121 reader.read_exact(&mut len).unwrap();
122let len = u32::from_be_bytes(len);
123124 (0..len)
125 .map(|_| Polynomial::<F, B>::read(reader, format))
126 .collect()
127}
128129/// Writes a slice of polynomials to buffer
130pub(crate) fn write_polynomial_slice<W: io::Write, F: SerdePrimeField, B>(
131 slice: &[Polynomial<F, B>],
132 writer: &mut W,
133 format: SerdeFormat,
134) {
135 writer
136 .write_all(&(slice.len() as u32).to_be_bytes())
137 .unwrap();
138for poly in slice.iter() {
139 poly.write(writer, format);
140 }
141}
142143/// Gets the total number of bytes of a slice of polynomials, assuming all polynomials are the same length
144pub(crate) fn polynomial_slice_byte_length<F: PrimeField, B>(slice: &[Polynomial<F, B>]) -> usize {
145let field_len = F::default().to_repr().as_ref().len();
1464 + slice.len() * (4 + field_len * slice.get(0).map(|poly| poly.len()).unwrap_or(0))
147}