snarkvm_circuit_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
16#[cfg(test)]
17use snarkvm_circuit_types::environment::assert_scope;
18
19mod encrypt;
20mod equal;
21mod find;
22mod from_bits;
23mod from_fields;
24mod num_randomizers;
25mod size_in_fields;
26mod to_bits;
27mod to_fields;
28
29use crate::{Access, Ciphertext, Identifier, Literal, Visibility};
30use snarkvm_circuit_network::Aleo;
31use snarkvm_circuit_types::{Address, Boolean, Field, Scalar, U8, U16, U32, environment::prelude::*};
32
33#[derive(Clone)]
34pub enum Plaintext<A: Aleo> {
35    /// A plaintext literal.
36    Literal(Literal<A>, OnceCell<Vec<Boolean<A>>>),
37    /// A plaintext struct.
38    Struct(IndexMap<Identifier<A>, Plaintext<A>>, OnceCell<Vec<Boolean<A>>>),
39    /// A plaintext array.
40    Array(Vec<Plaintext<A>>, OnceCell<Vec<Boolean<A>>>),
41}
42
43#[cfg(feature = "console")]
44impl<A: Aleo> Inject for Plaintext<A> {
45    type Primitive = console::Plaintext<A::Network>;
46
47    /// Initializes a new plaintext circuit from a primitive.
48    fn new(mode: Mode, plaintext: Self::Primitive) -> Self {
49        match plaintext {
50            Self::Primitive::Literal(literal, _) => Self::Literal(Literal::new(mode, literal), Default::default()),
51            Self::Primitive::Struct(struct_, _) => Self::Struct(Inject::new(mode, struct_), Default::default()),
52            Self::Primitive::Array(array, _) => Self::Array(Inject::new(mode, array), Default::default()),
53        }
54    }
55}
56
57#[cfg(feature = "console")]
58impl<A: Aleo> Eject for Plaintext<A> {
59    type Primitive = console::Plaintext<A::Network>;
60
61    /// Ejects the mode of the plaintext value.
62    fn eject_mode(&self) -> Mode {
63        match self {
64            Self::Literal(literal, _) => literal.eject_mode(),
65            Self::Struct(struct_, _) => struct_
66                .iter()
67                .map(|(identifier, value)| (identifier, value).eject_mode())
68                .collect::<Vec<_>>()
69                .eject_mode(),
70            Self::Array(array, _) => array.iter().map(Eject::eject_mode).collect::<Vec<_>>().eject_mode(),
71        }
72    }
73
74    /// Ejects the plaintext value.
75    fn eject_value(&self) -> Self::Primitive {
76        match self {
77            Self::Literal(literal, _) => console::Plaintext::Literal(literal.eject_value(), Default::default()),
78            Self::Struct(struct_, _) => {
79                console::Plaintext::Struct(struct_.iter().map(|pair| pair.eject_value()).collect(), Default::default())
80            }
81            Self::Array(array, _) => {
82                console::Plaintext::Array(array.iter().map(Eject::eject_value).collect(), Default::default())
83            }
84        }
85    }
86}
87
88impl<A: Aleo> From<Literal<A>> for Plaintext<A> {
89    /// Returns a new `Plaintext` from a `Literal`.
90    fn from(literal: Literal<A>) -> Self {
91        Self::Literal(literal, OnceCell::new())
92    }
93}
94
95impl<A: Aleo> From<&Literal<A>> for Plaintext<A> {
96    /// Returns a new `Plaintext` from a `Literal`.
97    fn from(literal: &Literal<A>) -> Self {
98        Self::Literal((*literal).clone(), OnceCell::new())
99    }
100}
101
102#[cfg(all(test, feature = "console"))]
103mod tests {
104    use super::*;
105    use crate::Circuit;
106    use snarkvm_utilities::{TestRng, Uniform};
107
108    use anyhow::Result;
109
110    #[test]
111    fn test_plaintext() -> Result<()> {
112        let run_test = |value: Plaintext<Circuit>| {
113            assert_eq!(
114                value.to_bits_le().eject(),
115                Plaintext::<Circuit>::from_bits_le(&value.to_bits_le()).to_bits_le().eject()
116            );
117            assert_eq!(value.eject(), Plaintext::<Circuit>::from_fields(&value.to_fields()).eject());
118            assert!(value.is_equal(&value).eject_value());
119            assert!(!value.is_not_equal(&value).eject_value());
120        };
121
122        let mut rng = TestRng::default();
123
124        // Test booleans.
125        run_test(Plaintext::<Circuit>::Literal(Literal::Boolean(Boolean::new(Mode::Private, true)), OnceCell::new()));
126        run_test(Plaintext::<Circuit>::Literal(Literal::Boolean(Boolean::new(Mode::Private, false)), OnceCell::new()));
127
128        // Test a random field element.
129        run_test(Plaintext::<Circuit>::Literal(
130            Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
131            OnceCell::new(),
132        ));
133
134        // Test a random struct with literal members.
135        run_test(Plaintext::<Circuit>::Struct(
136            IndexMap::from_iter(vec![
137                (
138                    Identifier::new(Mode::Private, "a".try_into()?),
139                    Plaintext::<Circuit>::Literal(Literal::Boolean(Boolean::new(Mode::Private, true)), OnceCell::new()),
140                ),
141                (
142                    Identifier::new(Mode::Private, "b".try_into()?),
143                    Plaintext::<Circuit>::Literal(
144                        Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
145                        OnceCell::new(),
146                    ),
147                ),
148            ]),
149            OnceCell::new(),
150        ));
151
152        // Test a random struct with array members.
153        run_test(Plaintext::<Circuit>::Struct(
154            IndexMap::from_iter(vec![
155                (
156                    Identifier::new(Mode::Private, "a".try_into()?),
157                    Plaintext::<Circuit>::Literal(Literal::Boolean(Boolean::new(Mode::Private, true)), OnceCell::new()),
158                ),
159                (
160                    Identifier::new(Mode::Private, "b".try_into()?),
161                    Plaintext::<Circuit>::Array(
162                        vec![
163                            Plaintext::<Circuit>::Literal(
164                                Literal::Boolean(Boolean::new(Mode::Private, true)),
165                                OnceCell::new(),
166                            ),
167                            Plaintext::<Circuit>::Literal(
168                                Literal::Boolean(Boolean::new(Mode::Private, false)),
169                                OnceCell::new(),
170                            ),
171                        ],
172                        OnceCell::new(),
173                    ),
174                ),
175            ]),
176            OnceCell::new(),
177        ));
178
179        // Test random deeply-nested struct.
180        run_test(Plaintext::<Circuit>::Struct(
181            IndexMap::from_iter(vec![
182                (
183                    Identifier::new(Mode::Private, "a".try_into()?),
184                    Plaintext::<Circuit>::Literal(Literal::Boolean(Boolean::new(Mode::Private, true)), OnceCell::new()),
185                ),
186                (
187                    Identifier::new(Mode::Private, "b".try_into()?),
188                    Plaintext::<Circuit>::Struct(
189                        IndexMap::from_iter(vec![
190                            (
191                                Identifier::new(Mode::Private, "c".try_into()?),
192                                Plaintext::<Circuit>::Literal(
193                                    Literal::Boolean(Boolean::new(Mode::Private, true)),
194                                    OnceCell::new(),
195                                ),
196                            ),
197                            (
198                                Identifier::new(Mode::Private, "d".try_into()?),
199                                Plaintext::<Circuit>::Struct(
200                                    IndexMap::from_iter(vec![
201                                        (
202                                            Identifier::new(Mode::Private, "e".try_into()?),
203                                            Plaintext::<Circuit>::Literal(
204                                                Literal::Boolean(Boolean::new(Mode::Private, true)),
205                                                OnceCell::new(),
206                                            ),
207                                        ),
208                                        (
209                                            Identifier::new(Mode::Private, "f".try_into()?),
210                                            Plaintext::<Circuit>::Literal(
211                                                Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
212                                                OnceCell::new(),
213                                            ),
214                                        ),
215                                    ]),
216                                    OnceCell::new(),
217                                ),
218                            ),
219                            (
220                                Identifier::new(Mode::Private, "g".try_into()?),
221                                Plaintext::<Circuit>::Array(
222                                    vec![
223                                        Plaintext::<Circuit>::Literal(
224                                            Literal::Boolean(Boolean::new(Mode::Private, true)),
225                                            OnceCell::new(),
226                                        ),
227                                        Plaintext::<Circuit>::Literal(
228                                            Literal::Boolean(Boolean::new(Mode::Private, false)),
229                                            OnceCell::new(),
230                                        ),
231                                    ],
232                                    OnceCell::new(),
233                                ),
234                            ),
235                        ]),
236                        OnceCell::new(),
237                    ),
238                ),
239                (
240                    Identifier::new(Mode::Private, "h".try_into()?),
241                    Plaintext::<Circuit>::Literal(
242                        Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
243                        OnceCell::new(),
244                    ),
245                ),
246            ]),
247            OnceCell::new(),
248        ));
249
250        // Test an array of literals.
251        run_test(Plaintext::<Circuit>::Array(
252            vec![
253                Plaintext::<Circuit>::Literal(
254                    Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
255                    OnceCell::new(),
256                ),
257                Plaintext::<Circuit>::Literal(
258                    Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
259                    OnceCell::new(),
260                ),
261                Plaintext::<Circuit>::Literal(
262                    Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
263                    OnceCell::new(),
264                ),
265                Plaintext::<Circuit>::Literal(
266                    Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
267                    OnceCell::new(),
268                ),
269                Plaintext::<Circuit>::Literal(
270                    Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
271                    OnceCell::new(),
272                ),
273            ],
274            OnceCell::new(),
275        ));
276
277        // Test an array of structs.
278        run_test(Plaintext::<Circuit>::Array(
279            vec![
280                Plaintext::<Circuit>::Struct(
281                    IndexMap::from_iter(vec![
282                        (
283                            Identifier::new(Mode::Private, "x".try_into()?),
284                            Plaintext::<Circuit>::Literal(
285                                Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
286                                OnceCell::new(),
287                            ),
288                        ),
289                        (
290                            Identifier::new(Mode::Private, "y".try_into()?),
291                            Plaintext::<Circuit>::Literal(
292                                Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
293                                OnceCell::new(),
294                            ),
295                        ),
296                    ]),
297                    OnceCell::new(),
298                ),
299                Plaintext::<Circuit>::Struct(
300                    IndexMap::from_iter(vec![
301                        (
302                            Identifier::new(Mode::Private, "x".try_into()?),
303                            Plaintext::<Circuit>::Literal(
304                                Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
305                                OnceCell::new(),
306                            ),
307                        ),
308                        (
309                            Identifier::new(Mode::Private, "y".try_into()?),
310                            Plaintext::<Circuit>::Literal(
311                                Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
312                                OnceCell::new(),
313                            ),
314                        ),
315                    ]),
316                    OnceCell::new(),
317                ),
318                Plaintext::<Circuit>::Struct(
319                    IndexMap::from_iter(vec![
320                        (
321                            Identifier::new(Mode::Private, "x".try_into()?),
322                            Plaintext::<Circuit>::Literal(
323                                Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
324                                OnceCell::new(),
325                            ),
326                        ),
327                        (
328                            Identifier::new(Mode::Private, "y".try_into()?),
329                            Plaintext::<Circuit>::Literal(
330                                Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
331                                OnceCell::new(),
332                            ),
333                        ),
334                    ]),
335                    OnceCell::new(),
336                ),
337            ],
338            OnceCell::new(),
339        ));
340
341        // Test a non-uniform array.
342        run_test(Plaintext::<Circuit>::Array(
343            vec![
344                Plaintext::<Circuit>::Literal(Literal::Boolean(Boolean::new(Mode::Private, true)), OnceCell::new()),
345                Plaintext::<Circuit>::Literal(
346                    Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
347                    OnceCell::new(),
348                ),
349                Plaintext::<Circuit>::Struct(
350                    IndexMap::from_iter(vec![
351                        (
352                            Identifier::new(Mode::Private, "x".try_into()?),
353                            Plaintext::<Circuit>::Literal(
354                                Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
355                                OnceCell::new(),
356                            ),
357                        ),
358                        (
359                            Identifier::new(Mode::Private, "y".try_into()?),
360                            Plaintext::<Circuit>::Literal(
361                                Literal::Field(Field::new(Mode::Private, Uniform::rand(&mut rng))),
362                                OnceCell::new(),
363                            ),
364                        ),
365                    ]),
366                    OnceCell::new(),
367                ),
368            ],
369            OnceCell::new(),
370        ));
371
372        Ok(())
373    }
374}