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
95/// Trait for converting raw bytes to/from the internal representation of a
96/// type. For example, field elements are represented in Montgomery form and
97/// serialized/deserialized without Montgomery reduction.
98pub trait SerdeObject: Sized {
99    /// The purpose of unchecked functions is to read the internal memory
100    /// representation of a type from bytes as quickly as possible. No
101    /// sanitization checks are performed to ensure the bytes represent a
102    /// valid object. As such this function should only be used internally
103    /// as an extension of machine memory. It should not be used to deserialize
104    /// externally provided data.
105    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    /// The purpose of unchecked functions is to read the internal memory
111    /// representation of a type from disk as quickly as possible. No
112    /// sanitization checks are performed to ensure the bytes represent a
113    /// valid object. This function should only be used internally when some
114    /// machine state cannot be kept in memory (e.g., between runs)
115    /// and needs to be reloaded as quickly as possible.
116    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    // NOTE: if needed we can add fields for bit positions
176
177    // Secp256k1, Secp256r1 curves should be encoded with
178    Extra, // sign: 0 identity: 1
179
180    // Pasta curves should be encoded with
181    SingleSpare, // sign: 0
182
183    // BN254 curve should be encoded with
184    TwoSpare, // sign: 0, identity: 1
185
186    // BLS12-{381, 377} curves should be encoded with
187    ThreeSpare, // is_compressed: 0, sign: 1, identity: 2
188}
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; // clear flag
211        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            // Most sig byte is always the flag byte when extra byte flag is used
226            CompressedFlagConfig::Extra => self.as_mut().first_mut().unwrap(),
227            _ => match C::Base::ENDIAN {
228                // Least sig byte is the flag byte
229                crate::serde::endian::Endian::LE => self.as_mut().last_mut().unwrap(),
230                // Most sig byte is the flag byte
231                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                // Most sig byte is always the flag byte when extra byte flag is used
310                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        // if is compressed set then it should be set one
323        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        // with extra byte config expect it goes to zero after it is read
330        // otherwise `from_byte` checks if flag or rest unused bytes are zero
331        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                // Most sig byte is always the flag byte when extra byte flag is used
340                <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                // identity flag active
351                Some(is_identity) => {
352                    // identity flag set:
353                    // * x must be zero
354                    // * sign must not be set
355
356                    // identity flag not set:
357                    // * x must not be zero
358
359                    let is_valid = (is_identity & is_zero & !sign) ^ (!is_identity & !is_zero);
360
361                    (is_valid, is_identity)
362                }
363
364                // identitity flag inactive
365                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}