Skip to main content

mina_hasher/
roinput.rs

1//! Random oracle input structures and algorithms
2//!
3//! Definition of random oracle input structure and
4//! methods for serializing into bytes and field elements
5
6use alloc::{vec, vec::Vec};
7use core::fmt::Error;
8
9use super::Hashable;
10use ark_ff::{BigInteger, PrimeField};
11use bitvec::{prelude::*, view::AsBits};
12use mina_curves::pasta::{Fp, Fq};
13use o1_utils::FieldHelpers;
14
15/// Total number of bytes for the header of the serialized [`ROInput`].
16const SER_HEADER_SIZE: usize = 8;
17/// Number of bytes for each part of the header of the serialized [`ROInput`].
18const SINGLE_HEADER_SIZE: usize = 4;
19
20/// Random oracle input structure
21///
22/// The random oracle input encapsulates the serialization format and methods
23/// using during hashing.
24///
25/// When implementing the [`Hashable`] trait to enable hashing for a type, you
26/// must implement its `to_roinput()` serialization method using the [`ROInput`]
27/// functions below.
28///
29/// The random oracle input structure is used (by generic code) to serialize the
30/// object into both a vector of `pasta::Fp` field elements and into a vector of
31/// bytes, depending on the situation.
32///
33/// Here is an example of how `ROInput` is used during the definition of the
34/// `Hashable` trait.
35///
36/// ```rust
37/// use mina_hasher::{Hashable, ROInput};
38/// use mina_curves::pasta::Fp;
39///
40/// #[derive(Clone)]
41/// pub struct MyExample {
42///     pub x: Fp,
43///     pub y: Fp,
44///     pub nonce: u64,
45/// }
46///
47/// impl Hashable for MyExample {
48///     type D = ();
49///
50///     fn to_roinput(&self) -> ROInput {
51///         ROInput::new()
52///             .append_field(self.x)
53///             .append_field(self.y)
54///             .append_u64(self.nonce)
55///     }
56///
57///     fn domain_string(_: Self::D) -> Option<String> {
58///         format!("MyExampleMainnet").into()
59///     }
60/// }
61/// ```
62/// **Details:** For technical reasons related to our proof system and
63/// performance, non-field-element members are serialized for signing
64/// differently than other types. Additionally, during signing all members of
65/// the random oracle input get serialized together in two different ways: both
66/// as *bytes* and as a vector of *field elements*. The random oracle input
67/// automates and encapsulates this complexity.
68#[derive(Default, Debug, Clone, PartialEq, Eq)]
69pub struct ROInput {
70    fields: Vec<Fp>,
71    bits: BitVec<u8>,
72}
73
74impl ROInput {
75    /// Create a new empty random oracle input
76    #[must_use]
77    pub fn new() -> Self {
78        Self {
79            fields: vec![],
80            bits: BitVec::new(),
81        }
82    }
83
84    /// Append a [`Hashable`] input
85    #[must_use]
86    pub fn append_hashable(self, input: &impl Hashable) -> Self {
87        self.append_roinput(input.to_roinput())
88    }
89
90    /// Append another random oracle input
91    #[must_use]
92    pub fn append_roinput(mut self, mut roi: Self) -> Self {
93        self.fields.append(&mut roi.fields);
94        self.bits.extend(roi.bits);
95        self
96    }
97
98    /// Append a base field element
99    #[must_use]
100    pub fn append_field(mut self, f: Fp) -> Self {
101        self.fields.push(f);
102        self
103    }
104
105    /// Append a scalar field element by converting it to bits.
106    ///
107    /// This method converts the scalar field element to its byte representation,
108    /// then extracts exactly [`Fq::MODULUS_BIT_SIZE`] bits (255 bits for Pallas curve)
109    /// in little-endian bit order and appends them to the bits vector.
110    ///
111    /// # Bit Representation
112    ///
113    /// - Uses little-endian bit ordering within bytes (LSB first)
114    /// - Extracts exactly 255 bits from the 32-byte scalar representation
115    /// - The scalar field modulus is 255 bits, so the MSB of the 32nd byte is unused
116    ///
117    /// # Differences from [`Self::append_field`]
118    ///
119    /// - [`Self::append_scalar`]: Converts scalar to 255 bits and adds to the `bits` vector
120    /// - [`Self::append_field`]: Adds base field element directly to the `fields` vector
121    ///
122    /// # Examples
123    ///
124    /// ```rust
125    /// use mina_hasher::ROInput;
126    /// use mina_curves::pasta::Fq;
127    ///
128    /// // Regular scalar value
129    /// let scalar = Fq::from(42u64);
130    /// let roi = ROInput::new().append_scalar(scalar);
131    /// let bytes = roi.to_bytes();
132    /// assert_eq!(bytes.len(), 32); // 255 bits rounded up to 32 bytes
133    ///
134    /// // Maximum scalar value (modulus - 1)
135    /// let max_scalar = Fq::from(0u64) - Fq::from(1u64);
136    /// let roi = ROInput::new().append_scalar(max_scalar);
137    /// let bytes = roi.to_bytes();
138    /// assert_eq!(bytes.len(), 32); // 255 bits rounded up to 32 bytes
139    /// ```
140    ///
141    /// # Note
142    ///
143    /// All scalar field values, including the maximum value (modulus - 1),
144    /// will fit exactly in 255 bits and can be safely appended.
145    #[must_use]
146    pub fn append_scalar(mut self, s: Fq) -> Self {
147        // mina scalars are 255 bits
148        let bytes = s.to_bytes();
149        let bits = &bytes.as_bits::<Lsb0>()[..Fq::MODULUS_BIT_SIZE as usize];
150        self.bits.extend(bits);
151        self
152    }
153
154    /// Append a single bit
155    #[must_use]
156    pub fn append_bool(mut self, b: bool) -> Self {
157        self.bits.push(b);
158        self
159    }
160
161    /// Append bytes
162    #[must_use]
163    pub fn append_bytes(mut self, bytes: &[u8]) -> Self {
164        self.bits.extend_from_bitslice(bytes.as_bits::<Lsb0>());
165        self
166    }
167
168    /// Append a 32-bit unsigned integer
169    #[must_use]
170    pub fn append_u32(self, x: u32) -> Self {
171        self.append_bytes(&x.to_le_bytes())
172    }
173
174    /// Append a 64-bit unsigned integer
175    #[must_use]
176    pub fn append_u64(self, x: u64) -> Self {
177        self.append_bytes(&x.to_le_bytes())
178    }
179
180    /// Serialize random oracle input to bytes
181    #[must_use]
182    pub fn to_bytes(&self) -> Vec<u8> {
183        let mut bits: BitVec<u8> = self.fields.iter().fold(BitVec::new(), |mut acc, fe| {
184            acc.extend_from_bitslice(
185                &fe.to_bytes().as_bits::<Lsb0>()[..Fp::MODULUS_BIT_SIZE as usize],
186            );
187
188            acc
189        });
190
191        bits.extend(&self.bits);
192
193        bits.into()
194    }
195
196    /// Convert the random oracle input to a vector of packed field elements
197    /// by packing the bits into field elements and appending them to the fields.
198    /// The bits are packed by taking chunks of size `Fp::MODULUS_BIT_SIZE - 1`.
199    ///
200    /// # Panics
201    ///
202    /// Panics if a bit chunk cannot be converted to a valid base field element.
203    #[must_use]
204    pub fn to_fields(&self) -> Vec<Fp> {
205        let mut fields: Vec<Fp> = self.fields.clone();
206
207        let bits_as_fields =
208            self.bits
209                .chunks(Fp::MODULUS_BIT_SIZE as usize - 1)
210                .fold(vec![], |mut acc, chunk| {
211                    // Workaround: chunk.clone() does not appear to respect
212                    // the chunk's boundaries when it's not byte-aligned.
213                    //
214                    // That is,
215                    //
216                    //   let mut bv = chunk.clone().to_bitvec();
217                    //   bv.resize(B::size_in_bits(), false);
218                    //   fields.push(B::from_bytes(bv.into()));
219                    //
220                    // doesn't work.
221                    //
222                    // Instead we must do
223
224                    let mut bv = BitVec::<u8>::new();
225                    bv.resize(chunk.len(), false);
226                    bv.clone_from_bitslice(chunk);
227
228                    // extend to the size of a field;
229                    bv.resize(Fp::MODULUS_BIT_SIZE as usize, false);
230
231                    acc.push(
232                        Fp::from_bytes(&bv.into_vec())
233                            .expect("failed to create base field element"),
234                    );
235
236                    acc
237                });
238
239        fields.extend(bits_as_fields);
240
241        fields
242    }
243
244    /// Serialize the [`ROInput`](Self) into bytes
245    #[must_use]
246    #[allow(clippy::cast_possible_truncation)]
247    pub fn serialize(&self) -> Vec<u8> {
248        // 4-byte LE field count, 4-byte LE bit count, then payload
249        // Truncation is safe: field/bit counts cannot realistically exceed u32::MAX
250        let fields_len = self.fields.len() as u32;
251        let bits_len = self.bits.len() as u32;
252
253        let mut bytes = Vec::with_capacity(SER_HEADER_SIZE + self.to_bytes().len());
254        bytes.extend_from_slice(&fields_len.to_le_bytes());
255        bytes.extend_from_slice(&bits_len.to_le_bytes());
256        bytes.extend_from_slice(&self.to_bytes());
257        bytes
258    }
259
260    /// Deserialize a [`ROInput`](Self) from bytes
261    ///
262    /// # Errors
263    ///
264    /// Returns [`Error`] if the input is too short, the header lengths are
265    /// inconsistent with the payload size, or a field element cannot be
266    /// reconstructed from the bits.
267    ///
268    /// # Panics
269    ///
270    /// Panics if the header slice conversion to a fixed-size array fails
271    /// (unreachable after the length check).
272    pub fn deserialize(input: &[u8]) -> Result<Self, Error> {
273        if input.len() < SER_HEADER_SIZE {
274            return Err(Error);
275        }
276
277        // read back our two u32 little-endian lengths
278        let fields_len =
279            u32::from_le_bytes(input[0..SINGLE_HEADER_SIZE].try_into().unwrap()) as usize;
280        let bits_len = u32::from_le_bytes(
281            input[SINGLE_HEADER_SIZE..SER_HEADER_SIZE]
282                .try_into()
283                .unwrap(),
284        ) as usize;
285
286        // the rest is payload
287        let bits = input[SER_HEADER_SIZE..].view_bits::<Lsb0>();
288
289        // Check that the number of bytes is consistent with the expected lengths
290        let expected_len_bits = fields_len * Fp::MODULUS_BIT_SIZE as usize + bits_len;
291        // Round up to nearest multiple of 8
292        let expected_len = expected_len_bits.div_ceil(8) + SER_HEADER_SIZE;
293        if input.len() != expected_len {
294            return Err(Error);
295        }
296
297        // allocate space for exactly `fields_len` elements
298        let mut fields = Vec::with_capacity(fields_len);
299
300        for chunk in bits.chunks(Fp::MODULUS_BIT_SIZE as usize).take(fields_len) {
301            let bools: Vec<bool> = chunk.iter().by_vals().collect();
302            // conver little-endian bits to a big integer representation
303            let repr = <Fp as PrimeField>::BigInt::from_bits_le(&bools);
304            // convert to field element (reduces mod p)
305            let elt = Fp::from_bigint(repr).ok_or(Error)?;
306            fields.push(elt);
307        }
308
309        let remainder = &bits[fields_len * Fp::MODULUS_BIT_SIZE as usize..];
310        // Delete the final bits according to the bits length
311        let bits = remainder.iter().take(bits_len).collect::<BitVec<u8>>();
312
313        let roi = Self { fields, bits };
314
315        Ok(roi)
316    }
317}
318
319#[cfg(test)]
320mod tests {
321    use super::*;
322    use crate::{
323        alloc::string::{String, ToString},
324        Hashable,
325    };
326
327    #[test]
328    fn append_bool() {
329        let roi = ROInput::new().append_bool(true);
330        assert!(roi.bits.len() == 1);
331        assert!(roi.bits.as_raw_slice() == [0x01]);
332    }
333
334    #[test]
335    fn append_two_bits() {
336        let roi = ROInput::new().append_bool(false).append_bool(true);
337        assert!(roi.bits.len() == 2);
338        assert!(roi.bits.as_raw_slice() == [0x02]);
339    }
340
341    #[test]
342    fn append_five_bits() {
343        let roi = ROInput::new()
344            .append_bool(false)
345            .append_bool(true)
346            .append_bool(false)
347            .append_bool(false)
348            .append_bool(true);
349        assert!(roi.bits.len() == 5);
350        assert!(roi.bits.as_raw_slice() == [0x12]);
351    }
352
353    #[test]
354    fn append_byte() {
355        let roi = ROInput::new().append_bytes(&[0x01]);
356        assert!(roi.bits.len() == 8);
357        assert!(roi.bits.as_raw_slice() == [0x01]);
358    }
359
360    #[test]
361    fn append_two_bytes() {
362        let roi = ROInput::new().append_bytes(&[0x10, 0xac]);
363        assert!(roi.bits.len() == 16);
364        assert!(roi.bits.as_raw_slice() == [0x10, 0xac]);
365    }
366
367    #[test]
368    fn append_five_bytes() {
369        let roi = ROInput::new().append_bytes(&[0x10, 0xac, 0x01, 0xeb, 0xca]);
370        assert!(roi.bits.len() == 40);
371        assert!(roi.bits.as_raw_slice() == [0x10, 0xac, 0x01, 0xeb, 0xca]);
372    }
373
374    #[test]
375    fn append_scalar() {
376        let scalar =
377            Fq::from_hex("18b7ef420128e69623c0c0dcfa28d47a029d462720deb769d7b5dd6f17444216")
378                .expect("failed to create scalar");
379        let roi = ROInput::new().append_scalar(scalar);
380        assert_eq!(roi.bits.len(), 255);
381        assert_eq!(
382            roi.bits.as_raw_slice(),
383            [
384                0x18, 0xb7, 0xef, 0x42, 0x01, 0x28, 0xe6, 0x96, 0x23, 0xc0, 0xc0, 0xdc, 0xfa, 0x28,
385                0xd4, 0x7a, 0x02, 0x9d, 0x46, 0x27, 0x20, 0xde, 0xb7, 0x69, 0xd7, 0xb5, 0xdd, 0x6f,
386                0x17, 0x44, 0x42, 0x16
387            ]
388        );
389        assert_eq!(
390            roi.to_bytes(),
391            [
392                0x18, 0xb7, 0xef, 0x42, 0x01, 0x28, 0xe6, 0x96, 0x23, 0xc0, 0xc0, 0xdc, 0xfa, 0x28,
393                0xd4, 0x7a, 0x02, 0x9d, 0x46, 0x27, 0x20, 0xde, 0xb7, 0x69, 0xd7, 0xb5, 0xdd, 0x6f,
394                0x17, 0x44, 0x42, 0x16
395            ]
396        );
397    }
398
399    #[test]
400    fn append_scalar_and_byte() {
401        let scalar =
402            Fq::from_hex("18b7ef420128e69623c0c0dcfa28d47a029d462720deb769d7b5dd6f17444216")
403                .expect("failed to create scalar");
404        let roi = ROInput::new().append_scalar(scalar).append_bytes(&[0x01]);
405        assert!(roi.bits.len() == 263);
406        assert!(
407            roi.bits.as_raw_slice()
408                == [
409                    0x18, 0xb7, 0xef, 0x42, 0x01, 0x28, 0xe6, 0x96, 0x23, 0xc0, 0xc0, 0xdc, 0xfa,
410                    0x28, 0xd4, 0x7a, 0x02, 0x9d, 0x46, 0x27, 0x20, 0xde, 0xb7, 0x69, 0xd7, 0xb5,
411                    0xdd, 0x6f, 0x17, 0x44, 0x42, 0x96, 0x00
412                ]
413        );
414    }
415
416    #[test]
417    fn append_two_scalars() {
418        let scalar1 =
419            Fq::from_hex("18b7ef420128e69623c0c0dcfa28d47a029d462720deb769d7b5dd6f17444216")
420                .expect("failed to create scalar");
421        let scalar2 =
422            Fq::from_hex("a1b1e948835be341277548134e0effabdbcb95b742e8c5e967e9bf13eb4ae805")
423                .expect("failed to create scalar");
424        let roi = ROInput::new().append_scalar(scalar1).append_scalar(scalar2);
425        assert!(roi.bits.len() == 510);
426        assert!(
427            roi.bits.as_raw_slice()
428                == [
429                    0x18, 0xb7, 0xef, 0x42, 0x01, 0x28, 0xe6, 0x96, 0x23, 0xc0, 0xc0, 0xdc, 0xfa,
430                    0x28, 0xd4, 0x7a, 0x02, 0x9d, 0x46, 0x27, 0x20, 0xde, 0xb7, 0x69, 0xd7, 0xb5,
431                    0xdd, 0x6f, 0x17, 0x44, 0x42, 0x96, 0xd0, 0xd8, 0x74, 0xa4, 0xc1, 0xad, 0xf1,
432                    0xa0, 0x93, 0x3a, 0xa4, 0x09, 0x27, 0x87, 0xff, 0xd5, 0xed, 0xe5, 0xca, 0x5b,
433                    0x21, 0xf4, 0xe2, 0xf4, 0xb3, 0xf4, 0xdf, 0x89, 0x75, 0x25, 0xf4, 0x02
434                ]
435        );
436    }
437
438    #[test]
439    fn append_two_scalars_and_byte() {
440        let scalar1 =
441            Fq::from_hex("60db6f4f5b8ce1c7cb747fba9e324cc3268c7a6e3f43cd82d451ae99a7b2bd1f")
442                .expect("failed to create scalar");
443        let scalar2 =
444            Fq::from_hex("fe7775b106bceb58f3e23e5a4eb99f404b8ed8cf2afeef9c9d1800f12138cd07")
445                .expect("failed to create scalar");
446        let roi = ROInput::new()
447            .append_scalar(scalar1)
448            .append_bytes(&[0x2a])
449            .append_scalar(scalar2);
450        assert!(roi.bits.len() == 518);
451        assert!(
452            roi.bits.as_raw_slice()
453                == [
454                    0x60, 0xdb, 0x6f, 0x4f, 0x5b, 0x8c, 0xe1, 0xc7, 0xcb, 0x74, 0x7f, 0xba, 0x9e,
455                    0x32, 0x4c, 0xc3, 0x26, 0x8c, 0x7a, 0x6e, 0x3f, 0x43, 0xcd, 0x82, 0xd4, 0x51,
456                    0xae, 0x99, 0xa7, 0xb2, 0xbd, 0x1f, 0x15, 0xff, 0xbb, 0xba, 0x58, 0x03, 0xde,
457                    0x75, 0xac, 0x79, 0x71, 0x1f, 0x2d, 0xa7, 0xdc, 0x4f, 0xa0, 0x25, 0x47, 0xec,
458                    0x67, 0x15, 0xff, 0x77, 0xce, 0x4e, 0x0c, 0x80, 0xf8, 0x10, 0x9c, 0xe6, 0x03
459                ]
460        );
461    }
462
463    #[test]
464    fn test_append_scalar_max_value() {
465        // Test with the maximum scalar field value (modulus - 1)
466        let max_scalar = Fq::from(0u64) - Fq::from(1u64); // Fq modulus - 1
467        let roi = ROInput::new().append_scalar(max_scalar);
468
469        // Should add 255 bits (Fq::MODULUS_BIT_SIZE)
470        assert_eq!(roi.bits.len(), 255);
471        assert_eq!(roi.fields.len(), 0);
472
473        // Verify the bits represent the maximum scalar value
474        let reconstructed_bytes = roi.bits.as_raw_slice();
475        let expected_bytes = max_scalar.to_bytes();
476
477        // Compare the first 31 bytes (255 bits = 31 bytes + 7 bits)
478        assert_eq!(&reconstructed_bytes[..31], &expected_bytes[..31]);
479
480        // Check the last partial byte (7 bits from the 32nd byte)
481        let last_byte_mask = 0x7F; // Mask for 7 bits: 0111_1111
482        assert_eq!(
483            reconstructed_bytes[31] & last_byte_mask,
484            expected_bytes[31] & last_byte_mask
485        );
486
487        // Test serialization to bytes
488        let serialized_bytes = roi.to_bytes();
489        assert_eq!(serialized_bytes.len(), 32); // 255 bits rounded up to 32 bytes
490
491        // Test that max scalar converts to proper field elements
492        let fields = roi.to_fields();
493        assert_eq!(fields.len(), 2); // Should pack into 2 field elements
494
495        // Verify we can append multiple max scalars
496        let roi_double = ROInput::new()
497            .append_scalar(max_scalar)
498            .append_scalar(max_scalar);
499        assert_eq!(roi_double.bits.len(), 510); // 2 * 255 bits
500
501        let fields_double = roi_double.to_fields();
502        assert_eq!(fields_double.len(), 3); // Should pack into 3 field elements
503    }
504
505    #[test]
506    fn append_u32() {
507        let roi = ROInput::new().append_u32(1984u32);
508        assert!(roi.bits.len() == 32);
509        assert!(roi.bits.as_raw_slice() == [0xc0, 0x07, 0x00, 0x00]);
510    }
511
512    #[test]
513    fn append_two_u32_and_bit() {
514        let roi = ROInput::new()
515            .append_u32(1729u32)
516            .append_bool(false)
517            .append_u32(u32::MAX);
518        assert!(roi.bits.len() == 65);
519        assert!(roi.bits.as_raw_slice() == [0xc1, 0x06, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x01]);
520    }
521
522    #[test]
523    fn append_u64() {
524        let roi = ROInput::new().append_u64(6174u64);
525        assert!(roi.bits.len() == 64);
526        assert!(roi.bits.as_raw_slice() == [0x1e, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
527    }
528
529    #[test]
530    fn append_two_u64_and_bits() {
531        let roi = ROInput::new()
532            .append_bool(true)
533            .append_u64(u64::MAX / 6174u64)
534            .append_bool(false)
535            .append_u64(u64::MAX / 1111u64);
536        assert!(roi.bits.len() == 130);
537        assert!(
538            roi.bits.as_raw_slice()
539                == [
540                    0xe1, 0x29, 0x89, 0xd6, 0xcb, 0x3a, 0x15, 0x00, 0x08, 0x17, 0xc4, 0x9b, 0x04,
541                    0xf4, 0xeb, 0x00, 0x00
542                ]
543        );
544    }
545
546    #[test]
547    fn all_1() {
548        let roi = ROInput::new()
549            .append_bool(true)
550            .append_scalar(
551                Fq::from_hex("01d1755db21c8cd2a9cf5a3436178da3d70f484cd4b4c8834b799921e7d7a102")
552                    .expect("failed to create scalar"),
553            )
554            .append_u64(18_446_744_073_709_551_557)
555            .append_bytes(&[0xba, 0xdc, 0x0f, 0xfe])
556            .append_scalar(
557                Fq::from_hex("e70187e9b125524489d0433da76fd8287fa652eaebde147b45fa0cd86f171810")
558                    .expect("failed to create scalar"),
559            )
560            .append_bool(false)
561            .append_u32(2_147_483_647)
562            .append_bool(true);
563
564        assert!(roi.bits.len() == 641);
565        assert!(
566            roi.bits.as_raw_slice()
567                == [
568                    0x03, 0xa2, 0xeb, 0xba, 0x64, 0x39, 0x18, 0xa5, 0x53, 0x9f, 0xb5, 0x68, 0x6c,
569                    0x2e, 0x1a, 0x47, 0xaf, 0x1f, 0x90, 0x98, 0xa8, 0x69, 0x91, 0x07, 0x97, 0xf2,
570                    0x32, 0x43, 0xce, 0xaf, 0x43, 0x05, 0xc5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
571                    0xff, 0xba, 0xdc, 0x0f, 0xfe, 0xe7, 0x01, 0x87, 0xe9, 0xb1, 0x25, 0x52, 0x44,
572                    0x89, 0xd0, 0x43, 0x3d, 0xa7, 0x6f, 0xd8, 0x28, 0x7f, 0xa6, 0x52, 0xea, 0xeb,
573                    0xde, 0x14, 0x7b, 0x45, 0xfa, 0x0c, 0xd8, 0x6f, 0x17, 0x18, 0x10, 0xff, 0xff,
574                    0xff, 0x7f, 0x01
575                ]
576        );
577    }
578
579    #[test]
580    fn transaction_bits() {
581        let roi = ROInput::new()
582            .append_u64(1_000_000) // fee
583            .append_u64(1) // fee token
584            .append_bool(true) // fee payer pk odd
585            .append_u32(0) // nonce
586            .append_u32(u32::MAX) // valid_until
587            .append_bytes(&[0; 34]) // memo
588            .append_bool(false) // tags[0]
589            .append_bool(false) // tags[1]
590            .append_bool(false) // tags[2]
591            .append_bool(true) // sender pk odd
592            .append_bool(false) // receiver pk odd
593            .append_u64(1) // token_id
594            .append_u64(10_000_000_000) // amount
595            .append_bool(false) // token_locked
596            .append_scalar(
597                Fq::from_hex("de217a3017ca0b7a278e75f63c09890e3894be532d8dbadd30a7d450055f6d2d")
598                    .expect("failed to create scalar"),
599            )
600            .append_bytes(&[0x01]);
601        assert_eq!(roi.bits.len(), 862);
602        assert_eq!(
603            roi.bits.as_raw_slice(),
604            [
605                0x40, 0x42, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
606                0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
607                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
608                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
609                0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x02,
610                0x95, 0x00, 0x00, 0x00, 0x00, 0xef, 0x10, 0x3d, 0x98, 0x0b, 0xe5, 0x05, 0xbd, 0x13,
611                0xc7, 0x3a, 0x7b, 0x9e, 0x84, 0x44, 0x07, 0x1c, 0x4a, 0xdf, 0xa9, 0x96, 0x46, 0xdd,
612                0x6e, 0x98, 0x53, 0x6a, 0xa8, 0x82, 0xaf, 0xb6, 0x56, 0x00
613            ]
614        );
615    }
616
617    #[test]
618    fn append_field() {
619        let roi = ROInput::new().append_field(
620            Fp::from_hex("2eaedae42a7461d5952d27b97ecad068b698ebb94e8a0e4c45388bb613de7e08")
621                .expect("failed to create field"),
622        );
623
624        assert_eq!(
625            roi.to_bytes(),
626            [
627                0x2e, 0xae, 0xda, 0xe4, 0x2a, 0x74, 0x61, 0xd5, 0x95, 0x2d, 0x27, 0xb9, 0x7e, 0xca,
628                0xd0, 0x68, 0xb6, 0x98, 0xeb, 0xb9, 0x4e, 0x8a, 0x0e, 0x4c, 0x45, 0x38, 0x8b, 0xb6,
629                0x13, 0xde, 0x7e, 0x08
630            ]
631        );
632    }
633
634    #[test]
635    fn append_two_fields() {
636        let roi = ROInput::new()
637            .append_field(
638                Fp::from_hex("0cdaf334e9632268a5aa959c2781fb32bf45565fe244ae42c849d3fdc7c6441d")
639                    .expect("failed to create field"),
640            )
641            .append_field(
642                Fp::from_hex("2eaedae42a7461d5952d27b97ecad068b698ebb94e8a0e4c45388bb613de7e08")
643                    .expect("failed to create field"),
644            );
645
646        assert_eq!(
647            roi.to_bytes(),
648            [
649                0x0c, 0xda, 0xf3, 0x34, 0xe9, 0x63, 0x22, 0x68, 0xa5, 0xaa, 0x95, 0x9c, 0x27, 0x81,
650                0xfb, 0x32, 0xbf, 0x45, 0x56, 0x5f, 0xe2, 0x44, 0xae, 0x42, 0xc8, 0x49, 0xd3, 0xfd,
651                0xc7, 0xc6, 0x44, 0x1d, 0x17, 0x57, 0x6d, 0x72, 0x15, 0xba, 0xb0, 0xea, 0xca, 0x96,
652                0x93, 0x5c, 0x3f, 0x65, 0x68, 0x34, 0x5b, 0xcc, 0xf5, 0x5c, 0x27, 0x45, 0x07, 0xa6,
653                0x22, 0x9c, 0x45, 0xdb, 0x09, 0x6f, 0x3f, 0x04
654            ]
655        );
656    }
657
658    #[test]
659    fn append_three_fields() {
660        let roi = ROInput::new()
661            .append_field(
662                Fp::from_hex("1f3f142986041b54427aa2032632e34df2fa9bde9bce70c04c5034266619e529")
663                    .expect("failed to create field"),
664            )
665            .append_field(
666                Fp::from_hex("37f4433b85e753a91a1d79751645f1448954c433f9492e36a933ca7f3df61a04")
667                    .expect("failed to create field"),
668            )
669            .append_field(
670                Fp::from_hex("6cf4772d3e1aab98a2b514b73a4f6e0df1fb4f703ecfa762196b22c26da4341c")
671                    .expect("failed to create field"),
672            );
673
674        assert_eq!(
675            roi.to_bytes(),
676            [
677                0x1f, 0x3f, 0x14, 0x29, 0x86, 0x04, 0x1b, 0x54, 0x42, 0x7a, 0xa2, 0x03, 0x26, 0x32,
678                0xe3, 0x4d, 0xf2, 0xfa, 0x9b, 0xde, 0x9b, 0xce, 0x70, 0xc0, 0x4c, 0x50, 0x34, 0x26,
679                0x66, 0x19, 0xe5, 0xa9, 0x1b, 0xfa, 0xa1, 0x9d, 0xc2, 0xf3, 0xa9, 0x54, 0x8d, 0x8e,
680                0xbc, 0x3a, 0x8b, 0xa2, 0x78, 0xa2, 0x44, 0x2a, 0xe2, 0x99, 0xfc, 0x24, 0x17, 0x9b,
681                0xd4, 0x19, 0xe5, 0xbf, 0x1e, 0x7b, 0x0d, 0x02, 0x1b, 0xfd, 0x5d, 0x8b, 0x8f, 0xc6,
682                0x2a, 0xa6, 0x68, 0x2d, 0xc5, 0xad, 0xce, 0x93, 0x5b, 0x43, 0xfc, 0xfe, 0x13, 0x9c,
683                0xcf, 0xf3, 0xa9, 0x58, 0xc6, 0x9a, 0x88, 0x70, 0x1b, 0x29, 0x0d, 0x07
684            ]
685        );
686    }
687
688    #[test]
689    fn append_field_and_scalar() {
690        let roi = ROInput::new()
691            .append_field(
692                Fp::from_hex("64cde530327a36fcb88b6d769adca9b7c5d266e7d0042482203f3fd3a0d71721")
693                    .expect("failed to create field"),
694            )
695            .append_scalar(
696                Fq::from_hex("604355d0daa455db783fd7ee11c5bd9b04d67ba64c27c95bef95e379f98c6432")
697                    .expect("failed to create scalar"),
698            );
699
700        assert_eq!(
701            roi.to_bytes(),
702            [
703                0x64, 0xcd, 0xe5, 0x30, 0x32, 0x7a, 0x36, 0xfc, 0xb8, 0x8b, 0x6d, 0x76, 0x9a, 0xdc,
704                0xa9, 0xb7, 0xc5, 0xd2, 0x66, 0xe7, 0xd0, 0x04, 0x24, 0x82, 0x20, 0x3f, 0x3f, 0xd3,
705                0xa0, 0xd7, 0x17, 0x21, 0xb0, 0xa1, 0x2a, 0x68, 0x6d, 0xd2, 0xaa, 0x6d, 0xbc, 0x9f,
706                0x6b, 0xf7, 0x88, 0xe2, 0xde, 0x4d, 0x02, 0xeb, 0x3d, 0x53, 0xa6, 0x93, 0xe4, 0xad,
707                0xf7, 0xca, 0xf1, 0xbc, 0x7c, 0x46, 0x32, 0x19
708            ]
709        );
710    }
711
712    #[test]
713    fn append_field_bit_and_scalar() {
714        let roi = ROInput::new()
715            .append_field(
716                Fp::from_hex("d897c7a8b811d8acd3eeaa4adf42292802eed80031c2ad7c8989aea1fe94322c")
717                    .expect("failed to create field"),
718            )
719            .append_bool(false)
720            .append_scalar(
721                Fq::from_hex("79586cc6b8b53c8991b2abe0ca76508f056ca50f06836ce4d818c2ff73d42b28")
722                    .expect("failed to create scalar"),
723            );
724
725        assert_eq!(
726            roi.to_bytes(),
727            [
728                0xd8, 0x97, 0xc7, 0xa8, 0xb8, 0x11, 0xd8, 0xac, 0xd3, 0xee, 0xaa, 0x4a, 0xdf, 0x42,
729                0x29, 0x28, 0x02, 0xee, 0xd8, 0x00, 0x31, 0xc2, 0xad, 0x7c, 0x89, 0x89, 0xae, 0xa1,
730                0xfe, 0x94, 0x32, 0x2c, 0x79, 0x58, 0x6c, 0xc6, 0xb8, 0xb5, 0x3c, 0x89, 0x91, 0xb2,
731                0xab, 0xe0, 0xca, 0x76, 0x50, 0x8f, 0x05, 0x6c, 0xa5, 0x0f, 0x06, 0x83, 0x6c, 0xe4,
732                0xd8, 0x18, 0xc2, 0xff, 0x73, 0xd4, 0x2b, 0x28
733            ]
734        );
735    }
736
737    #[test]
738    fn to_bytes() {
739        let roi = ROInput::new()
740            .append_field(
741                Fp::from_hex("a5984f2bd00906f9a86e75bfb4b2c3625f1a0d1cfacc1501e8e82ae7041efc14")
742                    .expect("failed to create field"),
743            )
744            .append_field(
745                Fp::from_hex("8af0bc770d49a5b9fcabfcdd033bab470b2a211ef80b710efe71315cfa818c0a")
746                    .expect("failed to create field"),
747            )
748            .append_bool(false)
749            .append_u32(314u32)
750            .append_scalar(
751                Fq::from_hex("c23c43a23ddc1516578b0f0d81b93cdbbc97744acc697cfc8c5dfd01cc448323")
752                    .expect("failed to create scalar"),
753            );
754
755        assert_eq!(
756            roi.to_bytes(),
757            [
758                0xa5, 0x98, 0x4f, 0x2b, 0xd0, 0x09, 0x06, 0xf9, 0xa8, 0x6e, 0x75, 0xbf, 0xb4, 0xb2,
759                0xc3, 0x62, 0x5f, 0x1a, 0x0d, 0x1c, 0xfa, 0xcc, 0x15, 0x01, 0xe8, 0xe8, 0x2a, 0xe7,
760                0x04, 0x1e, 0xfc, 0x14, 0x45, 0x78, 0xde, 0xbb, 0x86, 0xa4, 0xd2, 0x5c, 0xfe, 0x55,
761                0xfe, 0xee, 0x81, 0x9d, 0xd5, 0xa3, 0x05, 0x95, 0x10, 0x0f, 0xfc, 0x85, 0x38, 0x07,
762                0xff, 0xb8, 0x18, 0x2e, 0xfd, 0x40, 0x46, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x61, 0x9e,
763                0x21, 0xd1, 0x1e, 0xee, 0x0a, 0x8b, 0xab, 0xc5, 0x87, 0x86, 0xc0, 0x5c, 0x9e, 0x6d,
764                0xde, 0x4b, 0x3a, 0x25, 0xe6, 0x34, 0x3e, 0x7e, 0xc6, 0xae, 0xfe, 0x00, 0x66, 0xa2,
765                0xc1, 0x11
766            ]
767        );
768    }
769
770    #[test]
771    fn to_fields_1_scalar() {
772        let roi = ROInput::new().append_scalar(
773            Fq::from_hex("5d496dd8ff63f640c006887098092b16bc8c78504f84fa1ee3a0b54f85f0a625")
774                .expect("failed to create scalar"),
775        );
776
777        assert_eq!(
778            roi.to_bytes(),
779            [
780                0x5d, 0x49, 0x6d, 0xd8, 0xff, 0x63, 0xf6, 0x40, 0xc0, 0x06, 0x88, 0x70, 0x98, 0x09,
781                0x2b, 0x16, 0xbc, 0x8c, 0x78, 0x50, 0x4f, 0x84, 0xfa, 0x1e, 0xe3, 0xa0, 0xb5, 0x4f,
782                0x85, 0xf0, 0xa6, 0x25
783            ]
784        );
785
786        assert_eq!(
787            roi.to_fields(),
788            [
789                Fp::from_hex("5d496dd8ff63f640c006887098092b16bc8c78504f84fa1ee3a0b54f85f0a625")
790                    .expect("failed to create field"),
791                Fp::from_hex("0000000000000000000000000000000000000000000000000000000000000000")
792                    .expect("failed to create field"),
793            ]
794        );
795    }
796
797    #[test]
798    fn to_fields_1_scalar_2_bits() {
799        let roi = ROInput::new()
800            .append_scalar(
801                Fq::from_hex("e8a9961c8c417b0d0e3d7366f6b0e6ef90a6dad123070f715e8a9eaa02e47330")
802                    .expect("failed to create scalar"),
803            )
804            .append_bool(false)
805            .append_bool(true);
806
807        assert_eq!(
808            roi.to_bytes(),
809            [
810                0xe8, 0xa9, 0x96, 0x1c, 0x8c, 0x41, 0x7b, 0x0d, 0x0e, 0x3d, 0x73, 0x66, 0xf6, 0xb0,
811                0xe6, 0xef, 0x90, 0xa6, 0xda, 0xd1, 0x23, 0x07, 0x0f, 0x71, 0x5e, 0x8a, 0x9e, 0xaa,
812                0x02, 0xe4, 0x73, 0x30, 0x01
813            ]
814        );
815
816        assert_eq!(
817            roi.to_fields(),
818            [
819                Fp::from_hex("e8a9961c8c417b0d0e3d7366f6b0e6ef90a6dad123070f715e8a9eaa02e47330")
820                    .expect("failed to create field"),
821                Fp::from_hex("0400000000000000000000000000000000000000000000000000000000000000")
822                    .expect("failed to create field"),
823            ]
824        );
825    }
826
827    #[test]
828    fn to_fields_2_scalars() {
829        let roi = ROInput::new()
830            .append_scalar(
831                Fq::from_hex("e05c25d2c17ec20d6bc8fd21204af52808451076cff687407164a21d352ddd22")
832                    .expect("failed to create scalar"),
833            )
834            .append_scalar(
835                Fq::from_hex("c356dbb39478508818e0320dffa6c1ef512564366ec885ee2fc4d385dd36df0f")
836                    .expect("failed to create scalar"),
837            );
838
839        assert_eq!(
840            roi.to_bytes(),
841            [
842                0xe0, 0x5c, 0x25, 0xd2, 0xc1, 0x7e, 0xc2, 0x0d, 0x6b, 0xc8, 0xfd, 0x21, 0x20, 0x4a,
843                0xf5, 0x28, 0x08, 0x45, 0x10, 0x76, 0xcf, 0xf6, 0x87, 0x40, 0x71, 0x64, 0xa2, 0x1d,
844                0x35, 0x2d, 0xdd, 0xa2, 0x61, 0xab, 0xed, 0x59, 0x4a, 0x3c, 0x28, 0x44, 0x0c, 0x70,
845                0x99, 0x86, 0x7f, 0xd3, 0xe0, 0xf7, 0xa8, 0x12, 0x32, 0x1b, 0x37, 0xe4, 0x42, 0xf7,
846                0x17, 0xe2, 0xe9, 0xc2, 0x6e, 0x9b, 0xef, 0x07
847            ]
848        );
849
850        assert_eq!(
851            roi.to_fields(),
852            [
853                Fp::from_hex("e05c25d2c17ec20d6bc8fd21204af52808451076cff687407164a21d352ddd22")
854                    .expect("failed to create field"),
855                Fp::from_hex("86adb66729f1a01031c0651afe4d83dfa34ac86cdc900bdd5f88a70bbb6dbe1f")
856                    .expect("failed to create field"),
857                Fp::from_hex("0000000000000000000000000000000000000000000000000000000000000000")
858                    .expect("failed to create field"),
859            ]
860        );
861    }
862
863    #[test]
864    fn to_fields_2_bits_scalar_u32() {
865        let roi = ROInput::new()
866            .append_bool(true)
867            .append_bool(false)
868            .append_scalar(
869                Fq::from_hex("689634de233b06251a80ac7df64483922727757eea1adc6f0c8f184441cfe10d")
870                    .expect("failed to create scalar"),
871            )
872            .append_u32(834_803);
873
874        assert_eq!(
875            roi.to_bytes(),
876            [
877                0xa1, 0x59, 0xd2, 0x78, 0x8f, 0xec, 0x18, 0x94, 0x68, 0x00, 0xb2, 0xf6, 0xd9, 0x13,
878                0x0d, 0x4a, 0x9e, 0x9c, 0xd4, 0xf9, 0xa9, 0x6b, 0x70, 0xbf, 0x31, 0x3c, 0x62, 0x10,
879                0x05, 0x3d, 0x87, 0x37, 0xe6, 0x79, 0x19, 0x00, 0x00
880            ]
881        );
882
883        assert_eq!(
884            roi.to_fields(),
885            [
886                Fp::from_hex("a159d2788fec18946800b2f6d9130d4a9e9cd4f9a96b70bf313c6210053d8737")
887                    .expect("failed to create field"),
888                Fp::from_hex("98e7650000000000000000000000000000000000000000000000000000000000")
889                    .expect("failed to create field"),
890            ]
891        );
892    }
893
894    #[test]
895    fn to_fields_2_bits_field_scalar() {
896        let roi = ROInput::new()
897            .append_bool(false)
898            .append_bool(true)
899            .append_field(
900                Fp::from_hex("90926b620ad09ed616d5df158504faed42928719c58ae619d9eccc062f920411")
901                    .expect("failed to create field"),
902            )
903            .append_scalar(
904                Fq::from_hex("689634de233b06251a80ac7df64483922727757eea1adc6f0c8f184441cfe10d")
905                    .expect("failed to create scalar"),
906            );
907
908        assert_eq!(
909            roi.to_bytes(),
910            [
911                0x90, 0x92, 0x6b, 0x62, 0x0a, 0xd0, 0x9e, 0xd6, 0x16, 0xd5, 0xdf, 0x15, 0x85, 0x04,
912                0xfa, 0xed, 0x42, 0x92, 0x87, 0x19, 0xc5, 0x8a, 0xe6, 0x19, 0xd9, 0xec, 0xcc, 0x06,
913                0x2f, 0x92, 0x04, 0x11, 0xd1, 0x2c, 0x69, 0xbc, 0x47, 0x76, 0x0c, 0x4a, 0x34, 0x00,
914                0x59, 0xfb, 0xec, 0x89, 0x06, 0x25, 0x4f, 0x4e, 0xea, 0xfc, 0xd4, 0x35, 0xb8, 0xdf,
915                0x18, 0x1e, 0x31, 0x88, 0x82, 0x9e, 0xc3, 0x1b
916            ]
917        );
918
919        assert_eq!(
920            roi.to_fields(),
921            [
922                Fp::from_hex("90926b620ad09ed616d5df158504faed42928719c58ae619d9eccc062f920411")
923                    .expect("failed to create field"),
924                Fp::from_hex("a259d2788fec18946800b2f6d9130d4a9e9cd4f9a96b70bf313c6210053d8737")
925                    .expect("failed to create field"),
926                Fp::from_hex("0000000000000000000000000000000000000000000000000000000000000000")
927                    .expect("failed to create field"),
928            ]
929        );
930    }
931
932    #[test]
933    fn transaction_test_1() {
934        let roi = ROInput::new()
935            .append_field(
936                Fp::from_hex("41203c6bbac14b357301e1f386d80f52123fd00f02197491b690bddfa742ca22")
937                    .expect("failed to create field"),
938            ) // fee payer
939            .append_field(
940                Fp::from_hex("992cdaf29ffe15b2bcea5d00e498ed4fffd117c197f0f98586e405f72ef88e00")
941                    .expect("failed to create field"),
942            ) // source
943            .append_field(
944                Fp::from_hex("3fba4fa71bce0dfdf709d827463036d6291458dfef772ff65e87bd6d1b1e062a")
945                    .expect("failed to create field"),
946            ) // receiver
947            .append_u64(1_000_000) // fee
948            .append_u64(1) // fee token
949            .append_bool(true) // fee payer pk odd
950            .append_u32(0) // nonce
951            .append_u32(u32::MAX) // valid_until
952            .append_bytes(&[0; 34]) // memo
953            .append_bool(false) // tags[0]
954            .append_bool(false) // tags[1]
955            .append_bool(false) // tags[2]
956            .append_bool(true) // sender pk odd
957            .append_bool(false) // receiver pk odd
958            .append_u64(1) // token_id
959            .append_u64(10_000_000_000) // amount
960            .append_bool(false); // token_locked
961        assert_eq!(roi.bits.len() + roi.fields.len() * 255, 1364);
962        assert_eq!(
963            roi.to_bytes(),
964            [
965                0x41, 0x20, 0x3c, 0x6b, 0xba, 0xc1, 0x4b, 0x35, 0x73, 0x01, 0xe1, 0xf3, 0x86, 0xd8,
966                0x0f, 0x52, 0x12, 0x3f, 0xd0, 0x0f, 0x02, 0x19, 0x74, 0x91, 0xb6, 0x90, 0xbd, 0xdf,
967                0xa7, 0x42, 0xca, 0xa2, 0x4c, 0x16, 0x6d, 0xf9, 0x4f, 0xff, 0x0a, 0x59, 0x5e, 0xf5,
968                0x2e, 0x00, 0x72, 0xcc, 0xf6, 0xa7, 0xff, 0xe8, 0x8b, 0xe0, 0x4b, 0xf8, 0xfc, 0x42,
969                0x43, 0xf2, 0x82, 0x7b, 0x17, 0x7c, 0x47, 0xc0, 0x8f, 0xee, 0xd3, 0xe9, 0x86, 0x73,
970                0x43, 0xff, 0x7d, 0x02, 0xf6, 0x89, 0x11, 0x8c, 0x8d, 0x75, 0x0a, 0x05, 0xd6, 0xf7,
971                0xfb, 0xdd, 0x8b, 0xbd, 0xd7, 0x61, 0x6f, 0xdb, 0x86, 0x87, 0x81, 0x0a, 0x48, 0xe8,
972                0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
973                0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
974                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
975                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
976                0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x5f, 0xa0, 0x12, 0x00,
977                0x00, 0x00, 0x00
978            ]
979        );
980
981        assert_eq!(
982            roi.to_fields(),
983            [
984                Fp::from_hex("41203c6bbac14b357301e1f386d80f52123fd00f02197491b690bddfa742ca22")
985                    .expect("failed to create field"),
986                Fp::from_hex("992cdaf29ffe15b2bcea5d00e498ed4fffd117c197f0f98586e405f72ef88e00")
987                    .expect("failed to create field"),
988                Fp::from_hex("3fba4fa71bce0dfdf709d827463036d6291458dfef772ff65e87bd6d1b1e062a")
989                    .expect("failed to create field"),
990                Fp::from_hex("40420f0000000000010000000000000001000000feffffff0100000000000000")
991                    .expect("failed to create field"),
992                Fp::from_hex("0000000000000000000000000000000000000000000000000000400100000000")
993                    .expect("failed to create field"),
994                Fp::from_hex("00000000902f5009000000000000000000000000000000000000000000000000")
995                    .expect("failed to create field"),
996            ]
997        );
998    }
999
1000    #[test]
1001    fn nested_roinput_test() {
1002        #[derive(Clone, Debug)]
1003        struct A {
1004            x: u32,
1005            y: bool,
1006            z: u32,
1007        }
1008
1009        impl Hashable for A {
1010            type D = ();
1011
1012            fn to_roinput(&self) -> ROInput {
1013                ROInput::new()
1014                    .append_u32(self.x)
1015                    .append_bool(self.y)
1016                    .append_u32(self.z)
1017            }
1018
1019            fn domain_string((): Self::D) -> Option<String> {
1020                "A".to_string().into()
1021            }
1022        }
1023
1024        #[derive(Clone, Debug)]
1025        struct B1 {
1026            a: A,
1027            b: u64,
1028            c: bool,
1029        }
1030
1031        impl Hashable for B1 {
1032            type D = ();
1033
1034            fn to_roinput(&self) -> ROInput {
1035                self.a.to_roinput().append_u64(self.b).append_bool(self.c)
1036            }
1037
1038            fn domain_string((): Self::D) -> Option<String> {
1039                "B".to_string().into()
1040            }
1041        }
1042
1043        #[derive(Clone, Debug)]
1044        struct B2 {
1045            a: A,
1046            b: u64,
1047            c: bool,
1048        }
1049
1050        impl Hashable for B2 {
1051            type D = ();
1052
1053            fn to_roinput(&self) -> ROInput {
1054                self.a
1055                    .to_roinput()
1056                    .append_roinput(ROInput::new().append_u64(self.b).append_bool(self.c))
1057            }
1058
1059            fn domain_string((): Self::D) -> Option<String> {
1060                "B".to_string().into()
1061            }
1062        }
1063
1064        let a = A {
1065            x: 16_830_533,
1066            y: false,
1067            z: 39_827_791,
1068        };
1069        let b1 = B1 {
1070            a,
1071            b: 124_819,
1072            c: true,
1073        };
1074        let b2 = B2 {
1075            a: b1.a.clone(),
1076            b: b1.b,
1077            c: b1.c,
1078        };
1079
1080        assert_eq!(b1.to_roinput(), b2.to_roinput());
1081
1082        let b2 = B2 {
1083            a: b1.a.clone(),
1084            b: b1.b,
1085            c: false,
1086        };
1087        assert_ne!(b1.to_roinput(), b2.to_roinput());
1088
1089        let b2 = B2 {
1090            a: b1.a.clone(),
1091            b: b1.b + 1,
1092            c: b1.c,
1093        };
1094        assert_ne!(b1.to_roinput(), b2.to_roinput());
1095    }
1096
1097    #[test]
1098    fn serialize_empty() {
1099        let roi = ROInput::new();
1100
1101        let serialized = roi.serialize();
1102
1103        assert_eq!(
1104            serialized,
1105            vec![0; SER_HEADER_SIZE],
1106            "Serialized empty ROInput should be zero bytes"
1107        );
1108
1109        let deserialized_roi =
1110            ROInput::deserialize(&serialized).expect("Failed to deserialize ROInput");
1111        assert_eq!(
1112            roi, deserialized_roi,
1113            "Serialized and deserialized ROInput do not match"
1114        );
1115    }
1116
1117    #[test]
1118    fn serialize_single_field() {
1119        let roi = ROInput::new().append_field(
1120            Fp::from_hex("41203c6bbac14b357301e1f386d80f52123fd00f02197491b690bddfa742ca22")
1121                .expect("failed to create field"),
1122        );
1123
1124        let serialized = roi.serialize();
1125        let expected_length = SER_HEADER_SIZE + 32; // 32 bytes for the field
1126        assert_eq!(
1127            serialized.len(),
1128            expected_length,
1129            "Serialized ROInput length mismatch"
1130        );
1131        assert_eq!(
1132            serialized,
1133            [
1134                0x01, 0x00, 0x00, 0x00, // Field count
1135                0x00, 0x00, 0x00, 0x00, // Bit count
1136                0x41, 0x20, 0x3c, 0x6b, 0xba, 0xc1, 0x4b, 0x35, 0x73, 0x01, 0xe1, 0xf3, 0x86, 0xd8,
1137                0x0f, 0x52, 0x12, 0x3f, 0xd0, 0x0f, 0x02, 0x19, 0x74, 0x91, 0xb6, 0x90, 0xbd, 0xdf,
1138                0xa7, 0x42, 0xca, 0x22
1139            ]
1140            .to_vec(),
1141            "Serialized ROInput does not match expected output"
1142        );
1143
1144        assert_eq!(
1145            roi,
1146            ROInput::deserialize(&serialized).expect("Failed to deserialize ROInput"),
1147            "Serialized and deserialized ROInput do not match"
1148        );
1149    }
1150
1151    #[test]
1152    fn serialize_single_bool() {
1153        let roi = ROInput::new().append_bool(true);
1154
1155        let serialized = roi.serialize();
1156        let expected_length = SER_HEADER_SIZE + 1; // 1 byte for the boolean
1157        assert_eq!(
1158            serialized.len(),
1159            expected_length,
1160            "Serialized ROInput length mismatch"
1161        );
1162        assert_eq!(
1163            serialized,
1164            [
1165                0x00, 0x00, 0x00, 0x00,
1166                0x01, 0x00, 0x00, 0x00,
1167                0x01  // Boolean value
1168            ]
1169            .to_vec(),
1170            "Serialized ROInput does not match expected output"
1171        );
1172
1173        assert_eq!(
1174            roi,
1175            ROInput::deserialize(&serialized).expect("Failed to deserialize ROInput"),
1176            "Serialized and deserialized ROInput do not match"
1177        );
1178    }
1179
1180    #[test]
1181    fn serialize_multiple_bools_length() {
1182        for i in 0..1024 {
1183            let roi = ROInput::new().append_bool(i % 2 == 0);
1184            let serialized = roi.serialize();
1185
1186            // Deserialize and check if it matches
1187            let deserialized_roi =
1188                ROInput::deserialize(&serialized).expect("Failed to deserialize ROInput");
1189            assert_eq!(
1190                roi, deserialized_roi,
1191                "Serialized and deserialized ROInput do not match for i={i}"
1192            );
1193        }
1194    }
1195
1196    #[test]
1197    fn deserialize_invalid() {
1198        let invalid_data = vec![0x01, 0x00, 0x00, 0x00]; // Invalid header, missing fields and bits
1199
1200        let result = ROInput::deserialize(&invalid_data);
1201        assert!(
1202            result.is_err(),
1203            "Deserialization should fail for invalid data"
1204        );
1205    }
1206
1207    #[test]
1208    fn deserialize_invalid_inconsistent_bitlen() {
1209        let invalid_data = vec![
1210            0x01, 0x00, 0x00, // Field count
1211            0x01, 0x00, 0x00, 0x00, // Bit count
1212            0x01, // Boolean value
1213                  // Missing bits for the boolean
1214        ];
1215
1216        let result = ROInput::deserialize(&invalid_data);
1217        assert!(
1218            result.is_err(),
1219            "Deserialization should fail for inconsistent bit length"
1220        );
1221    }
1222
1223    #[test]
1224    fn deserialize_invalid_message() {
1225        let msg = b"Test message for Mina compatibility".to_vec();
1226        let result = ROInput::deserialize(&msg);
1227        assert!(
1228            result.is_err(),
1229            "Deserialization should fail for invalid message format"
1230        );
1231    }
1232
1233    #[test]
1234    fn deserialize_invalid_fieldheader() {
1235        let invalid_data = vec![
1236            0x01, 0x00, 0x00, 0x00, // Field count
1237            0x01, 0x00, 0x00, 0x00, // Bit count
1238            // Incorrect number of bytes for field header
1239            0x01, 0x02, 0x03, 0x04, 0x01, // Boolean value
1240        ];
1241
1242        let result = ROInput::deserialize(&invalid_data);
1243        assert!(
1244            result.is_err(),
1245            "Deserialization should fail for overflow in field header"
1246        );
1247    }
1248
1249    #[test]
1250    fn serialize_tx() {
1251        let tx_roi = ROInput::new()
1252            .append_field(
1253                Fp::from_hex("41203c6bbac14b357301e1f386d80f52123fd00f02197491b690bddfa742ca22")
1254                    .expect("failed to create field"),
1255            )
1256            .append_field(
1257                Fp::from_hex("992cdaf29ffe15b2bcea5d00e498ed4fffd117c197f0f98586e405f72ef88e00")
1258                    .expect("failed to create field"),
1259            ) // source
1260            .append_field(
1261                Fp::from_hex("3fba4fa71bce0dfdf709d827463036d6291458dfef772ff65e87bd6d1b1e062a")
1262                    .expect("failed to create field"),
1263            ) // receiver
1264            .append_u64(1_000_000) // fee
1265            .append_u64(1) // fee token
1266            .append_bool(true) // fee payer pk odd
1267            .append_u32(0) // nonce
1268            .append_u32(u32::MAX) // valid_until
1269            .append_bytes(&[0; 34]) // memo
1270            .append_bool(false) // tags[0]
1271            .append_bool(false) // tags[1]
1272            .append_bool(false) // tags[2]
1273            .append_bool(true) // sender pk odd
1274            .append_bool(false) // receiver pk odd
1275            .append_u64(1) // token_id
1276            .append_u64(10_000_000_000) // amount
1277            .append_bool(false); // token_locked
1278
1279        let tx_bytes = tx_roi.serialize();
1280
1281        let deserialized_roi =
1282            ROInput::deserialize(&tx_bytes).expect("Failed to deserialize ROInput");
1283
1284        assert_eq!(
1285            tx_roi, deserialized_roi,
1286            "Serialized and deserialized ROInput do not match"
1287        );
1288    }
1289}