snarkvm_console_program/data/plaintext/
mod.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
16mod bytes;
17mod encrypt;
18mod equal;
19mod find;
20mod from_bits;
21mod from_fields;
22mod num_randomizers;
23mod parse;
24mod serialize;
25mod size_in_fields;
26mod to_bits;
27mod to_fields;
28
29use crate::{Access, Ciphertext, Identifier, Literal};
30use snarkvm_console_network::Network;
31use snarkvm_console_types::prelude::*;
32
33use indexmap::IndexMap;
34use std::sync::OnceLock;
35
36#[derive(Clone)]
37pub enum Plaintext<N: Network> {
38    /// A literal.
39    Literal(Literal<N>, OnceLock<Vec<bool>>),
40    /// A struct.
41    Struct(IndexMap<Identifier<N>, Plaintext<N>>, OnceLock<Vec<bool>>),
42    /// An array.
43    Array(Vec<Plaintext<N>>, OnceLock<Vec<bool>>),
44}
45
46impl<N: Network> From<Literal<N>> for Plaintext<N> {
47    /// Returns a new `Plaintext` from a `Literal`.
48    fn from(literal: Literal<N>) -> Self {
49        Self::Literal(literal, OnceLock::new())
50    }
51}
52
53impl<N: Network> From<&Literal<N>> for Plaintext<N> {
54    /// Returns a new `Plaintext` from a `&Literal`.
55    fn from(literal: &Literal<N>) -> Self {
56        Self::Literal(literal.clone(), OnceLock::new())
57    }
58}
59
60// A macro that derives implementations of `From` for arrays of a plaintext literals of various sizes.
61macro_rules! impl_plaintext_from_array {
62    ($element:ident, $($size:literal),+) => {
63        $(
64            impl<N: Network> From<[$element<N>; $size]> for Plaintext<N> {
65                fn from(value: [$element<N>; $size]) -> Self {
66                    Self::Array(
67                        value
68                            .into_iter()
69                            .map(|element| Plaintext::from(Literal::$element(element)))
70                            .collect(),
71                        OnceLock::new(),
72                    )
73                }
74            }
75        )+
76    };
77}
78
79// Implement for `[U8<N>, SIZE]` for sizes 1 through 32.
80impl_plaintext_from_array!(
81    U8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
82    31, 32
83);
84
85#[cfg(test)]
86mod tests {
87    use super::*;
88    use snarkvm_console_network::MainnetV0;
89    use snarkvm_console_types::Field;
90
91    use core::str::FromStr;
92
93    type CurrentNetwork = MainnetV0;
94
95    #[test]
96    fn test_plaintext() -> Result<()> {
97        let run_test = |value: Plaintext<CurrentNetwork>| {
98            assert_eq!(
99                value.to_bits_le(),
100                Plaintext::<CurrentNetwork>::from_bits_le(&value.to_bits_le()).unwrap().to_bits_le()
101            );
102            assert_eq!(value, Plaintext::<CurrentNetwork>::from_fields(&value.to_fields().unwrap()).unwrap());
103            assert_eq!(value, Plaintext::<CurrentNetwork>::from_str(&value.to_string()).unwrap());
104            assert!(*value.is_equal(&value));
105            assert!(*!value.is_not_equal(&value));
106        };
107
108        let mut rng = TestRng::default();
109
110        // Test booleans.
111        run_test(Plaintext::<CurrentNetwork>::from_str("true")?);
112        run_test(Plaintext::<CurrentNetwork>::from_str("false")?);
113
114        // Test a random field element.
115        run_test(Plaintext::<CurrentNetwork>::Literal(
116            Literal::Field(Field::new(Uniform::rand(&mut rng))),
117            OnceLock::new(),
118        ));
119
120        // Test a random struct with literal members.
121        run_test(Plaintext::<CurrentNetwork>::Struct(
122            IndexMap::from_iter(vec![
123                (Identifier::from_str("a")?, Plaintext::<CurrentNetwork>::from_str("true")?),
124                (
125                    Identifier::from_str("b")?,
126                    Plaintext::<CurrentNetwork>::Literal(
127                        Literal::Field(Field::new(Uniform::rand(&mut rng))),
128                        OnceLock::new(),
129                    ),
130                ),
131            ]),
132            OnceLock::new(),
133        ));
134
135        // Test a random struct with array members.
136        run_test(Plaintext::<CurrentNetwork>::Struct(
137            IndexMap::from_iter(vec![
138                (Identifier::from_str("a")?, Plaintext::<CurrentNetwork>::from_str("true")?),
139                (
140                    Identifier::from_str("b")?,
141                    Plaintext::<CurrentNetwork>::Array(
142                        vec![
143                            Plaintext::<CurrentNetwork>::from_str("true")?,
144                            Plaintext::<CurrentNetwork>::from_str("false")?,
145                        ],
146                        OnceLock::new(),
147                    ),
148                ),
149            ]),
150            OnceLock::new(),
151        ));
152
153        // Test random deeply-nested struct.
154        run_test(Plaintext::<CurrentNetwork>::Struct(
155            IndexMap::from_iter(vec![
156                (Identifier::from_str("a")?, Plaintext::<CurrentNetwork>::from_str("true")?),
157                (
158                    Identifier::from_str("b")?,
159                    Plaintext::<CurrentNetwork>::Struct(
160                        IndexMap::from_iter(vec![
161                            (Identifier::from_str("c")?, Plaintext::<CurrentNetwork>::from_str("true")?),
162                            (
163                                Identifier::from_str("d")?,
164                                Plaintext::<CurrentNetwork>::Struct(
165                                    IndexMap::from_iter(vec![
166                                        (Identifier::from_str("e")?, Plaintext::<CurrentNetwork>::from_str("true")?),
167                                        (
168                                            Identifier::from_str("f")?,
169                                            Plaintext::<CurrentNetwork>::Literal(
170                                                Literal::Field(Field::new(Uniform::rand(&mut rng))),
171                                                OnceLock::new(),
172                                            ),
173                                        ),
174                                    ]),
175                                    OnceLock::new(),
176                                ),
177                            ),
178                            (
179                                Identifier::from_str("g")?,
180                                Plaintext::Array(
181                                    vec![
182                                        Plaintext::<CurrentNetwork>::from_str("true")?,
183                                        Plaintext::<CurrentNetwork>::from_str("false")?,
184                                    ],
185                                    OnceLock::new(),
186                                ),
187                            ),
188                        ]),
189                        OnceLock::new(),
190                    ),
191                ),
192                (
193                    Identifier::from_str("h")?,
194                    Plaintext::<CurrentNetwork>::Literal(
195                        Literal::Field(Field::new(Uniform::rand(&mut rng))),
196                        OnceLock::new(),
197                    ),
198                ),
199            ]),
200            OnceLock::new(),
201        ));
202
203        // Test an array of literals.
204        run_test(Plaintext::<CurrentNetwork>::Array(
205            vec![
206                Plaintext::<CurrentNetwork>::from_str("0field")?,
207                Plaintext::<CurrentNetwork>::from_str("1field")?,
208                Plaintext::<CurrentNetwork>::from_str("2field")?,
209                Plaintext::<CurrentNetwork>::from_str("3field")?,
210                Plaintext::<CurrentNetwork>::from_str("4field")?,
211            ],
212            OnceLock::new(),
213        ));
214
215        // Test an array of structs.
216        run_test(Plaintext::<CurrentNetwork>::Array(
217            vec![
218                Plaintext::<CurrentNetwork>::from_str("{ x: 0field, y: 1field }")?,
219                Plaintext::<CurrentNetwork>::from_str("{ x: 2field, y: 3field }")?,
220                Plaintext::<CurrentNetwork>::from_str("{ x: 4field, y: 5field }")?,
221                Plaintext::<CurrentNetwork>::from_str("{ x: 6field, y: 7field }")?,
222                Plaintext::<CurrentNetwork>::from_str("{ x: 8field, y: 9field }")?,
223            ],
224            OnceLock::new(),
225        ));
226
227        // Test a non-uniform array.
228        run_test(Plaintext::<CurrentNetwork>::Array(
229            vec![
230                Plaintext::<CurrentNetwork>::from_str("true")?,
231                Plaintext::<CurrentNetwork>::from_str("1field")?,
232                Plaintext::<CurrentNetwork>::from_str("{ x: 4field, y: 1u8 }")?,
233            ],
234            OnceLock::new(),
235        ));
236
237        Ok(())
238    }
239}