1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#![cfg(feature = "ssz")]
#![cfg_attr(docsrs, doc(cfg(feature = "ssz")))]
use ssz::{Decode, DecodeError, Encode};

use crate::{nbytes, Uint};

impl<const BITS: usize, const LIMBS: usize> Encode for Uint<BITS, LIMBS> {
    fn is_ssz_fixed_len() -> bool {
        true
    }

    fn ssz_fixed_len() -> usize {
        nbytes(BITS)
    }

    fn ssz_bytes_len(&self) -> usize {
        nbytes(BITS)
    }

    fn ssz_append(&self, buf: &mut Vec<u8>) {
        buf.extend_from_slice(&self.as_le_bytes());
    }
}

impl<const BITS: usize, const LIMBS: usize> Decode for Uint<BITS, LIMBS> {
    fn is_ssz_fixed_len() -> bool {
        true
    }

    fn ssz_fixed_len() -> usize {
        nbytes(BITS)
    }

    fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
        if bytes.len() > nbytes(BITS) {
            return Err(DecodeError::InvalidByteLength {
                len:      bytes.len(),
                expected: nbytes(BITS),
            });
        }
        Ok(Self::from_le_slice(bytes))
    }
}

#[cfg(test)]
mod tests {
    use proptest::proptest;
    use ruint::{const_for, nlimbs, Uint};
    use ssz::DecodeError;

    #[test]
    fn test_ssz_human_readable() {
        const_for!(BITS in SIZES {
            const LIMBS: usize = nlimbs(BITS);
            proptest!(|(value: Uint<BITS, LIMBS>)| {
                let expected = value;
                let encoded = ssz::Encode::as_ssz_bytes(&expected);
                let actual = ssz::Decode::from_ssz_bytes(&encoded).unwrap();
                assert_eq!(expected, actual, "Failed for value: {value:?}" );
            });

        });
    }

    #[test]
    fn test_ssz_decode_error_length() {
        const_for!(BITS in SIZES {
            const LIMBS: usize = nlimbs(BITS);
            proptest!(|(value: Uint<BITS, LIMBS>)| {
                let encoded = ssz::Encode::as_ssz_bytes(&value);
                let mut oversized = encoded;
                oversized.push(0);

                let result = <Uint<BITS, LIMBS> as ssz::Decode>::from_ssz_bytes(&oversized);
                assert!(matches!(result, Err(DecodeError::InvalidByteLength { len:_, expected:_ })));
            });
        });
    }
}