snarkvm_circuit_program/data/plaintext/
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<A: Aleo> FromBits for Plaintext<A> {
19    type Boolean = Boolean<A>;
20
21    /// Initializes a new plaintext from a list of little-endian bits *without* trailing zeros.
22    fn from_bits_le(bits_le: &[Boolean<A>]) -> Self {
23        Self::from_bits_le_internal(bits_le, 0)
24    }
25
26    /// Initializes a new plaintext from a list of big-endian bits *without* trailing zeros.
27    fn from_bits_be(bits_be: &[Boolean<A>]) -> Self {
28        Self::from_bits_be_internal(bits_be, 0)
29    }
30}
31
32impl<A: Aleo> Plaintext<A> {
33    /// Initializes a new plaintext from a list of little-endian bits *without* trailing zeros, while tracking the depth of the data.
34    fn from_bits_le_internal(bits_le: &[Boolean<A>], depth: usize) -> Self {
35        // Ensure that the depth is within the maximum limit.
36        if depth > <A::Network as console::Network>::MAX_DATA_DEPTH {
37            A::halt(format!(
38                "Plaintext depth exceeds maximum limit: {}",
39                <A::Network as console::Network>::MAX_DATA_DEPTH
40            ))
41        }
42
43        let bits = bits_le;
44
45        // The starting index used to create subsequent subslices of the `bits` slice.
46        let mut index = 0;
47
48        // Helper function to get the next n bits as a slice.
49        let mut next_bits = |n: usize| -> &[Boolean<A>] {
50            // Safely procure a subslice with the length `n` starting at `index`.
51            let subslice = bits.get(index..index + n);
52            // Check if the range is within bounds.
53            if let Some(next_bits) = subslice {
54                // Move the starting index.
55                index += n;
56                // Return the subslice.
57                next_bits
58            } else {
59                A::halt("Insufficient bits.")
60            }
61        };
62
63        let mut variant = next_bits(2).iter().map(|b| b.eject_value());
64        let variant1 = variant.next().unwrap();
65        let variant2 = variant.next().unwrap();
66        let variant = [variant1, variant2];
67
68        // Literal
69        if variant == [false, false] {
70            let literal_variant = U8::from_bits_le(next_bits(8));
71            let literal_size = U16::from_bits_le(next_bits(16)).eject_value();
72            let literal = Literal::from_bits_le(&literal_variant, next_bits(*literal_size as usize));
73
74            // Cache the plaintext bits, and return the literal.
75            Self::Literal(literal, OnceCell::with_value(bits_le.to_vec()))
76        }
77        // Struct
78        else if variant == [false, true] {
79            let num_members = U8::from_bits_le(next_bits(8)).eject_value();
80
81            let mut members = IndexMap::with_capacity(*num_members as usize);
82            for _ in 0..*num_members {
83                let identifier_size = U8::from_bits_le(next_bits(8)).eject_value();
84                let identifier = Identifier::from_bits_le(next_bits(*identifier_size as usize));
85
86                let member_size = U16::from_bits_le(next_bits(16)).eject_value();
87                let value = Plaintext::from_bits_le_internal(next_bits(*member_size as usize), depth + 1);
88
89                members.insert(identifier, value);
90            }
91
92            // Cache the plaintext bits, and return the struct.
93            Self::Struct(members, OnceCell::with_value(bits_le.to_vec()))
94        }
95        // Array
96        else if variant == [true, false] {
97            let num_elements = U32::from_bits_le(next_bits(32)).eject_value();
98
99            let mut elements = Vec::with_capacity(*num_elements as usize);
100            for _ in 0..*num_elements {
101                let element_size = U16::from_bits_le(next_bits(16)).eject_value();
102                let value = Plaintext::from_bits_le_internal(next_bits(*element_size as usize), depth + 1);
103
104                elements.push(value);
105            }
106
107            // Cache the plaintext bits, and return the array.
108            Self::Array(elements, OnceCell::with_value(bits_le.to_vec()))
109        }
110        // Unknown variant.
111        else {
112            A::halt("Unknown plaintext variant.")
113        }
114    }
115
116    /// Initializes a new plaintext from a list of big-endian bits *without* trailing zeros, while tracking the depth of the data.
117    fn from_bits_be_internal(bits_be: &[Boolean<A>], depth: usize) -> Self {
118        // Ensure that the depth is within the maximum limit.
119        if depth > <A::Network as console::Network>::MAX_DATA_DEPTH {
120            A::halt(format!(
121                "Plaintext depth exceeds maximum limit: {}",
122                <A::Network as console::Network>::MAX_DATA_DEPTH
123            ))
124        }
125
126        let bits = bits_be;
127
128        // The starting index used to create subsequent subslices of the `bits` slice.
129        let mut index = 0;
130
131        // Helper function to get the next n bits as a slice.
132        let mut next_bits = |n: usize| -> &[Boolean<A>] {
133            // Safely procure a subslice with the length `n` starting at `index`.
134            let subslice = bits.get(index..index + n);
135            // Check if the range is within bounds.
136            if let Some(next_bits) = subslice {
137                // Move the starting index.
138                index += n;
139                // Return the subslice.
140                next_bits
141            } else {
142                A::halt("Insufficient bits.")
143            }
144        };
145
146        let mut variant = next_bits(2).iter().map(|b| b.eject_value());
147        let variant1 = variant.next().unwrap();
148        let variant2 = variant.next().unwrap();
149        let variant = [variant1, variant2];
150
151        // Literal
152        if variant == [false, false] {
153            let literal_variant = U8::from_bits_be(next_bits(8));
154            let literal_size = U16::from_bits_be(next_bits(16)).eject_value();
155            let literal = Literal::from_bits_be(&literal_variant, next_bits(*literal_size as usize));
156
157            // Cache the plaintext bits, and return the literal.
158            Self::Literal(literal, OnceCell::with_value(bits_be.to_vec()))
159        }
160        // Struct
161        else if variant == [false, true] {
162            let num_members = U8::from_bits_be(next_bits(8)).eject_value();
163
164            let mut members = IndexMap::with_capacity(*num_members as usize);
165            for _ in 0..*num_members {
166                let identifier_size = U8::from_bits_be(next_bits(8)).eject_value();
167                let identifier = Identifier::from_bits_be(next_bits(*identifier_size as usize));
168
169                let member_size = U16::from_bits_be(next_bits(16)).eject_value();
170                let value = Plaintext::from_bits_be_internal(next_bits(*member_size as usize), depth + 1);
171
172                members.insert(identifier, value);
173            }
174
175            // Cache the plaintext bits, and return the struct.
176            Self::Struct(members, OnceCell::with_value(bits_be.to_vec()))
177        }
178        // Array
179        else if variant == [true, false] {
180            let num_elements = U32::from_bits_be(next_bits(32)).eject_value();
181
182            let mut elements = Vec::with_capacity(*num_elements as usize);
183            for _ in 0..*num_elements {
184                let element_size = U16::from_bits_be(next_bits(16)).eject_value();
185                let value = Plaintext::from_bits_be_internal(next_bits(*element_size as usize), depth + 1);
186
187                elements.push(value);
188            }
189
190            // Cache the plaintext bits, and return the array.
191            Self::Array(elements, OnceCell::with_value(bits_be.to_vec()))
192        }
193        // Unknown variant.
194        else {
195            A::halt("Unknown plaintext variant.")
196        }
197    }
198}