miden_protocol/block/
block_outputs.rs1use alloc::vec::Vec;
2
3use crate::errors::BlockOutputError;
4use crate::vm::StackOutputs;
5use crate::{Felt, Word};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct BlockOutputs {
15 block_commitment: Word,
17 nullifier_commitment: Word,
19}
20
21impl BlockOutputs {
22 pub const BLOCK_COMMITMENT_WORD_IDX: usize = 0;
27 pub const NULLIFIER_COMMITMENT_WORD_IDX: usize = 4;
29
30 const NUM_OUTPUT_ELEMENTS: usize = 8;
32
33 pub fn new(block_commitment: Word, nullifier_commitment: Word) -> Self {
38 Self { block_commitment, nullifier_commitment }
39 }
40
41 pub fn parse(stack: &StackOutputs) -> Result<Self, BlockOutputError> {
51 let block_commitment = stack
52 .get_word(Self::BLOCK_COMMITMENT_WORD_IDX)
53 .expect("block commitment word should be within the output stack");
54
55 let nullifier_commitment = stack
56 .get_word(Self::NULLIFIER_COMMITMENT_WORD_IDX)
57 .expect("nullifier commitment word should be within the output stack");
58
59 if let Some(index) = stack[Self::NUM_OUTPUT_ELEMENTS..]
61 .iter()
62 .position(|&felt| felt != Felt::ZERO)
63 .map(|offset| offset + Self::NUM_OUTPUT_ELEMENTS)
64 {
65 return Err(BlockOutputError::PaddingNotZero { index });
66 }
67
68 Ok(Self::new(block_commitment, nullifier_commitment))
69 }
70
71 pub fn block_commitment(&self) -> Word {
76 self.block_commitment
77 }
78
79 pub fn nullifier_commitment(&self) -> Word {
81 self.nullifier_commitment
82 }
83
84 pub fn into_stack_outputs(self) -> StackOutputs {
95 let mut outputs: Vec<Felt> = Vec::with_capacity(Self::NUM_OUTPUT_ELEMENTS);
96 outputs.extend_from_slice(self.block_commitment.as_elements());
97 outputs.extend_from_slice(self.nullifier_commitment.as_elements());
98
99 StackOutputs::new(&outputs).expect("number of stack outputs should be <= 16")
100 }
101}
102
103#[cfg(test)]
107mod tests {
108 use assert_matches::assert_matches;
109
110 use super::*;
111
112 #[test]
113 fn parse_returns_outputs_for_well_formed_stack() {
114 let block_commitment =
115 Word::from([Felt::from(1u32), Felt::from(2u32), Felt::from(3u32), Felt::from(4u32)]);
116 let nullifier_commitment =
117 Word::from([Felt::from(5u32), Felt::from(6u32), Felt::from(7u32), Felt::from(8u32)]);
118 let stack = BlockOutputs::new(block_commitment, nullifier_commitment).into_stack_outputs();
119
120 let outputs = BlockOutputs::parse(&stack).unwrap();
121
122 assert_eq!(outputs.block_commitment(), block_commitment);
123 assert_eq!(outputs.nullifier_commitment(), nullifier_commitment);
124 }
125
126 #[test]
127 fn parse_reports_the_index_of_the_first_non_zero_padding_cell() {
128 let mut elements = [Felt::ZERO; 12];
130 elements[11] = Felt::from(1u32);
131 let stack = StackOutputs::new(&elements).unwrap();
132
133 assert_matches!(
134 BlockOutputs::parse(&stack),
135 Err(BlockOutputError::PaddingNotZero { index: 11 })
136 );
137 }
138}