snarkvm_console_program/request/
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 input_id;
17pub use input_id::InputID;
18
19mod bytes;
20mod serialize;
21mod sign;
22mod string;
23mod verify;
24
25use crate::{Identifier, Plaintext, ProgramID, Record, Value, ValueType, compute_function_id};
26use snarkvm_console_account::{Address, ComputeKey, GraphKey, PrivateKey, Signature, ViewKey};
27use snarkvm_console_network::Network;
28use snarkvm_console_types::prelude::*;
29
30#[derive(Clone, PartialEq, Eq)]
31pub struct Request<N: Network> {
32    /// The request signer.
33    signer: Address<N>,
34    /// The network ID.
35    network_id: U16<N>,
36    /// The program ID.
37    program_id: ProgramID<N>,
38    /// The function name.
39    function_name: Identifier<N>,
40    /// The input ID for the transition.
41    input_ids: Vec<InputID<N>>,
42    /// The function inputs.
43    inputs: Vec<Value<N>>,
44    /// The signature for the transition.
45    signature: Signature<N>,
46    /// The tag secret key.
47    sk_tag: Field<N>,
48    /// The transition view key.
49    tvk: Field<N>,
50    /// The transition commitment.
51    tcm: Field<N>,
52    /// The signer commitment.
53    scm: Field<N>,
54}
55
56impl<N: Network>
57    From<(
58        Address<N>,
59        U16<N>,
60        ProgramID<N>,
61        Identifier<N>,
62        Vec<InputID<N>>,
63        Vec<Value<N>>,
64        Signature<N>,
65        Field<N>,
66        Field<N>,
67        Field<N>,
68        Field<N>,
69    )> for Request<N>
70{
71    /// Note: See `Request::sign` to create the request. This method is used to eject from a circuit.
72    fn from(
73        (signer, network_id, program_id, function_name, input_ids, inputs, signature, sk_tag, tvk, tcm, scm): (
74            Address<N>,
75            U16<N>,
76            ProgramID<N>,
77            Identifier<N>,
78            Vec<InputID<N>>,
79            Vec<Value<N>>,
80            Signature<N>,
81            Field<N>,
82            Field<N>,
83            Field<N>,
84            Field<N>,
85        ),
86    ) -> Self {
87        // Ensure the network ID is correct.
88        if *network_id != N::ID {
89            N::halt(format!("Invalid network ID. Expected {}, found {}", N::ID, *network_id))
90        } else {
91            Self { signer, network_id, program_id, function_name, input_ids, inputs, signature, sk_tag, tvk, tcm, scm }
92        }
93    }
94}
95
96impl<N: Network> Request<N> {
97    /// Returns the request signer.
98    pub const fn signer(&self) -> &Address<N> {
99        &self.signer
100    }
101
102    /// Returns the network ID.
103    pub const fn network_id(&self) -> &U16<N> {
104        &self.network_id
105    }
106
107    /// Returns the program ID.
108    pub const fn program_id(&self) -> &ProgramID<N> {
109        &self.program_id
110    }
111
112    /// Returns the function name.
113    pub const fn function_name(&self) -> &Identifier<N> {
114        &self.function_name
115    }
116
117    /// Returns the input ID for the transition.
118    pub fn input_ids(&self) -> &[InputID<N>] {
119        &self.input_ids
120    }
121
122    /// Returns the function inputs.
123    pub fn inputs(&self) -> &[Value<N>] {
124        &self.inputs
125    }
126
127    /// Returns the signature for the transition.
128    pub const fn signature(&self) -> &Signature<N> {
129        &self.signature
130    }
131
132    /// Returns the tag secret key `sk_tag`.
133    pub const fn sk_tag(&self) -> &Field<N> {
134        &self.sk_tag
135    }
136
137    /// Returns the transition view key `tvk`.
138    pub const fn tvk(&self) -> &Field<N> {
139        &self.tvk
140    }
141
142    /// Returns the transition public key `tpk`.
143    pub fn to_tpk(&self) -> Group<N> {
144        // Retrieve the challenge from the signature.
145        let challenge = self.signature.challenge();
146        // Retrieve the response from the signature.
147        let response = self.signature.response();
148        // Retrieve `pk_sig` from the signature.
149        let pk_sig = self.signature.compute_key().pk_sig();
150        // Compute `tpk` as `(challenge * pk_sig) + (response * G)`, equivalent to `r * G`.
151        (pk_sig * challenge) + N::g_scalar_multiply(&response)
152    }
153
154    /// Returns the transition commitment `tcm`.
155    pub const fn tcm(&self) -> &Field<N> {
156        &self.tcm
157    }
158
159    /// Returns the signer commitment `scm`.
160    pub const fn scm(&self) -> &Field<N> {
161        &self.scm
162    }
163}
164
165#[cfg(test)]
166mod test_helpers {
167    use super::*;
168    use snarkvm_console_network::MainnetV0;
169
170    type CurrentNetwork = MainnetV0;
171
172    const ITERATIONS: u64 = 1000;
173
174    pub(super) fn sample_requests(rng: &mut TestRng) -> Vec<Request<CurrentNetwork>> {
175        (0..ITERATIONS)
176            .map(|i| {
177                // Sample a random private key and address.
178                let private_key = PrivateKey::<CurrentNetwork>::new(rng).unwrap();
179                let address = Address::try_from(&private_key).unwrap();
180
181                // Construct a program ID and function name.
182                let program_id = ProgramID::from_str("token.aleo").unwrap();
183                let function_name = Identifier::from_str("transfer").unwrap();
184
185                // Prepare a record belonging to the address.
186                let record_string =
187                    format!("{{ owner: {address}.private, token_amount: {i}u64.private, _nonce: 2293253577170800572742339369209137467208538700597121244293392265726446806023group.public }}");
188
189                // Construct four inputs.
190                let input_constant = Value::from_str(&format!("{{ token_amount: {i}u128 }}")).unwrap();
191                let input_public = Value::from_str(&format!("{{ token_amount: {i}u128 }}")).unwrap();
192                let input_private = Value::from_str(&format!("{{ token_amount: {i}u128 }}")).unwrap();
193                let input_record = Value::from_str(&record_string).unwrap();
194                let input_external_record = Value::from_str(&record_string).unwrap();
195                let inputs = vec![input_constant, input_public, input_private, input_record, input_external_record];
196
197                // Construct the input types.
198                let input_types = [
199                    ValueType::from_str("amount.constant").unwrap(),
200                    ValueType::from_str("amount.public").unwrap(),
201                    ValueType::from_str("amount.private").unwrap(),
202                    ValueType::from_str("token.record").unwrap(),
203                    ValueType::from_str("token.aleo/token.record").unwrap(),
204                ];
205
206                // Sample root_tvk.
207                let root_tvk = None;
208                // Construct 'is_root'.
209                let is_root = Uniform::rand(rng);
210                // Sample the program checksum.
211                let program_checksum = match i % 2 == 0 {
212                    true => Some(Field::rand(rng)),
213                    false => None,
214                };
215
216                // Compute the signed request.
217                let request =
218                    Request::sign(&private_key, program_id, function_name, inputs.into_iter(), &input_types, root_tvk, is_root, program_checksum, rng).unwrap();
219                assert!(request.verify(&input_types, is_root, program_checksum));
220                request
221            })
222            .collect()
223    }
224}