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_eq!(roi.bits.len(), 1);
331        assert_eq!(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_eq!(roi.bits.len(), 2);
338        assert_eq!(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_eq!(roi.bits.len(), 5);
350        assert_eq!(roi.bits.as_raw_slice(), [0x12]);
351    }
352
353    #[test]
354    fn append_byte() {
355        let roi = ROInput::new().append_bytes(&[0x01]);
356        assert_eq!(roi.bits.len(), 8);
357        assert_eq!(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_eq!(roi.bits.len(), 16);
364        assert_eq!(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_eq!(roi.bits.len(), 40);
371        assert_eq!(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_eq!(roi.bits.len(), 263);
406        assert_eq!(
407            roi.bits.as_raw_slice(),
408            [
409                0x18, 0xb7, 0xef, 0x42, 0x01, 0x28, 0xe6, 0x96, 0x23, 0xc0, 0xc0, 0xdc, 0xfa, 0x28,
410                0xd4, 0x7a, 0x02, 0x9d, 0x46, 0x27, 0x20, 0xde, 0xb7, 0x69, 0xd7, 0xb5, 0xdd, 0x6f,
411                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_eq!(roi.bits.len(), 510);
426        assert_eq!(
427            roi.bits.as_raw_slice(),
428            [
429                0x18, 0xb7, 0xef, 0x42, 0x01, 0x28, 0xe6, 0x96, 0x23, 0xc0, 0xc0, 0xdc, 0xfa, 0x28,
430                0xd4, 0x7a, 0x02, 0x9d, 0x46, 0x27, 0x20, 0xde, 0xb7, 0x69, 0xd7, 0xb5, 0xdd, 0x6f,
431                0x17, 0x44, 0x42, 0x96, 0xd0, 0xd8, 0x74, 0xa4, 0xc1, 0xad, 0xf1, 0xa0, 0x93, 0x3a,
432                0xa4, 0x09, 0x27, 0x87, 0xff, 0xd5, 0xed, 0xe5, 0xca, 0x5b, 0x21, 0xf4, 0xe2, 0xf4,
433                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_eq!(roi.bits.len(), 518);
451        assert_eq!(
452            roi.bits.as_raw_slice(),
453            [
454                0x60, 0xdb, 0x6f, 0x4f, 0x5b, 0x8c, 0xe1, 0xc7, 0xcb, 0x74, 0x7f, 0xba, 0x9e, 0x32,
455                0x4c, 0xc3, 0x26, 0x8c, 0x7a, 0x6e, 0x3f, 0x43, 0xcd, 0x82, 0xd4, 0x51, 0xae, 0x99,
456                0xa7, 0xb2, 0xbd, 0x1f, 0x15, 0xff, 0xbb, 0xba, 0x58, 0x03, 0xde, 0x75, 0xac, 0x79,
457                0x71, 0x1f, 0x2d, 0xa7, 0xdc, 0x4f, 0xa0, 0x25, 0x47, 0xec, 0x67, 0x15, 0xff, 0x77,
458                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_eq!(roi.bits.len(), 32);
509        assert_eq!(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_eq!(roi.bits.len(), 65);
519        assert_eq!(
520            roi.bits.as_raw_slice(),
521            [0xc1, 0x06, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x01]
522        );
523    }
524
525    #[test]
526    fn append_u64() {
527        let roi = ROInput::new().append_u64(6174u64);
528        assert_eq!(roi.bits.len(), 64);
529        assert_eq!(
530            roi.bits.as_raw_slice(),
531            [0x1e, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
532        );
533    }
534
535    #[test]
536    fn append_two_u64_and_bits() {
537        let roi = ROInput::new()
538            .append_bool(true)
539            .append_u64(u64::MAX / 6174u64)
540            .append_bool(false)
541            .append_u64(u64::MAX / 1111u64);
542        assert_eq!(roi.bits.len(), 130);
543        assert_eq!(
544            roi.bits.as_raw_slice(),
545            [
546                0xe1, 0x29, 0x89, 0xd6, 0xcb, 0x3a, 0x15, 0x00, 0x08, 0x17, 0xc4, 0x9b, 0x04, 0xf4,
547                0xeb, 0x00, 0x00
548            ]
549        );
550    }
551
552    #[test]
553    fn all_1() {
554        let roi = ROInput::new()
555            .append_bool(true)
556            .append_scalar(
557                Fq::from_hex("01d1755db21c8cd2a9cf5a3436178da3d70f484cd4b4c8834b799921e7d7a102")
558                    .expect("failed to create scalar"),
559            )
560            .append_u64(18_446_744_073_709_551_557)
561            .append_bytes(&[0xba, 0xdc, 0x0f, 0xfe])
562            .append_scalar(
563                Fq::from_hex("e70187e9b125524489d0433da76fd8287fa652eaebde147b45fa0cd86f171810")
564                    .expect("failed to create scalar"),
565            )
566            .append_bool(false)
567            .append_u32(2_147_483_647)
568            .append_bool(true);
569
570        assert_eq!(roi.bits.len(), 641);
571        assert_eq!(
572            roi.bits.as_raw_slice(),
573            [
574                0x03, 0xa2, 0xeb, 0xba, 0x64, 0x39, 0x18, 0xa5, 0x53, 0x9f, 0xb5, 0x68, 0x6c, 0x2e,
575                0x1a, 0x47, 0xaf, 0x1f, 0x90, 0x98, 0xa8, 0x69, 0x91, 0x07, 0x97, 0xf2, 0x32, 0x43,
576                0xce, 0xaf, 0x43, 0x05, 0xc5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xba, 0xdc,
577                0x0f, 0xfe, 0xe7, 0x01, 0x87, 0xe9, 0xb1, 0x25, 0x52, 0x44, 0x89, 0xd0, 0x43, 0x3d,
578                0xa7, 0x6f, 0xd8, 0x28, 0x7f, 0xa6, 0x52, 0xea, 0xeb, 0xde, 0x14, 0x7b, 0x45, 0xfa,
579                0x0c, 0xd8, 0x6f, 0x17, 0x18, 0x10, 0xff, 0xff, 0xff, 0x7f, 0x01
580            ]
581        );
582    }
583
584    #[test]
585    fn transaction_bits() {
586        let roi = ROInput::new()
587            .append_u64(1_000_000) // fee
588            .append_u64(1) // fee token
589            .append_bool(true) // fee payer pk odd
590            .append_u32(0) // nonce
591            .append_u32(u32::MAX) // valid_until
592            .append_bytes(&[0; 34]) // memo
593            .append_bool(false) // tags[0]
594            .append_bool(false) // tags[1]
595            .append_bool(false) // tags[2]
596            .append_bool(true) // sender pk odd
597            .append_bool(false) // receiver pk odd
598            .append_u64(1) // token_id
599            .append_u64(10_000_000_000) // amount
600            .append_bool(false) // token_locked
601            .append_scalar(
602                Fq::from_hex("de217a3017ca0b7a278e75f63c09890e3894be532d8dbadd30a7d450055f6d2d")
603                    .expect("failed to create scalar"),
604            )
605            .append_bytes(&[0x01]);
606        assert_eq!(roi.bits.len(), 862);
607        assert_eq!(
608            roi.bits.as_raw_slice(),
609            [
610                0x40, 0x42, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
611                0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
612                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
613                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
614                0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x02,
615                0x95, 0x00, 0x00, 0x00, 0x00, 0xef, 0x10, 0x3d, 0x98, 0x0b, 0xe5, 0x05, 0xbd, 0x13,
616                0xc7, 0x3a, 0x7b, 0x9e, 0x84, 0x44, 0x07, 0x1c, 0x4a, 0xdf, 0xa9, 0x96, 0x46, 0xdd,
617                0x6e, 0x98, 0x53, 0x6a, 0xa8, 0x82, 0xaf, 0xb6, 0x56, 0x00
618            ]
619        );
620    }
621
622    #[test]
623    fn append_field() {
624        let roi = ROInput::new().append_field(
625            Fp::from_hex("2eaedae42a7461d5952d27b97ecad068b698ebb94e8a0e4c45388bb613de7e08")
626                .expect("failed to create field"),
627        );
628
629        assert_eq!(
630            roi.to_bytes(),
631            [
632                0x2e, 0xae, 0xda, 0xe4, 0x2a, 0x74, 0x61, 0xd5, 0x95, 0x2d, 0x27, 0xb9, 0x7e, 0xca,
633                0xd0, 0x68, 0xb6, 0x98, 0xeb, 0xb9, 0x4e, 0x8a, 0x0e, 0x4c, 0x45, 0x38, 0x8b, 0xb6,
634                0x13, 0xde, 0x7e, 0x08
635            ]
636        );
637    }
638
639    #[test]
640    fn append_two_fields() {
641        let roi = ROInput::new()
642            .append_field(
643                Fp::from_hex("0cdaf334e9632268a5aa959c2781fb32bf45565fe244ae42c849d3fdc7c6441d")
644                    .expect("failed to create field"),
645            )
646            .append_field(
647                Fp::from_hex("2eaedae42a7461d5952d27b97ecad068b698ebb94e8a0e4c45388bb613de7e08")
648                    .expect("failed to create field"),
649            );
650
651        assert_eq!(
652            roi.to_bytes(),
653            [
654                0x0c, 0xda, 0xf3, 0x34, 0xe9, 0x63, 0x22, 0x68, 0xa5, 0xaa, 0x95, 0x9c, 0x27, 0x81,
655                0xfb, 0x32, 0xbf, 0x45, 0x56, 0x5f, 0xe2, 0x44, 0xae, 0x42, 0xc8, 0x49, 0xd3, 0xfd,
656                0xc7, 0xc6, 0x44, 0x1d, 0x17, 0x57, 0x6d, 0x72, 0x15, 0xba, 0xb0, 0xea, 0xca, 0x96,
657                0x93, 0x5c, 0x3f, 0x65, 0x68, 0x34, 0x5b, 0xcc, 0xf5, 0x5c, 0x27, 0x45, 0x07, 0xa6,
658                0x22, 0x9c, 0x45, 0xdb, 0x09, 0x6f, 0x3f, 0x04
659            ]
660        );
661    }
662
663    #[test]
664    fn append_three_fields() {
665        let roi = ROInput::new()
666            .append_field(
667                Fp::from_hex("1f3f142986041b54427aa2032632e34df2fa9bde9bce70c04c5034266619e529")
668                    .expect("failed to create field"),
669            )
670            .append_field(
671                Fp::from_hex("37f4433b85e753a91a1d79751645f1448954c433f9492e36a933ca7f3df61a04")
672                    .expect("failed to create field"),
673            )
674            .append_field(
675                Fp::from_hex("6cf4772d3e1aab98a2b514b73a4f6e0df1fb4f703ecfa762196b22c26da4341c")
676                    .expect("failed to create field"),
677            );
678
679        assert_eq!(
680            roi.to_bytes(),
681            [
682                0x1f, 0x3f, 0x14, 0x29, 0x86, 0x04, 0x1b, 0x54, 0x42, 0x7a, 0xa2, 0x03, 0x26, 0x32,
683                0xe3, 0x4d, 0xf2, 0xfa, 0x9b, 0xde, 0x9b, 0xce, 0x70, 0xc0, 0x4c, 0x50, 0x34, 0x26,
684                0x66, 0x19, 0xe5, 0xa9, 0x1b, 0xfa, 0xa1, 0x9d, 0xc2, 0xf3, 0xa9, 0x54, 0x8d, 0x8e,
685                0xbc, 0x3a, 0x8b, 0xa2, 0x78, 0xa2, 0x44, 0x2a, 0xe2, 0x99, 0xfc, 0x24, 0x17, 0x9b,
686                0xd4, 0x19, 0xe5, 0xbf, 0x1e, 0x7b, 0x0d, 0x02, 0x1b, 0xfd, 0x5d, 0x8b, 0x8f, 0xc6,
687                0x2a, 0xa6, 0x68, 0x2d, 0xc5, 0xad, 0xce, 0x93, 0x5b, 0x43, 0xfc, 0xfe, 0x13, 0x9c,
688                0xcf, 0xf3, 0xa9, 0x58, 0xc6, 0x9a, 0x88, 0x70, 0x1b, 0x29, 0x0d, 0x07
689            ]
690        );
691    }
692
693    #[test]
694    fn append_field_and_scalar() {
695        let roi = ROInput::new()
696            .append_field(
697                Fp::from_hex("64cde530327a36fcb88b6d769adca9b7c5d266e7d0042482203f3fd3a0d71721")
698                    .expect("failed to create field"),
699            )
700            .append_scalar(
701                Fq::from_hex("604355d0daa455db783fd7ee11c5bd9b04d67ba64c27c95bef95e379f98c6432")
702                    .expect("failed to create scalar"),
703            );
704
705        assert_eq!(
706            roi.to_bytes(),
707            [
708                0x64, 0xcd, 0xe5, 0x30, 0x32, 0x7a, 0x36, 0xfc, 0xb8, 0x8b, 0x6d, 0x76, 0x9a, 0xdc,
709                0xa9, 0xb7, 0xc5, 0xd2, 0x66, 0xe7, 0xd0, 0x04, 0x24, 0x82, 0x20, 0x3f, 0x3f, 0xd3,
710                0xa0, 0xd7, 0x17, 0x21, 0xb0, 0xa1, 0x2a, 0x68, 0x6d, 0xd2, 0xaa, 0x6d, 0xbc, 0x9f,
711                0x6b, 0xf7, 0x88, 0xe2, 0xde, 0x4d, 0x02, 0xeb, 0x3d, 0x53, 0xa6, 0x93, 0xe4, 0xad,
712                0xf7, 0xca, 0xf1, 0xbc, 0x7c, 0x46, 0x32, 0x19
713            ]
714        );
715    }
716
717    #[test]
718    fn append_field_bit_and_scalar() {
719        let roi = ROInput::new()
720            .append_field(
721                Fp::from_hex("d897c7a8b811d8acd3eeaa4adf42292802eed80031c2ad7c8989aea1fe94322c")
722                    .expect("failed to create field"),
723            )
724            .append_bool(false)
725            .append_scalar(
726                Fq::from_hex("79586cc6b8b53c8991b2abe0ca76508f056ca50f06836ce4d818c2ff73d42b28")
727                    .expect("failed to create scalar"),
728            );
729
730        assert_eq!(
731            roi.to_bytes(),
732            [
733                0xd8, 0x97, 0xc7, 0xa8, 0xb8, 0x11, 0xd8, 0xac, 0xd3, 0xee, 0xaa, 0x4a, 0xdf, 0x42,
734                0x29, 0x28, 0x02, 0xee, 0xd8, 0x00, 0x31, 0xc2, 0xad, 0x7c, 0x89, 0x89, 0xae, 0xa1,
735                0xfe, 0x94, 0x32, 0x2c, 0x79, 0x58, 0x6c, 0xc6, 0xb8, 0xb5, 0x3c, 0x89, 0x91, 0xb2,
736                0xab, 0xe0, 0xca, 0x76, 0x50, 0x8f, 0x05, 0x6c, 0xa5, 0x0f, 0x06, 0x83, 0x6c, 0xe4,
737                0xd8, 0x18, 0xc2, 0xff, 0x73, 0xd4, 0x2b, 0x28
738            ]
739        );
740    }
741
742    #[test]
743    fn to_bytes() {
744        let roi = ROInput::new()
745            .append_field(
746                Fp::from_hex("a5984f2bd00906f9a86e75bfb4b2c3625f1a0d1cfacc1501e8e82ae7041efc14")
747                    .expect("failed to create field"),
748            )
749            .append_field(
750                Fp::from_hex("8af0bc770d49a5b9fcabfcdd033bab470b2a211ef80b710efe71315cfa818c0a")
751                    .expect("failed to create field"),
752            )
753            .append_bool(false)
754            .append_u32(314u32)
755            .append_scalar(
756                Fq::from_hex("c23c43a23ddc1516578b0f0d81b93cdbbc97744acc697cfc8c5dfd01cc448323")
757                    .expect("failed to create scalar"),
758            );
759
760        assert_eq!(
761            roi.to_bytes(),
762            [
763                0xa5, 0x98, 0x4f, 0x2b, 0xd0, 0x09, 0x06, 0xf9, 0xa8, 0x6e, 0x75, 0xbf, 0xb4, 0xb2,
764                0xc3, 0x62, 0x5f, 0x1a, 0x0d, 0x1c, 0xfa, 0xcc, 0x15, 0x01, 0xe8, 0xe8, 0x2a, 0xe7,
765                0x04, 0x1e, 0xfc, 0x14, 0x45, 0x78, 0xde, 0xbb, 0x86, 0xa4, 0xd2, 0x5c, 0xfe, 0x55,
766                0xfe, 0xee, 0x81, 0x9d, 0xd5, 0xa3, 0x05, 0x95, 0x10, 0x0f, 0xfc, 0x85, 0x38, 0x07,
767                0xff, 0xb8, 0x18, 0x2e, 0xfd, 0x40, 0x46, 0x05, 0x9d, 0x00, 0x00, 0x00, 0x61, 0x9e,
768                0x21, 0xd1, 0x1e, 0xee, 0x0a, 0x8b, 0xab, 0xc5, 0x87, 0x86, 0xc0, 0x5c, 0x9e, 0x6d,
769                0xde, 0x4b, 0x3a, 0x25, 0xe6, 0x34, 0x3e, 0x7e, 0xc6, 0xae, 0xfe, 0x00, 0x66, 0xa2,
770                0xc1, 0x11
771            ]
772        );
773    }
774
775    #[test]
776    fn to_fields_1_scalar() {
777        let roi = ROInput::new().append_scalar(
778            Fq::from_hex("5d496dd8ff63f640c006887098092b16bc8c78504f84fa1ee3a0b54f85f0a625")
779                .expect("failed to create scalar"),
780        );
781
782        assert_eq!(
783            roi.to_bytes(),
784            [
785                0x5d, 0x49, 0x6d, 0xd8, 0xff, 0x63, 0xf6, 0x40, 0xc0, 0x06, 0x88, 0x70, 0x98, 0x09,
786                0x2b, 0x16, 0xbc, 0x8c, 0x78, 0x50, 0x4f, 0x84, 0xfa, 0x1e, 0xe3, 0xa0, 0xb5, 0x4f,
787                0x85, 0xf0, 0xa6, 0x25
788            ]
789        );
790
791        assert_eq!(
792            roi.to_fields(),
793            [
794                Fp::from_hex("5d496dd8ff63f640c006887098092b16bc8c78504f84fa1ee3a0b54f85f0a625")
795                    .expect("failed to create field"),
796                Fp::from_hex("0000000000000000000000000000000000000000000000000000000000000000")
797                    .expect("failed to create field"),
798            ]
799        );
800    }
801
802    #[test]
803    fn to_fields_1_scalar_2_bits() {
804        let roi = ROInput::new()
805            .append_scalar(
806                Fq::from_hex("e8a9961c8c417b0d0e3d7366f6b0e6ef90a6dad123070f715e8a9eaa02e47330")
807                    .expect("failed to create scalar"),
808            )
809            .append_bool(false)
810            .append_bool(true);
811
812        assert_eq!(
813            roi.to_bytes(),
814            [
815                0xe8, 0xa9, 0x96, 0x1c, 0x8c, 0x41, 0x7b, 0x0d, 0x0e, 0x3d, 0x73, 0x66, 0xf6, 0xb0,
816                0xe6, 0xef, 0x90, 0xa6, 0xda, 0xd1, 0x23, 0x07, 0x0f, 0x71, 0x5e, 0x8a, 0x9e, 0xaa,
817                0x02, 0xe4, 0x73, 0x30, 0x01
818            ]
819        );
820
821        assert_eq!(
822            roi.to_fields(),
823            [
824                Fp::from_hex("e8a9961c8c417b0d0e3d7366f6b0e6ef90a6dad123070f715e8a9eaa02e47330")
825                    .expect("failed to create field"),
826                Fp::from_hex("0400000000000000000000000000000000000000000000000000000000000000")
827                    .expect("failed to create field"),
828            ]
829        );
830    }
831
832    #[test]
833    fn to_fields_2_scalars() {
834        let roi = ROInput::new()
835            .append_scalar(
836                Fq::from_hex("e05c25d2c17ec20d6bc8fd21204af52808451076cff687407164a21d352ddd22")
837                    .expect("failed to create scalar"),
838            )
839            .append_scalar(
840                Fq::from_hex("c356dbb39478508818e0320dffa6c1ef512564366ec885ee2fc4d385dd36df0f")
841                    .expect("failed to create scalar"),
842            );
843
844        assert_eq!(
845            roi.to_bytes(),
846            [
847                0xe0, 0x5c, 0x25, 0xd2, 0xc1, 0x7e, 0xc2, 0x0d, 0x6b, 0xc8, 0xfd, 0x21, 0x20, 0x4a,
848                0xf5, 0x28, 0x08, 0x45, 0x10, 0x76, 0xcf, 0xf6, 0x87, 0x40, 0x71, 0x64, 0xa2, 0x1d,
849                0x35, 0x2d, 0xdd, 0xa2, 0x61, 0xab, 0xed, 0x59, 0x4a, 0x3c, 0x28, 0x44, 0x0c, 0x70,
850                0x99, 0x86, 0x7f, 0xd3, 0xe0, 0xf7, 0xa8, 0x12, 0x32, 0x1b, 0x37, 0xe4, 0x42, 0xf7,
851                0x17, 0xe2, 0xe9, 0xc2, 0x6e, 0x9b, 0xef, 0x07
852            ]
853        );
854
855        assert_eq!(
856            roi.to_fields(),
857            [
858                Fp::from_hex("e05c25d2c17ec20d6bc8fd21204af52808451076cff687407164a21d352ddd22")
859                    .expect("failed to create field"),
860                Fp::from_hex("86adb66729f1a01031c0651afe4d83dfa34ac86cdc900bdd5f88a70bbb6dbe1f")
861                    .expect("failed to create field"),
862                Fp::from_hex("0000000000000000000000000000000000000000000000000000000000000000")
863                    .expect("failed to create field"),
864            ]
865        );
866    }
867
868    #[test]
869    fn to_fields_2_bits_scalar_u32() {
870        let roi = ROInput::new()
871            .append_bool(true)
872            .append_bool(false)
873            .append_scalar(
874                Fq::from_hex("689634de233b06251a80ac7df64483922727757eea1adc6f0c8f184441cfe10d")
875                    .expect("failed to create scalar"),
876            )
877            .append_u32(834_803);
878
879        assert_eq!(
880            roi.to_bytes(),
881            [
882                0xa1, 0x59, 0xd2, 0x78, 0x8f, 0xec, 0x18, 0x94, 0x68, 0x00, 0xb2, 0xf6, 0xd9, 0x13,
883                0x0d, 0x4a, 0x9e, 0x9c, 0xd4, 0xf9, 0xa9, 0x6b, 0x70, 0xbf, 0x31, 0x3c, 0x62, 0x10,
884                0x05, 0x3d, 0x87, 0x37, 0xe6, 0x79, 0x19, 0x00, 0x00
885            ]
886        );
887
888        assert_eq!(
889            roi.to_fields(),
890            [
891                Fp::from_hex("a159d2788fec18946800b2f6d9130d4a9e9cd4f9a96b70bf313c6210053d8737")
892                    .expect("failed to create field"),
893                Fp::from_hex("98e7650000000000000000000000000000000000000000000000000000000000")
894                    .expect("failed to create field"),
895            ]
896        );
897    }
898
899    #[test]
900    fn to_fields_2_bits_field_scalar() {
901        let roi = ROInput::new()
902            .append_bool(false)
903            .append_bool(true)
904            .append_field(
905                Fp::from_hex("90926b620ad09ed616d5df158504faed42928719c58ae619d9eccc062f920411")
906                    .expect("failed to create field"),
907            )
908            .append_scalar(
909                Fq::from_hex("689634de233b06251a80ac7df64483922727757eea1adc6f0c8f184441cfe10d")
910                    .expect("failed to create scalar"),
911            );
912
913        assert_eq!(
914            roi.to_bytes(),
915            [
916                0x90, 0x92, 0x6b, 0x62, 0x0a, 0xd0, 0x9e, 0xd6, 0x16, 0xd5, 0xdf, 0x15, 0x85, 0x04,
917                0xfa, 0xed, 0x42, 0x92, 0x87, 0x19, 0xc5, 0x8a, 0xe6, 0x19, 0xd9, 0xec, 0xcc, 0x06,
918                0x2f, 0x92, 0x04, 0x11, 0xd1, 0x2c, 0x69, 0xbc, 0x47, 0x76, 0x0c, 0x4a, 0x34, 0x00,
919                0x59, 0xfb, 0xec, 0x89, 0x06, 0x25, 0x4f, 0x4e, 0xea, 0xfc, 0xd4, 0x35, 0xb8, 0xdf,
920                0x18, 0x1e, 0x31, 0x88, 0x82, 0x9e, 0xc3, 0x1b
921            ]
922        );
923
924        assert_eq!(
925            roi.to_fields(),
926            [
927                Fp::from_hex("90926b620ad09ed616d5df158504faed42928719c58ae619d9eccc062f920411")
928                    .expect("failed to create field"),
929                Fp::from_hex("a259d2788fec18946800b2f6d9130d4a9e9cd4f9a96b70bf313c6210053d8737")
930                    .expect("failed to create field"),
931                Fp::from_hex("0000000000000000000000000000000000000000000000000000000000000000")
932                    .expect("failed to create field"),
933            ]
934        );
935    }
936
937    #[test]
938    fn transaction_test_1() {
939        let roi = ROInput::new()
940            .append_field(
941                Fp::from_hex("41203c6bbac14b357301e1f386d80f52123fd00f02197491b690bddfa742ca22")
942                    .expect("failed to create field"),
943            ) // fee payer
944            .append_field(
945                Fp::from_hex("992cdaf29ffe15b2bcea5d00e498ed4fffd117c197f0f98586e405f72ef88e00")
946                    .expect("failed to create field"),
947            ) // source
948            .append_field(
949                Fp::from_hex("3fba4fa71bce0dfdf709d827463036d6291458dfef772ff65e87bd6d1b1e062a")
950                    .expect("failed to create field"),
951            ) // receiver
952            .append_u64(1_000_000) // fee
953            .append_u64(1) // fee token
954            .append_bool(true) // fee payer pk odd
955            .append_u32(0) // nonce
956            .append_u32(u32::MAX) // valid_until
957            .append_bytes(&[0; 34]) // memo
958            .append_bool(false) // tags[0]
959            .append_bool(false) // tags[1]
960            .append_bool(false) // tags[2]
961            .append_bool(true) // sender pk odd
962            .append_bool(false) // receiver pk odd
963            .append_u64(1) // token_id
964            .append_u64(10_000_000_000) // amount
965            .append_bool(false); // token_locked
966        assert_eq!(roi.bits.len() + roi.fields.len() * 255, 1364);
967        assert_eq!(
968            roi.to_bytes(),
969            [
970                0x41, 0x20, 0x3c, 0x6b, 0xba, 0xc1, 0x4b, 0x35, 0x73, 0x01, 0xe1, 0xf3, 0x86, 0xd8,
971                0x0f, 0x52, 0x12, 0x3f, 0xd0, 0x0f, 0x02, 0x19, 0x74, 0x91, 0xb6, 0x90, 0xbd, 0xdf,
972                0xa7, 0x42, 0xca, 0xa2, 0x4c, 0x16, 0x6d, 0xf9, 0x4f, 0xff, 0x0a, 0x59, 0x5e, 0xf5,
973                0x2e, 0x00, 0x72, 0xcc, 0xf6, 0xa7, 0xff, 0xe8, 0x8b, 0xe0, 0x4b, 0xf8, 0xfc, 0x42,
974                0x43, 0xf2, 0x82, 0x7b, 0x17, 0x7c, 0x47, 0xc0, 0x8f, 0xee, 0xd3, 0xe9, 0x86, 0x73,
975                0x43, 0xff, 0x7d, 0x02, 0xf6, 0x89, 0x11, 0x8c, 0x8d, 0x75, 0x0a, 0x05, 0xd6, 0xf7,
976                0xfb, 0xdd, 0x8b, 0xbd, 0xd7, 0x61, 0x6f, 0xdb, 0x86, 0x87, 0x81, 0x0a, 0x48, 0xe8,
977                0x01, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
978                0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
979                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
980                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
981                0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x5f, 0xa0, 0x12, 0x00,
982                0x00, 0x00, 0x00
983            ]
984        );
985
986        assert_eq!(
987            roi.to_fields(),
988            [
989                Fp::from_hex("41203c6bbac14b357301e1f386d80f52123fd00f02197491b690bddfa742ca22")
990                    .expect("failed to create field"),
991                Fp::from_hex("992cdaf29ffe15b2bcea5d00e498ed4fffd117c197f0f98586e405f72ef88e00")
992                    .expect("failed to create field"),
993                Fp::from_hex("3fba4fa71bce0dfdf709d827463036d6291458dfef772ff65e87bd6d1b1e062a")
994                    .expect("failed to create field"),
995                Fp::from_hex("40420f0000000000010000000000000001000000feffffff0100000000000000")
996                    .expect("failed to create field"),
997                Fp::from_hex("0000000000000000000000000000000000000000000000000000400100000000")
998                    .expect("failed to create field"),
999                Fp::from_hex("00000000902f5009000000000000000000000000000000000000000000000000")
1000                    .expect("failed to create field"),
1001            ]
1002        );
1003    }
1004
1005    #[test]
1006    fn nested_roinput_test() {
1007        #[derive(Clone, Debug)]
1008        struct A {
1009            x: u32,
1010            y: bool,
1011            z: u32,
1012        }
1013
1014        impl Hashable for A {
1015            type D = ();
1016
1017            fn to_roinput(&self) -> ROInput {
1018                ROInput::new()
1019                    .append_u32(self.x)
1020                    .append_bool(self.y)
1021                    .append_u32(self.z)
1022            }
1023
1024            fn domain_string((): Self::D) -> Option<String> {
1025                "A".to_string().into()
1026            }
1027        }
1028
1029        #[derive(Clone, Debug)]
1030        struct B1 {
1031            a: A,
1032            b: u64,
1033            c: bool,
1034        }
1035
1036        impl Hashable for B1 {
1037            type D = ();
1038
1039            fn to_roinput(&self) -> ROInput {
1040                self.a.to_roinput().append_u64(self.b).append_bool(self.c)
1041            }
1042
1043            fn domain_string((): Self::D) -> Option<String> {
1044                "B".to_string().into()
1045            }
1046        }
1047
1048        #[derive(Clone, Debug)]
1049        struct B2 {
1050            a: A,
1051            b: u64,
1052            c: bool,
1053        }
1054
1055        impl Hashable for B2 {
1056            type D = ();
1057
1058            fn to_roinput(&self) -> ROInput {
1059                self.a
1060                    .to_roinput()
1061                    .append_roinput(ROInput::new().append_u64(self.b).append_bool(self.c))
1062            }
1063
1064            fn domain_string((): Self::D) -> Option<String> {
1065                "B".to_string().into()
1066            }
1067        }
1068
1069        let a = A {
1070            x: 16_830_533,
1071            y: false,
1072            z: 39_827_791,
1073        };
1074        let b1 = B1 {
1075            a,
1076            b: 124_819,
1077            c: true,
1078        };
1079        let b2 = B2 {
1080            a: b1.a.clone(),
1081            b: b1.b,
1082            c: b1.c,
1083        };
1084
1085        assert_eq!(b1.to_roinput(), b2.to_roinput());
1086
1087        let b2 = B2 {
1088            a: b1.a.clone(),
1089            b: b1.b,
1090            c: false,
1091        };
1092        assert_ne!(b1.to_roinput(), b2.to_roinput());
1093
1094        let b2 = B2 {
1095            a: b1.a.clone(),
1096            b: b1.b + 1,
1097            c: b1.c,
1098        };
1099        assert_ne!(b1.to_roinput(), b2.to_roinput());
1100    }
1101
1102    #[test]
1103    fn serialize_empty() {
1104        let roi = ROInput::new();
1105
1106        let serialized = roi.serialize();
1107
1108        assert_eq!(
1109            serialized,
1110            vec![0; SER_HEADER_SIZE],
1111            "Serialized empty ROInput should be zero bytes"
1112        );
1113
1114        let deserialized_roi =
1115            ROInput::deserialize(&serialized).expect("Failed to deserialize ROInput");
1116        assert_eq!(
1117            roi, deserialized_roi,
1118            "Serialized and deserialized ROInput do not match"
1119        );
1120    }
1121
1122    #[test]
1123    fn serialize_single_field() {
1124        let roi = ROInput::new().append_field(
1125            Fp::from_hex("41203c6bbac14b357301e1f386d80f52123fd00f02197491b690bddfa742ca22")
1126                .expect("failed to create field"),
1127        );
1128
1129        let serialized = roi.serialize();
1130        let expected_length = SER_HEADER_SIZE + 32; // 32 bytes for the field
1131        assert_eq!(
1132            serialized.len(),
1133            expected_length,
1134            "Serialized ROInput length mismatch"
1135        );
1136        assert_eq!(
1137            serialized,
1138            [
1139                0x01, 0x00, 0x00, 0x00, // Field count
1140                0x00, 0x00, 0x00, 0x00, // Bit count
1141                0x41, 0x20, 0x3c, 0x6b, 0xba, 0xc1, 0x4b, 0x35, 0x73, 0x01, 0xe1, 0xf3, 0x86, 0xd8,
1142                0x0f, 0x52, 0x12, 0x3f, 0xd0, 0x0f, 0x02, 0x19, 0x74, 0x91, 0xb6, 0x90, 0xbd, 0xdf,
1143                0xa7, 0x42, 0xca, 0x22
1144            ]
1145            .to_vec(),
1146            "Serialized ROInput does not match expected output"
1147        );
1148
1149        assert_eq!(
1150            roi,
1151            ROInput::deserialize(&serialized).expect("Failed to deserialize ROInput"),
1152            "Serialized and deserialized ROInput do not match"
1153        );
1154    }
1155
1156    #[test]
1157    fn serialize_single_bool() {
1158        let roi = ROInput::new().append_bool(true);
1159
1160        let serialized = roi.serialize();
1161        let expected_length = SER_HEADER_SIZE + 1; // 1 byte for the boolean
1162        assert_eq!(
1163            serialized.len(),
1164            expected_length,
1165            "Serialized ROInput length mismatch"
1166        );
1167        assert_eq!(
1168            serialized,
1169            [
1170                0x00, 0x00, 0x00, 0x00,
1171                0x01, 0x00, 0x00, 0x00,
1172                0x01  // Boolean value
1173            ]
1174            .to_vec(),
1175            "Serialized ROInput does not match expected output"
1176        );
1177
1178        assert_eq!(
1179            roi,
1180            ROInput::deserialize(&serialized).expect("Failed to deserialize ROInput"),
1181            "Serialized and deserialized ROInput do not match"
1182        );
1183    }
1184
1185    #[test]
1186    fn serialize_multiple_bools_length() {
1187        for i in 0..1024 {
1188            let roi = ROInput::new().append_bool(i % 2 == 0);
1189            let serialized = roi.serialize();
1190
1191            // Deserialize and check if it matches
1192            let deserialized_roi =
1193                ROInput::deserialize(&serialized).expect("Failed to deserialize ROInput");
1194            assert_eq!(
1195                roi, deserialized_roi,
1196                "Serialized and deserialized ROInput do not match for i={i}"
1197            );
1198        }
1199    }
1200
1201    #[test]
1202    fn deserialize_invalid() {
1203        let invalid_data = vec![0x01, 0x00, 0x00, 0x00]; // Invalid header, missing fields and bits
1204
1205        let result = ROInput::deserialize(&invalid_data);
1206        assert!(
1207            result.is_err(),
1208            "Deserialization should fail for invalid data"
1209        );
1210    }
1211
1212    #[test]
1213    fn deserialize_invalid_inconsistent_bitlen() {
1214        let invalid_data = vec![
1215            0x01, 0x00, 0x00, // Field count
1216            0x01, 0x00, 0x00, 0x00, // Bit count
1217            0x01, // Boolean value
1218                  // Missing bits for the boolean
1219        ];
1220
1221        let result = ROInput::deserialize(&invalid_data);
1222        assert!(
1223            result.is_err(),
1224            "Deserialization should fail for inconsistent bit length"
1225        );
1226    }
1227
1228    #[test]
1229    fn deserialize_invalid_message() {
1230        let msg = b"Test message for Mina compatibility".to_vec();
1231        let result = ROInput::deserialize(&msg);
1232        assert!(
1233            result.is_err(),
1234            "Deserialization should fail for invalid message format"
1235        );
1236    }
1237
1238    #[test]
1239    fn deserialize_invalid_fieldheader() {
1240        let invalid_data = vec![
1241            0x01, 0x00, 0x00, 0x00, // Field count
1242            0x01, 0x00, 0x00, 0x00, // Bit count
1243            // Incorrect number of bytes for field header
1244            0x01, 0x02, 0x03, 0x04, 0x01, // Boolean value
1245        ];
1246
1247        let result = ROInput::deserialize(&invalid_data);
1248        assert!(
1249            result.is_err(),
1250            "Deserialization should fail for overflow in field header"
1251        );
1252    }
1253
1254    #[test]
1255    fn serialize_tx() {
1256        let tx_roi = ROInput::new()
1257            .append_field(
1258                Fp::from_hex("41203c6bbac14b357301e1f386d80f52123fd00f02197491b690bddfa742ca22")
1259                    .expect("failed to create field"),
1260            )
1261            .append_field(
1262                Fp::from_hex("992cdaf29ffe15b2bcea5d00e498ed4fffd117c197f0f98586e405f72ef88e00")
1263                    .expect("failed to create field"),
1264            ) // source
1265            .append_field(
1266                Fp::from_hex("3fba4fa71bce0dfdf709d827463036d6291458dfef772ff65e87bd6d1b1e062a")
1267                    .expect("failed to create field"),
1268            ) // receiver
1269            .append_u64(1_000_000) // fee
1270            .append_u64(1) // fee token
1271            .append_bool(true) // fee payer pk odd
1272            .append_u32(0) // nonce
1273            .append_u32(u32::MAX) // valid_until
1274            .append_bytes(&[0; 34]) // memo
1275            .append_bool(false) // tags[0]
1276            .append_bool(false) // tags[1]
1277            .append_bool(false) // tags[2]
1278            .append_bool(true) // sender pk odd
1279            .append_bool(false) // receiver pk odd
1280            .append_u64(1) // token_id
1281            .append_u64(10_000_000_000) // amount
1282            .append_bool(false); // token_locked
1283
1284        let tx_bytes = tx_roi.serialize();
1285
1286        let deserialized_roi =
1287            ROInput::deserialize(&tx_bytes).expect("Failed to deserialize ROInput");
1288
1289        assert_eq!(
1290            tx_roi, deserialized_roi,
1291            "Serialized and deserialized ROInput do not match"
1292        );
1293    }
1294}