risc0_zkp/core/hash/sha/
rust_crypto.rs1use alloc::{format, vec::Vec};
44use core::fmt::{Debug, Formatter};
45
46use digest::{
47 block_buffer::Eager,
48 const_oid::{AssociatedOid, ObjectIdentifier},
49 core_api::{
50 AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, CoreWrapper,
51 CtVariableCoreWrapper, OutputSizeUser, TruncSide, UpdateCore, VariableOutputCore,
52 },
53 typenum::{U32, U64},
54 HashMarker, InvalidOutputSize,
55};
56pub use digest::{Digest, Output};
57
58use super::{BLOCK_BYTES, SHA256_INIT};
59
60#[derive(Clone)]
64pub struct Sha256VarCore<S: super::Sha256> {
65 state: Option<S::DigestPtr>,
67 block_len: u32,
70}
71
72impl<S: super::Sha256> HashMarker for Sha256VarCore<S> {}
73
74impl<S: super::Sha256> BlockSizeUser for Sha256VarCore<S> {
75 type BlockSize = U64;
76}
77
78impl<S: super::Sha256> BufferKindUser for Sha256VarCore<S> {
79 type BufferKind = Eager;
80}
81
82impl<S: super::Sha256> UpdateCore for Sha256VarCore<S> {
83 #[inline]
84 fn update_blocks(&mut self, blocks: &[Block<Self>]) {
85 self.block_len += u32::try_from(blocks.len()).unwrap();
86
87 let current_state = self.state.as_deref().unwrap_or(&SHA256_INIT);
97 self.state = Some(match unsafe { blocks.align_to::<super::Block>() } {
98 (&[], aligned_blocks, &[]) => S::compress_slice(current_state, aligned_blocks),
99 _ => S::compress_slice(
100 current_state,
101 &blocks
102 .iter()
103 .map(|block| bytemuck::pod_read_unaligned(block.as_slice()))
104 .collect::<Vec<_>>(),
105 ),
106 });
107 }
108}
109
110impl<S: super::Sha256> OutputSizeUser for Sha256VarCore<S> {
111 type OutputSize = U32;
112}
113
114impl<S: super::Sha256> VariableOutputCore for Sha256VarCore<S> {
115 const TRUNC_SIDE: TruncSide = TruncSide::Left;
116
117 #[inline]
118 fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
119 let state = match output_size {
120 32 => None,
121 _ => return Err(InvalidOutputSize),
122 };
123 let block_len = 0;
124 Ok(Self { state, block_len })
125 }
126
127 #[inline]
128 fn finalize_variable_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
129 let bit_len =
130 8 * (u32::try_from(buffer.get_pos()).unwrap() + (BLOCK_BYTES as u32) * self.block_len);
131 buffer.len64_padding_be(bit_len as u64, |block| {
132 let current_state = self.state.as_deref().unwrap_or(&SHA256_INIT);
135 self.state = Some(
136 match bytemuck::try_from_bytes::<super::Block>(block.as_slice()) {
137 Ok(b) => S::compress(current_state, b.as_half_blocks().0, b.as_half_blocks().1),
138 Err(_) => {
139 let b: super::Block = bytemuck::pod_read_unaligned(block.as_slice());
140 S::compress(current_state, b.as_half_blocks().0, b.as_half_blocks().1)
141 }
142 },
143 );
144 });
145
146 out.copy_from_slice(self.state.as_deref().unwrap().as_bytes())
151 }
152}
153
154impl<S: super::Sha256> AlgorithmName for Sha256VarCore<S> {
155 #[inline]
156 fn write_alg_name(f: &mut Formatter<'_>) -> core::fmt::Result {
157 f.write_str("Sha256")
158 }
159}
160
161impl<S: super::Sha256> Debug for Sha256VarCore<S> {
162 #[inline]
163 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
164 f.write_str(&format!(
165 "Sha256VarCore<{}> {{ ... }}",
166 core::any::type_name::<S>()
167 ))
168 }
169}
170
171#[doc(hidden)]
172#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
173pub struct OidSha256;
174
175impl AssociatedOid for OidSha256 {
176 const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.2.1");
177}
178
179pub type Sha256<S> = CoreWrapper<CtVariableCoreWrapper<Sha256VarCore<S>, U32, OidSha256>>;