Skip to main content

snarkvm_console_program/data/plaintext/
bytes.rs

1// Copyright (c) 2019-2026 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                    // Ensure the declared region is entirely present.
54                    if bytes.len() != num_bytes as usize {
55                        return Err(error("Failed to deserialize plaintext: struct member is truncated"));
56                    }
57                    // Recover the plaintext value.
58                    let mut slice = bytes.as_slice();
59                    let plaintext = Self::read_le_internal(&mut slice, depth + 1)?;
60                    // Ensure the member fills its region. Bytes left unread would be
61                    // dropped on re-serialization, giving one value a second encoding.
62                    if !slice.is_empty() {
63                        return Err(error("Failed to deserialize plaintext: struct member has trailing bytes"));
64                    }
65                    // Add the member.
66                    members.insert(identifier, plaintext);
67                }
68                // Return the struct.
69                Self::Struct(members, Default::default())
70            }
71            2 => {
72                // Read the length of the array.
73                let num_elements = u32::read_le(&mut reader)?;
74                if num_elements as usize > N::LATEST_MAX_ARRAY_ELEMENTS() {
75                    return Err(error("Failed to deserialize plaintext: Array exceeds maximum length"));
76                }
77                // Read the elements.
78                let mut elements = Vec::with_capacity(num_elements as usize);
79                for _ in 0..num_elements {
80                    // Read the plaintext value (in 2 steps to prevent infinite recursion).
81                    let num_bytes = u16::read_le(&mut reader)?;
82                    // Read the plaintext bytes.
83                    let mut bytes = Vec::new();
84                    (&mut reader).take(num_bytes as u64).read_to_end(&mut bytes)?;
85                    // Ensure the declared region is entirely present.
86                    if bytes.len() != num_bytes as usize {
87                        return Err(error("Failed to deserialize plaintext: array element is truncated"));
88                    }
89                    // Recover the plaintext value.
90                    let mut slice = bytes.as_slice();
91                    let plaintext = Self::read_le_internal(&mut slice, depth + 1)?;
92                    // Ensure the element fills its region. Bytes left unread would be
93                    // dropped on re-serialization, giving one value a second encoding.
94                    if !slice.is_empty() {
95                        return Err(error("Failed to deserialize plaintext: array element has trailing bytes"));
96                    }
97                    // Add the element.
98                    elements.push(plaintext);
99                }
100                // Return the array.
101                Self::Array(elements, Default::default())
102            }
103            3.. => return Err(error(format!("Failed to decode plaintext variant {index}"))),
104        };
105        Ok(plaintext)
106    }
107}
108
109impl<N: Network> ToBytes for Plaintext<N> {
110    /// Writes the plaintext to a buffer.
111    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
112        match self {
113            Self::Literal(literal, ..) => {
114                0u8.write_le(&mut writer)?;
115                literal.write_le(&mut writer)
116            }
117            Self::Struct(struct_, ..) => {
118                1u8.write_le(&mut writer)?;
119
120                // Write the number of members in the struct.
121                u8::try_from(struct_.len()).map_err(error)?.write_le(&mut writer)?;
122
123                // Write each member.
124                for (member_name, member_value) in struct_ {
125                    // Write the member name.
126                    member_name.write_le(&mut writer)?;
127
128                    // Write the member value (performed in 2 steps to prevent infinite recursion).
129                    let bytes = member_value.to_bytes_le().map_err(|e| error(e.to_string()))?;
130                    // Write the number of bytes.
131                    u16::try_from(bytes.len()).map_err(error)?.write_le(&mut writer)?;
132                    // Write the bytes.
133                    bytes.write_le(&mut writer)?;
134                }
135                Ok(())
136            }
137            Self::Array(array, ..) => {
138                2u8.write_le(&mut writer)?;
139
140                // Write the length of the array.
141                u32::try_from(array.len()).map_err(error)?.write_le(&mut writer)?;
142
143                // Write each element.
144                for element in array {
145                    // Write the element (performed in 2 steps to prevent infinite recursion).
146                    let bytes = element.to_bytes_le().map_err(error)?;
147                    // Write the number of bytes.
148                    u16::try_from(bytes.len()).map_err(error)?.write_le(&mut writer)?;
149                    // Write the bytes.
150                    bytes.write_le(&mut writer)?;
151                }
152                Ok(())
153            }
154        }
155    }
156}
157
158#[cfg(test)]
159mod tests {
160    use super::*;
161    use snarkvm_console_network::MainnetV0;
162
163    type CurrentNetwork = MainnetV0;
164
165    const ITERATIONS: u32 = 1000;
166
167    fn check_bytes(expected: Plaintext<CurrentNetwork>) -> Result<()> {
168        // Check the byte representation.
169        let expected_bytes = expected.to_bytes_le()?;
170        assert_eq!(expected, Plaintext::read_le(&expected_bytes[..])?);
171        Ok(())
172    }
173
174    #[test]
175    fn test_bytes() -> Result<()> {
176        let rng = &mut TestRng::default();
177
178        for _ in 0..ITERATIONS {
179            let private_key = snarkvm_console_account::PrivateKey::<CurrentNetwork>::new(rng)?;
180
181            // Address
182            check_bytes(Plaintext::Literal(
183                Literal::<CurrentNetwork>::Address(Address::try_from(private_key)?),
184                Default::default(),
185            ))?;
186            // Boolean
187            check_bytes(Plaintext::Literal(
188                Literal::<CurrentNetwork>::Boolean(Boolean::new(Uniform::rand(rng))),
189                Default::default(),
190            ))?;
191            // Field
192            check_bytes(Plaintext::Literal(Literal::<CurrentNetwork>::Field(Uniform::rand(rng)), Default::default()))?;
193            // Group
194            check_bytes(Plaintext::Literal(Literal::<CurrentNetwork>::Group(Uniform::rand(rng)), Default::default()))?;
195            // I8
196            check_bytes(Plaintext::Literal(
197                Literal::<CurrentNetwork>::I8(I8::new(Uniform::rand(rng))),
198                Default::default(),
199            ))?;
200            // I16
201            check_bytes(Plaintext::Literal(
202                Literal::<CurrentNetwork>::I16(I16::new(Uniform::rand(rng))),
203                Default::default(),
204            ))?;
205            // I32
206            check_bytes(Plaintext::Literal(
207                Literal::<CurrentNetwork>::I32(I32::new(Uniform::rand(rng))),
208                Default::default(),
209            ))?;
210            // I64
211            check_bytes(Plaintext::Literal(
212                Literal::<CurrentNetwork>::I64(I64::new(Uniform::rand(rng))),
213                Default::default(),
214            ))?;
215            // I128
216            check_bytes(Plaintext::Literal(
217                Literal::<CurrentNetwork>::I128(I128::new(Uniform::rand(rng))),
218                Default::default(),
219            ))?;
220            // U8
221            check_bytes(Plaintext::Literal(
222                Literal::<CurrentNetwork>::U8(U8::new(Uniform::rand(rng))),
223                Default::default(),
224            ))?;
225            // U16
226            check_bytes(Plaintext::Literal(
227                Literal::<CurrentNetwork>::U16(U16::new(Uniform::rand(rng))),
228                Default::default(),
229            ))?;
230            // U32
231            check_bytes(Plaintext::Literal(
232                Literal::<CurrentNetwork>::U32(U32::new(Uniform::rand(rng))),
233                Default::default(),
234            ))?;
235            // U64
236            check_bytes(Plaintext::Literal(
237                Literal::<CurrentNetwork>::U64(U64::new(Uniform::rand(rng))),
238                Default::default(),
239            ))?;
240            // U128
241            check_bytes(Plaintext::Literal(
242                Literal::<CurrentNetwork>::U128(U128::new(Uniform::rand(rng))),
243                Default::default(),
244            ))?;
245            // Scalar
246            check_bytes(Plaintext::Literal(Literal::<CurrentNetwork>::Scalar(Uniform::rand(rng)), Default::default()))?;
247            // String
248            check_bytes(Plaintext::Literal(
249                Literal::<CurrentNetwork>::String(StringType::rand(rng)),
250                Default::default(),
251            ))?;
252        }
253
254        // Check the struct manually.
255        let expected = Plaintext::<CurrentNetwork>::from_str(
256            "{ owner: aleo1d5hg2z3ma00382pngntdp68e74zv54jdxy249qhaujhks9c72yrs33ddah, token_amount: 100u64 }",
257        )?;
258
259        // Check the byte representation.
260        let expected_bytes = expected.to_bytes_le()?;
261        assert_eq!(expected, Plaintext::read_le(&expected_bytes[..])?);
262
263        // Check the array manually.
264        let expected = Plaintext::<CurrentNetwork>::from_str("[ 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8, 10u8 ]")?;
265
266        // Check the byte representation.
267        let expected_bytes = expected.to_bytes_le()?;
268        assert_eq!(expected, Plaintext::read_le(&expected_bytes[..])?);
269
270        Ok(())
271    }
272
273    // A helper function to get the depth of the plaintext.
274    fn get_depth(plaintext: &Plaintext<CurrentNetwork>) -> usize {
275        match plaintext {
276            Plaintext::Literal(_, _) => 0,
277            Plaintext::Struct(members, _) => members.values().map(get_depth).max().unwrap_or(0) + 1,
278            Plaintext::Array(elements, _) => elements.iter().map(get_depth).max().unwrap_or(0) + 1,
279        }
280    }
281
282    #[test]
283    fn test_deeply_nested_plaintext() {
284        // Creates a nested array-like `Plaintext` structure by wrapping a root value `depth` times.
285        fn create_nested_array(depth: usize, root: impl Display) -> Vec<u8> {
286            // Start from the innermost value.
287            let mut result = Plaintext::<CurrentNetwork>::from_str(&root.to_string()).unwrap().to_bytes_le().unwrap();
288            // Reverse the bytes.
289            result.reverse();
290            // Build up the structure in reverse.
291            for _ in 0..depth {
292                // Write the size of the object in bytes in reverse.
293                let mut length = (u16::try_from(result.len()).unwrap()).to_bytes_le().unwrap();
294                length.reverse();
295                result.extend(length);
296                // Write the number of elements in the array in reverse.
297                let mut num_elements = 1u32.to_bytes_le().unwrap();
298                num_elements.reverse();
299                result.extend(num_elements);
300                // Write the plaintext variant in reverse.
301                let mut variant = 2u8.to_bytes_le().unwrap();
302                variant.reverse();
303                result.extend(variant);
304            }
305            // Reverse the result to get the correct order.
306            result.reverse();
307            result
308        }
309
310        // Creates a nested struct-like `Plaintext` structure by wrapping a root value `depth` times.
311        fn create_nested_struct(depth: usize, root: impl Display) -> Vec<u8> {
312            // Start from the innermost value.
313            let mut result = Plaintext::<CurrentNetwork>::from_str(&root.to_string()).unwrap().to_bytes_le().unwrap();
314            // Reverse the bytes.
315            result.reverse();
316            // Build up the structure in reverse.
317            for _ in 0..depth {
318                // Write the size of the object in bytes in reverse.
319                let mut length = (u16::try_from(result.len()).unwrap()).to_bytes_le().unwrap();
320                length.reverse();
321                result.extend(length);
322                // Write the member name in reverse.
323                let mut member_name = Identifier::<CurrentNetwork>::from_str("inner").unwrap().to_bytes_le().unwrap();
324                member_name.reverse();
325                result.extend(member_name);
326                // Write the number of members in the struct in reverse.
327                let mut num_members = 1u8.to_bytes_le().unwrap();
328                num_members.reverse();
329                result.extend(num_members);
330                // Write the plaintext variant in reverse.
331                let mut variant = 1u8.to_bytes_le().unwrap();
332                variant.reverse();
333                result.extend(variant);
334            }
335            // Reverse the result to get the correct order.
336            result.reverse();
337            result
338        }
339
340        // Creates a nested `Plaintext` structure with alternating array and struct wrappers.
341        fn create_alternated_nested(depth: usize, root: impl Display) -> Vec<u8> {
342            // Start from the innermost value.
343            let mut result = Plaintext::<CurrentNetwork>::from_str(&root.to_string()).unwrap().to_bytes_le().unwrap();
344            // Reverse the bytes.
345            result.reverse();
346            // Build up the structure in reverse.
347            for i in 0..depth {
348                // Write the size of the object in bytes in reverse.
349                let mut length = (u16::try_from(result.len()).unwrap()).to_bytes_le().unwrap();
350                length.reverse();
351                result.extend(length);
352                // Determine the type of the wrapper (array or struct) and handle accordingly.
353                if i % 2 == 0 {
354                    // Write the number of elements in the array in reverse.
355                    let mut num_elements = 1u32.to_bytes_le().unwrap();
356                    num_elements.reverse();
357                    result.extend(num_elements);
358                    // Write the plaintext variant for array in reverse.
359                    let mut variant = 2u8.to_bytes_le().unwrap();
360                    variant.reverse();
361                    result.extend(variant);
362                } else {
363                    // Write the member name in reverse.
364                    let mut member_name =
365                        Identifier::<CurrentNetwork>::from_str("inner").unwrap().to_bytes_le().unwrap();
366                    member_name.reverse();
367                    result.extend(member_name);
368                    // Write the number of members in the struct in reverse.
369                    let mut num_members = 1u8.to_bytes_le().unwrap();
370                    num_members.reverse();
371                    result.extend(num_members);
372                    // Write the plaintext variant for struct in reverse.
373                    let mut variant = 1u8.to_bytes_le().unwrap();
374                    variant.reverse();
375                    result.extend(variant);
376                }
377            }
378            // Reverse the result to get the correct order.
379            result.reverse();
380            result
381        }
382
383        // A helper function to run the test.
384        fn run_test(expected_depth: usize, input: Vec<u8>, expected_error: bool) {
385            // Parse the input string.
386            let result = Plaintext::<CurrentNetwork>::read_le(&*input);
387            // Check if the result is an error.
388            match expected_error {
389                true => {
390                    assert!(result.is_err());
391                    return;
392                }
393                false => assert!(result.is_ok()),
394            };
395            // Unwrap the result.
396            let candidate = result.unwrap();
397            // Check if the candidate is equal to the input.
398            assert_eq!(input, candidate.to_bytes_le().unwrap());
399            // Check if the candidate is equal to the expected depth.
400            assert_eq!(get_depth(&candidate), expected_depth);
401        }
402
403        // Initialize a sequence of depths to check.
404        // Note that 6500 is approximate maximum depth that can be constructed in this test.
405        let mut depths = (0usize..100).collect_vec();
406        depths.extend((100..6500).step_by(100));
407
408        // Test deeply nested arrays with different literal types.
409        for i in depths.iter().copied() {
410            run_test(i, create_nested_array(i, "false"), i > CurrentNetwork::MAX_DATA_DEPTH);
411            run_test(i, create_nested_array(i, "1u8"), i > CurrentNetwork::MAX_DATA_DEPTH);
412            run_test(i, create_nested_array(i, "0u128"), i > CurrentNetwork::MAX_DATA_DEPTH);
413            run_test(i, create_nested_array(i, "10field"), i > CurrentNetwork::MAX_DATA_DEPTH);
414        }
415
416        // Test deeply nested structs with different literal types.
417        for i in depths.iter().copied() {
418            run_test(i, create_nested_struct(i, "false"), i > CurrentNetwork::MAX_DATA_DEPTH);
419            run_test(i, create_nested_struct(i, "1u8"), i > CurrentNetwork::MAX_DATA_DEPTH);
420            run_test(i, create_nested_struct(i, "0u128"), i > CurrentNetwork::MAX_DATA_DEPTH);
421            run_test(i, create_nested_struct(i, "10field"), i > CurrentNetwork::MAX_DATA_DEPTH);
422        }
423
424        // Test alternating nested arrays and structs.
425        for i in depths.iter().copied() {
426            run_test(i, create_alternated_nested(i, "false"), i > CurrentNetwork::MAX_DATA_DEPTH);
427            run_test(i, create_alternated_nested(i, "1u8"), i > CurrentNetwork::MAX_DATA_DEPTH);
428            run_test(i, create_alternated_nested(i, "0u128"), i > CurrentNetwork::MAX_DATA_DEPTH);
429            run_test(i, create_alternated_nested(i, "10field"), i > CurrentNetwork::MAX_DATA_DEPTH);
430        }
431    }
432
433    /// Builds the encoding of a one-member struct, declaring `padding` more bytes
434    /// for the member than the member actually occupies.
435    fn struct_with_padded_member(padding: usize) -> Result<Vec<u8>> {
436        let member = Plaintext::<CurrentNetwork>::Literal(Literal::U8(U8::new(7)), Default::default());
437        let member_bytes = member.to_bytes_le()?;
438
439        let mut bytes = Vec::new();
440        1u8.write_le(&mut bytes)?;
441        1u8.write_le(&mut bytes)?;
442        Identifier::<CurrentNetwork>::from_str("a")?.write_le(&mut bytes)?;
443        u16::try_from(member_bytes.len() + padding)?.write_le(&mut bytes)?;
444        bytes.extend_from_slice(&member_bytes);
445        bytes.extend(std::iter::repeat_n(0u8, padding));
446        Ok(bytes)
447    }
448
449    /// Builds the encoding of a one-element array, declaring `padding` more bytes
450    /// for the element than the element actually occupies.
451    fn array_with_padded_element(padding: usize) -> Result<Vec<u8>> {
452        let element = Plaintext::<CurrentNetwork>::Literal(Literal::U8(U8::new(7)), Default::default());
453        let element_bytes = element.to_bytes_le()?;
454
455        let mut bytes = Vec::new();
456        2u8.write_le(&mut bytes)?;
457        1u32.write_le(&mut bytes)?;
458        u16::try_from(element_bytes.len() + padding)?.write_le(&mut bytes)?;
459        bytes.extend_from_slice(&element_bytes);
460        bytes.extend(std::iter::repeat_n(0u8, padding));
461        Ok(bytes)
462    }
463
464    #[test]
465    fn test_struct_member_rejects_trailing_bytes() -> Result<()> {
466        // Unpadded, this is the encoding `to_bytes_le` produces, and it must keep working.
467        let exact = struct_with_padded_member(0)?;
468        let plaintext = Plaintext::<CurrentNetwork>::read_le(&exact[..])?;
469        assert_eq!(exact, plaintext.to_bytes_le()?, "the unpadded encoding must round trip");
470
471        // A member region larger than the member fills leaves bytes unread. Accepting
472        // it gives one value a second encoding, since re-serializing emits the exact
473        // length -- and two encodings of one transaction are two TransmissionIDs.
474        for padding in [1, 8, 32] {
475            let padded = struct_with_padded_member(padding)?;
476            assert_ne!(padded, exact);
477            assert!(
478                Plaintext::<CurrentNetwork>::read_le(&padded[..]).is_err(),
479                "a struct member declaring {padding} bytes more than it uses must be rejected"
480            );
481        }
482        Ok(())
483    }
484
485    #[test]
486    fn test_array_element_rejects_trailing_bytes() -> Result<()> {
487        let exact = array_with_padded_element(0)?;
488        let plaintext = Plaintext::<CurrentNetwork>::read_le(&exact[..])?;
489        assert_eq!(exact, plaintext.to_bytes_le()?, "the unpadded encoding must round trip");
490
491        for padding in [1, 8, 32] {
492            let padded = array_with_padded_element(padding)?;
493            assert_ne!(padded, exact);
494            assert!(
495                Plaintext::<CurrentNetwork>::read_le(&padded[..]).is_err(),
496                "an array element declaring {padding} bytes more than it uses must be rejected"
497            );
498        }
499        Ok(())
500    }
501}