snarkvm_console_program/data/plaintext/
bytes.rs

1// Copyright (c) 2019-2025 Provable Inc.
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> FromBytes for Plaintext<N> {
19    /// Reads the plaintext from a buffer.
20    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
21        Self::read_le_internal(&mut reader, 0)
22    }
23}
24
25impl<N: Network> Plaintext<N> {
26    /// Reads the plaintext from a buffer, while tracking the depth of the data.
27    fn read_le_internal<R: Read>(mut reader: R, depth: usize) -> IoResult<Self> {
28        // Ensure that the depth is within the maximum limit.
29        if depth > N::MAX_DATA_DEPTH {
30            return Err(error(format!(
31                "Failed to deserialize plaintext: Depth exceeds maximum limit: {}",
32                N::MAX_DATA_DEPTH
33            )));
34        }
35        // Read the index.
36        let index = u8::read_le(&mut reader)?;
37        // Read the plaintext.
38        let plaintext = match index {
39            0 => Self::Literal(Literal::read_le(&mut reader)?, Default::default()),
40            1 => {
41                // Read the number of members in the struct.
42                let num_members = u8::read_le(&mut reader)?;
43                // Read the members.
44                let mut members = IndexMap::with_capacity(num_members as usize);
45                for _ in 0..num_members {
46                    // Read the identifier.
47                    let identifier = Identifier::<N>::read_le(&mut reader)?;
48                    // Read the plaintext value (in 2 steps to prevent infinite recursion).
49                    let num_bytes = u16::read_le(&mut reader)?;
50                    // Read the plaintext bytes.
51                    let mut bytes = Vec::new();
52                    (&mut reader).take(num_bytes as u64).read_to_end(&mut bytes)?;
53                    // Recover the plaintext value.
54                    let plaintext = Self::read_le_internal(&mut bytes.as_slice(), depth + 1)?;
55                    // Add the member.
56                    members.insert(identifier, plaintext);
57                }
58                // Return the struct.
59                Self::Struct(members, Default::default())
60            }
61            2 => {
62                // Read the length of the array.
63                let num_elements = u32::read_le(&mut reader)?;
64                if num_elements as usize > N::MAX_ARRAY_ELEMENTS {
65                    return Err(error("Failed to deserialize plaintext: Array exceeds maximum length"));
66                }
67                // Read the elements.
68                let mut elements = Vec::with_capacity(num_elements as usize);
69                for _ in 0..num_elements {
70                    // Read the plaintext value (in 2 steps to prevent infinite recursion).
71                    let num_bytes = u16::read_le(&mut reader)?;
72                    // Read the plaintext bytes.
73                    let mut bytes = Vec::new();
74                    (&mut reader).take(num_bytes as u64).read_to_end(&mut bytes)?;
75                    // Recover the plaintext value.
76                    let plaintext = Self::read_le_internal(&mut bytes.as_slice(), depth + 1)?;
77                    // Add the element.
78                    elements.push(plaintext);
79                }
80                // Return the array.
81                Self::Array(elements, Default::default())
82            }
83            3.. => return Err(error(format!("Failed to decode plaintext variant {index}"))),
84        };
85        Ok(plaintext)
86    }
87}
88
89impl<N: Network> ToBytes for Plaintext<N> {
90    /// Writes the plaintext to a buffer.
91    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
92        match self {
93            Self::Literal(literal, ..) => {
94                0u8.write_le(&mut writer)?;
95                literal.write_le(&mut writer)
96            }
97            Self::Struct(struct_, ..) => {
98                1u8.write_le(&mut writer)?;
99
100                // Write the number of members in the struct.
101                u8::try_from(struct_.len()).map_err(error)?.write_le(&mut writer)?;
102
103                // Write each member.
104                for (member_name, member_value) in struct_ {
105                    // Write the member name.
106                    member_name.write_le(&mut writer)?;
107
108                    // Write the member value (performed in 2 steps to prevent infinite recursion).
109                    let bytes = member_value.to_bytes_le().map_err(|e| error(e.to_string()))?;
110                    // Write the number of bytes.
111                    u16::try_from(bytes.len()).map_err(error)?.write_le(&mut writer)?;
112                    // Write the bytes.
113                    bytes.write_le(&mut writer)?;
114                }
115                Ok(())
116            }
117            Self::Array(array, ..) => {
118                2u8.write_le(&mut writer)?;
119
120                // Write the length of the array.
121                u32::try_from(array.len()).map_err(error)?.write_le(&mut writer)?;
122
123                // Write each element.
124                for element in array {
125                    // Write the element (performed in 2 steps to prevent infinite recursion).
126                    let bytes = element.to_bytes_le().map_err(error)?;
127                    // Write the number of bytes.
128                    u16::try_from(bytes.len()).map_err(error)?.write_le(&mut writer)?;
129                    // Write the bytes.
130                    bytes.write_le(&mut writer)?;
131                }
132                Ok(())
133            }
134        }
135    }
136}
137
138#[cfg(test)]
139mod tests {
140    use super::*;
141    use snarkvm_console_network::MainnetV0;
142
143    type CurrentNetwork = MainnetV0;
144
145    const ITERATIONS: u32 = 1000;
146
147    fn check_bytes(expected: Plaintext<CurrentNetwork>) -> Result<()> {
148        // Check the byte representation.
149        let expected_bytes = expected.to_bytes_le()?;
150        assert_eq!(expected, Plaintext::read_le(&expected_bytes[..])?);
151        Ok(())
152    }
153
154    #[test]
155    fn test_bytes() -> Result<()> {
156        let rng = &mut TestRng::default();
157
158        for _ in 0..ITERATIONS {
159            let private_key = snarkvm_console_account::PrivateKey::<CurrentNetwork>::new(rng)?;
160
161            // Address
162            check_bytes(Plaintext::Literal(
163                Literal::<CurrentNetwork>::Address(Address::try_from(private_key)?),
164                Default::default(),
165            ))?;
166            // Boolean
167            check_bytes(Plaintext::Literal(
168                Literal::<CurrentNetwork>::Boolean(Boolean::new(Uniform::rand(rng))),
169                Default::default(),
170            ))?;
171            // Field
172            check_bytes(Plaintext::Literal(Literal::<CurrentNetwork>::Field(Uniform::rand(rng)), Default::default()))?;
173            // Group
174            check_bytes(Plaintext::Literal(Literal::<CurrentNetwork>::Group(Uniform::rand(rng)), Default::default()))?;
175            // I8
176            check_bytes(Plaintext::Literal(
177                Literal::<CurrentNetwork>::I8(I8::new(Uniform::rand(rng))),
178                Default::default(),
179            ))?;
180            // I16
181            check_bytes(Plaintext::Literal(
182                Literal::<CurrentNetwork>::I16(I16::new(Uniform::rand(rng))),
183                Default::default(),
184            ))?;
185            // I32
186            check_bytes(Plaintext::Literal(
187                Literal::<CurrentNetwork>::I32(I32::new(Uniform::rand(rng))),
188                Default::default(),
189            ))?;
190            // I64
191            check_bytes(Plaintext::Literal(
192                Literal::<CurrentNetwork>::I64(I64::new(Uniform::rand(rng))),
193                Default::default(),
194            ))?;
195            // I128
196            check_bytes(Plaintext::Literal(
197                Literal::<CurrentNetwork>::I128(I128::new(Uniform::rand(rng))),
198                Default::default(),
199            ))?;
200            // U8
201            check_bytes(Plaintext::Literal(
202                Literal::<CurrentNetwork>::U8(U8::new(Uniform::rand(rng))),
203                Default::default(),
204            ))?;
205            // U16
206            check_bytes(Plaintext::Literal(
207                Literal::<CurrentNetwork>::U16(U16::new(Uniform::rand(rng))),
208                Default::default(),
209            ))?;
210            // U32
211            check_bytes(Plaintext::Literal(
212                Literal::<CurrentNetwork>::U32(U32::new(Uniform::rand(rng))),
213                Default::default(),
214            ))?;
215            // U64
216            check_bytes(Plaintext::Literal(
217                Literal::<CurrentNetwork>::U64(U64::new(Uniform::rand(rng))),
218                Default::default(),
219            ))?;
220            // U128
221            check_bytes(Plaintext::Literal(
222                Literal::<CurrentNetwork>::U128(U128::new(Uniform::rand(rng))),
223                Default::default(),
224            ))?;
225            // Scalar
226            check_bytes(Plaintext::Literal(Literal::<CurrentNetwork>::Scalar(Uniform::rand(rng)), Default::default()))?;
227            // String
228            check_bytes(Plaintext::Literal(
229                Literal::<CurrentNetwork>::String(StringType::rand(rng)),
230                Default::default(),
231            ))?;
232        }
233
234        // Check the struct manually.
235        let expected = Plaintext::<CurrentNetwork>::from_str(
236            "{ owner: aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah, token_amount: 100u64 }",
237        )?;
238
239        // Check the byte representation.
240        let expected_bytes = expected.to_bytes_le()?;
241        assert_eq!(expected, Plaintext::read_le(&expected_bytes[..])?);
242
243        // Check the array manually.
244        let expected = Plaintext::<CurrentNetwork>::from_str("[ 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8, 10u8 ]")?;
245
246        // Check the byte representation.
247        let expected_bytes = expected.to_bytes_le()?;
248        assert_eq!(expected, Plaintext::read_le(&expected_bytes[..])?);
249
250        Ok(())
251    }
252
253    // A helper function to get the depth of the plaintext.
254    fn get_depth(plaintext: &Plaintext<CurrentNetwork>) -> usize {
255        match plaintext {
256            Plaintext::Literal(_, _) => 0,
257            Plaintext::Struct(members, _) => members.values().map(get_depth).max().unwrap_or(0) + 1,
258            Plaintext::Array(elements, _) => elements.iter().map(get_depth).max().unwrap_or(0) + 1,
259        }
260    }
261
262    #[test]
263    fn test_deeply_nested_plaintext() {
264        // Creates a nested array-like `Plaintext` structure by wrapping a root value `depth` times.
265        fn create_nested_array(depth: usize, root: impl Display) -> Vec<u8> {
266            // Start from the innermost value.
267            let mut result = Plaintext::<CurrentNetwork>::from_str(&root.to_string()).unwrap().to_bytes_le().unwrap();
268            // Reverse the bytes.
269            result.reverse();
270            // Build up the structure in reverse.
271            for _ in 0..depth {
272                // Write the size of the object in bytes in reverse.
273                let mut length = (u16::try_from(result.len()).unwrap()).to_bytes_le().unwrap();
274                length.reverse();
275                result.extend(length);
276                // Write the number of elements in the array in reverse.
277                let mut num_elements = 1u32.to_bytes_le().unwrap();
278                num_elements.reverse();
279                result.extend(num_elements);
280                // Write the plaintext variant in reverse.
281                let mut variant = 2u8.to_bytes_le().unwrap();
282                variant.reverse();
283                result.extend(variant);
284            }
285            // Reverse the result to get the correct order.
286            result.reverse();
287            result
288        }
289
290        // Creates a nested struct-like `Plaintext` structure by wrapping a root value `depth` times.
291        fn create_nested_struct(depth: usize, root: impl Display) -> Vec<u8> {
292            // Start from the innermost value.
293            let mut result = Plaintext::<CurrentNetwork>::from_str(&root.to_string()).unwrap().to_bytes_le().unwrap();
294            // Reverse the bytes.
295            result.reverse();
296            // Build up the structure in reverse.
297            for _ in 0..depth {
298                // Write the size of the object in bytes in reverse.
299                let mut length = (u16::try_from(result.len()).unwrap()).to_bytes_le().unwrap();
300                length.reverse();
301                result.extend(length);
302                // Write the member name in reverse.
303                let mut member_name = Identifier::<CurrentNetwork>::from_str("inner").unwrap().to_bytes_le().unwrap();
304                member_name.reverse();
305                result.extend(member_name);
306                // Write the number of members in the struct in reverse.
307                let mut num_members = 1u8.to_bytes_le().unwrap();
308                num_members.reverse();
309                result.extend(num_members);
310                // Write the plaintext variant in reverse.
311                let mut variant = 1u8.to_bytes_le().unwrap();
312                variant.reverse();
313                result.extend(variant);
314            }
315            // Reverse the result to get the correct order.
316            result.reverse();
317            result
318        }
319
320        // Creates a nested `Plaintext` structure with alternating array and struct wrappers.
321        fn create_alternated_nested(depth: usize, root: impl Display) -> Vec<u8> {
322            // Start from the innermost value.
323            let mut result = Plaintext::<CurrentNetwork>::from_str(&root.to_string()).unwrap().to_bytes_le().unwrap();
324            // Reverse the bytes.
325            result.reverse();
326            // Build up the structure in reverse.
327            for i in 0..depth {
328                // Write the size of the object in bytes in reverse.
329                let mut length = (u16::try_from(result.len()).unwrap()).to_bytes_le().unwrap();
330                length.reverse();
331                result.extend(length);
332                // Determine the type of the wrapper (array or struct) and handle accordingly.
333                if i % 2 == 0 {
334                    // Write the number of elements in the array in reverse.
335                    let mut num_elements = 1u32.to_bytes_le().unwrap();
336                    num_elements.reverse();
337                    result.extend(num_elements);
338                    // Write the plaintext variant for array in reverse.
339                    let mut variant = 2u8.to_bytes_le().unwrap();
340                    variant.reverse();
341                    result.extend(variant);
342                } else {
343                    // Write the member name in reverse.
344                    let mut member_name =
345                        Identifier::<CurrentNetwork>::from_str("inner").unwrap().to_bytes_le().unwrap();
346                    member_name.reverse();
347                    result.extend(member_name);
348                    // Write the number of members in the struct in reverse.
349                    let mut num_members = 1u8.to_bytes_le().unwrap();
350                    num_members.reverse();
351                    result.extend(num_members);
352                    // Write the plaintext variant for struct in reverse.
353                    let mut variant = 1u8.to_bytes_le().unwrap();
354                    variant.reverse();
355                    result.extend(variant);
356                }
357            }
358            // Reverse the result to get the correct order.
359            result.reverse();
360            result
361        }
362
363        // A helper function to run the test.
364        fn run_test(expected_depth: usize, input: Vec<u8>, expected_error: bool) {
365            // Parse the input string.
366            let result = Plaintext::<CurrentNetwork>::read_le(&*input);
367            // Check if the result is an error.
368            match expected_error {
369                true => {
370                    assert!(result.is_err());
371                    return;
372                }
373                false => assert!(result.is_ok()),
374            };
375            // Unwrap the result.
376            let candidate = result.unwrap();
377            // Check if the candidate is equal to the input.
378            assert_eq!(input, candidate.to_bytes_le().unwrap());
379            // Check if the candidate is equal to the expected depth.
380            assert_eq!(get_depth(&candidate), expected_depth);
381        }
382
383        // Initialize a sequence of depths to check.
384        // Note that 6500 is approximate maximum depth that can be constructed in this test.
385        let mut depths = (0usize..100).collect_vec();
386        depths.extend((100..6500).step_by(100));
387
388        // Test deeply nested arrays with different literal types.
389        for i in depths.iter().copied() {
390            run_test(i, create_nested_array(i, "false"), i > CurrentNetwork::MAX_DATA_DEPTH);
391            run_test(i, create_nested_array(i, "1u8"), i > CurrentNetwork::MAX_DATA_DEPTH);
392            run_test(i, create_nested_array(i, "0u128"), i > CurrentNetwork::MAX_DATA_DEPTH);
393            run_test(i, create_nested_array(i, "10field"), i > CurrentNetwork::MAX_DATA_DEPTH);
394        }
395
396        // Test deeply nested structs with different literal types.
397        for i in depths.iter().copied() {
398            run_test(i, create_nested_struct(i, "false"), i > CurrentNetwork::MAX_DATA_DEPTH);
399            run_test(i, create_nested_struct(i, "1u8"), i > CurrentNetwork::MAX_DATA_DEPTH);
400            run_test(i, create_nested_struct(i, "0u128"), i > CurrentNetwork::MAX_DATA_DEPTH);
401            run_test(i, create_nested_struct(i, "10field"), i > CurrentNetwork::MAX_DATA_DEPTH);
402        }
403
404        // Test alternating nested arrays and structs.
405        for i in depths.iter().copied() {
406            run_test(i, create_alternated_nested(i, "false"), i > CurrentNetwork::MAX_DATA_DEPTH);
407            run_test(i, create_alternated_nested(i, "1u8"), i > CurrentNetwork::MAX_DATA_DEPTH);
408            run_test(i, create_alternated_nested(i, "0u128"), i > CurrentNetwork::MAX_DATA_DEPTH);
409            run_test(i, create_alternated_nested(i, "10field"), i > CurrentNetwork::MAX_DATA_DEPTH);
410        }
411    }
412}