snarkvm_circuit_program/data/plaintext/
from_bits.rs

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