snarkvm_synthesizer_program/logic/instruction/operation/
hash.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::{Opcode, Operand, RegistersCircuit, RegistersTrait, StackTrait};
17use console::{
18    network::prelude::*,
19    program::{Identifier, Literal, LiteralType, Locator, Plaintext, PlaintextType, Register, RegisterType, Value},
20};
21
22use enum_iterator::Sequence;
23
24/// BHP256 is a collision-resistant hash function that processes inputs in 256-bit chunks.
25pub type HashBHP256<N> = HashInstruction<N, { HashVariant::HashBHP256 as u8 }>;
26/// BHP512 is a collision-resistant hash function that processes inputs in 512-bit chunks.
27pub type HashBHP512<N> = HashInstruction<N, { HashVariant::HashBHP512 as u8 }>;
28/// BHP768 is a collision-resistant hash function that processes inputs in 768-bit chunks.
29pub type HashBHP768<N> = HashInstruction<N, { HashVariant::HashBHP768 as u8 }>;
30/// BHP1024 is a collision-resistant hash function that processes inputs in 1024-bit chunks.
31pub type HashBHP1024<N> = HashInstruction<N, { HashVariant::HashBHP1024 as u8 }>;
32
33/// BHP256Raw is a collision-resistant hash function that processes the input's raw bits in 256-bit chunks.
34pub type HashBHP256Raw<N> = HashInstruction<N, { HashVariant::HashBHP256Raw as u8 }>;
35/// BHP512Raw is a collision-resistant hash function that processes the input's raw bits in 512-bit chunks.
36pub type HashBHP512Raw<N> = HashInstruction<N, { HashVariant::HashBHP512Raw as u8 }>;
37/// BHP768Raw is a collision-resistant hash function that processes the input's raw bits in 768-bit chunks.
38pub type HashBHP768Raw<N> = HashInstruction<N, { HashVariant::HashBHP768Raw as u8 }>;
39/// BHP1024Raw is a collision-resistant hash function that processes the input's raw bits in 1024-bit chunks.
40pub type HashBHP1024Raw<N> = HashInstruction<N, { HashVariant::HashBHP1024Raw as u8 }>;
41
42/// Keccak256 is a cryptographic hash function that outputs a 256-bit digest.
43pub type HashKeccak256<N> = HashInstruction<N, { HashVariant::HashKeccak256 as u8 }>;
44/// Keccak384 is a cryptographic hash function that outputs a 384-bit digest.
45pub type HashKeccak384<N> = HashInstruction<N, { HashVariant::HashKeccak384 as u8 }>;
46/// Keccak512 is a cryptographic hash function that outputs a 512-bit digest.
47pub type HashKeccak512<N> = HashInstruction<N, { HashVariant::HashKeccak512 as u8 }>;
48
49/// Keccak256Raw is a cryptographic hash function that outputs a 256-bit digest using the input's raw bits.
50pub type HashKeccak256Raw<N> = HashInstruction<N, { HashVariant::HashKeccak256Raw as u8 }>;
51/// Keccak384Raw is a cryptographic hash function that outputs a 384-bit digest using the input's raw bits.
52pub type HashKeccak384Raw<N> = HashInstruction<N, { HashVariant::HashKeccak384Raw as u8 }>;
53/// Keccak512Raw is a cryptographic hash function that outputs a 512-bit digest using the input's raw bits.
54pub type HashKeccak512Raw<N> = HashInstruction<N, { HashVariant::HashKeccak512Raw as u8 }>;
55
56/// Keccak256Native is a cryptographic hash function that outputs a 256-bit digest as a bit array.
57pub type HashKeccak256Native<N> = HashInstruction<N, { HashVariant::HashKeccak256Native as u8 }>;
58/// Keccak384Native is a cryptographic hash function that outputs a 384-bit digest as a bit array.
59pub type HashKeccak384Native<N> = HashInstruction<N, { HashVariant::HashKeccak384Native as u8 }>;
60/// Keccak512Native is a cryptographic hash function that outputs a 512-bit digest as a bit array.
61pub type HashKeccak512Native<N> = HashInstruction<N, { HashVariant::HashKeccak512Native as u8 }>;
62
63/// Keccak256NativeRaw is a cryptographic hash function that outputs a 256-bit digest as a bit array using the input's raw bits.
64pub type HashKeccak256NativeRaw<N> = HashInstruction<N, { HashVariant::HashKeccak256NativeRaw as u8 }>;
65/// Keccak384NativeRaw is a cryptographic hash function that outputs a 384-bit digest as a bit array using the input's raw bits.
66pub type HashKeccak384NativeRaw<N> = HashInstruction<N, { HashVariant::HashKeccak384NativeRaw as u8 }>;
67/// Keccak512NativeRaw is a cryptographic hash function that outputs a 512-bit digest as a bit array using the input's raw bits.
68pub type HashKeccak512NativeRaw<N> = HashInstruction<N, { HashVariant::HashKeccak512NativeRaw as u8 }>;
69
70/// Pedersen64 is a collision-resistant hash function that processes inputs in 64-bit chunks.
71pub type HashPED64<N> = HashInstruction<N, { HashVariant::HashPED64 as u8 }>;
72/// Pedersen128 is a collision-resistant hash function that processes inputs in 128-bit chunks.
73pub type HashPED128<N> = HashInstruction<N, { HashVariant::HashPED128 as u8 }>;
74
75/// Pedersen64Raw is a collision-resistant hash function that processes the input's raw bits in 64-bit chunks.
76pub type HashPED64Raw<N> = HashInstruction<N, { HashVariant::HashPED64Raw as u8 }>;
77/// Pedersen128Raw is a collision-resistant hash function that processes the input's raw bits in 128-bit chunks.
78pub type HashPED128Raw<N> = HashInstruction<N, { HashVariant::HashPED128Raw as u8 }>;
79
80/// Poseidon2 is a cryptographic hash function that processes inputs in 2-field chunks.
81pub type HashPSD2<N> = HashInstruction<N, { HashVariant::HashPSD2 as u8 }>;
82/// Poseidon4 is a cryptographic hash function that processes inputs in 4-field chunks.
83pub type HashPSD4<N> = HashInstruction<N, { HashVariant::HashPSD4 as u8 }>;
84/// Poseidon8 is a cryptographic hash function that processes inputs in 8-field chunks.
85pub type HashPSD8<N> = HashInstruction<N, { HashVariant::HashPSD8 as u8 }>;
86
87/// Poseidon2Raw is a cryptographic hash function that processes the input's raw fields in 2-field chunks.
88pub type HashPSD2Raw<N> = HashInstruction<N, { HashVariant::HashPSD2Raw as u8 }>;
89/// Poseidon4Raw is a cryptographic hash function that processes the input's raw fields in 4-field chunks.
90pub type HashPSD4Raw<N> = HashInstruction<N, { HashVariant::HashPSD4Raw as u8 }>;
91/// Poseidon8Raw is a cryptographic hash function that processes the input's raw fields in 8-field chunks.
92pub type HashPSD8Raw<N> = HashInstruction<N, { HashVariant::HashPSD8Raw as u8 }>;
93
94/// SHA3-256 is a cryptographic hash function that outputs a 256-bit digest.
95pub type HashSha3_256<N> = HashInstruction<N, { HashVariant::HashSha3_256 as u8 }>;
96/// SHA3-384 is a cryptographic hash function that outputs a 384-bit digest.
97pub type HashSha3_384<N> = HashInstruction<N, { HashVariant::HashSha3_384 as u8 }>;
98/// SHA3-512 is a cryptographic hash function that outputs a 512-bit digest.
99pub type HashSha3_512<N> = HashInstruction<N, { HashVariant::HashSha3_512 as u8 }>;
100
101/// SHA3-256Raw is a cryptographic hash function that outputs a 256-bit digest using the input's raw bits.
102pub type HashSha3_256Raw<N> = HashInstruction<N, { HashVariant::HashSha3_256Raw as u8 }>;
103/// SHA3-384Raw is a cryptographic hash function that outputs a 384-bit digest using the input's raw bits.
104pub type HashSha3_384Raw<N> = HashInstruction<N, { HashVariant::HashSha3_384Raw as u8 }>;
105/// SHA3-512Raw is a cryptographic hash function that outputs a 512-bit digest using the input's raw bits.
106pub type HashSha3_512Raw<N> = HashInstruction<N, { HashVariant::HashSha3_512Raw as u8 }>;
107
108/// SHA3-256Native is a cryptographic hash function that outputs a 256-bit digest as a bit array.
109pub type HashSha3_256Native<N> = HashInstruction<N, { HashVariant::HashSha3_256Native as u8 }>;
110/// SHA3-384Native is a cryptographic hash function that outputs a 384-bit digest as a bit array.
111pub type HashSha3_384Native<N> = HashInstruction<N, { HashVariant::HashSha3_384Native as u8 }>;
112/// SHA3-512Native is a cryptographic hash function that outputs a 512-bit digest as a bit array.
113pub type HashSha3_512Native<N> = HashInstruction<N, { HashVariant::HashSha3_512Native as u8 }>;
114
115/// SHA3-256NativeRaw is a cryptographic hash function that outputs a 256-bit digest as a bit array using the input's raw bits.
116pub type HashSha3_256NativeRaw<N> = HashInstruction<N, { HashVariant::HashSha3_256NativeRaw as u8 }>;
117/// SHA3-384NativeRaw is a cryptographic hash function that outputs a 384-bit digest as a bit array using the input's raw bits.
118pub type HashSha3_384NativeRaw<N> = HashInstruction<N, { HashVariant::HashSha3_384NativeRaw as u8 }>;
119/// SHA3-512NativeRaw is a cryptographic hash function that outputs a 512-bit digest as a bit array using the input's raw bits.
120pub type HashSha3_512NativeRaw<N> = HashInstruction<N, { HashVariant::HashSha3_512NativeRaw as u8 }>;
121
122/// Poseidon2 is a cryptographic hash function that processes inputs in 2-field chunks.
123pub type HashManyPSD2<N> = HashInstruction<N, { HashVariant::HashManyPSD2 as u8 }>;
124/// Poseidon4 is a cryptographic hash function that processes inputs in 4-field chunks.
125pub type HashManyPSD4<N> = HashInstruction<N, { HashVariant::HashManyPSD4 as u8 }>;
126/// Poseidon8 is a cryptographic hash function that processes inputs in 8-field chunks.
127pub type HashManyPSD8<N> = HashInstruction<N, { HashVariant::HashManyPSD8 as u8 }>;
128
129/// Which hash function to use.
130#[derive(Debug, Copy, Clone, Eq, PartialEq, Sequence)]
131pub enum HashVariant {
132    HashBHP256,
133    HashBHP512,
134    HashBHP768,
135    HashBHP1024,
136    HashKeccak256,
137    HashKeccak384,
138    HashKeccak512,
139    HashPED64,
140    HashPED128,
141    HashPSD2,
142    HashPSD4,
143    HashPSD8,
144    HashSha3_256,
145    HashSha3_384,
146    HashSha3_512,
147    HashManyPSD2,
148    HashManyPSD4,
149    HashManyPSD8,
150    // The variants that hash the raw inputs.
151    HashBHP256Raw,
152    HashBHP512Raw,
153    HashBHP768Raw,
154    HashBHP1024Raw,
155    HashKeccak256Raw,
156    HashKeccak384Raw,
157    HashKeccak512Raw,
158    HashPED64Raw,
159    HashPED128Raw,
160    HashPSD2Raw,
161    HashPSD4Raw,
162    HashPSD8Raw,
163    HashSha3_256Raw,
164    HashSha3_384Raw,
165    HashSha3_512Raw,
166    // The variants that perform the underlying hash, returning bit arrays.
167    HashKeccak256Native,
168    HashKeccak256NativeRaw,
169    HashKeccak384Native,
170    HashKeccak384NativeRaw,
171    HashKeccak512Native,
172    HashKeccak512NativeRaw,
173    HashSha3_256Native,
174    HashSha3_256NativeRaw,
175    HashSha3_384Native,
176    HashSha3_384NativeRaw,
177    HashSha3_512Native,
178    HashSha3_512NativeRaw,
179}
180
181impl HashVariant {
182    // Initializes a new `HashVariant`.
183    pub const fn new(variant: u8) -> Self {
184        match variant {
185            0 => Self::HashBHP256,
186            1 => Self::HashBHP512,
187            2 => Self::HashBHP768,
188            3 => Self::HashBHP1024,
189            4 => Self::HashKeccak256,
190            5 => Self::HashKeccak384,
191            6 => Self::HashKeccak512,
192            7 => Self::HashPED64,
193            8 => Self::HashPED128,
194            9 => Self::HashPSD2,
195            10 => Self::HashPSD4,
196            11 => Self::HashPSD8,
197            12 => Self::HashSha3_256,
198            13 => Self::HashSha3_384,
199            14 => Self::HashSha3_512,
200            15 => Self::HashManyPSD2,
201            16 => Self::HashManyPSD4,
202            17 => Self::HashManyPSD8,
203            // The variants that hash the raw inputs.
204            18 => Self::HashBHP256Raw,
205            19 => Self::HashBHP512Raw,
206            20 => Self::HashBHP768Raw,
207            21 => Self::HashBHP1024Raw,
208            22 => Self::HashKeccak256Raw,
209            23 => Self::HashKeccak384Raw,
210            24 => Self::HashKeccak512Raw,
211            25 => Self::HashPED64Raw,
212            26 => Self::HashPED128Raw,
213            27 => Self::HashPSD2Raw,
214            28 => Self::HashPSD4Raw,
215            29 => Self::HashPSD8Raw,
216            30 => Self::HashSha3_256Raw,
217            31 => Self::HashSha3_384Raw,
218            32 => Self::HashSha3_512Raw,
219            // The variants that perform the underlying hash, returning bit arrays.
220            33 => Self::HashKeccak256Native,
221            34 => Self::HashKeccak256NativeRaw,
222            35 => Self::HashKeccak384Native,
223            36 => Self::HashKeccak384NativeRaw,
224            37 => Self::HashKeccak512Native,
225            38 => Self::HashKeccak512NativeRaw,
226            39 => Self::HashSha3_256Native,
227            40 => Self::HashSha3_256NativeRaw,
228            41 => Self::HashSha3_384Native,
229            42 => Self::HashSha3_384NativeRaw,
230            43 => Self::HashSha3_512Native,
231            44 => Self::HashSha3_512NativeRaw,
232            _ => panic!("Invalid 'hash' instruction opcode"),
233        }
234    }
235
236    // Returns the opcode associated with the variant.
237    pub const fn opcode(&self) -> &'static str {
238        match self {
239            Self::HashBHP256 => "hash.bhp256",
240            Self::HashBHP512 => "hash.bhp512",
241            Self::HashBHP768 => "hash.bhp768",
242            Self::HashBHP1024 => "hash.bhp1024",
243            Self::HashKeccak256 => "hash.keccak256",
244            Self::HashKeccak384 => "hash.keccak384",
245            Self::HashKeccak512 => "hash.keccak512",
246            Self::HashPED64 => "hash.ped64",
247            Self::HashPED128 => "hash.ped128",
248            Self::HashPSD2 => "hash.psd2",
249            Self::HashPSD4 => "hash.psd4",
250            Self::HashPSD8 => "hash.psd8",
251            Self::HashSha3_256 => "hash.sha3_256",
252            Self::HashSha3_384 => "hash.sha3_384",
253            Self::HashSha3_512 => "hash.sha3_512",
254            Self::HashManyPSD2 => "hash_many.psd2",
255            Self::HashManyPSD4 => "hash_many.psd4",
256            Self::HashManyPSD8 => "hash_many.psd8",
257            // The variants that hash the raw inputs.
258            Self::HashBHP256Raw => "hash.bhp256.raw",
259            Self::HashBHP512Raw => "hash.bhp512.raw",
260            Self::HashBHP768Raw => "hash.bhp768.raw",
261            Self::HashBHP1024Raw => "hash.bhp1024.raw",
262            Self::HashKeccak256Raw => "hash.keccak256.raw",
263            Self::HashKeccak384Raw => "hash.keccak384.raw",
264            Self::HashKeccak512Raw => "hash.keccak512.raw",
265            Self::HashPED64Raw => "hash.ped64.raw",
266            Self::HashPED128Raw => "hash.ped128.raw",
267            Self::HashPSD2Raw => "hash.psd2.raw",
268            Self::HashPSD4Raw => "hash.psd4.raw",
269            Self::HashPSD8Raw => "hash.psd8.raw",
270            Self::HashSha3_256Raw => "hash.sha3_256.raw",
271            Self::HashSha3_384Raw => "hash.sha3_384.raw",
272            Self::HashSha3_512Raw => "hash.sha3_512.raw",
273            // The variants that perform the underlying hash returning bit arrays.
274            Self::HashKeccak256Native => "hash.keccak256.native",
275            Self::HashKeccak256NativeRaw => "hash.keccak256.native.raw",
276            Self::HashKeccak384Native => "hash.keccak384.native",
277            Self::HashKeccak384NativeRaw => "hash.keccak384.native.raw",
278            Self::HashKeccak512Native => "hash.keccak512.native",
279            Self::HashKeccak512NativeRaw => "hash.keccak512.native.raw",
280            Self::HashSha3_256Native => "hash.sha3_256.native",
281            Self::HashSha3_256NativeRaw => "hash.sha3_256.native.raw",
282            Self::HashSha3_384Native => "hash.sha3_384.native",
283            Self::HashSha3_384NativeRaw => "hash.sha3_384.native.raw",
284            Self::HashSha3_512Native => "hash.sha3_512.native",
285            Self::HashSha3_512NativeRaw => "hash.sha3_512.native.raw",
286        }
287    }
288
289    // Returns true if the variant requires byte alignment.
290    pub const fn requires_byte_alignment(&self) -> bool {
291        match self {
292            Self::HashBHP256
293            | Self::HashBHP512
294            | Self::HashBHP768
295            | Self::HashBHP1024
296            | Self::HashKeccak256
297            | Self::HashKeccak384
298            | Self::HashKeccak512
299            | Self::HashPED64
300            | Self::HashPED128
301            | Self::HashPSD2
302            | Self::HashPSD4
303            | Self::HashPSD8
304            | Self::HashSha3_256
305            | Self::HashSha3_384
306            | Self::HashSha3_512
307            | Self::HashManyPSD2
308            | Self::HashManyPSD4
309            | Self::HashManyPSD8 => false,
310            // The variants that hash the raw inputs.
311            Self::HashBHP256Raw | Self::HashBHP512Raw | Self::HashBHP768Raw | Self::HashBHP1024Raw => false,
312            Self::HashKeccak256Raw | Self::HashKeccak384Raw | Self::HashKeccak512Raw => true,
313            Self::HashPED64Raw | Self::HashPED128Raw | Self::HashPSD2Raw | Self::HashPSD4Raw | Self::HashPSD8Raw => {
314                false
315            }
316            Self::HashSha3_256Raw | Self::HashSha3_384Raw | Self::HashSha3_512Raw => true,
317            // The variants that perform the underlying hash returning bit arrays.
318            Self::HashKeccak256Native
319            | Self::HashKeccak256NativeRaw
320            | Self::HashKeccak384Native
321            | Self::HashKeccak384NativeRaw
322            | Self::HashKeccak512Native
323            | Self::HashKeccak512NativeRaw
324            | Self::HashSha3_256Native
325            | Self::HashSha3_256NativeRaw
326            | Self::HashSha3_384Native
327            | Self::HashSha3_384NativeRaw
328            | Self::HashSha3_512Native
329            | Self::HashSha3_512NativeRaw => true,
330        }
331    }
332
333    // Returns `true` if the variant uses raw bits.
334    pub const fn is_raw(&self) -> bool {
335        match self {
336            Self::HashBHP256
337            | Self::HashBHP512
338            | Self::HashBHP768
339            | Self::HashBHP1024
340            | Self::HashKeccak256
341            | Self::HashKeccak384
342            | Self::HashKeccak512
343            | Self::HashPED64
344            | Self::HashPED128
345            | Self::HashPSD2
346            | Self::HashPSD4
347            | Self::HashPSD8
348            | Self::HashSha3_256
349            | Self::HashSha3_384
350            | Self::HashSha3_512
351            | Self::HashManyPSD2
352            | Self::HashManyPSD4
353            | Self::HashManyPSD8 => false,
354            // The variants that hash the raw inputs.
355            Self::HashBHP256Raw
356            | Self::HashBHP512Raw
357            | Self::HashBHP768Raw
358            | Self::HashBHP1024Raw
359            | Self::HashKeccak256Raw
360            | Self::HashKeccak384Raw
361            | Self::HashKeccak512Raw
362            | Self::HashPED64Raw
363            | Self::HashPED128Raw
364            | Self::HashPSD2Raw
365            | Self::HashPSD4Raw
366            | Self::HashPSD8Raw
367            | Self::HashSha3_256Raw
368            | Self::HashSha3_384Raw
369            | Self::HashSha3_512Raw => true,
370            // The variants that perform the underlying hash returning bit arrays.
371            Self::HashKeccak256Native
372            | Self::HashKeccak256NativeRaw
373            | Self::HashKeccak384Native
374            | Self::HashKeccak384NativeRaw
375            | Self::HashKeccak512Native
376            | Self::HashKeccak512NativeRaw
377            | Self::HashSha3_256Native
378            | Self::HashSha3_256NativeRaw
379            | Self::HashSha3_384Native
380            | Self::HashSha3_384NativeRaw
381            | Self::HashSha3_512Native
382            | Self::HashSha3_512NativeRaw => true,
383        }
384    }
385
386    /// Returns the expected number of operands given the variant.
387    pub const fn expected_num_operands(&self) -> usize {
388        match self {
389            Self::HashManyPSD2 | Self::HashManyPSD4 | Self::HashManyPSD8 => 2,
390            _ => 1,
391        }
392    }
393}
394
395/// Returns 'Ok(())' if the number of operands is correct.
396/// Otherwise, returns an error.
397fn check_number_of_operands(variant: u8, opcode: Opcode, num_operands: usize) -> Result<()> {
398    let variant = HashVariant::new(variant);
399    let expected = variant.expected_num_operands();
400    if expected != num_operands {
401        bail!("Instruction '{opcode}' expects {expected} operands, found {num_operands} operands")
402    }
403    Ok(())
404}
405
406/// Returns 'true' if the destination type is valid.
407fn is_valid_destination_type<N: Network>(variant: u8, destination_type: &PlaintextType<N>) -> bool {
408    match variant {
409        0..=32 => !matches!(
410            destination_type,
411            PlaintextType::Literal(LiteralType::Boolean)
412                | PlaintextType::Literal(LiteralType::String)
413                | PlaintextType::Struct(..)
414                | PlaintextType::Array(..)
415        ),
416        33..=44 => matches!(destination_type, PlaintextType::Array(array_type) if array_type.is_bit_array()),
417        _ => panic!("Invalid 'hash' instruction opcode"),
418    }
419}
420
421/// Hashes the operand into the declared type.
422#[derive(Clone, PartialEq, Eq, Hash)]
423pub struct HashInstruction<N: Network, const VARIANT: u8> {
424    /// The operand as `input`.
425    operands: Vec<Operand<N>>,
426    /// The destination register.
427    destination: Register<N>,
428    /// The destination register type.
429    destination_type: PlaintextType<N>,
430}
431
432impl<N: Network, const VARIANT: u8> HashInstruction<N, VARIANT> {
433    /// Initializes a new `hash` instruction.
434    pub fn new(
435        operands: Vec<Operand<N>>,
436        destination: Register<N>,
437        destination_type: PlaintextType<N>,
438    ) -> Result<Self> {
439        // Sanity check the number of operands.
440        check_number_of_operands(VARIANT, Self::opcode(), operands.len())?;
441        // Sanity check the destination type.
442        if !is_valid_destination_type(VARIANT, &destination_type) {
443            bail!("Invalid destination type for 'hash' instruction")
444        }
445        // Return the instruction.
446        Ok(Self { operands, destination, destination_type })
447    }
448
449    /// Returns the opcode.
450    pub const fn opcode() -> Opcode {
451        Opcode::Hash(HashVariant::new(VARIANT).opcode())
452    }
453
454    /// Returns the operands in the operation.
455    pub fn operands(&self) -> &[Operand<N>] {
456        // Sanity check that the operands is the correct length.
457        debug_assert!(
458            check_number_of_operands(VARIANT, Self::opcode(), self.operands.len()).is_ok(),
459            "Invalid number of operands for '{}'",
460            Self::opcode()
461        );
462        // Return the operand.
463        &self.operands
464    }
465
466    /// Returns the destination register.
467    #[inline]
468    pub fn destinations(&self) -> Vec<Register<N>> {
469        vec![self.destination.clone()]
470    }
471
472    /// Returns the destination register type.
473    #[inline]
474    pub const fn destination_type(&self) -> &PlaintextType<N> {
475        &self.destination_type
476    }
477}
478
479// This code is nearly identical in `execute` and `evaluate`; we
480// extract it here in a macro.
481//
482// The `$q` parameter allows us to wrap a value in `Result::Ok`, since
483// the `Aleo` functions don't return a `Result` but the `Network` ones do.
484#[rustfmt::skip]
485macro_rules! do_hash {
486    ($N: ident, $variant: expr, $destination_type: expr, $input: expr, $pt: ty, $lt: ty, $q: expr) => {{
487        let bits = || $input.to_bits_le();
488        let bits_raw = || $input.to_bits_raw_le();
489
490        let fields = || $q($input.to_fields());
491        let fields_raw = || $q($input.to_fields_raw());
492
493        let check_multiple_of_8 = |bits: Vec<_>| -> Result<Vec<_>> {
494            ensure!(bits.len() % 8 == 0, "The opcode '{}' expects input whose size in bits is a multiple of 8.", $variant.opcode());
495            Ok(bits)
496        };
497
498        match ($variant, $destination_type) {
499            (HashVariant::HashBHP256,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp256(&bits()))?).cast_lossy(*literal_type)?),
500            (HashVariant::HashBHP512,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&bits()))?).cast_lossy(*literal_type)?),
501            (HashVariant::HashBHP768,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp768(&bits()))?).cast_lossy(*literal_type)?),
502            (HashVariant::HashBHP1024,   PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp1024(&bits()))?).cast_lossy(*literal_type)?),
503            (HashVariant::HashKeccak256, PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp256(&$q($N::hash_keccak256(&bits()))?))?).cast_lossy(*literal_type)?),
504            (HashVariant::HashKeccak384, PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&$q($N::hash_keccak384(&bits()))?))?).cast_lossy(*literal_type)?),
505            (HashVariant::HashKeccak512, PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&$q($N::hash_keccak512(&bits()))?))?).cast_lossy(*literal_type)?),
506            (HashVariant::HashPED64,     PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_ped64(&bits()))?).cast_lossy(*literal_type)?),
507            (HashVariant::HashPED128,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_ped128(&bits()))?).cast_lossy(*literal_type)?),
508            (HashVariant::HashPSD2,      PlaintextType::Literal(literal_type @ LiteralType::Address) | PlaintextType::Literal(literal_type @ LiteralType::Group)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_psd2(&fields()?))?).cast_lossy(*literal_type)?),
509            (HashVariant::HashPSD2,      PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_psd2(&fields()?))?).cast_lossy(*literal_type)?),
510            (HashVariant::HashPSD4,      PlaintextType::Literal(literal_type @ LiteralType::Address) | PlaintextType::Literal(literal_type @ LiteralType::Group)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_psd4(&fields()?))?).cast_lossy(*literal_type)?),
511            (HashVariant::HashPSD4,      PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_psd4(&fields()?))?).cast_lossy(*literal_type)?),
512            (HashVariant::HashPSD8,      PlaintextType::Literal(literal_type @ LiteralType::Address) | PlaintextType::Literal(literal_type @ LiteralType::Group)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_psd8(&fields()?))?).cast_lossy(*literal_type)?),
513            (HashVariant::HashPSD8,      PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_psd8(&fields()?))?).cast_lossy(*literal_type)?),
514            (HashVariant::HashSha3_256,  PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp256(&$q($N::hash_sha3_256(&bits()))?))?).cast_lossy(*literal_type)?),
515            (HashVariant::HashSha3_384,  PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&$q($N::hash_sha3_384(&bits()))?))?).cast_lossy(*literal_type)?),
516            (HashVariant::HashSha3_512,  PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&$q($N::hash_sha3_512(&bits()))?))?).cast_lossy(*literal_type)?),
517            (HashVariant::HashManyPSD2,  PlaintextType::Literal(_)) => bail!("'hash_many.psd2' is not yet implemented"),
518            (HashVariant::HashManyPSD4,  PlaintextType::Literal(_)) => bail!("'hash_many.psd4' is not yet implemented"),
519            (HashVariant::HashManyPSD8,  PlaintextType::Literal(_)) => bail!("'hash_many.psd8' is not yet implemented"),
520
521            // The variants that hash the raw inputs.
522            (HashVariant::HashBHP256Raw,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp256(&bits_raw()))?).cast_lossy(*literal_type)?),
523            (HashVariant::HashBHP512Raw,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&bits_raw()))?).cast_lossy(*literal_type)?),
524            (HashVariant::HashBHP768Raw,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp768(&bits_raw()))?).cast_lossy(*literal_type)?),
525            (HashVariant::HashBHP1024Raw,   PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp1024(&bits_raw()))?).cast_lossy(*literal_type)?),
526            (HashVariant::HashKeccak256Raw, PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp256(&$q($N::hash_keccak256(&check_multiple_of_8(bits_raw())?))?))?).cast_lossy(*literal_type)?),
527            (HashVariant::HashKeccak384Raw, PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&$q($N::hash_keccak384(&check_multiple_of_8(bits_raw())?))?))?).cast_lossy(*literal_type)?),
528            (HashVariant::HashKeccak512Raw, PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&$q($N::hash_keccak512(&check_multiple_of_8(bits_raw())?))?))?).cast_lossy(*literal_type)?),
529            (HashVariant::HashPED64Raw,     PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_ped64(&bits_raw()))?).cast_lossy(*literal_type)?),
530            (HashVariant::HashPED128Raw,    PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_ped128(&bits_raw()))?).cast_lossy(*literal_type)?),
531            (HashVariant::HashPSD2Raw,      PlaintextType::Literal(literal_type @ LiteralType::Address) | PlaintextType::Literal(literal_type @ LiteralType::Group)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_psd2(&fields_raw()?))?).cast_lossy(*literal_type)?),
532            (HashVariant::HashPSD2Raw,      PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_psd2(&fields_raw()?))?).cast_lossy(*literal_type)?),
533            (HashVariant::HashPSD4Raw,      PlaintextType::Literal(literal_type @ LiteralType::Address) | PlaintextType::Literal(literal_type @ LiteralType::Group)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_psd4(&fields_raw()?))?).cast_lossy(*literal_type)?),
534            (HashVariant::HashPSD4Raw,      PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_psd4(&fields_raw()?))?).cast_lossy(*literal_type)?),
535            (HashVariant::HashPSD8Raw,      PlaintextType::Literal(literal_type @ LiteralType::Address) | PlaintextType::Literal(literal_type @ LiteralType::Group)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_psd8(&fields_raw()?))?).cast_lossy(*literal_type)?),
536            (HashVariant::HashPSD8Raw,      PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_psd8(&fields_raw()?))?).cast_lossy(*literal_type)?),
537            (HashVariant::HashSha3_256Raw,  PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp256(&$q($N::hash_sha3_256(&check_multiple_of_8(bits_raw())?))?))?).cast_lossy(*literal_type)?),
538            (HashVariant::HashSha3_384Raw,  PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&$q($N::hash_sha3_384(&check_multiple_of_8(bits_raw())?))?))?).cast_lossy(*literal_type)?),
539            (HashVariant::HashSha3_512Raw,  PlaintextType::Literal(literal_type)) => <$pt>::from(<$lt>::from($q($N::hash_to_group_bhp512(&$q($N::hash_sha3_512(&check_multiple_of_8(bits_raw())?))?))?).cast_lossy(*literal_type)?),
540
541            // The variants that perform the underlying hash, returning bit arrays.
542            (HashVariant::HashKeccak256Native,    PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_keccak256(&bits()))?, **array_type.length())?,
543            (HashVariant::HashKeccak256NativeRaw, PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_keccak256(&check_multiple_of_8(bits_raw())?))?, **array_type.length())?,
544            (HashVariant::HashKeccak384Native,    PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_keccak384(&bits()))?, **array_type.length())?,
545            (HashVariant::HashKeccak384NativeRaw, PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_keccak384(&check_multiple_of_8(bits_raw())?))?, **array_type.length())?,
546            (HashVariant::HashKeccak512Native,    PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_keccak512(&bits()))?, **array_type.length())?,
547            (HashVariant::HashKeccak512NativeRaw, PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_keccak512(&check_multiple_of_8(bits_raw())?))?, **array_type.length())?,
548            (HashVariant::HashSha3_256Native,     PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_sha3_256(&bits()))?, **array_type.length())?,
549            (HashVariant::HashSha3_256NativeRaw,  PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_sha3_256(&check_multiple_of_8(bits_raw())?))?, **array_type.length())?,
550            (HashVariant::HashSha3_384Native,     PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_sha3_384(&bits()))?, **array_type.length())?,
551            (HashVariant::HashSha3_384NativeRaw,  PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_sha3_384(&check_multiple_of_8(bits_raw())?))?, **array_type.length())?,
552            (HashVariant::HashSha3_512Native,     PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_sha3_512(&bits()))?, **array_type.length())?,
553            (HashVariant::HashSha3_512NativeRaw,  PlaintextType::Array(array_type)) => <$pt>::from_bit_array($q($N::hash_sha3_512(&check_multiple_of_8(bits_raw())?))?, **array_type.length())?,
554            (_, destination_type) => bail!("Invalid destination type '{destination_type}' for 'hash' variant: {}", $variant.opcode()),
555        }
556    }};
557}
558
559/// Evaluate a hash operation.
560///
561/// This allows running the hash without the machinery of stacks and registers.
562/// This is necessary for the Leo interpreter.
563pub fn evaluate_hash<N: Network>(
564    variant: HashVariant,
565    input: &Value<N>,
566    destination_type: &PlaintextType<N>,
567) -> Result<Plaintext<N>> {
568    evaluate_hash_internal(variant, input, destination_type)
569}
570
571fn evaluate_hash_internal<N: Network>(
572    variant: HashVariant,
573    input: &Value<N>,
574    destination_type: &PlaintextType<N>,
575) -> Result<Plaintext<N>> {
576    Ok(do_hash!(N, variant, destination_type, input, Plaintext::<N>, Literal::<N>, |x| x))
577}
578
579impl<N: Network, const VARIANT: u8> HashInstruction<N, VARIANT> {
580    /// Evaluates the instruction.
581    pub fn evaluate(&self, stack: &impl StackTrait<N>, registers: &mut impl RegistersTrait<N>) -> Result<()> {
582        // Ensure the number of operands is correct.
583        check_number_of_operands(VARIANT, Self::opcode(), self.operands.len())?;
584        // Ensure the destination type is valid.
585        ensure!(
586            is_valid_destination_type(VARIANT, &self.destination_type),
587            "Invalid destination type in 'hash' instruction"
588        );
589
590        // Load the operand.
591        let input = registers.load(stack, &self.operands[0])?;
592
593        // Compute the output.
594        let output = evaluate_hash_internal(HashVariant::new(VARIANT), &input, &self.destination_type)?;
595
596        // Store the output.
597        registers.store(stack, &self.destination, Value::Plaintext(output))
598    }
599
600    /// Executes the instruction.
601    pub fn execute<A: circuit::Aleo<Network = N>>(
602        &self,
603        stack: &impl StackTrait<N>,
604        registers: &mut impl RegistersCircuit<N, A>,
605    ) -> Result<()> {
606        use circuit::traits::{ToBits, ToBitsRaw, ToFields, ToFieldsRaw};
607
608        // Ensure the number of operands is correct.
609        check_number_of_operands(VARIANT, Self::opcode(), self.operands.len())?;
610        // Ensure the destination type is valid.
611        ensure!(
612            is_valid_destination_type(VARIANT, &self.destination_type),
613            "Invalid destination type in 'hash' instruction"
614        );
615
616        // Load the operand.
617        let input = registers.load_circuit(stack, &self.operands[0])?;
618
619        // Compute the output.
620        let output = do_hash!(
621            A,
622            HashVariant::new(VARIANT),
623            &self.destination_type,
624            input,
625            circuit::Plaintext::<A>,
626            circuit::Literal::<A>,
627            Result::<_>::Ok
628        );
629
630        // Store the output.
631        registers.store_circuit(stack, &self.destination, circuit::Value::Plaintext(output))
632    }
633
634    /// Finalizes the instruction.
635    #[inline]
636    pub fn finalize(&self, stack: &impl StackTrait<N>, registers: &mut impl RegistersTrait<N>) -> Result<()> {
637        self.evaluate(stack, registers)
638    }
639
640    /// Returns the output type from the given program and input types.
641    pub fn output_types(
642        &self,
643        stack: &impl StackTrait<N>,
644        input_types: &[RegisterType<N>],
645    ) -> Result<Vec<RegisterType<N>>> {
646        // Ensure the number of input types is correct.
647        check_number_of_operands(VARIANT, Self::opcode(), input_types.len())?;
648        // Ensure the number of operands is correct.
649        check_number_of_operands(VARIANT, Self::opcode(), self.operands.len())?;
650        // Ensure the destination type is valid.
651        ensure!(
652            is_valid_destination_type(VARIANT, &self.destination_type),
653            "Invalid destination type in 'hash' instruction"
654        );
655
656        // Get the variant.
657        let variant = HashVariant::new(VARIANT);
658
659        // If the variant needs to be byte aligned, check that its size in bits is a multiple of 8.
660        if variant.requires_byte_alignment() {
661            // Check that there is only one operand type.
662            ensure!(
663                variant.expected_num_operands() == 1,
664                "Expected one operand for '{}', found '{}'",
665                variant.opcode(),
666                variant.expected_num_operands()
667            );
668
669            // A helper to get a struct declaration.
670            let get_struct = |identifier: &Identifier<N>| stack.program().get_struct(identifier).cloned();
671
672            // A helper to get a record declaration.
673            let get_record = |identifier: &Identifier<N>| stack.program().get_record(identifier).cloned();
674
675            // A helper to get an external record declaration.
676            let get_external_record = |locator: &Locator<N>| {
677                stack.get_external_stack(locator.program_id())?.program().get_record(locator.resource()).cloned()
678            };
679
680            // A helper to get the argument types of a future.
681            let get_future = |locator: &Locator<N>| {
682                Ok(match stack.program_id() == locator.program_id() {
683                    true => stack
684                        .program()
685                        .get_function_ref(locator.resource())?
686                        .finalize_logic()
687                        .ok_or_else(|| anyhow!("'{locator}' does not have a finalize scope"))?
688                        .input_types(),
689                    false => stack
690                        .get_external_stack(locator.program_id())?
691                        .program()
692                        .get_function_ref(locator.resource())?
693                        .finalize_logic()
694                        .ok_or_else(|| anyhow!("Failed to find function '{locator}'"))?
695                        .input_types(),
696                })
697            };
698
699            // Get the size in bits.
700            let size_in_bits = match variant.is_raw() {
701                false => input_types[0].size_in_bits(&get_struct, &get_record, &get_external_record, &get_future)?,
702                true => input_types[0].size_in_bits_raw(&get_struct, &get_record, &get_external_record, &get_future)?,
703            };
704            // Check the number of bits.
705            ensure!(
706                size_in_bits % 8 == 0,
707                "Expected a multiple of 8 bits for '{}', found '{size_in_bits}'",
708                variant.opcode()
709            );
710        }
711
712        // TODO (howardwu): If the operation is Pedersen, check that it is within the number of bits.
713
714        match variant {
715            HashVariant::HashManyPSD2 | HashVariant::HashManyPSD4 | HashVariant::HashManyPSD8 => {
716                bail!("'hash_many' is not yet implemented")
717            }
718            _ => Ok(vec![RegisterType::Plaintext(self.destination_type.clone())]),
719        }
720    }
721}
722
723impl<N: Network, const VARIANT: u8> Parser for HashInstruction<N, VARIANT> {
724    /// Parses a string into an operation.
725    fn parse(string: &str) -> ParserResult<Self> {
726        /// Parse the operands from the string.
727        fn parse_operands<N: Network>(string: &str, num_operands: usize) -> ParserResult<Vec<Operand<N>>> {
728            let mut operands = Vec::with_capacity(num_operands);
729            let mut string = string;
730
731            for _ in 0..num_operands {
732                // Parse the whitespace from the string.
733                let (next_string, _) = Sanitizer::parse_whitespaces(string)?;
734                // Parse the operand from the string.
735                let (next_string, operand) = Operand::parse(next_string)?;
736                // Update the string.
737                string = next_string;
738                // Push the operand.
739                operands.push(operand);
740            }
741
742            Ok((string, operands))
743        }
744
745        // Parse the opcode from the string.
746        let (string, _) = tag(*Self::opcode())(string)?;
747        // Parse the operands from the string.
748        let (string, operands) = parse_operands(string, HashVariant::new(VARIANT).expected_num_operands())?;
749        // Parse the whitespace from the string.
750        let (string, _) = Sanitizer::parse_whitespaces(string)?;
751        // Parse the "into" from the string.
752        let (string, _) = tag("into")(string)?;
753        // Parse the whitespace from the string.
754        let (string, _) = Sanitizer::parse_whitespaces(string)?;
755        // Parse the destination register from the string.
756        let (string, destination) = Register::parse(string)?;
757        // Parse the whitespace from the string.
758        let (string, _) = Sanitizer::parse_whitespaces(string)?;
759        // Parse the "as" from the string.
760        let (string, _) = tag("as")(string)?;
761        // Parse the whitespace from the string.
762        let (string, _) = Sanitizer::parse_whitespaces(string)?;
763        // Parse the destination register type from the string.
764        let (string, destination_type) = PlaintextType::parse(string)?;
765        // Ensure the destination type is allowed.
766        match destination_type {
767            PlaintextType::Literal(LiteralType::Boolean) | PlaintextType::Literal(LiteralType::String) => {
768                map_res(fail, |_: ParserResult<Self>| {
769                    Err(error(format!("Failed to parse 'hash': '{destination_type}' is invalid")))
770                })(string)
771            }
772            _ => Ok((string, Self { operands, destination, destination_type })),
773        }
774    }
775}
776
777impl<N: Network, const VARIANT: u8> FromStr for HashInstruction<N, VARIANT> {
778    type Err = Error;
779
780    /// Parses a string into an operation.
781    fn from_str(string: &str) -> Result<Self> {
782        match Self::parse(string) {
783            Ok((remainder, object)) => {
784                // Ensure the remainder is empty.
785                ensure!(remainder.is_empty(), "Failed to parse string. Found invalid character in: \"{remainder}\"");
786                // Return the object.
787                Ok(object)
788            }
789            Err(error) => bail!("Failed to parse string. {error}"),
790        }
791    }
792}
793
794impl<N: Network, const VARIANT: u8> Debug for HashInstruction<N, VARIANT> {
795    /// Prints the operation as a string.
796    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
797        Display::fmt(self, f)
798    }
799}
800
801impl<N: Network, const VARIANT: u8> Display for HashInstruction<N, VARIANT> {
802    /// Prints the operation to a string.
803    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
804        // Ensure the number of operands is correct.
805        check_number_of_operands(VARIANT, Self::opcode(), self.operands.len()).map_err(|_| fmt::Error)?;
806        // Print the operation.
807        write!(f, "{} ", Self::opcode())?;
808        self.operands.iter().try_for_each(|operand| write!(f, "{operand} "))?;
809        write!(f, "into {} as {}", self.destination, self.destination_type)
810    }
811}
812
813impl<N: Network, const VARIANT: u8> FromBytes for HashInstruction<N, VARIANT> {
814    /// Reads the operation from a buffer.
815    fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
816        // Prepare the number of operands.
817        let num_operands = HashVariant::new(VARIANT).expected_num_operands();
818        // Read the operands.
819        let operands = (0..num_operands).map(|_| Operand::read_le(&mut reader)).collect::<Result<_, _>>()?;
820        // Read the destination register.
821        let destination = Register::read_le(&mut reader)?;
822        // Read the destination register type.
823        let destination_type = PlaintextType::read_le(&mut reader)?;
824        // Return the operation.
825        Ok(Self { operands, destination, destination_type })
826    }
827}
828
829impl<N: Network, const VARIANT: u8> ToBytes for HashInstruction<N, VARIANT> {
830    /// Writes the operation to a buffer.
831    fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
832        // Ensure the number of operands is correct.
833        check_number_of_operands(VARIANT, Self::opcode(), self.operands.len()).map_err(|e| error(format!("{e}")))?;
834        // Write the operands.
835        self.operands.iter().try_for_each(|operand| operand.write_le(&mut writer))?;
836        // Write the destination register.
837        self.destination.write_le(&mut writer)?;
838        // Write the destination register type.
839        self.destination_type.write_le(&mut writer)
840    }
841}
842
843#[cfg(test)]
844mod tests {
845    use super::*;
846    use console::{network::MainnetV0, program::ArrayType, types::U32};
847
848    type CurrentNetwork = MainnetV0;
849
850    /// **Attention**: When changing this, also update in `tests/instruction/hash.rs`.
851    fn sample_valid_destination_types<N: Network, R: CryptoRng + Rng>(
852        variant: u8,
853        rng: &mut R,
854    ) -> Vec<PlaintextType<N>> {
855        match variant {
856            0..=32 => vec![
857                PlaintextType::Literal(LiteralType::Address),
858                PlaintextType::Literal(LiteralType::Field),
859                PlaintextType::Literal(LiteralType::Group),
860                PlaintextType::Literal(LiteralType::I8),
861                PlaintextType::Literal(LiteralType::I16),
862                PlaintextType::Literal(LiteralType::I32),
863                PlaintextType::Literal(LiteralType::I64),
864                PlaintextType::Literal(LiteralType::I128),
865                PlaintextType::Literal(LiteralType::U8),
866                PlaintextType::Literal(LiteralType::U16),
867                PlaintextType::Literal(LiteralType::U32),
868                PlaintextType::Literal(LiteralType::U64),
869                PlaintextType::Literal(LiteralType::U128),
870                PlaintextType::Literal(LiteralType::Scalar),
871            ],
872            33..=44 => (0..10)
873                .map(|_| {
874                    PlaintextType::Array(
875                        ArrayType::new(PlaintextType::Literal(LiteralType::Boolean), vec![U32::new(
876                            u32::try_from(rng.gen_range(1..=CurrentNetwork::MAX_ARRAY_ELEMENTS)).unwrap(),
877                        )])
878                        .unwrap(),
879                    )
880                })
881                .collect(),
882            _ => panic!("Invalid 'hash' instruction opcode"),
883        }
884    }
885
886    // A helper function to run a test.
887    fn run_test<N: Network, const VARIANT: u8>() {
888        // Initialize the RNG.
889        let rng = &mut TestRng::default();
890
891        // Get the opcode.
892        let opcode = HashInstruction::<N, VARIANT>::opcode();
893
894        for destination_type in sample_valid_destination_types(VARIANT, rng) {
895            let instruction = format!("{opcode} r0 into r1 as {destination_type}");
896            println!("Testing instruction: '{instruction}'");
897
898            let (string, hash) = HashInstruction::<CurrentNetwork, VARIANT>::parse(&instruction).unwrap();
899            assert!(string.is_empty(), "Parser did not consume all of the string: '{string}'");
900            assert_eq!(hash.operands.len(), 1, "The number of operands is incorrect");
901            assert_eq!(hash.operands[0], Operand::Register(Register::Locator(0)), "The first operand is incorrect");
902            assert_eq!(hash.destination, Register::Locator(1), "The destination register is incorrect");
903            assert_eq!(&hash.destination_type, &destination_type, "The destination type is incorrect");
904        }
905    }
906
907    #[test]
908    fn test_parse() {
909        run_test::<CurrentNetwork, { HashVariant::HashBHP256 as u8 }>();
910        run_test::<CurrentNetwork, { HashVariant::HashBHP512 as u8 }>();
911        run_test::<CurrentNetwork, { HashVariant::HashBHP768 as u8 }>();
912        run_test::<CurrentNetwork, { HashVariant::HashBHP1024 as u8 }>();
913
914        run_test::<CurrentNetwork, { HashVariant::HashKeccak256 as u8 }>();
915        run_test::<CurrentNetwork, { HashVariant::HashKeccak384 as u8 }>();
916        run_test::<CurrentNetwork, { HashVariant::HashKeccak512 as u8 }>();
917
918        run_test::<CurrentNetwork, { HashVariant::HashPED64 as u8 }>();
919        run_test::<CurrentNetwork, { HashVariant::HashPED128 as u8 }>();
920
921        run_test::<CurrentNetwork, { HashVariant::HashPSD2 as u8 }>();
922        run_test::<CurrentNetwork, { HashVariant::HashPSD4 as u8 }>();
923        run_test::<CurrentNetwork, { HashVariant::HashPSD8 as u8 }>();
924
925        run_test::<CurrentNetwork, { HashVariant::HashSha3_256 as u8 }>();
926        run_test::<CurrentNetwork, { HashVariant::HashSha3_384 as u8 }>();
927        run_test::<CurrentNetwork, { HashVariant::HashSha3_512 as u8 }>();
928
929        // Note: `run_test` needs to be updated when `hash_many` is implemented.
930        //run_test::<CurrentNetwork, { HashVariant::HashManyPSD2 as u8 }>();
931        //run_test::<CurrentNetwork, { HashVariant::HashManyPSD4 as u8 }>();
932        //run_test::<CurrentNetwork, { HashVariant::HashManyPSD8 as u8 }>();
933
934        run_test::<CurrentNetwork, { HashVariant::HashBHP256Raw as u8 }>();
935        run_test::<CurrentNetwork, { HashVariant::HashBHP512Raw as u8 }>();
936        run_test::<CurrentNetwork, { HashVariant::HashBHP768Raw as u8 }>();
937        run_test::<CurrentNetwork, { HashVariant::HashBHP1024Raw as u8 }>();
938
939        run_test::<CurrentNetwork, { HashVariant::HashKeccak256Raw as u8 }>();
940        run_test::<CurrentNetwork, { HashVariant::HashKeccak384Raw as u8 }>();
941        run_test::<CurrentNetwork, { HashVariant::HashKeccak512Raw as u8 }>();
942
943        run_test::<CurrentNetwork, { HashVariant::HashPED64Raw as u8 }>();
944        run_test::<CurrentNetwork, { HashVariant::HashPED128Raw as u8 }>();
945
946        run_test::<CurrentNetwork, { HashVariant::HashPSD2Raw as u8 }>();
947        run_test::<CurrentNetwork, { HashVariant::HashPSD4Raw as u8 }>();
948        run_test::<CurrentNetwork, { HashVariant::HashPSD8Raw as u8 }>();
949
950        run_test::<CurrentNetwork, { HashVariant::HashSha3_256Raw as u8 }>();
951        run_test::<CurrentNetwork, { HashVariant::HashSha3_384Raw as u8 }>();
952        run_test::<CurrentNetwork, { HashVariant::HashSha3_512Raw as u8 }>();
953
954        run_test::<CurrentNetwork, { HashVariant::HashKeccak256Native as u8 }>();
955        run_test::<CurrentNetwork, { HashVariant::HashKeccak384Native as u8 }>();
956        run_test::<CurrentNetwork, { HashVariant::HashKeccak512Native as u8 }>();
957
958        run_test::<CurrentNetwork, { HashVariant::HashSha3_256Native as u8 }>();
959        run_test::<CurrentNetwork, { HashVariant::HashSha3_384Native as u8 }>();
960        run_test::<CurrentNetwork, { HashVariant::HashSha3_512Native as u8 }>();
961
962        run_test::<CurrentNetwork, { HashVariant::HashKeccak256NativeRaw as u8 }>();
963        run_test::<CurrentNetwork, { HashVariant::HashKeccak384NativeRaw as u8 }>();
964        run_test::<CurrentNetwork, { HashVariant::HashKeccak512NativeRaw as u8 }>();
965
966        run_test::<CurrentNetwork, { HashVariant::HashSha3_256NativeRaw as u8 }>();
967        run_test::<CurrentNetwork, { HashVariant::HashSha3_384NativeRaw as u8 }>();
968        run_test::<CurrentNetwork, { HashVariant::HashSha3_512NativeRaw as u8 }>();
969    }
970
971    #[test]
972    fn check_number_of_hash_variants() {
973        assert_eq!(enum_iterator::cardinality::<HashVariant>(), 45);
974    }
975
976    #[test]
977    fn check_byte_aligned_variants_all_have_one_opcode() {
978        for variant in enum_iterator::all::<HashVariant>() {
979            if variant.requires_byte_alignment() {
980                assert_eq!(variant.expected_num_operands(), 1)
981            }
982        }
983    }
984}