Skip to content

Commit e875136

Browse files
Update SHA-256 subair to support SHA-512 and SHA_384
1 parent 3924b9b commit e875136

File tree

8 files changed

+1655
-806
lines changed

8 files changed

+1655
-806
lines changed

crates/circuits/sha2-air/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
[package]
2-
name = "openvm-sha256-air"
2+
name = "openvm-sha2-air"
33
version.workspace = true
44
authors.workspace = true
55
edition.workspace = true
66

77
[dependencies]
88
openvm-circuit-primitives = { workspace = true }
99
openvm-stark-backend = { workspace = true }
10+
openvm-circuit-primitives-derive = { workspace = true }
1011
sha2 = { version = "0.10", features = ["compress"] }
1112
rand.workspace = true
13+
ndarray.workspace = true
1214

1315
[dev-dependencies]
1416
openvm-stark-sdk = { workspace = true }

crates/circuits/sha2-air/src/air.rs

Lines changed: 323 additions & 239 deletions
Large diffs are not rendered by default.

crates/circuits/sha2-air/src/columns.rs

Lines changed: 102 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,130 +1,159 @@
11
//! WARNING: the order of fields in the structs is important, do not change it
22
3-
use openvm_circuit_primitives::{utils::not, AlignedBorrow};
3+
use openvm_circuit_primitives::utils::not;
4+
use openvm_circuit_primitives_derive::ColsRef;
45
use openvm_stark_backend::p3_field::FieldAlgebra;
56

6-
use super::{
7-
SHA256_HASH_WORDS, SHA256_ROUNDS_PER_ROW, SHA256_ROW_VAR_CNT, SHA256_WORD_BITS,
8-
SHA256_WORD_U16S, SHA256_WORD_U8S,
9-
};
7+
use crate::Sha2Config;
108

11-
/// In each SHA256 block:
12-
/// - First 16 rows use Sha256RoundCols
13-
/// - Final row uses Sha256DigestCols
9+
/// In each SHA block:
10+
/// - First C::ROUND_ROWS rows use ShaRoundCols
11+
/// - Final row uses ShaDigestCols
1412
///
15-
/// Note that for soundness, we require that there is always a padding row after the last digest row in the trace.
16-
/// Right now, this is true because the unpadded height is a multiple of 17, and thus not a power of 2.
17-
///
18-
/// Sha256RoundCols and Sha256DigestCols share the same first 3 fields:
13+
/// ShaRoundCols and ShaDigestCols share the same first 3 fields:
1914
/// - flags
2015
/// - work_vars/hash (same type, different name)
2116
/// - schedule_helper
2217
///
2318
/// This design allows for:
2419
/// 1. Common constraints to work on either struct type by accessing these shared fields
2520
/// 2. Specific constraints to use the appropriate struct, with flags helping to do conditional constraints
26-
///
27-
/// Note that the `Sha256WorkVarsCols` field it is used for different purposes in the two structs.
2821
#[repr(C)]
29-
#[derive(Clone, Copy, Debug, AlignedBorrow)]
30-
pub struct Sha256RoundCols<T> {
31-
pub flags: Sha256FlagsCols<T>,
32-
/// Stores the current state of the working variables
33-
pub work_vars: Sha256WorkVarsCols<T>,
34-
pub schedule_helper: Sha256MessageHelperCols<T>,
35-
pub message_schedule: Sha256MessageScheduleCols<T>,
22+
#[derive(Clone, Copy, Debug, ColsRef)]
23+
#[config(Sha2Config)]
24+
pub struct ShaRoundCols<
25+
T,
26+
const WORD_BITS: usize,
27+
const WORD_U8S: usize,
28+
const WORD_U16S: usize,
29+
const ROUNDS_PER_ROW: usize,
30+
const ROUNDS_PER_ROW_MINUS_ONE: usize,
31+
const ROW_VAR_CNT: usize,
32+
> {
33+
pub flags: Sha2FlagsCols<T, ROW_VAR_CNT>,
34+
pub work_vars: ShaWorkVarsCols<T, WORD_BITS, ROUNDS_PER_ROW, WORD_U16S>,
35+
pub schedule_helper:
36+
Sha2MessageHelperCols<T, WORD_U16S, ROUNDS_PER_ROW, ROUNDS_PER_ROW_MINUS_ONE>,
37+
pub message_schedule: ShaMessageScheduleCols<T, WORD_BITS, ROUNDS_PER_ROW, WORD_U8S>,
3638
}
3739

3840
#[repr(C)]
39-
#[derive(Clone, Copy, Debug, AlignedBorrow)]
40-
pub struct Sha256DigestCols<T> {
41-
pub flags: Sha256FlagsCols<T>,
42-
/// Will serve as previous hash values for the next block.
43-
/// - on non-last blocks, this is the final hash of the current block
44-
/// - on last blocks, this is the initial state constants, SHA256_H.
45-
/// The work variables constraints are applied on all rows, so `carry_a` and `carry_e`
46-
/// must be filled in with dummy values to ensure these constraints hold.
47-
pub hash: Sha256WorkVarsCols<T>,
48-
pub schedule_helper: Sha256MessageHelperCols<T>,
41+
#[derive(Clone, Copy, Debug, ColsRef)]
42+
#[config(Sha2Config)]
43+
pub struct ShaDigestCols<
44+
T,
45+
const WORD_BITS: usize,
46+
const WORD_U8S: usize,
47+
const WORD_U16S: usize,
48+
const HASH_WORDS: usize,
49+
const ROUNDS_PER_ROW: usize,
50+
const ROUNDS_PER_ROW_MINUS_ONE: usize,
51+
const ROW_VAR_CNT: usize,
52+
> {
53+
pub flags: Sha2FlagsCols<T, ROW_VAR_CNT>,
54+
/// Will serve as previous hash values for the next block
55+
pub hash: ShaWorkVarsCols<T, WORD_BITS, ROUNDS_PER_ROW, WORD_U16S>,
56+
pub schedule_helper:
57+
Sha2MessageHelperCols<T, WORD_U16S, ROUNDS_PER_ROW, ROUNDS_PER_ROW_MINUS_ONE>,
4958
/// The actual final hash values of the given block
5059
/// Note: the above `hash` will be equal to `final_hash` unless we are on the last block
51-
pub final_hash: [[T; SHA256_WORD_U8S]; SHA256_HASH_WORDS],
60+
pub final_hash: [[T; WORD_U8S]; HASH_WORDS],
5261
/// The final hash of the previous block
5362
/// Note: will be constrained using interactions with the chip itself
54-
pub prev_hash: [[T; SHA256_WORD_U16S]; SHA256_HASH_WORDS],
63+
pub prev_hash: [[T; WORD_U16S]; HASH_WORDS],
5564
}
5665

5766
#[repr(C)]
58-
#[derive(Clone, Copy, Debug, AlignedBorrow)]
59-
pub struct Sha256MessageScheduleCols<T> {
67+
#[derive(Clone, Copy, Debug, ColsRef)]
68+
#[config(Sha2Config)]
69+
pub struct ShaMessageScheduleCols<
70+
T,
71+
const WORD_BITS: usize,
72+
const ROUNDS_PER_ROW: usize,
73+
const WORD_U8S: usize,
74+
> {
6075
/// The message schedule words as 32-bit integers
61-
/// The first 16 words will be the message data
62-
pub w: [[T; SHA256_WORD_BITS]; SHA256_ROUNDS_PER_ROW],
63-
/// Will be message schedule carries for rows 4..16 and a buffer for rows 0..4 to be used freely by wrapper chips
64-
/// Note: carries are 2 bit numbers represented using 2 cells as individual bits
65-
pub carry_or_buffer: [[T; SHA256_WORD_U8S]; SHA256_ROUNDS_PER_ROW],
76+
pub w: [[T; WORD_BITS]; ROUNDS_PER_ROW],
77+
/// Will be message schedule carries for rows 4..C::ROUND_ROWS and a buffer for rows 0..4 to be used freely by wrapper chips
78+
/// Note: carries are represented as 2 bit numbers
79+
pub carry_or_buffer: [[T; WORD_U8S]; ROUNDS_PER_ROW],
6680
}
6781

6882
#[repr(C)]
69-
#[derive(Clone, Copy, Debug, AlignedBorrow)]
70-
pub struct Sha256WorkVarsCols<T> {
83+
#[derive(Clone, Copy, Debug, ColsRef)]
84+
#[config(Sha2Config)]
85+
pub struct ShaWorkVarsCols<
86+
T,
87+
const WORD_BITS: usize,
88+
const ROUNDS_PER_ROW: usize,
89+
const WORD_U16S: usize,
90+
> {
7191
/// `a` and `e` after each iteration as 32-bits
72-
pub a: [[T; SHA256_WORD_BITS]; SHA256_ROUNDS_PER_ROW],
73-
pub e: [[T; SHA256_WORD_BITS]; SHA256_ROUNDS_PER_ROW],
92+
pub a: [[T; WORD_BITS]; ROUNDS_PER_ROW],
93+
pub e: [[T; WORD_BITS]; ROUNDS_PER_ROW],
7494
/// The carry's used for addition during each iteration when computing `a` and `e`
75-
pub carry_a: [[T; SHA256_WORD_U16S]; SHA256_ROUNDS_PER_ROW],
76-
pub carry_e: [[T; SHA256_WORD_U16S]; SHA256_ROUNDS_PER_ROW],
95+
pub carry_a: [[T; WORD_U16S]; ROUNDS_PER_ROW],
96+
pub carry_e: [[T; WORD_U16S]; ROUNDS_PER_ROW],
7797
}
7898

7999
/// These are the columns that are used to help with the message schedule additions
80100
/// Note: these need to be correctly assigned for every row even on padding rows
81101
#[repr(C)]
82-
#[derive(Clone, Copy, Debug, AlignedBorrow)]
83-
pub struct Sha256MessageHelperCols<T> {
102+
#[derive(Clone, Copy, Debug, ColsRef)]
103+
#[config(Sha2Config)]
104+
pub struct Sha2MessageHelperCols<
105+
T,
106+
const WORD_U16S: usize,
107+
const ROUNDS_PER_ROW: usize,
108+
const ROUNDS_PER_ROW_MINUS_ONE: usize,
109+
> {
84110
/// The following are used to move data forward to constrain the message schedule additions
85-
/// The value of `w` (message schedule word) from 3 rounds ago
86-
/// In general, `w_i` means `w` from `i` rounds ago
87-
pub w_3: [[T; SHA256_WORD_U16S]; SHA256_ROUNDS_PER_ROW - 1],
111+
/// The value of `w` from 3 rounds ago
112+
pub w_3: [[T; WORD_U16S]; ROUNDS_PER_ROW_MINUS_ONE],
88113
/// Here intermediate(i) = w_i + sig_0(w_{i+1})
89114
/// Intermed_t represents the intermediate t rounds ago
90-
/// This is needed to constrain the message schedule, since we can only constrain on two rows at a time
91-
pub intermed_4: [[T; SHA256_WORD_U16S]; SHA256_ROUNDS_PER_ROW],
92-
pub intermed_8: [[T; SHA256_WORD_U16S]; SHA256_ROUNDS_PER_ROW],
93-
pub intermed_12: [[T; SHA256_WORD_U16S]; SHA256_ROUNDS_PER_ROW],
115+
pub intermed_4: [[T; WORD_U16S]; ROUNDS_PER_ROW],
116+
pub intermed_8: [[T; WORD_U16S]; ROUNDS_PER_ROW],
117+
pub intermed_12: [[T; WORD_U16S]; ROUNDS_PER_ROW],
94118
}
95119

96120
#[repr(C)]
97-
#[derive(Clone, Copy, Debug, AlignedBorrow)]
98-
pub struct Sha256FlagsCols<T> {
99-
/// A flag that indicates if the current row is among the first 16 rows of a block.
121+
#[derive(Clone, Copy, Debug, ColsRef)]
122+
#[config(Sha2Config)]
123+
pub struct Sha2FlagsCols<T, const ROW_VAR_CNT: usize> {
100124
pub is_round_row: T,
101-
/// A flag that indicates if the current row is among the first 4 rows of a block.
125+
/// A flag that indicates if the current row is among the first 4 rows of a block (the message rows)
102126
pub is_first_4_rows: T,
103-
/// A flag that indicates if the current row is the last (17th) row of a block.
104127
pub is_digest_row: T,
105-
// A flag that indicates if the current row is the last block of the message.
106-
// This flag is only used in digest rows.
107128
pub is_last_block: T,
108129
/// We will encode the row index [0..17) using 5 cells
109-
pub row_idx: [T; SHA256_ROW_VAR_CNT],
110-
/// The index of the current block in the trace starting at 1.
111-
/// Set to 0 on padding rows.
130+
pub row_idx: [T; ROW_VAR_CNT],
131+
/// The global index of the current block
112132
pub global_block_idx: T,
113-
/// The index of the current block in the current message starting at 0.
114-
/// Resets after every message.
115-
/// Set to 0 on padding rows.
133+
/// Will store the index of the current block in the current message starting from 0
116134
pub local_block_idx: T,
117135
}
118136

119-
impl<O, T: Copy + core::ops::Add<Output = O>> Sha256FlagsCols<T> {
120-
// This refers to the padding rows that are added to the air to make the trace length a power of 2.
121-
// Not to be confused with the padding added to messages as part of the SHA hash function.
137+
impl<O, T: Copy + core::ops::Add<Output = O>, const ROW_VAR_CNT: usize>
138+
Sha2FlagsCols<T, ROW_VAR_CNT>
139+
{
122140
pub fn is_not_padding_row(&self) -> O {
123141
self.is_round_row + self.is_digest_row
124142
}
125143

126-
// This refers to the padding rows that are added to the air to make the trace length a power of 2.
127-
// Not to be confused with the padding added to messages as part of the SHA hash function.
144+
pub fn is_padding_row(&self) -> O
145+
where
146+
O: FieldAlgebra,
147+
{
148+
not(self.is_not_padding_row())
149+
}
150+
}
151+
152+
impl<O, T: Copy + core::ops::Add<Output = O>> Sha2FlagsColsRef<'_, T> {
153+
pub fn is_not_padding_row(&self) -> O {
154+
*self.is_round_row + *self.is_digest_row
155+
}
156+
128157
pub fn is_padding_row(&self) -> O
129158
where
130159
O: FieldAlgebra,

0 commit comments

Comments
 (0)