Skip to content

Commit 1dc632f

Browse files
VanhGerweilzkm
andauthored
feat: add Sha256 precompile (#222)
* add temply test for sha256 syscall * add runtime/emualtor/witness support for sha256 syscall * fix memory channel * add missed cpu row * fix typo. and add debug log * fix: update memory every loop * feat: add columns for SHA circuit * feat: add trace generation for SHA precompile circuits * chore: change the columns in SHA extend phase * feat: add constraints for ShaExtend precompile * chore: make the logic functions support generic input sizes * chore: change the location of get_input_range function * chore: adjust the type of input * chore: change the columns in SHA compress table. * feat: add constraints for SHA compress table. * chore: change the columns in SHA compress sponge table. * chore: adjust SHA compress sponge operation. * feat: add constraints for SHA compress sponge table. * chore: adjust the sha extend tables * feat: add CTL for sha extend tables. * chore: rename function. * feat: add columns for sha compress * feat: add CTL for Sha compress * chore: refactor code * feat: wrap SHA Ch, Ma, Sigma0, Sigma1 to functions * chore: switch to byte format in sha extend * feat: optimize sha extend precompile * chore: change the name of wrapping add 4 function. * feat: optimize the Sha compress precompile by using byte representation. * chore: remove deadcode * refactor code styles. * chore: rename ShaCompress column element and delete debug * fix: fix cargo clippy & fmt check * chore: resolve conflict & change column element name. * opt: Reduce the number of carry bytes * chore: using u32 for wrapping add input in SHA --------- Co-authored-by: Angell Li <angell.l@zkm.io>
1 parent 6e5f694 commit 1dc632f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+5794
-15
lines changed

emulator/src/state.rs

+113
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,17 @@ impl Display for InstrumentedState {
498498
}
499499
}
500500

501+
pub const SHA_COMPRESS_K: [u32; 64] = [
502+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
503+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
504+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
505+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
506+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
507+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
508+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
509+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
510+
];
511+
501512
impl InstrumentedState {
502513
pub fn new(state: Box<State>, block_path: String) -> Box<Self> {
503514
Box::new(Self {
@@ -530,7 +541,109 @@ impl InstrumentedState {
530541
log::debug!("syscall {} {} {} {}", syscall_num, a0, a1, a2);
531542

532543
match syscall_num {
544+
0x300105 => {
545+
// SHA_EXTEND
546+
let w_ptr = a0;
547+
assert!(a1 == 0, "arg2 must be 0");
548+
549+
for i in 16..64 {
550+
// Read w[i-15].
551+
let w_i_minus_15 = self.state.memory.get_memory(w_ptr + (i - 15) * 4);
552+
// Compute `s0`.
553+
let s0 = w_i_minus_15.rotate_right(7)
554+
^ w_i_minus_15.rotate_right(18)
555+
^ (w_i_minus_15 >> 3);
556+
557+
// Read w[i-2].
558+
let w_i_minus_2 = self.state.memory.get_memory(w_ptr + (i - 2) * 4);
559+
// Compute `s1`.
560+
let s1 = w_i_minus_2.rotate_right(17)
561+
^ w_i_minus_2.rotate_right(19)
562+
^ (w_i_minus_2 >> 10);
563+
564+
// Read w[i-16].
565+
let w_i_minus_16 = self.state.memory.get_memory(w_ptr + (i - 16) * 4);
566+
567+
// Read w[i-7].
568+
let w_i_minus_7 = self.state.memory.get_memory(w_ptr + (i - 7) * 4);
569+
570+
// Compute `w_i`.
571+
let w_i = s1
572+
.wrapping_add(w_i_minus_16)
573+
.wrapping_add(s0)
574+
.wrapping_add(w_i_minus_7);
575+
576+
// Write w[i].
577+
log::debug!(
578+
"{:X}, {:X}, {:X} {:X} {:X} {:X}",
579+
s1,
580+
s0,
581+
w_i_minus_16,
582+
w_i_minus_7,
583+
w_i_minus_15,
584+
w_i_minus_2
585+
);
586+
self.state.memory.set_memory(w_ptr + i * 4, w_i);
587+
log::debug!("extend write {:X} {:X}", w_ptr + i * 4, w_i);
588+
}
589+
}
590+
0x010106 => {
591+
// SHA_COMPRESS
592+
let w_ptr = a0;
593+
let h_ptr = a1;
594+
let mut hx = [0u32; 8];
595+
for (i, hx_item) in hx.iter_mut().enumerate() {
596+
*hx_item = self.state.memory.get_memory(h_ptr + i as u32 * 4);
597+
}
598+
599+
let mut original_w = Vec::new();
600+
// Execute the "compress" phase.
601+
let mut a = hx[0];
602+
let mut b = hx[1];
603+
let mut c = hx[2];
604+
let mut d = hx[3];
605+
let mut e = hx[4];
606+
let mut f = hx[5];
607+
let mut g = hx[6];
608+
let mut h = hx[7];
609+
for i in 0..64 {
610+
let s1 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25);
611+
let ch = (e & f) ^ (!e & g);
612+
let w_i = self.state.memory.get_memory(w_ptr + i * 4);
613+
original_w.push(w_i);
614+
let temp1 = h
615+
.wrapping_add(s1)
616+
.wrapping_add(ch)
617+
.wrapping_add(SHA_COMPRESS_K[i as usize])
618+
.wrapping_add(w_i);
619+
let s0 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22);
620+
let maj = (a & b) ^ (a & c) ^ (b & c);
621+
let temp2 = s0.wrapping_add(maj);
622+
623+
h = g;
624+
g = f;
625+
f = e;
626+
e = d.wrapping_add(temp1);
627+
d = c;
628+
c = b;
629+
b = a;
630+
a = temp1.wrapping_add(temp2);
631+
}
632+
// Execute the "finalize" phase.
633+
let v = [a, b, c, d, e, f, g, h];
634+
for i in 0..8 {
635+
self.state
636+
.memory
637+
.set_memory(h_ptr + i as u32 * 4, hx[i].wrapping_add(v[i]));
638+
log::debug!(
639+
"write {:X} {:X}",
640+
h_ptr + i as u32 * 4,
641+
hx[i].wrapping_add(v[i])
642+
);
643+
}
644+
}
533645
0x010109 => {
646+
//keccak
534647
assert!((a0 & 3) == 0);
535648
assert!((a2 & 3) == 0);
536649
let bytes = (0..a1)

prover/examples/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ members = [
44
"sha2-rust/host",
55
"sha2-composition/host",
66
"sha2-go/host",
7+
"sha2-syscall/host",
78
"keccak/host",
89
"split-seg",
910
"prove-seg"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[workspace]
2+
[package]
3+
version = "0.1.0"
4+
name = "sha2-syscall"
5+
edition = "2021"
6+
7+
[dependencies]
8+
#zkm-runtime = { git = "https://github.com/zkMIPS/zkm", package = "zkm-runtime" }
9+
zkm-runtime = { path = "../../../../runtime/entrypoint" }
10+
digest = "0.10.4"
11+
cfg-if = "1.0"
12+
hex-literal = "0.2.2"
13+
14+
[features]
15+
default = ["std"]
16+
std = ["digest/std"]
17+
oid = ["digest/oid"] # Enable OID support. WARNING: Bumps MSRV to 1.57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
2+
#![allow(dead_code, clippy::unreadable_literal)]
3+
4+
pub const STATE_LEN: usize = 8;
5+
pub const BLOCK_LEN: usize = 16;
6+
7+
pub type State256 = [u32; STATE_LEN];
8+
pub type State512 = [u64; STATE_LEN];
9+
10+
/// Constants necessary for SHA-256 family of digests.
11+
pub const K32: [u32; 64] = [
12+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
13+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
14+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
15+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
16+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
17+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
18+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
19+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
20+
];
21+
22+
/// Constants necessary for SHA-256 family of digests.
23+
pub const K32X4: [[u32; 4]; 16] = [
24+
[K32[3], K32[2], K32[1], K32[0]],
25+
[K32[7], K32[6], K32[5], K32[4]],
26+
[K32[11], K32[10], K32[9], K32[8]],
27+
[K32[15], K32[14], K32[13], K32[12]],
28+
[K32[19], K32[18], K32[17], K32[16]],
29+
[K32[23], K32[22], K32[21], K32[20]],
30+
[K32[27], K32[26], K32[25], K32[24]],
31+
[K32[31], K32[30], K32[29], K32[28]],
32+
[K32[35], K32[34], K32[33], K32[32]],
33+
[K32[39], K32[38], K32[37], K32[36]],
34+
[K32[43], K32[42], K32[41], K32[40]],
35+
[K32[47], K32[46], K32[45], K32[44]],
36+
[K32[51], K32[50], K32[49], K32[48]],
37+
[K32[55], K32[54], K32[53], K32[52]],
38+
[K32[59], K32[58], K32[57], K32[56]],
39+
[K32[63], K32[62], K32[61], K32[60]],
40+
];
41+
42+
/// Constants necessary for SHA-512 family of digests.
43+
pub const K64: [u64; 80] = [
44+
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
45+
0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
46+
0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
47+
0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
48+
0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
49+
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
50+
0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
51+
0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
52+
0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
53+
0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
54+
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
55+
0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
56+
0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
57+
0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
58+
0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
59+
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
60+
0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
61+
0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
62+
0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
63+
0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817,
64+
];
65+
66+
/// Constants necessary for SHA-512 family of digests.
67+
pub const K64X2: [[u64; 2]; 40] = [
68+
[K64[1], K64[0]], [K64[3], K64[2]], [K64[5], K64[4]], [K64[7], K64[6]],
69+
[K64[9], K64[8]], [K64[11], K64[10]], [K64[13], K64[12]], [K64[15], K64[14]],
70+
[K64[17], K64[16]], [K64[19], K64[18]], [K64[21], K64[20]], [K64[23], K64[22]],
71+
[K64[25], K64[24]], [K64[27], K64[26]], [K64[29], K64[28]], [K64[31], K64[30]],
72+
[K64[33], K64[32]], [K64[35], K64[34]], [K64[37], K64[36]], [K64[39], K64[38]],
73+
[K64[41], K64[40]], [K64[43], K64[42]], [K64[45], K64[44]], [K64[47], K64[46]],
74+
[K64[49], K64[48]], [K64[51], K64[50]], [K64[53], K64[52]], [K64[55], K64[54]],
75+
[K64[57], K64[56]], [K64[59], K64[58]], [K64[61], K64[60]], [K64[63], K64[62]],
76+
[K64[65], K64[64]], [K64[67], K64[66]], [K64[69], K64[68]], [K64[71], K64[70]],
77+
[K64[73], K64[72]], [K64[75], K64[74]], [K64[77], K64[76]], [K64[79], K64[78]],
78+
];
79+
80+
pub const H256_224: State256 = [
81+
0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
82+
0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4,
83+
];
84+
85+
pub const H256_256: State256 = [
86+
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
87+
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
88+
];
89+
90+
pub const H512_224: State512 = [
91+
0x8c3d37c819544da2, 0x73e1996689dcd4d6, 0x1dfab7ae32ff9c82, 0x679dd514582f9fcf,
92+
0x0f6d2b697bd44da8, 0x77e36f7304c48942, 0x3f9d85a86a1d36c8, 0x1112e6ad91d692a1,
93+
];
94+
95+
pub const H512_256: State512 = [
96+
0x22312194fc2bf72c, 0x9f555fa3c84c64c2, 0x2393b86b6f53b151, 0x963877195940eabd,
97+
0x96283ee2a88effe3, 0xbe5e1e2553863992, 0x2b0199fc2c85b8aa, 0x0eb72ddc81c52ca2,
98+
];
99+
100+
pub const H512_384: State512 = [
101+
0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939,
102+
0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4,
103+
];
104+
105+
pub const H512_512: State512 = [
106+
0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
107+
0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
108+
];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
use crate::consts;
2+
use core::{fmt, slice::from_ref};
3+
use digest::{
4+
block_buffer::Eager,
5+
core_api::{
6+
AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, OutputSizeUser, TruncSide,
7+
UpdateCore, VariableOutputCore,
8+
},
9+
typenum::{Unsigned, U32, U64},
10+
HashMarker, InvalidOutputSize, Output,
11+
generic_array::GenericArray,
12+
};
13+
14+
/// Core block-level SHA-256 hasher with variable output size.
15+
///
16+
/// Supports initialization only for 28 and 32 byte output sizes,
17+
/// i.e. 224 and 256 bits respectively.
18+
#[derive(Clone)]
19+
pub struct Sha256VarCore {
20+
state: consts::State256,
21+
block_len: u64,
22+
}
23+
24+
impl HashMarker for Sha256VarCore {}
25+
26+
impl BlockSizeUser for Sha256VarCore {
27+
type BlockSize = U64;
28+
}
29+
30+
impl BufferKindUser for Sha256VarCore {
31+
type BufferKind = Eager;
32+
}
33+
34+
impl UpdateCore for Sha256VarCore {
35+
#[inline]
36+
fn update_blocks(&mut self, blocks: &[Block<Self>]) {
37+
self.block_len += blocks.len() as u64;
38+
compress256(&mut self.state, blocks);
39+
}
40+
}
41+
42+
impl OutputSizeUser for Sha256VarCore {
43+
type OutputSize = U32;
44+
}
45+
46+
impl VariableOutputCore for Sha256VarCore {
47+
const TRUNC_SIDE: TruncSide = TruncSide::Left;
48+
49+
#[inline]
50+
fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
51+
let state = match output_size {
52+
28 => consts::H256_224,
53+
32 => consts::H256_256,
54+
_ => return Err(InvalidOutputSize),
55+
};
56+
let block_len = 0;
57+
Ok(Self { state, block_len })
58+
}
59+
60+
#[inline]
61+
fn finalize_variable_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
62+
let bs = Self::BlockSize::U64;
63+
let bit_len = 8 * (buffer.get_pos() as u64 + bs * self.block_len);
64+
buffer.len64_padding_be(bit_len, |b| compress256(&mut self.state, from_ref(b)));
65+
66+
for (chunk, v) in out.chunks_exact_mut(4).zip(self.state.iter()) {
67+
chunk.copy_from_slice(&v.to_be_bytes());
68+
}
69+
}
70+
}
71+
72+
impl AlgorithmName for Sha256VarCore {
73+
#[inline]
74+
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
75+
f.write_str("Sha256")
76+
}
77+
}
78+
79+
impl fmt::Debug for Sha256VarCore {
80+
#[inline]
81+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82+
f.write_str("Sha256VarCore { ... }")
83+
}
84+
}
85+
86+
pub fn compress256(state: &mut [u32; 8], blocks: &[GenericArray<u8, U64>]) {
87+
// SAFETY: GenericArray<u8, U64> and [u8; 64] have
88+
// exactly the same memory layout
89+
let p = blocks.as_ptr() as *const [u8; 64];
90+
let blocks = unsafe { core::slice::from_raw_parts(p, blocks.len()) };
91+
zkm_runtime::io::compress(state, blocks)
92+
}

0 commit comments

Comments
 (0)