snarkvm_circuit_program/data/record/helpers/
owner.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
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
29impl<A: Aleo> Inject for Owner<A, Plaintext<A>> {
30    type Primitive = console::Owner<A::Network, console::Plaintext<A::Network>>;
31
32    /// Initializes plaintext owner from a primitive.
33    fn new(_: Mode, owner: Self::Primitive) -> Self {
34        match owner {
35            console::Owner::Public(owner) => Self::Public(Address::new(Mode::Private, owner)),
36            console::Owner::Private(console::Plaintext::Literal(console::Literal::Address(owner), ..)) => {
37                Self::Private(Plaintext::Literal(
38                    Literal::Address(Address::new(Mode::Private, owner)),
39                    Default::default(),
40                ))
41            }
42            _ => A::halt("Owner::<Plaintext>::new: Invalid primitive type for owner"),
43        }
44    }
45}
46
47impl<A: Aleo> Inject for Owner<A, Ciphertext<A>> {
48    type Primitive = console::Owner<A::Network, console::Ciphertext<A::Network>>;
49
50    /// Initializes ciphertext owner from a primitive.
51    fn new(_: Mode, owner: Self::Primitive) -> Self {
52        match owner {
53            console::Owner::Public(owner) => Self::Public(Address::new(Mode::Private, owner)),
54            console::Owner::Private(ciphertext) => Self::Private(Ciphertext::new(Mode::Private, ciphertext)),
55        }
56    }
57}
58
59impl<A: Aleo> Deref for Owner<A, Plaintext<A>> {
60    type Target = Address<A>;
61
62    /// Returns the address of the owner.
63    fn deref(&self) -> &Self::Target {
64        match self {
65            Self::Public(public) => public,
66            Self::Private(Plaintext::Literal(Literal::Address(address), ..)) => address,
67            _ => A::halt("Internal error: plaintext deref corrupted in record owner"),
68        }
69    }
70}
71
72impl<A: Aleo, Private: Visibility<A>> Owner<A, Private> {
73    /// Returns `true` if `self` is public.
74    pub fn is_public(&self) -> Boolean<A> {
75        Boolean::constant(matches!(self, Self::Public(..)))
76    }
77
78    /// Returns `true` if `self` is private.
79    pub fn is_private(&self) -> Boolean<A> {
80        Boolean::constant(matches!(self, Self::Private(..)))
81    }
82}
83
84impl<A: Aleo> Owner<A, Plaintext<A>> {
85    /// Returns the owner as an `Entry`.
86    pub fn to_entry(&self) -> Entry<A, Plaintext<A>> {
87        match self {
88            Self::Public(owner) => Entry::Public(Plaintext::from(Literal::Address(owner.clone()))),
89            Self::Private(plaintext, ..) => Entry::Private(plaintext.clone()),
90        }
91    }
92}
93
94impl<A: Aleo, Private: Visibility<A>> Equal<Self> for Owner<A, Private> {
95    type Output = Boolean<A>;
96
97    /// Returns `true` if `self` and `other` are equal.
98    fn is_equal(&self, other: &Self) -> Self::Output {
99        match (self, other) {
100            (Self::Public(a), Self::Public(b)) => a.is_equal(b),
101            (Self::Private(a), Self::Private(b)) => a.is_equal(b),
102            (Self::Public(_), _) | (Self::Private(_), _) => Boolean::constant(false),
103        }
104    }
105
106    /// Returns `true` if `self` and `other` are *not* equal.
107    fn is_not_equal(&self, other: &Self) -> Self::Output {
108        match (self, other) {
109            (Self::Public(a), Self::Public(b)) => a.is_not_equal(b),
110            (Self::Private(a), Self::Private(b)) => a.is_not_equal(b),
111            (Self::Public(_), _) | (Self::Private(_), _) => Boolean::constant(true),
112        }
113    }
114}
115
116impl<A: Aleo> Owner<A, Plaintext<A>> {
117    /// Encrypts `self` under the given randomizer.
118    pub fn encrypt(&self, randomizer: &[Field<A>]) -> Owner<A, Ciphertext<A>> {
119        match self {
120            Self::Public(public) => {
121                // Ensure there is exactly zero randomizers.
122                if !randomizer.is_empty() {
123                    A::halt(format!("Expected 0 randomizers, found {}", randomizer.len()))
124                }
125                // Return the owner.
126                Owner::Public(public.clone())
127            }
128            Self::Private(Plaintext::Literal(Literal::Address(address), ..)) => {
129                // Ensure there is exactly one randomizer.
130                if randomizer.len() != 1 {
131                    A::halt(format!("Expected 1 randomizer, found {}", randomizer.len()))
132                }
133                // Encrypt the owner.
134                let ciphertext = address.to_field() + &randomizer[0];
135                // Return the encrypted owner.
136                Owner::Private(Ciphertext::from_fields(&[ciphertext]))
137            }
138            _ => A::halt("Internal error: plaintext encryption corrupted in record owner"),
139        }
140    }
141}
142
143impl<A: Aleo> Owner<A, Ciphertext<A>> {
144    /// Decrypts the owner under the given randomizer.
145    pub fn decrypt(&self, randomizer: &[Field<A>]) -> Owner<A, Plaintext<A>> {
146        match self {
147            Self::Public(public) => {
148                // Ensure there is exactly zero randomizers.
149                if !randomizer.is_empty() {
150                    A::halt(format!("Expected 0 randomizers, found {}", randomizer.len()))
151                }
152                // Return the owner.
153                Owner::Public(public.clone())
154            }
155            Self::Private(ciphertext) => {
156                // Ensure there is exactly one randomizer.
157                if randomizer.len() != 1 {
158                    A::halt(format!("Expected 1 randomizer, found {}", randomizer.len()))
159                }
160                // Ensure there is exactly one field element in the ciphertext.
161                if ciphertext.len() != 1 {
162                    A::halt(format!("Expected 1 ciphertext, found {}", ciphertext.len()))
163                }
164                // Decrypt the owner.
165                let owner = Address::from_field(&ciphertext[0] - &randomizer[0]);
166                // Return the owner.
167                Owner::Private(Plaintext::from(Literal::Address(owner)))
168            }
169        }
170    }
171}