halo2curves/
serde.rs
1use std::{
2 fmt::Debug,
3 io::{self, Read, Write},
4};
5
6#[cfg(feature = "derive_serde")]
7use serde::{Deserialize, Serialize};
8
9#[derive(Clone, Copy, Debug)]
10#[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))]
11pub struct Repr<const T: usize>(
12 #[cfg_attr(feature = "derive_serde", serde(with = "serde_arrays"))] [u8; T],
13);
14
15impl<const T: usize> Repr<T> {
16 pub fn inner(&self) -> &[u8; T] {
17 &self.0
18 }
19}
20
21impl<const T: usize> From<[u8; T]> for Repr<T> {
22 fn from(bytes: [u8; T]) -> Self {
23 Self(bytes)
24 }
25}
26
27impl<'a, const T: usize> From<&'a [u8]> for Repr<T> {
28 fn from(bytes: &[u8]) -> Self {
29 Self(bytes.try_into().unwrap())
30 }
31}
32
33impl<const T: usize> From<Repr<T>> for [u8; T] {
34 fn from(repr: Repr<T>) -> Self {
35 repr.0
36 }
37}
38
39impl<const T: usize> Default for Repr<T> {
40 fn default() -> Self {
41 Self([0u8; T])
42 }
43}
44
45impl<const T: usize> AsMut<[u8]> for Repr<T> {
46 fn as_mut(&mut self) -> &mut [u8] {
47 &mut self.0
48 }
49}
50
51impl<const T: usize> AsRef<[u8]> for Repr<T> {
52 fn as_ref(&self) -> &[u8] {
53 &self.0
54 }
55}
56
57impl<const T: usize> std::ops::Index<std::ops::Range<usize>> for Repr<T> {
58 type Output = [u8];
59
60 fn index(&self, range: std::ops::Range<usize>) -> &Self::Output {
61 &self.0[range]
62 }
63}
64
65impl<const T: usize> std::ops::Index<usize> for Repr<T> {
66 type Output = u8;
67
68 fn index(&self, index: usize) -> &Self::Output {
69 &self.0[index]
70 }
71}
72
73impl<const T: usize> std::ops::Index<std::ops::RangeTo<usize>> for Repr<T> {
74 type Output = [u8];
75
76 fn index(&self, range: std::ops::RangeTo<usize>) -> &Self::Output {
77 &self.0[range]
78 }
79}
80
81impl<const T: usize> std::ops::Index<std::ops::RangeFrom<usize>> for Repr<T> {
82 type Output = [u8];
83
84 fn index(&self, range: std::ops::RangeFrom<usize>) -> &Self::Output {
85 &self.0[range]
86 }
87}
88
89impl<const T: usize> std::ops::IndexMut<std::ops::Range<usize>> for Repr<T> {
90 fn index_mut(&mut self, range: std::ops::Range<usize>) -> &mut Self::Output {
91 &mut self.0[range]
92 }
93}
94
95pub trait SerdeObject: Sized {
99 fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self;
106 fn from_raw_bytes(bytes: &[u8]) -> Option<Self>;
107
108 fn to_raw_bytes(&self) -> Vec<u8>;
109
110 fn read_raw_unchecked<R: Read>(reader: &mut R) -> Self;
117 fn read_raw<R: Read>(reader: &mut R) -> io::Result<Self>;
118
119 fn write_raw<W: Write>(&self, writer: &mut W) -> io::Result<()>;
120}
121
122pub mod endian {
123
124 pub trait EndianRepr: Sized {
125 const ENDIAN: Endian;
126
127 fn to_bytes(&self) -> Vec<u8>;
128
129 fn from_bytes(x: &[u8]) -> subtle::CtOption<Self>;
130 }
131
132 pub enum Endian {
133 LE,
134 BE,
135 }
136
137 impl Endian {
138 pub fn to_bytes(&self, res: &mut [u8], el: &[u64]) {
139 match self {
140 Endian::LE => {
141 el.iter().enumerate().for_each(|(i, limb)| {
142 let off = i * 8;
143 res[off..off + 8].copy_from_slice(&limb.to_le_bytes());
144 });
145 }
146 Endian::BE => {
147 el.iter().rev().enumerate().for_each(|(i, limb)| {
148 let off = i * 8;
149 res[off..off + 8].copy_from_slice(&limb.to_be_bytes());
150 });
151 }
152 }
153 }
154
155 pub fn from_bytes(&self, res: &[u8], el: &mut [u64]) {
156 match self {
157 Endian::LE => {
158 el.iter_mut().enumerate().for_each(|(i, limb)| {
159 let off = i * 8;
160 *limb = u64::from_le_bytes(res[off..off + 8].try_into().unwrap());
161 });
162 }
163 Endian::BE => {
164 el.iter_mut().rev().enumerate().for_each(|(i, limb)| {
165 let off = i * 8;
166 *limb = u64::from_be_bytes(res[off..off + 8].try_into().unwrap());
167 });
168 }
169 }
170 }
171 }
172}
173
174pub(crate) enum CompressedFlagConfig {
175 Extra, SingleSpare, TwoSpare, ThreeSpare, }
189
190impl CompressedFlagConfig {
191 pub(crate) const fn has_extra_byte(&self) -> bool {
192 matches!(self, CompressedFlagConfig::Extra)
193 }
194}
195
196pub(crate) struct Flag {}
197
198impl Flag {
199 fn flag(pos: u8) -> u8 {
200 1 << 7u8.checked_sub(pos).unwrap()
201 }
202
203 fn set(pos: u8, value: bool, flag_byte: &mut u8) {
204 value.then(|| *flag_byte |= Self::flag(pos));
205 }
206
207 fn get(pos: u8, flag_byte: &mut u8) -> subtle::Choice {
208 let flag = Self::flag(pos);
209 let value = (*flag_byte & flag) != 0;
210 *flag_byte &= !flag; subtle::Choice::from(value as u8)
212 }
213}
214
215pub(crate) trait Compressed<C: crate::CurveAffine>:
216 Debug + Copy + Default + AsRef<[u8]> + AsMut<[u8]> + Send + Sync + 'static
217where
218 C::Base: crate::serde::endian::EndianRepr,
219{
220 const CONFIG: CompressedFlagConfig;
221
222 fn flag_byte(&mut self) -> &mut u8 {
223 use crate::serde::endian::EndianRepr;
224 match Self::CONFIG {
225 CompressedFlagConfig::Extra => self.as_mut().first_mut().unwrap(),
227 _ => match C::Base::ENDIAN {
228 crate::serde::endian::Endian::LE => self.as_mut().last_mut().unwrap(),
230 crate::serde::endian::Endian::BE => self.as_mut().first_mut().unwrap(),
232 },
233 }
234 }
235
236 fn sign(y: &C) -> subtle::Choice;
237
238 fn resolve(x: C::Base, sign: subtle::Choice) -> subtle::CtOption<C>;
239
240 fn pos_sign() -> u8 {
241 match Self::CONFIG {
242 CompressedFlagConfig::Extra => 0,
243 CompressedFlagConfig::SingleSpare => 0,
244 CompressedFlagConfig::TwoSpare => 0,
245 CompressedFlagConfig::ThreeSpare => 2,
246 }
247 }
248
249 fn pos_compressed() -> Option<u8> {
250 match Self::CONFIG {
251 CompressedFlagConfig::ThreeSpare => Some(0),
252 _ => None,
253 }
254 }
255
256 fn pos_idetity() -> Option<u8> {
257 match Self::CONFIG {
258 CompressedFlagConfig::Extra => Some(1),
259 CompressedFlagConfig::SingleSpare => None,
260 CompressedFlagConfig::TwoSpare => Some(1),
261 CompressedFlagConfig::ThreeSpare => Some(1),
262 }
263 }
264
265 fn set_sign(&mut self, c: &C) {
266 let sign = bool::from(Self::sign(c));
267 let pos = Self::pos_sign();
268 Flag::set(pos, sign, self.flag_byte());
269 }
270
271 fn set_compressed(&mut self) {
272 if let Some(pos) = Self::pos_compressed() {
273 Flag::set(pos, true, self.flag_byte())
274 }
275 }
276
277 fn set_identity(&mut self, c: &C) {
278 if let Some(pos) = Self::pos_idetity() {
279 Flag::set(pos, bool::from(c.is_identity()), self.flag_byte());
280 };
281 }
282
283 fn get_sign(&mut self) -> subtle::Choice {
284 Flag::get(Self::pos_sign(), self.flag_byte())
285 }
286
287 fn get_is_compressed(&mut self) -> Option<subtle::Choice> {
288 Self::pos_compressed().map(|pos| Flag::get(pos, self.flag_byte()))
289 }
290
291 fn get_is_identity(&mut self) -> Option<subtle::Choice> {
292 Self::pos_idetity().map(|pos| Flag::get(pos, self.flag_byte()))
293 }
294
295 fn set_flags(&mut self, c: &C) {
296 self.set_identity(c);
297 self.set_sign(c);
298 self.set_compressed();
299 }
300
301 fn encode(c: &C) -> Self {
302 use crate::serde::endian::EndianRepr;
303 let mut this = Self::default();
304 let coordinates = c.coordinates().unwrap();
305 let x = coordinates.x();
306 let x_bytes = x.to_bytes();
307 match Self::CONFIG {
308 CompressedFlagConfig::Extra => {
309 this.as_mut()[1..1 + x_bytes.len()].copy_from_slice(&x_bytes)
311 }
312 _ => this.as_mut()[..x_bytes.len()].copy_from_slice(&x_bytes),
313 };
314 this.set_identity(c);
315 this.set_sign(c);
316 this.set_compressed();
317 this
318 }
319
320 fn decode(mut self) -> subtle::CtOption<C> {
321 let is_compressed = self.get_is_compressed();
322 let is_valid_0: subtle::Choice = is_compressed.unwrap_or(subtle::Choice::from(1u8));
324
325 let is_identity = self.get_is_identity();
326
327 let sign = self.get_sign();
328
329 let is_valid_1 = match Self::CONFIG {
332 CompressedFlagConfig::Extra => *self.flag_byte() == 0,
333 _ => true,
334 };
335 let is_valid_1: subtle::Choice = (is_valid_1 as u8).into();
336
337 let x = match Self::CONFIG {
338 CompressedFlagConfig::Extra => {
339 <C::Base as crate::serde::endian::EndianRepr>::from_bytes(&self.as_ref()[1..])
341 }
342 _ => <C::Base as crate::serde::endian::EndianRepr>::from_bytes(self.as_ref()),
343 };
344
345 x.and_then(|x| -> subtle::CtOption<C> {
346 use ff::Field;
347 let is_zero = x.is_zero();
348
349 let (is_valid_2, is_identity) = match is_identity {
350 Some(is_identity) => {
352 let is_valid = (is_identity & is_zero & !sign) ^ (!is_identity & !is_zero);
360
361 (is_valid, is_identity)
362 }
363
364 None => (subtle::Choice::from(1u8), is_zero),
366 };
367
368 let is_valid = is_valid_0 & is_valid_1 & is_valid_2;
369
370 subtle::CtOption::new(C::identity(), is_valid & is_identity)
371 .or_else(|| Self::resolve(x, sign).and_then(|c| subtle::CtOption::new(c, is_valid)))
372 })
373 }
374}