snarkvm_console_program/data/literal/
from_bits.rs

1// Copyright 2024-2025 Aleo Network Foundation
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::*;
17
18impl<N: Network> Literal<N> {
19    /// Initializes a new literal from a list of little-endian bits *without* trailing zeros.
20    pub fn from_bits_le(variant: u8, bits_le: &[bool]) -> Result<Self> {
21        let literal = bits_le;
22        let literal = match variant {
23            0 => Literal::Address(Address::new(Group::from_x_coordinate(Field::<N>::from_bits_le(literal)?)?)),
24            1 => match bits_le.len() {
25                1 => Literal::Boolean(Boolean::new(literal[0])),
26                _ => bail!("Expected a boolean literal, but found a list of {} bits.", bits_le.len()),
27            },
28            2 => Literal::Field(Field::from_bits_le(literal)?),
29            3 => Literal::Group(Group::from_bits_le(literal)?),
30            4 => Literal::I8(I8::from_bits_le(literal)?),
31            5 => Literal::I16(I16::from_bits_le(literal)?),
32            6 => Literal::I32(I32::from_bits_le(literal)?),
33            7 => Literal::I64(I64::from_bits_le(literal)?),
34            8 => Literal::I128(I128::from_bits_le(literal)?),
35            9 => Literal::U8(U8::from_bits_le(literal)?),
36            10 => Literal::U16(U16::from_bits_le(literal)?),
37            11 => Literal::U32(U32::from_bits_le(literal)?),
38            12 => Literal::U64(U64::from_bits_le(literal)?),
39            13 => Literal::U128(U128::from_bits_le(literal)?),
40            14 => Literal::Scalar(Scalar::from_bits_le(literal)?),
41            15 => Literal::Signature(Box::new(Signature::from_bits_le(literal)?)),
42            16 => {
43                let buffer = Vec::<u8>::from_bits_le(literal)?;
44                match buffer.len() <= N::MAX_STRING_BYTES as usize {
45                    true => {
46                        let string = String::from_utf8(buffer).map_err(|e| error(format!("{e}")))?;
47                        Self::String(StringType::new(&string))
48                    }
49                    false => bail!("String literal exceeds maximum length of {} bytes.", N::MAX_STRING_BYTES),
50                }
51            }
52            17.. => bail!("Failed to initialize literal variant {} from bits (LE)", variant),
53        };
54        Ok(literal)
55    }
56
57    /// Initializes a new literal from a list of big-endian bits *without* leading zeros.
58    pub fn from_bits_be(variant: u8, bits_be: &[bool]) -> Result<Self> {
59        let literal = bits_be;
60        let literal = match variant {
61            0 => Literal::Address(Address::new(Group::from_x_coordinate(Field::from_bits_be(literal)?)?)),
62            1 => match bits_be.len() {
63                1 => Literal::Boolean(Boolean::new(literal[0])),
64                _ => bail!("Expected a boolean literal, but found a list of {} bits.", bits_be.len()),
65            },
66            2 => Literal::Field(Field::from_bits_be(literal)?),
67            3 => Literal::Group(Group::from_bits_be(literal)?),
68            4 => Literal::I8(I8::from_bits_be(literal)?),
69            5 => Literal::I16(I16::from_bits_be(literal)?),
70            6 => Literal::I32(I32::from_bits_be(literal)?),
71            7 => Literal::I64(I64::from_bits_be(literal)?),
72            8 => Literal::I128(I128::from_bits_be(literal)?),
73            9 => Literal::U8(U8::from_bits_be(literal)?),
74            10 => Literal::U16(U16::from_bits_be(literal)?),
75            11 => Literal::U32(U32::from_bits_be(literal)?),
76            12 => Literal::U64(U64::from_bits_be(literal)?),
77            13 => Literal::U128(U128::from_bits_be(literal)?),
78            14 => Literal::Scalar(Scalar::from_bits_be(literal)?),
79            15 => Literal::Signature(Box::new(Signature::from_bits_be(literal)?)),
80            16 => {
81                let buffer = Vec::<u8>::from_bits_be(literal)?;
82                match buffer.len() <= N::MAX_STRING_BYTES as usize {
83                    true => {
84                        let string = String::from_utf8(buffer).map_err(|e| error(format!("{e}")))?;
85                        Self::String(StringType::new(&string))
86                    }
87                    false => bail!("String literal exceeds maximum length of {} bytes.", N::MAX_STRING_BYTES),
88                }
89            }
90            17.. => bail!("Failed to initialize literal variant {} from bits (BE)", variant),
91        };
92        Ok(literal)
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99    use snarkvm_console_network::MainnetV0;
100
101    type CurrentNetwork = MainnetV0;
102
103    const ITERATIONS: u32 = 1000;
104
105    fn check_serialization(expected: Literal<CurrentNetwork>) -> Result<()> {
106        println!("{expected}");
107        assert_eq!(expected, Literal::from_bits_le(expected.variant(), &expected.to_bits_le())?);
108        assert_eq!(expected, Literal::from_bits_be(expected.variant(), &expected.to_bits_be())?);
109        Ok(())
110    }
111
112    #[test]
113    fn test_from_bits() -> Result<()> {
114        let rng = &mut TestRng::default();
115
116        for _ in 0..ITERATIONS {
117            let private_key = snarkvm_console_account::PrivateKey::<CurrentNetwork>::new(rng)?;
118
119            // Address
120            check_serialization(Literal::<CurrentNetwork>::Address(Address::try_from(private_key)?))?;
121            // Boolean
122            check_serialization(Literal::<CurrentNetwork>::Boolean(Boolean::new(Uniform::rand(rng))))?;
123            // Field
124            check_serialization(Literal::<CurrentNetwork>::Field(Uniform::rand(rng)))?;
125            // Group
126            check_serialization(Literal::<CurrentNetwork>::Group(Uniform::rand(rng)))?;
127            // I8
128            check_serialization(Literal::<CurrentNetwork>::I8(I8::new(Uniform::rand(rng))))?;
129            // I16
130            check_serialization(Literal::<CurrentNetwork>::I16(I16::new(Uniform::rand(rng))))?;
131            // I32
132            check_serialization(Literal::<CurrentNetwork>::I32(I32::new(Uniform::rand(rng))))?;
133            // I64
134            check_serialization(Literal::<CurrentNetwork>::I64(I64::new(Uniform::rand(rng))))?;
135            // I128
136            check_serialization(Literal::<CurrentNetwork>::I128(I128::new(Uniform::rand(rng))))?;
137            // U8
138            check_serialization(Literal::<CurrentNetwork>::U8(U8::new(Uniform::rand(rng))))?;
139            // U16
140            check_serialization(Literal::<CurrentNetwork>::U16(U16::new(Uniform::rand(rng))))?;
141            // U32
142            check_serialization(Literal::<CurrentNetwork>::U32(U32::new(Uniform::rand(rng))))?;
143            // U64
144            check_serialization(Literal::<CurrentNetwork>::U64(U64::new(Uniform::rand(rng))))?;
145            // U128
146            check_serialization(Literal::<CurrentNetwork>::U128(U128::new(Uniform::rand(rng))))?;
147            // Scalar
148            check_serialization(Literal::<CurrentNetwork>::Scalar(Uniform::rand(rng)))?;
149            // Signature
150            check_serialization(Literal::sample(LiteralType::Signature, rng))?;
151            // String
152            // Sample a random string. Take 1/4th to ensure we fit for all code points.
153            let string = rng.next_string(CurrentNetwork::MAX_STRING_BYTES / 4, false);
154            check_serialization(Literal::<CurrentNetwork>::String(StringType::new(&string)))?;
155        }
156        Ok(())
157    }
158}