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