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_bits_raw;
28mod to_fields;
29mod to_fields_raw;
30
31use crate::{Access, Ciphertext, Identifier, Literal, PlaintextType};
32use snarkvm_console_network::Network;
33use snarkvm_console_types::prelude::*;
34
35use indexmap::IndexMap;
36use std::sync::OnceLock;
37
38#[derive(Clone)]
39pub enum Plaintext<N: Network> {
40    /// A literal.
41    Literal(Literal<N>, OnceLock<Vec<bool>>),
42    /// A struct.
43    Struct(IndexMap<Identifier<N>, Plaintext<N>>, OnceLock<Vec<bool>>),
44    /// An array.
45    Array(Vec<Plaintext<N>>, OnceLock<Vec<bool>>),
46}
47
48impl<N: Network> Plaintext<N> {
49    /// Returns a new `Plaintext::Array` from `Vec<bool>`, checking that the length is correct.
50    pub fn from_bit_array(bits: Vec<bool>, length: u32) -> Result<Self> {
51        ensure!(bits.len() == length as usize, "Expected '{length}' bits, got '{}' bits", bits.len());
52        Ok(Self::Array(
53            bits.into_iter().map(|bit| Plaintext::from(Literal::Boolean(Boolean::new(bit)))).collect(),
54            OnceLock::new(),
55        ))
56    }
57
58    /// Returns the `Plaintext` as a `Vec<bool>`, if it is a bit array.
59    pub fn as_bit_array(&self) -> Result<Vec<bool>> {
60        match self {
61            Self::Array(elements, _) => {
62                let mut bits = Vec::with_capacity(elements.len());
63                for element in elements {
64                    match element {
65                        Self::Literal(Literal::Boolean(bit), _) => bits.push(**bit),
66                        _ => bail!("Expected a bit array, found a non-boolean element."),
67                    }
68                }
69                Ok(bits)
70            }
71            _ => bail!("Expected a bit array, found a non-array plaintext."),
72        }
73    }
74}
75
76impl<N: Network> From<Literal<N>> for Plaintext<N> {
77    /// Returns a new `Plaintext` from a `Literal`.
78    fn from(literal: Literal<N>) -> Self {
79        Self::Literal(literal, OnceLock::new())
80    }
81}
82
83impl<N: Network> From<&Literal<N>> for Plaintext<N> {
84    /// Returns a new `Plaintext` from a `&Literal`.
85    fn from(literal: &Literal<N>) -> Self {
86        Self::Literal(literal.clone(), OnceLock::new())
87    }
88}
89
90// A macro that derives implementations of `From` for arrays of a plaintext literals of various sizes.
91macro_rules! impl_plaintext_from_array {
92    ($element:ident, $($size:literal),+) => {
93        $(
94            impl<N: Network> From<[$element<N>; $size]> for Plaintext<N> {
95                fn from(value: [$element<N>; $size]) -> Self {
96                    Self::Array(
97                        value
98                            .into_iter()
99                            .map(|element| Plaintext::from(Literal::$element(element)))
100                            .collect(),
101                        OnceLock::new(),
102                    )
103                }
104            }
105        )+
106    };
107}
108
109// Implement for `[U8<N>, SIZE]` for sizes 1 through 256.
110seq_macro::seq!(S in 1..=256 {
111    impl_plaintext_from_array!(U8, S);
112});
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117    use snarkvm_console_network::MainnetV0;
118    use snarkvm_console_types::Field;
119
120    use core::str::FromStr;
121
122    type CurrentNetwork = MainnetV0;
123
124    #[test]
125    fn test_plaintext() -> Result<()> {
126        let run_test = |value: Plaintext<CurrentNetwork>| {
127            assert_eq!(
128                value.to_bits_le(),
129                Plaintext::<CurrentNetwork>::from_bits_le(&value.to_bits_le()).unwrap().to_bits_le()
130            );
131            assert_eq!(value, Plaintext::<CurrentNetwork>::from_fields(&value.to_fields().unwrap()).unwrap());
132            assert_eq!(value, Plaintext::<CurrentNetwork>::from_str(&value.to_string()).unwrap());
133            assert!(*value.is_equal(&value));
134            assert!(*!value.is_not_equal(&value));
135        };
136
137        let mut rng = TestRng::default();
138
139        // Test booleans.
140        run_test(Plaintext::<CurrentNetwork>::from_str("true")?);
141        run_test(Plaintext::<CurrentNetwork>::from_str("false")?);
142
143        // Test a random field element.
144        run_test(Plaintext::<CurrentNetwork>::Literal(
145            Literal::Field(Field::new(Uniform::rand(&mut rng))),
146            OnceLock::new(),
147        ));
148
149        // Test a random struct with literal members.
150        run_test(Plaintext::<CurrentNetwork>::Struct(
151            IndexMap::from_iter(vec![
152                (Identifier::from_str("a")?, Plaintext::<CurrentNetwork>::from_str("true")?),
153                (
154                    Identifier::from_str("b")?,
155                    Plaintext::<CurrentNetwork>::Literal(
156                        Literal::Field(Field::new(Uniform::rand(&mut rng))),
157                        OnceLock::new(),
158                    ),
159                ),
160            ]),
161            OnceLock::new(),
162        ));
163
164        // Test a random struct with array members.
165        run_test(Plaintext::<CurrentNetwork>::Struct(
166            IndexMap::from_iter(vec![
167                (Identifier::from_str("a")?, Plaintext::<CurrentNetwork>::from_str("true")?),
168                (
169                    Identifier::from_str("b")?,
170                    Plaintext::<CurrentNetwork>::Array(
171                        vec![
172                            Plaintext::<CurrentNetwork>::from_str("true")?,
173                            Plaintext::<CurrentNetwork>::from_str("false")?,
174                        ],
175                        OnceLock::new(),
176                    ),
177                ),
178            ]),
179            OnceLock::new(),
180        ));
181
182        // Test random deeply-nested struct.
183        run_test(Plaintext::<CurrentNetwork>::Struct(
184            IndexMap::from_iter(vec![
185                (Identifier::from_str("a")?, Plaintext::<CurrentNetwork>::from_str("true")?),
186                (
187                    Identifier::from_str("b")?,
188                    Plaintext::<CurrentNetwork>::Struct(
189                        IndexMap::from_iter(vec![
190                            (Identifier::from_str("c")?, Plaintext::<CurrentNetwork>::from_str("true")?),
191                            (
192                                Identifier::from_str("d")?,
193                                Plaintext::<CurrentNetwork>::Struct(
194                                    IndexMap::from_iter(vec![
195                                        (Identifier::from_str("e")?, Plaintext::<CurrentNetwork>::from_str("true")?),
196                                        (
197                                            Identifier::from_str("f")?,
198                                            Plaintext::<CurrentNetwork>::Literal(
199                                                Literal::Field(Field::new(Uniform::rand(&mut rng))),
200                                                OnceLock::new(),
201                                            ),
202                                        ),
203                                    ]),
204                                    OnceLock::new(),
205                                ),
206                            ),
207                            (
208                                Identifier::from_str("g")?,
209                                Plaintext::Array(
210                                    vec![
211                                        Plaintext::<CurrentNetwork>::from_str("true")?,
212                                        Plaintext::<CurrentNetwork>::from_str("false")?,
213                                    ],
214                                    OnceLock::new(),
215                                ),
216                            ),
217                        ]),
218                        OnceLock::new(),
219                    ),
220                ),
221                (
222                    Identifier::from_str("h")?,
223                    Plaintext::<CurrentNetwork>::Literal(
224                        Literal::Field(Field::new(Uniform::rand(&mut rng))),
225                        OnceLock::new(),
226                    ),
227                ),
228            ]),
229            OnceLock::new(),
230        ));
231
232        // Test an array of literals.
233        run_test(Plaintext::<CurrentNetwork>::Array(
234            vec![
235                Plaintext::<CurrentNetwork>::from_str("0field")?,
236                Plaintext::<CurrentNetwork>::from_str("1field")?,
237                Plaintext::<CurrentNetwork>::from_str("2field")?,
238                Plaintext::<CurrentNetwork>::from_str("3field")?,
239                Plaintext::<CurrentNetwork>::from_str("4field")?,
240            ],
241            OnceLock::new(),
242        ));
243
244        // Test an array of structs.
245        run_test(Plaintext::<CurrentNetwork>::Array(
246            vec![
247                Plaintext::<CurrentNetwork>::from_str("{ x: 0field, y: 1field }")?,
248                Plaintext::<CurrentNetwork>::from_str("{ x: 2field, y: 3field }")?,
249                Plaintext::<CurrentNetwork>::from_str("{ x: 4field, y: 5field }")?,
250                Plaintext::<CurrentNetwork>::from_str("{ x: 6field, y: 7field }")?,
251                Plaintext::<CurrentNetwork>::from_str("{ x: 8field, y: 9field }")?,
252            ],
253            OnceLock::new(),
254        ));
255
256        // Test a non-uniform array.
257        run_test(Plaintext::<CurrentNetwork>::Array(
258            vec![
259                Plaintext::<CurrentNetwork>::from_str("true")?,
260                Plaintext::<CurrentNetwork>::from_str("1field")?,
261                Plaintext::<CurrentNetwork>::from_str("{ x: 4field, y: 1u8 }")?,
262            ],
263            OnceLock::new(),
264        ));
265
266        Ok(())
267    }
268}