miden_objects/transaction/
transaction_id.rs

1use alloc::string::String;
2use core::fmt::{Debug, Display};
3
4use super::{Felt, Hasher, ProvenTransaction, WORD_SIZE, Word, ZERO};
5use crate::utils::serde::{
6    ByteReader,
7    ByteWriter,
8    Deserializable,
9    DeserializationError,
10    Serializable,
11};
12
13// TRANSACTION ID
14// ================================================================================================
15
16/// A unique identifier of a transaction.
17///
18/// Transaction ID is computed as:
19///
20/// hash(init_account_commitment, final_account_commitment, input_notes_commitment,
21/// output_notes_commitment)
22///
23/// This achieves the following properties:
24/// - Transactions are identical if and only if they have the same ID.
25/// - Computing transaction ID can be done solely from public transaction data.
26#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
27pub struct TransactionId(Word);
28
29impl TransactionId {
30    /// Returns a new [TransactionId] instantiated from the provided transaction components.
31    pub fn new(
32        init_account_commitment: Word,
33        final_account_commitment: Word,
34        input_notes_commitment: Word,
35        output_notes_commitment: Word,
36    ) -> Self {
37        let mut elements = [ZERO; 4 * WORD_SIZE];
38        elements[..4].copy_from_slice(init_account_commitment.as_elements());
39        elements[4..8].copy_from_slice(final_account_commitment.as_elements());
40        elements[8..12].copy_from_slice(input_notes_commitment.as_elements());
41        elements[12..].copy_from_slice(output_notes_commitment.as_elements());
42        Self(Hasher::hash_elements(&elements))
43    }
44
45    /// Returns the elements representation of this transaction ID.
46    pub fn as_elements(&self) -> &[Felt] {
47        self.0.as_elements()
48    }
49
50    /// Returns the byte representation of this transaction ID.
51    pub fn as_bytes(&self) -> [u8; 32] {
52        self.0.as_bytes()
53    }
54
55    /// Returns a big-endian, hex-encoded string.
56    pub fn to_hex(&self) -> String {
57        self.0.to_hex()
58    }
59
60    /// Returns the digest defining this transaction ID.
61    pub fn as_word(&self) -> Word {
62        self.0
63    }
64}
65
66impl Debug for TransactionId {
67    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
68        write!(f, "{}", self.to_hex())
69    }
70}
71
72impl Display for TransactionId {
73    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
74        write!(f, "{}", self.to_hex())
75    }
76}
77
78// CONVERSIONS INTO TRANSACTION ID
79// ================================================================================================
80
81impl From<&ProvenTransaction> for TransactionId {
82    fn from(tx: &ProvenTransaction) -> Self {
83        Self::new(
84            tx.account_update().initial_state_commitment(),
85            tx.account_update().final_state_commitment(),
86            tx.input_notes().commitment(),
87            tx.output_notes().commitment(),
88        )
89    }
90}
91
92impl From<Word> for TransactionId {
93    fn from(digest: Word) -> Self {
94        Self(digest)
95    }
96}
97
98// CONVERSIONS FROM TRANSACTION ID
99// ================================================================================================
100
101impl From<TransactionId> for Word {
102    fn from(id: TransactionId) -> Self {
103        id.0
104    }
105}
106
107impl From<TransactionId> for [u8; 32] {
108    fn from(id: TransactionId) -> Self {
109        id.0.into()
110    }
111}
112
113impl From<&TransactionId> for Word {
114    fn from(id: &TransactionId) -> Self {
115        id.0
116    }
117}
118
119impl From<&TransactionId> for [u8; 32] {
120    fn from(id: &TransactionId) -> Self {
121        id.0.into()
122    }
123}
124
125// SERIALIZATION
126// ================================================================================================
127
128impl Serializable for TransactionId {
129    fn write_into<W: ByteWriter>(&self, target: &mut W) {
130        target.write_bytes(&self.0.to_bytes());
131    }
132}
133
134impl Deserializable for TransactionId {
135    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
136        let id = Word::read_from(source)?;
137        Ok(Self(id))
138    }
139}