Skip to main content

miden_stdlib_sys/intrinsics/
crypto.rs

1//! Cryptographic intrinsics for the Miden VM.
2//!
3//! This module provides Rust bindings for cryptographic operations available in the Miden VM.
4#![allow(warnings, clippy::infallible_try_from)]
5
6use core::convert::Infallible;
7
8use crate::intrinsics::{Felt, Word};
9
10/// A cryptographic digest representing a 256-bit hash value.
11///
12/// This is a wrapper around `Word` which contains 4 field elements.
13#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
14#[repr(transparent)]
15pub struct Digest {
16    pub inner: Word,
17}
18
19impl Digest {
20    /// Creates a new `Digest` from a `[Felt; 4]` array.
21    #[inline]
22    pub fn new(felts: [Felt; 4]) -> Self {
23        Self {
24            inner: Word::from(felts),
25        }
26    }
27
28    /// Creates a new `Digest` from a `Word`.
29    #[inline]
30    pub const fn from_word(word: Word) -> Self {
31        Self { inner: word }
32    }
33}
34
35impl TryFrom<Word> for Digest {
36    type Error = Infallible;
37
38    #[inline]
39    fn try_from(word: Word) -> Result<Self, Self::Error> {
40        Ok(Self::from_word(word))
41    }
42}
43
44impl From<Digest> for Word {
45    #[inline]
46    fn from(digest: Digest) -> Self {
47        digest.inner
48    }
49}
50
51impl From<[Felt; 4]> for Digest {
52    #[inline]
53    fn from(felts: [Felt; 4]) -> Self {
54        Self::new(felts)
55    }
56}
57
58impl From<Digest> for [Felt; 4] {
59    #[inline]
60    fn from(digest: Digest) -> Self {
61        (&digest.inner).into()
62    }
63}
64
65#[cfg(all(target_family = "wasm", miden))]
66unsafe extern "C" {
67    /// Merges two words (256-bit digests) via Poseidon2.
68    ///
69    /// This maps to `miden::core::crypto::hashes::poseidon2::merge`.
70    ///
71    /// Inputs:  `[A, B, ...]`
72    /// Outputs: `[C, ...]` where `C = Poseidon2(A || B)`
73    ///
74    /// The digest output is returned to the caller via `result_ptr`.
75    #[cfg_attr(all(target_family = "wasm", miden), linkage = "extern_weak")]
76    #[link_name = "miden::core::crypto::hashes::poseidon2::merge"]
77    fn extern_poseidon2_merge(
78        a0: Felt,
79        a1: Felt,
80        a2: Felt,
81        a3: Felt,
82        b0: Felt,
83        b1: Felt,
84        b2: Felt,
85        b3: Felt,
86        result_ptr: *mut Felt,
87    );
88}
89
90/// Computes the hash of two digests using the Rescue Prime Optimized (RPO)
91/// permutation in 2-to-1 mode.
92///
93/// This directly maps to the `hmerge` VM instruction.
94///
95/// # Arguments
96/// * `digests` - An array of two digests to be merged. The function internally
97///   reorders them as required by the VM instruction (from [A, B] to [B, A] on the stack).
98#[inline]
99#[cfg(all(target_family = "wasm", miden))]
100pub fn merge(digests: [Digest; 2]) -> Digest {
101    use crate::intrinsics::WordAligned;
102
103    unsafe {
104        let mut ret_area = ::core::mem::MaybeUninit::<WordAligned<Word>>::uninit();
105        let result_ptr = ret_area.as_mut_ptr() as *mut Felt;
106
107        extern_poseidon2_merge(
108            digests[0].inner.a,
109            digests[0].inner.b,
110            digests[0].inner.c,
111            digests[0].inner.d,
112            digests[1].inner.a,
113            digests[1].inner.b,
114            digests[1].inner.c,
115            digests[1].inner.d,
116            result_ptr,
117        );
118
119        Digest::from_word(ret_area.assume_init().into_inner())
120    }
121}
122
123/// Computes the hash of two digests using the Rescue Prime Optimized (RPO) permutation in 2-to-1
124/// mode.
125#[inline]
126#[cfg(not(all(target_family = "wasm", miden)))]
127pub fn merge(_digests: [Digest; 2]) -> Digest {
128    unimplemented!("crypto intrinsics are only available when targeting the Miden VM")
129}