Skip to main content

snarkvm_console_program/request/input_id/
mod.rs

1// Copyright (c) 2019-2026 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 serialize;
18mod string;
19
20use crate::{Identifier, Plaintext, ProgramID, Record, Value};
21use snarkvm_console_account::ViewKey;
22use snarkvm_console_network::Network;
23use snarkvm_console_types::prelude::*;
24
25#[derive(Copy, Clone, PartialEq, Eq, Hash)]
26pub enum InputID<N: Network> {
27    /// The hash of the constant input.
28    Constant(Field<N>),
29    /// The hash of the public input.
30    Public(Field<N>),
31    /// The ciphertext hash of the private input.
32    Private(Field<N>),
33    /// The commitment, gamma, record view key, serial number, and tag of the record input.
34    Record(Field<N>, Group<N>, Field<N>, Field<N>, Field<N>),
35    /// The hash of the external record's (function_id, record, tvk, input index).
36    ExternalRecord(Field<N>),
37    /// The hash of the dynamic record's (function_id, record, tvk, input index).
38    DynamicRecord(Field<N>),
39}
40
41impl<N: Network> InputID<N> {
42    /// Returns the (primary) input ID.
43    pub const fn id(&self) -> &Field<N> {
44        match self {
45            InputID::Constant(id) => id,
46            InputID::Public(id) => id,
47            InputID::Private(id) => id,
48            InputID::Record(id, ..) => id,
49            InputID::ExternalRecord(id) => id,
50            InputID::DynamicRecord(id) => id,
51        }
52    }
53
54    /// Computes the input ID for a constant input.
55    /// Constructs the preimage as `(function_id || input || tcm || index)` and hashes it.
56    pub fn constant(function_id: Field<N>, input: &Value<N>, tcm: Field<N>, index: u16) -> Result<Self> {
57        // Ensure the input is a plaintext.
58        ensure!(matches!(input, Value::Plaintext(..)), "Expected a plaintext input");
59
60        // Construct the (console) input index as a field element.
61        let index = Field::from_u16(index);
62        // Construct the preimage as `(function ID || input || tcm || index)`.
63        let mut preimage = Vec::new();
64        preimage.push(function_id);
65        preimage.extend(input.to_fields()?);
66        preimage.push(tcm);
67        preimage.push(index);
68        // Hash the input to a field element.
69        let hash = N::hash_psd8(&preimage)?;
70
71        Ok(Self::Constant(hash))
72    }
73
74    /// Computes the input ID for a public input.
75    /// Constructs the preimage as `(function_id || input || tcm || index)` and hashes it.
76    pub fn public(function_id: Field<N>, input: &Value<N>, tcm: Field<N>, index: u16) -> Result<Self> {
77        // Ensure the input is a plaintext.
78        ensure!(matches!(input, Value::Plaintext(..)), "Expected a plaintext input");
79
80        // Construct the (console) input index as a field element.
81        let index = Field::from_u16(index);
82        // Construct the preimage as `(function ID || input || tcm || index)`.
83        let mut preimage = Vec::new();
84        preimage.push(function_id);
85        preimage.extend(input.to_fields()?);
86        preimage.push(tcm);
87        preimage.push(index);
88        // Hash the input to a field element.
89        let hash = N::hash_psd8(&preimage)?;
90
91        Ok(Self::Public(hash))
92    }
93
94    /// Computes the input ID for a private input.
95    /// Encrypts the input using the input view key and hashes the ciphertext.
96    pub fn private(function_id: Field<N>, input: &Value<N>, tvk: Field<N>, index: u16) -> Result<Self> {
97        // Ensure the input is a plaintext.
98        ensure!(matches!(input, Value::Plaintext(..)), "Expected a plaintext input");
99
100        // Construct the (console) input index as a field element.
101        let index = Field::from_u16(index);
102        // Compute the input view key as `Hash(function ID || tvk || index)`.
103        let input_view_key = N::hash_psd4(&[function_id, tvk, index])?;
104        // Compute the ciphertext.
105        let ciphertext = match &input {
106            Value::Plaintext(plaintext) => plaintext.encrypt_symmetric(input_view_key)?,
107            // Ensure the input is a plaintext.
108            Value::Record(..) => bail!("Expected a plaintext input, found a record input"),
109            Value::Future(..) => bail!("Expected a plaintext input, found a future input"),
110            Value::DynamicRecord(..) => bail!("Expected a plaintext input, found a dynamic record input"),
111            Value::DynamicFuture(..) => bail!("Expected a plaintext input, found a dynamic future input"),
112        };
113        // Hash the ciphertext to a field element.
114        let hash = N::hash_psd8(&ciphertext.to_fields()?)?;
115
116        Ok(Self::Private(hash))
117    }
118
119    /// Computes the input ID for a record input.
120    /// Returns the full InputID::Record variant with commitment, gamma, record view key, serial number, and tag.
121    pub fn record(
122        program_id: &ProgramID<N>,
123        record_name: &Identifier<N>,
124        input: &Value<N>,
125        signer: &Address<N>,
126        view_key: &ViewKey<N>,
127        sk_sig: &Scalar<N>,
128        sk_tag: Field<N>,
129    ) -> Result<Self> {
130        // Retrieve the record.
131        let record = match &input {
132            Value::Record(record) => record,
133            // Ensure the input is a record.
134            Value::Plaintext(..) => bail!("Expected a record input, found a plaintext input"),
135            Value::Future(..) => bail!("Expected a record input, found a future input"),
136            Value::DynamicRecord(..) => bail!("Expected a record input, found a dynamic record input"),
137            Value::DynamicFuture(..) => bail!("Expected a record input, found a dynamic future input"),
138        };
139        // Ensure the record belongs to the signer.
140        ensure!(**record.owner() == *signer, "Input record '{program_id}/{record_name}' must belong to the signer");
141        // Compute the record view key.
142        let record_view_key = (*record.nonce() * **view_key).to_x_coordinate();
143        // Compute the record commitment.
144        let commitment = record.to_commitment(program_id, record_name, &record_view_key)?;
145
146        // Compute the generator `H` as `HashToGroup(commitment)`.
147        let h = N::hash_to_group_psd2(&[N::serial_number_domain(), commitment])?;
148        // Compute `gamma` as `sk_sig * H`.
149        let gamma = h * sk_sig;
150
151        // Compute the `serial_number` from `gamma`.
152        let serial_number = Record::<N, Plaintext<N>>::serial_number_from_gamma(&gamma, commitment)?;
153        // Compute the tag.
154        let tag = Record::<N, Plaintext<N>>::tag(sk_tag, commitment)?;
155
156        Ok(InputID::Record(commitment, gamma, record_view_key, serial_number, tag))
157    }
158
159    /// Computes the input ID for an external record input.
160    /// Constructs the preimage as `(function_id || input || tvk || index)` and hashes it.
161    pub fn external_record(function_id: Field<N>, input: &Value<N>, tvk: Field<N>, index: u16) -> Result<Self> {
162        // Ensure the input is a record.
163        ensure!(matches!(input, Value::Record(..)), "Expected a record input");
164
165        // Construct the (console) input index as a field element.
166        let index = Field::from_u16(index);
167        // Construct the preimage as `(function ID || input || tvk || index)`.
168        let mut preimage = Vec::new();
169        preimage.push(function_id);
170        preimage.extend(input.to_fields()?);
171        preimage.push(tvk);
172        preimage.push(index);
173        // Hash the input to a field element.
174        let hash = N::hash_psd8(&preimage)?;
175
176        Ok(Self::ExternalRecord(hash))
177    }
178
179    /// Computes the input ID for a dynamic record input.
180    /// Constructs the preimage as `(function_id || input || tvk || index)` and hashes it.
181    pub fn dynamic_record(function_id: Field<N>, input: &Value<N>, tvk: Field<N>, index: u16) -> Result<Self> {
182        // Ensure the input is a dynamic record.
183        ensure!(matches!(input, Value::DynamicRecord(..)), "Expected a dynamic record input");
184
185        // Construct the (console) input index as a field element.
186        let index = Field::from_u16(index);
187        // Construct the preimage as `(function ID || input || tvk || index)`.
188        let mut preimage = Vec::new();
189        preimage.push(function_id);
190        preimage.extend(input.to_fields()?);
191        preimage.push(tvk);
192        preimage.push(index);
193        // Hash the input to a field element.
194        let hash = N::hash_psd8(&preimage)?;
195
196        Ok(Self::DynamicRecord(hash))
197    }
198}