|
1 | | -//! Maps for encoding prover messages and decoding verifier messages. |
| 1 | +//! Re-exports of the Argus-owned transcript codec traits. |
2 | 2 |
|
3 | | -/// Marker trait for types that have encoding and decoding maps. |
4 | | -/// |
5 | | -/// A type is a [`Codec`] if it implements [`Encoding`], [`Decoding`], |
6 | | -/// [`NargSerialize`][crate::io::NargSerialize], and [`NargDeserialize`][crate::io::NargDeserialize] |
7 | | -/// |
8 | | -/// # Derive Macros |
9 | | -/// |
10 | | -/// With the `derive` feature enabled: |
11 | | -/// |
12 | | -/// ``` |
13 | | -/// # #[cfg(feature = "derive")] |
14 | | -/// # { |
15 | | -/// use spongefish::Codec; |
16 | | -/// |
17 | | -/// #[derive(Codec)] |
18 | | -/// struct MyStruct { |
19 | | -/// field1: u32, |
20 | | -/// field2: u32, |
21 | | -/// #[spongefish(skip)] // Skip this field (uses Default) |
22 | | -/// cached: Option<String>, |
23 | | -/// } |
24 | | -/// # } |
25 | | -/// ``` |
26 | | -/// |
27 | | -/// Equivalent to deriving `Encoding`, `Decoding`, and `NargDeserialize`. Fields marked with |
28 | | -/// `#[spongefish(skip)]` are initialized via `Default`. |
29 | | -pub trait Codec<T = [u8]>: |
30 | | - crate::NargDeserialize + crate::NargSerialize + Encoding<T> + Decoding<T> |
31 | | -where |
32 | | - T: ?Sized, |
33 | | -{ |
34 | | -} |
35 | | - |
36 | | -/// Interface for turning a type into a duplex sponge input. |
37 | | -/// |
38 | | -/// [`Encoding<T>`] defines an encoding into a type `T`. |
39 | | -/// By default `T = [u8]` in order to serve encoding for byte-oriented hash functions. |
40 | | -/// |
41 | | -/// # Safety |
42 | | -/// |
43 | | -/// [`spongefish`][`crate`] assumes that prover and verifier will know the length of all the prover messages. |
44 | | -/// [`Encoding`] must be **prefix-free**: the output of [`Encoding::encode`] is never a prefix of any other |
45 | | -/// instance of the same type. |
46 | | -/// |
47 | | -/// More information on the theoretical requirements is in [[CO25], Theorem 6.2]. |
48 | | -/// |
49 | | -/// # Blanket implementations |
50 | | -/// |
51 | | -/// # Encoding conventions |
52 | | -/// |
53 | | -/// For byte sequences, encoding must be the identity function. |
54 | | -/// Strings are encoded as their little-endian `u32` byte length followed by their UTF-8 bytes. |
55 | | -/// Integers are encoded via [] |
56 | | -/// |
57 | | -/// [CO25]: https://eprint.iacr.org/2025/536.pdf |
58 | | -pub trait Encoding<T = [u8]> |
59 | | -where |
60 | | - T: ?Sized, |
61 | | -{ |
62 | | - /// The function encoding prover messages into inputs to be absorbed by the duplex sponge. |
63 | | - /// |
64 | | - /// This map must be injective. The computation of the pre-image of this map will affect the extraction time. |
65 | | - fn encode(&self) -> impl AsRef<T>; |
66 | | -} |
67 | | - |
68 | | -/// The interface for all types that can be turned into verifier messages. |
69 | | -pub trait Decoding<T = [u8]> |
70 | | -where |
71 | | - T: ?Sized, |
72 | | -{ |
73 | | - /// The output type (and length) expected by the duplex sponge. |
74 | | - /// |
75 | | - /// # Example |
76 | | - /// |
77 | | - /// ``` |
78 | | - /// # use spongefish::{Decoding, ByteArray}; |
79 | | - /// let repr: ByteArray<4> = Default::default(); |
80 | | - /// assert_eq!(repr.as_ref(), &[0u8; 4]); |
81 | | - /// ``` |
82 | | - type Repr: Default + AsMut<T>; |
83 | | - |
84 | | - /// The distribution-preserving map, that re-maps a squeezed output [`Decoding::Repr`] into a verifier message. |
85 | | - /// |
86 | | - /// This map is not exactly a decoding function (e.g., it can be onto). What is demanded from this function is that |
87 | | - /// it preserves the uniform distribution: if [`Decoding::Repr`] is distributed uniformly at random, the also the output of [`decode`][Decoding::decode] is so. |
88 | | - fn decode(buf: Self::Repr) -> Self; |
89 | | -} |
90 | | - |
91 | | -impl<U, T> Encoding<U> for &T |
92 | | -where |
93 | | - U: ?Sized, |
94 | | - T: Encoding<U> + ?Sized, |
95 | | -{ |
96 | | - fn encode(&self) -> impl AsRef<U> { |
97 | | - (*self).encode() |
98 | | - } |
99 | | -} |
100 | | - |
101 | | -impl<U: Clone, T: Encoding<[U]>, const N: usize> Encoding<[U]> for [T; N] { |
102 | | - fn encode(&self) -> impl AsRef<[U]> { |
103 | | - let mut output = alloc::vec::Vec::new(); |
104 | | - for element in self { |
105 | | - output.extend_from_slice(element.encode().as_ref()); |
106 | | - } |
107 | | - output |
108 | | - } |
109 | | -} |
110 | | - |
111 | | -macro_rules! impl_int_encoding { |
112 | | - ($type: ty) => { |
113 | | - impl Encoding<[u8]> for $type { |
114 | | - fn encode(&self) -> impl AsRef<[u8]> { |
115 | | - self.to_le_bytes() |
116 | | - } |
117 | | - } |
118 | | - }; |
119 | | -} |
120 | | - |
121 | | -macro_rules! impl_int_decoding { |
122 | | - ($type: ty) => { |
123 | | - impl Decoding<[u8]> for $type { |
124 | | - type Repr = ByteArray<{ core::mem::size_of::<$type>() }>; |
125 | | - |
126 | | - fn decode(buf: Self::Repr) -> Self { |
127 | | - <$type>::from_le_bytes(Decoding::decode(buf)) |
128 | | - } |
129 | | - } |
130 | | - }; |
131 | | -} |
132 | | - |
133 | | -impl_int_encoding!(u8); |
134 | | -impl_int_decoding!(u8); |
135 | | -impl_int_encoding!(u16); |
136 | | -impl_int_decoding!(u16); |
137 | | -impl_int_encoding!(u32); |
138 | | -impl_int_decoding!(u32); |
139 | | -impl_int_encoding!(u64); |
140 | | -impl_int_decoding!(u64); |
141 | | -impl_int_encoding!(u128); |
142 | | -impl_int_decoding!(u128); |
143 | | - |
144 | | -#[derive(Debug, Clone)] |
145 | | -pub struct ByteArray<const N: usize>([u8; N]); |
146 | | - |
147 | | -impl<const N: usize> Default for ByteArray<N> { |
148 | | - fn default() -> Self { |
149 | | - Self([0; N]) |
150 | | - } |
151 | | -} |
152 | | -impl<const N: usize> AsRef<[u8; N]> for ByteArray<N> { |
153 | | - fn as_ref(&self) -> &[u8; N] { |
154 | | - &self.0 |
155 | | - } |
156 | | -} |
157 | | - |
158 | | -impl<const N: usize> AsMut<[u8]> for ByteArray<N> { |
159 | | - fn as_mut(&mut self) -> &mut [u8] { |
160 | | - self.0.as_mut() |
161 | | - } |
162 | | -} |
163 | | - |
164 | | -impl<const N: usize> Decoding<[u8]> for [u8; N] { |
165 | | - type Repr = ByteArray<N>; |
166 | | - |
167 | | - fn decode(buf: Self::Repr) -> Self { |
168 | | - buf.0 |
169 | | - } |
170 | | -} |
171 | | - |
172 | | -/// Handy for serializing byte strings. |
173 | | -/// |
174 | | -/// # Safety |
175 | | -/// |
176 | | -/// This implementation is the identity map on `[u8]`. |
177 | | -/// > **Warning:** |
178 | | -/// > It is the responsibility of the caller to ensure that the byte string length is fixed by |
179 | | -/// > the surrounding protocol and that any value encoded this way is prefix-free. Otherwise, |
180 | | -/// > distinct prover messages may become ambiguous in the transcript. |
181 | | -impl Encoding<[u8]> for [u8] { |
182 | | - fn encode(&self) -> impl AsRef<[u8]> { |
183 | | - self |
184 | | - } |
185 | | -} |
186 | | - |
187 | | -/// Handy for serializing UTF-8 strings. |
188 | | -/// |
189 | | -/// Strings are encoded as their little-endian `u32` byte length followed by their UTF-8 bytes. |
190 | | -/// This makes the byte-oriented encoding prefix-free. |
191 | | -impl Encoding<[u8]> for str { |
192 | | - fn encode(&self) -> impl AsRef<[u8]> { |
193 | | - let len: u32 = self |
194 | | - .len() |
195 | | - .try_into() |
196 | | - .expect("string encoding requires length to fit in u32"); |
197 | | - let mut out = alloc::vec::Vec::new(); |
198 | | - out.extend_from_slice(&len.to_le_bytes()); |
199 | | - out.extend_from_slice(self.as_bytes()); |
200 | | - out |
201 | | - } |
202 | | -} |
203 | | - |
204 | | -impl<U: Clone, T: Encoding<[U]>> Encoding<[U]> for alloc::vec::Vec<T> { |
205 | | - fn encode(&self) -> impl AsRef<[U]> { |
206 | | - let mut out = alloc::vec::Vec::new(); |
207 | | - for x in self { |
208 | | - out.extend_from_slice(x.encode().as_ref()); |
209 | | - } |
210 | | - out |
211 | | - } |
212 | | -} |
213 | | - |
214 | | -impl<A, B> Encoding<[u8]> for (A, B) |
215 | | -where |
216 | | - A: Encoding<[u8]>, |
217 | | - B: Encoding<[u8]>, |
218 | | -{ |
219 | | - fn encode(&self) -> impl AsRef<[u8]> { |
220 | | - let mut output = alloc::vec::Vec::new(); |
221 | | - output.extend_from_slice(self.0.encode().as_ref()); |
222 | | - output.extend_from_slice(self.1.encode().as_ref()); |
223 | | - output |
224 | | - } |
225 | | -} |
226 | | - |
227 | | -impl<A, B, C> Encoding<[u8]> for (A, B, C) |
228 | | -where |
229 | | - A: Encoding<[u8]>, |
230 | | - B: Encoding<[u8]>, |
231 | | - C: Encoding<[u8]>, |
232 | | -{ |
233 | | - fn encode(&self) -> impl AsRef<[u8]> { |
234 | | - let mut output = alloc::vec::Vec::new(); |
235 | | - output.extend_from_slice(self.0.encode().as_ref()); |
236 | | - output.extend_from_slice(self.1.encode().as_ref()); |
237 | | - output.extend_from_slice(self.2.encode().as_ref()); |
238 | | - output |
239 | | - } |
240 | | -} |
241 | | - |
242 | | -/// Blanket implementation of [`Codec`] for all traits implementing |
243 | | -/// [`NargSerialize`][`crate::NargSerialize`], |
244 | | -/// [`NargDeserialize`][`crate::NargSerialize`], |
245 | | -/// [`Encoding`], and [`Decoding`] |
246 | | -impl<T, E> Codec<T> for E |
247 | | -where |
248 | | - T: ?Sized, |
249 | | - E: crate::NargDeserialize + crate::NargSerialize + Encoding<T> + Decoding<T>, |
250 | | -{ |
251 | | -} |
| 3 | +pub use ia_core::{ByteArray, Codec, Decoding, Encoding}; |
0 commit comments