snarkvm_circuit_program/data/record/helpers/
owner.rs

1// Copyright 2024 Aleo Network Foundation
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 crate::{Ciphertext, Entry, Literal, Plaintext, Visibility};
17use snarkvm_circuit_network::Aleo;
18use snarkvm_circuit_types::{Address, Boolean, Field, environment::prelude::*};
19
20/// A value stored in program data.
21#[derive(Clone)]
22pub enum Owner<A: Aleo, Private: Visibility<A>> {
23    /// A publicly-visible value.
24    Public(Address<A>),
25    /// A private value is encrypted under the account owner's address.
26    Private(Private),
27}
28
29#[cfg(feature = "console")]
30impl<A: Aleo> Inject for Owner<A, Plaintext<A>> {
31    type Primitive = console::Owner<A::Network, console::Plaintext<A::Network>>;
32
33    /// Initializes plaintext owner from a primitive.
34    fn new(_: Mode, owner: Self::Primitive) -> Self {
35        match owner {
36            console::Owner::Public(owner) => Self::Public(Address::new(Mode::Private, owner)),
37            console::Owner::Private(console::Plaintext::Literal(console::Literal::Address(owner), ..)) => {
38                Self::Private(Plaintext::Literal(
39                    Literal::Address(Address::new(Mode::Private, owner)),
40                    Default::default(),
41                ))
42            }
43            _ => A::halt("Owner::<Plaintext>::new: Invalid primitive type for owner"),
44        }
45    }
46}
47
48#[cfg(feature = "console")]
49impl<A: Aleo> Inject for Owner<A, Ciphertext<A>> {
50    type Primitive = console::Owner<A::Network, console::Ciphertext<A::Network>>;
51
52    /// Initializes ciphertext owner from a primitive.
53    fn new(_: Mode, owner: Self::Primitive) -> Self {
54        match owner {
55            console::Owner::Public(owner) => Self::Public(Address::new(Mode::Private, owner)),
56            console::Owner::Private(ciphertext) => Self::Private(Ciphertext::new(Mode::Private, ciphertext)),
57        }
58    }
59}
60
61impl<A: Aleo> Deref for Owner<A, Plaintext<A>> {
62    type Target = Address<A>;
63
64    /// Returns the address of the owner.
65    fn deref(&self) -> &Self::Target {
66        match self {
67            Self::Public(public) => public,
68            Self::Private(Plaintext::Literal(Literal::Address(address), ..)) => address,
69            _ => A::halt("Internal error: plaintext deref corrupted in record owner"),
70        }
71    }
72}
73
74impl<A: Aleo, Private: Visibility<A>> Owner<A, Private> {
75    /// Returns `true` if `self` is public.
76    pub fn is_public(&self) -> Boolean<A> {
77        Boolean::constant(matches!(self, Self::Public(..)))
78    }
79
80    /// Returns `true` if `self` is private.
81    pub fn is_private(&self) -> Boolean<A> {
82        Boolean::constant(matches!(self, Self::Private(..)))
83    }
84}
85
86impl<A: Aleo> Owner<A, Plaintext<A>> {
87    /// Returns the owner as an `Entry`.
88    pub fn to_entry(&self) -> Entry<A, Plaintext<A>> {
89        match self {
90            Self::Public(owner) => Entry::Public(Plaintext::from(Literal::Address(owner.clone()))),
91            Self::Private(plaintext, ..) => Entry::Private(plaintext.clone()),
92        }
93    }
94}
95
96impl<A: Aleo, Private: Visibility<A>> Equal<Self> for Owner<A, Private> {
97    type Output = Boolean<A>;
98
99    /// Returns `true` if `self` and `other` are equal.
100    fn is_equal(&self, other: &Self) -> Self::Output {
101        match (self, other) {
102            (Self::Public(a), Self::Public(b)) => a.is_equal(b),
103            (Self::Private(a), Self::Private(b)) => a.is_equal(b),
104            (Self::Public(_), _) | (Self::Private(_), _) => Boolean::constant(false),
105        }
106    }
107
108    /// Returns `true` if `self` and `other` are *not* equal.
109    fn is_not_equal(&self, other: &Self) -> Self::Output {
110        match (self, other) {
111            (Self::Public(a), Self::Public(b)) => a.is_not_equal(b),
112            (Self::Private(a), Self::Private(b)) => a.is_not_equal(b),
113            (Self::Public(_), _) | (Self::Private(_), _) => Boolean::constant(true),
114        }
115    }
116}
117
118impl<A: Aleo> Owner<A, Plaintext<A>> {
119    /// Encrypts `self` under the given randomizer.
120    pub fn encrypt(&self, randomizer: &[Field<A>]) -> Owner<A, Ciphertext<A>> {
121        match self {
122            Self::Public(public) => {
123                // Ensure there is exactly zero randomizers.
124                if !randomizer.is_empty() {
125                    A::halt(format!("Expected 0 randomizers, found {}", randomizer.len()))
126                }
127                // Return the owner.
128                Owner::Public(public.clone())
129            }
130            Self::Private(Plaintext::Literal(Literal::Address(address), ..)) => {
131                // Ensure there is exactly one randomizer.
132                if randomizer.len() != 1 {
133                    A::halt(format!("Expected 1 randomizer, found {}", randomizer.len()))
134                }
135                // Encrypt the owner.
136                let ciphertext = address.to_field() + &randomizer[0];
137                // Return the encrypted owner.
138                Owner::Private(Ciphertext::from_fields(&[ciphertext]))
139            }
140            _ => A::halt("Internal error: plaintext encryption corrupted in record owner"),
141        }
142    }
143}
144
145impl<A: Aleo> Owner<A, Ciphertext<A>> {
146    /// Decrypts the owner under the given randomizer.
147    pub fn decrypt(&self, randomizer: &[Field<A>]) -> Owner<A, Plaintext<A>> {
148        match self {
149            Self::Public(public) => {
150                // Ensure there is exactly zero randomizers.
151                if !randomizer.is_empty() {
152                    A::halt(format!("Expected 0 randomizers, found {}", randomizer.len()))
153                }
154                // Return the owner.
155                Owner::Public(public.clone())
156            }
157            Self::Private(ciphertext) => {
158                // Ensure there is exactly one randomizer.
159                if randomizer.len() != 1 {
160                    A::halt(format!("Expected 1 randomizer, found {}", randomizer.len()))
161                }
162                // Ensure there is exactly one field element in the ciphertext.
163                if ciphertext.len() != 1 {
164                    A::halt(format!("Expected 1 ciphertext, found {}", ciphertext.len()))
165                }
166                // Decrypt the owner.
167                let owner = Address::from_field(&ciphertext[0] - &randomizer[0]);
168                // Return the owner.
169                Owner::Private(Plaintext::from(Literal::Address(owner)))
170            }
171        }
172    }
173}
174
175impl<A: Aleo> ToBits for Owner<A, Plaintext<A>> {
176    type Boolean = Boolean<A>;
177
178    /// Returns `self` as a boolean vector in little-endian order.
179    fn write_bits_le(&self, vec: &mut Vec<Boolean<A>>) {
180        vec.push(self.is_private());
181        match self {
182            Self::Public(public) => public.write_bits_le(vec),
183            Self::Private(Plaintext::Literal(Literal::Address(address), ..)) => address.write_bits_le(vec),
184            _ => A::halt("Internal error: plaintext to_bits_le corrupted in record owner"),
185        };
186    }
187
188    /// Returns `self` as a boolean vector in big-endian order.
189    fn write_bits_be(&self, vec: &mut Vec<Boolean<A>>) {
190        vec.push(self.is_private());
191        match self {
192            Self::Public(public) => public.write_bits_be(vec),
193            Self::Private(Plaintext::Literal(Literal::Address(address), ..)) => address.write_bits_be(vec),
194            _ => A::halt("Internal error: plaintext to_bits_be corrupted in record owner"),
195        };
196    }
197}
198
199impl<A: Aleo> ToBits for Owner<A, Ciphertext<A>> {
200    type Boolean = Boolean<A>;
201
202    /// Returns `self` as a boolean vector in little-endian order.
203    fn write_bits_le(&self, vec: &mut Vec<Boolean<A>>) {
204        vec.push(self.is_private());
205        match self {
206            Self::Public(public) => public.write_bits_le(vec),
207            Self::Private(ciphertext) => {
208                // Ensure there is exactly one field element in the ciphertext.
209                match ciphertext.len() == 1 {
210                    true => ciphertext[0].write_bits_le(vec),
211                    false => A::halt("Internal error: ciphertext to_bits_le corrupted in record owner"),
212                }
213            }
214        };
215    }
216
217    /// Returns `self` as a boolean vector in big-endian order.
218    fn write_bits_be(&self, vec: &mut Vec<Boolean<A>>) {
219        vec.push(self.is_private());
220        match self {
221            Self::Public(public) => public.write_bits_be(vec),
222            Self::Private(ciphertext) => {
223                // Ensure there is exactly one field element in the ciphertext.
224                match ciphertext.len() == 1 {
225                    true => ciphertext[0].write_bits_be(vec),
226                    false => A::halt("Internal error: ciphertext to_bits_be corrupted in record owner"),
227                }
228            }
229        };
230    }
231}