snarkvm_ledger_block/transition/input/
mod.rs1mod bytes;
17mod serialize;
18mod string;
19
20use console::{
21 network::prelude::*,
22 program::{Ciphertext, Plaintext, TransitionLeaf},
23 types::Field,
24};
25
26type Variant = u8;
27
28#[derive(Clone, PartialEq, Eq)]
30pub enum Input<N: Network> {
31 Constant(Field<N>, Option<Plaintext<N>>),
33 Public(Field<N>, Option<Plaintext<N>>),
35 Private(Field<N>, Option<Ciphertext<N>>),
37 Record(Field<N>, Field<N>),
39 ExternalRecord(Field<N>),
41}
42
43impl<N: Network> Input<N> {
44 pub const fn variant(&self) -> Variant {
46 match self {
47 Input::Constant(..) => 0,
48 Input::Public(..) => 1,
49 Input::Private(..) => 2,
50 Input::Record(..) => 3, Input::ExternalRecord(..) => 4,
52 }
53 }
54
55 pub const fn id(&self) -> &Field<N> {
57 match self {
58 Input::Constant(id, ..) => id,
59 Input::Public(id, ..) => id,
60 Input::Private(id, ..) => id,
61 Input::Record(serial_number, ..) => serial_number,
62 Input::ExternalRecord(id) => id,
63 }
64 }
65
66 pub fn to_transition_leaf(&self, index: u8) -> TransitionLeaf<N> {
68 TransitionLeaf::new_with_version(index, self.variant(), *self.id())
69 }
70
71 pub const fn tag(&self) -> Option<&Field<N>> {
73 match self {
74 Input::Record(_, tag) => Some(tag),
75 _ => None,
76 }
77 }
78
79 pub fn into_tag(self) -> Option<Field<N>> {
81 match self {
82 Input::Record(_, tag) => Some(tag),
83 _ => None,
84 }
85 }
86
87 pub const fn serial_number(&self) -> Option<&Field<N>> {
89 match self {
90 Input::Record(serial_number, ..) => Some(serial_number),
91 _ => None,
92 }
93 }
94
95 pub fn into_serial_number(self) -> Option<Field<N>> {
97 match self {
98 Input::Record(serial_number, ..) => Some(serial_number),
99 _ => None,
100 }
101 }
102
103 pub fn verifier_inputs(&self) -> impl '_ + Iterator<Item = N::Field> {
105 [Some(self.id()), self.tag()].into_iter().flatten().map(|id| **id)
106 }
107
108 pub fn verify(&self, function_id: Field<N>, tcm: &Field<N>, index: usize) -> bool {
111 let result = || match self {
113 Input::Constant(hash, Some(input)) => {
114 match input.to_fields() {
115 Ok(fields) => {
116 let index = Field::from_u16(index as u16);
118 let mut preimage = Vec::new();
120 preimage.push(function_id);
121 preimage.extend(fields);
122 preimage.push(*tcm);
123 preimage.push(index);
124 match N::hash_psd8(&preimage) {
126 Ok(candidate_hash) => Ok(hash == &candidate_hash),
127 Err(error) => Err(error),
128 }
129 }
130 Err(error) => Err(error),
131 }
132 }
133 Input::Public(hash, Some(input)) => {
134 match input.to_fields() {
135 Ok(fields) => {
136 let index = Field::from_u16(index as u16);
138 let mut preimage = Vec::new();
140 preimage.push(function_id);
141 preimage.extend(fields);
142 preimage.push(*tcm);
143 preimage.push(index);
144 match N::hash_psd8(&preimage) {
146 Ok(candidate_hash) => Ok(hash == &candidate_hash),
147 Err(error) => Err(error),
148 }
149 }
150 Err(error) => Err(error),
151 }
152 }
153 Input::Private(hash, Some(value)) => {
154 match value.to_fields() {
155 Ok(fields) => match N::hash_psd8(&fields) {
157 Ok(candidate_hash) => Ok(hash == &candidate_hash),
158 Err(error) => Err(error),
159 },
160 Err(error) => Err(error),
161 }
162 }
163 Input::Constant(_, None) | Input::Public(_, None) | Input::Private(_, None) => {
164 bail!("A transition input value is missing")
167 }
168 Input::Record(_, _) | Input::ExternalRecord(_) => Ok(true),
169 };
170
171 match result() {
172 Ok(is_hash_valid) => is_hash_valid,
173 Err(error) => {
174 eprintln!("{error}");
175 false
176 }
177 }
178 }
179}
180
181#[cfg(test)]
182pub(crate) mod test_helpers {
183 use super::*;
184 use console::{network::MainnetV0, program::Literal};
185
186 type CurrentNetwork = MainnetV0;
187
188 pub(crate) fn sample_inputs() -> Vec<(<CurrentNetwork as Network>::TransitionID, Input<CurrentNetwork>)> {
190 let rng = &mut TestRng::default();
191
192 let transaction = crate::transaction::test_helpers::sample_execution_transaction_with_fee(true, rng, 0);
194 let transition = transaction.transitions().next().unwrap();
195
196 let transition_id = *transition.id();
198 let input = transition.inputs().iter().next().unwrap().clone();
199
200 let plaintext = Plaintext::Literal(Literal::Field(Uniform::rand(rng)), Default::default());
202 let plaintext_hash = CurrentNetwork::hash_bhp1024(&plaintext.to_bits_le()).unwrap();
203 let fields: Vec<_> = (0..10).map(|_| Uniform::rand(rng)).collect();
205 let ciphertext = Ciphertext::from_fields(&fields).unwrap();
206 let ciphertext_hash = CurrentNetwork::hash_bhp1024(&ciphertext.to_bits_le()).unwrap();
207
208 vec![
209 (transition_id, input),
210 (Uniform::rand(rng), Input::Constant(Uniform::rand(rng), None)),
211 (Uniform::rand(rng), Input::Constant(plaintext_hash, Some(plaintext.clone()))),
212 (Uniform::rand(rng), Input::Public(Uniform::rand(rng), None)),
213 (Uniform::rand(rng), Input::Public(plaintext_hash, Some(plaintext))),
214 (Uniform::rand(rng), Input::Private(Uniform::rand(rng), None)),
215 (Uniform::rand(rng), Input::Private(ciphertext_hash, Some(ciphertext))),
216 (Uniform::rand(rng), Input::Record(Uniform::rand(rng), Uniform::rand(rng))),
217 (Uniform::rand(rng), Input::ExternalRecord(Uniform::rand(rng))),
218 ]
219 }
220}