snarkvm_circuit_program/request/
mod.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
16#[cfg(test)]
17use snarkvm_circuit_types::environment::assert_scope;
18
19mod to_tpk;
20mod verify;
21
22use crate::{Identifier, Plaintext, ProgramID, Record, Value, compute_function_id};
23use snarkvm_circuit_account::Signature;
24use snarkvm_circuit_network::Aleo;
25use snarkvm_circuit_types::{Address, Boolean, Field, Group, U16, environment::prelude::*};
26
27pub enum InputID<A: Aleo> {
28    /// The hash of the constant input.
29    Constant(Field<A>),
30    /// The hash of the public input.
31    Public(Field<A>),
32    /// The ciphertext hash of the private input.
33    Private(Field<A>),
34    /// The `(commitment, gamma, serial_number, tag)` tuple of the record input.
35    Record(Field<A>, Box<Group<A>>, Field<A>, Field<A>),
36    /// The hash of the external record input.
37    ExternalRecord(Field<A>),
38}
39
40#[cfg(feature = "console")]
41impl<A: Aleo> Inject for InputID<A> {
42    type Primitive = console::InputID<A::Network>;
43
44    /// Initializes the input ID from the given mode and console input ID.
45    fn new(_: Mode, input: Self::Primitive) -> Self {
46        match input {
47            // Inject the expected hash as `Mode::Public`.
48            console::InputID::Constant(field) => Self::Constant(Field::new(Mode::Public, field)),
49            // Inject the expected hash as `Mode::Public`.
50            console::InputID::Public(field) => Self::Public(Field::new(Mode::Public, field)),
51            // Inject the ciphertext hash as `Mode::Public`.
52            console::InputID::Private(field) => Self::Private(Field::new(Mode::Public, field)),
53            // Inject commitment and gamma as `Mode::Private`, and the expected serial number and tag as `Mode::Public`.
54            console::InputID::Record(commitment, gamma, serial_number, tag) => Self::Record(
55                Field::new(Mode::Private, commitment),
56                Box::new(Group::new(Mode::Private, gamma)),
57                Field::new(Mode::Public, serial_number),
58                Field::new(Mode::Public, tag),
59            ),
60            // Inject the commitment as `Mode::Public`.
61            console::InputID::ExternalRecord(field) => Self::ExternalRecord(Field::new(Mode::Public, field)),
62        }
63    }
64}
65
66#[cfg(feature = "console")]
67impl<A: Aleo> Eject for InputID<A> {
68    type Primitive = console::InputID<A::Network>;
69
70    /// Ejects the mode of the input ID.
71    fn eject_mode(&self) -> Mode {
72        match self {
73            Self::Constant(field) => field.eject_mode(),
74            Self::Public(field) => field.eject_mode(),
75            Self::Private(field) => field.eject_mode(),
76            Self::Record(commitment, gamma, serial_number, tag) => Mode::combine(commitment.eject_mode(), [
77                gamma.eject_mode(),
78                serial_number.eject_mode(),
79                tag.eject_mode(),
80            ]),
81            Self::ExternalRecord(field) => field.eject_mode(),
82        }
83    }
84
85    /// Ejects the input ID as a primitive.
86    fn eject_value(&self) -> Self::Primitive {
87        match self {
88            Self::Constant(field) => console::InputID::Constant(field.eject_value()),
89            Self::Public(field) => console::InputID::Public(field.eject_value()),
90            Self::Private(field) => console::InputID::Private(field.eject_value()),
91            Self::Record(commitment, gamma, serial_number, tag) => console::InputID::Record(
92                commitment.eject_value(),
93                gamma.eject_value(),
94                serial_number.eject_value(),
95                tag.eject_value(),
96            ),
97            Self::ExternalRecord(field) => console::InputID::ExternalRecord(field.eject_value()),
98        }
99    }
100}
101
102impl<A: Aleo> ToFields for InputID<A> {
103    type Field = Field<A>;
104
105    /// Returns the input as a list of field elements.
106    fn to_fields(&self) -> Vec<Self::Field> {
107        match self {
108            InputID::Constant(field) => vec![field.clone()],
109            InputID::Public(field) => vec![field.clone()],
110            InputID::Private(field) => vec![field.clone()],
111            InputID::Record(commitment, gamma, serial_number, tag) => {
112                vec![commitment.clone(), gamma.to_x_coordinate(), serial_number.clone(), tag.clone()]
113            }
114            InputID::ExternalRecord(field) => vec![field.clone()],
115        }
116    }
117}
118
119pub struct Request<A: Aleo> {
120    /// The request signer.
121    signer: Address<A>,
122    /// The network ID.
123    network_id: U16<A>,
124    /// The program ID.
125    program_id: ProgramID<A>,
126    /// The function name.
127    function_name: Identifier<A>,
128    /// The function input IDs.
129    input_ids: Vec<InputID<A>>,
130    /// The function inputs.
131    inputs: Vec<Value<A>>,
132    /// The signature for the transition.
133    signature: Signature<A>,
134    /// The tag secret key.
135    sk_tag: Field<A>,
136    /// The transition view key.
137    tvk: Field<A>,
138    /// The transition commitment.
139    tcm: Field<A>,
140    /// The signer commitment.
141    scm: Field<A>,
142}
143
144#[cfg(feature = "console")]
145impl<A: Aleo> Inject for Request<A> {
146    type Primitive = console::Request<A::Network>;
147
148    /// Initializes the request from the given mode and console request.
149    fn new(mode: Mode, request: Self::Primitive) -> Self {
150        // Inject the transition commitment `tcm` as `Mode::Public`.
151        let tcm = Field::new(Mode::Public, *request.tcm());
152
153        // Inject the signer commitment `scm` as `Mode::Public`.
154        let scm = Field::new(Mode::Public, *request.scm());
155
156        // Inject the inputs.
157        let inputs = match request
158            .input_ids()
159            .iter()
160            .zip_eq(request.inputs())
161            .map(|(input_id, input)| {
162                match input_id {
163                    // A constant input is injected as `Mode::Constant`.
164                    console::InputID::Constant(..) => {
165                        // Inject the input as `Mode::Constant`.
166                        let input = Value::new(Mode::Constant, input.clone());
167                        // Ensure the input is a plaintext.
168                        ensure!(matches!(input, Value::Plaintext(..)), "Expected a plaintext input");
169                        // Return the input.
170                        Ok(input)
171                    }
172                    // A public input is injected as `Mode::Private`.
173                    console::InputID::Public(..) => {
174                        // Inject the input as `Mode::Private`.
175                        let input = Value::new(Mode::Private, input.clone());
176                        // Ensure the input is a plaintext.
177                        ensure!(matches!(input, Value::Plaintext(..)), "Expected a plaintext input");
178                        // Return the input.
179                        Ok(input)
180                    }
181                    // A private input is injected as `Mode::Private`.
182                    console::InputID::Private(..) => {
183                        // Inject the input as `Mode::Private`.
184                        let input = Value::new(Mode::Private, input.clone());
185                        // Ensure the input is a plaintext.
186                        ensure!(matches!(input, Value::Plaintext(..)), "Expected a plaintext input");
187                        // Return the input.
188                        Ok(input)
189                    }
190                    // A record input is injected as `Mode::Private`.
191                    console::InputID::Record(..) => {
192                        // Inject the input as `Mode::Private`.
193                        let input = Value::new(Mode::Private, input.clone());
194                        // Ensure the input is a record.
195                        ensure!(matches!(input, Value::Record(..)), "Expected a record input");
196                        // Return the input.
197                        Ok(input)
198                    }
199                    // An external record input is injected as `Mode::Private`.
200                    console::InputID::ExternalRecord(..) => {
201                        // Inject the input as `Mode::Private`.
202                        let input = Value::new(Mode::Private, input.clone());
203                        // Ensure the input is a record.
204                        ensure!(matches!(input, Value::Record(..)), "Expected an external record input");
205                        // Return the input.
206                        Ok(input)
207                    }
208                }
209            })
210            .collect::<Result<Vec<_>, _>>()
211        {
212            Ok(inputs) => inputs,
213            Err(error) => A::halt(format!("{error}")),
214        };
215
216        Self {
217            signer: Address::new(mode, *request.signer()),
218            network_id: U16::new(Mode::Constant, *request.network_id()),
219            program_id: ProgramID::new(Mode::Constant, *request.program_id()),
220            function_name: Identifier::new(Mode::Constant, *request.function_name()),
221            input_ids: request.input_ids().iter().map(|input_id| InputID::new(Mode::Public, *input_id)).collect(),
222            inputs,
223            signature: Signature::new(mode, *request.signature()),
224            sk_tag: Field::new(mode, *request.sk_tag()),
225            tvk: Field::new(mode, *request.tvk()),
226            tcm,
227            scm,
228        }
229    }
230}
231
232impl<A: Aleo> Request<A> {
233    /// Returns the request signer.
234    pub const fn signer(&self) -> &Address<A> {
235        &self.signer
236    }
237
238    /// Returns the network ID.
239    pub const fn network_id(&self) -> &U16<A> {
240        &self.network_id
241    }
242
243    /// Returns the program ID.
244    pub const fn program_id(&self) -> &ProgramID<A> {
245        &self.program_id
246    }
247
248    /// Returns the function name.
249    pub const fn function_name(&self) -> &Identifier<A> {
250        &self.function_name
251    }
252
253    /// Returns the input IDs for the transition.
254    pub fn input_ids(&self) -> &[InputID<A>] {
255        &self.input_ids
256    }
257
258    /// Returns the function inputs.
259    pub fn inputs(&self) -> &[Value<A>] {
260        &self.inputs
261    }
262
263    /// Returns the signature for the transition.
264    pub const fn signature(&self) -> &Signature<A> {
265        &self.signature
266    }
267
268    /// Returns the tag secret key.
269    pub const fn sk_tag(&self) -> &Field<A> {
270        &self.sk_tag
271    }
272
273    /// Returns the transition view key.
274    pub const fn tvk(&self) -> &Field<A> {
275        &self.tvk
276    }
277
278    /// Returns the transition commitment.
279    pub const fn tcm(&self) -> &Field<A> {
280        &self.tcm
281    }
282
283    /// Returns the signer commitment.
284    pub const fn scm(&self) -> &Field<A> {
285        &self.scm
286    }
287}
288
289#[cfg(feature = "console")]
290impl<A: Aleo> Eject for Request<A> {
291    type Primitive = console::Request<A::Network>;
292
293    /// Ejects the mode of the request.
294    fn eject_mode(&self) -> Mode {
295        Mode::combine(self.signer.eject_mode(), [
296            self.network_id.eject_mode(),
297            self.program_id.eject_mode(),
298            self.function_name.eject_mode(),
299            self.input_ids.eject_mode(),
300            self.inputs.eject_mode(),
301            self.signature.eject_mode(),
302            self.sk_tag.eject_mode(),
303            self.tvk.eject_mode(),
304            self.tcm.eject_mode(),
305            self.scm.eject_mode(),
306        ])
307    }
308
309    /// Ejects the request as a primitive.
310    fn eject_value(&self) -> Self::Primitive {
311        Self::Primitive::from((
312            self.signer.eject_value(),
313            self.network_id.eject_value(),
314            self.program_id.eject_value(),
315            self.function_name.eject_value(),
316            self.input_ids.iter().map(|input_id| input_id.eject_value()).collect(),
317            self.inputs.eject_value(),
318            self.signature.eject_value(),
319            self.sk_tag.eject_value(),
320            self.tvk.eject_value(),
321            self.tcm.eject_value(),
322            self.scm.eject_value(),
323        ))
324    }
325}