diff --git a/core/src/operations/and.rs b/core/src/operations/and.rs index a803dfdaa..375221c59 100644 --- a/core/src/operations/and.rs +++ b/core/src/operations/and.rs @@ -3,6 +3,8 @@ use sphinx_derive::AlignedBorrow; use crate::air::ByteAirBuilder; use crate::air::Word; +use crate::air::Word64; +use crate::air::WORD64_SIZE; use crate::bytes::event::ByteRecord; use crate::bytes::ByteLookupEvent; use crate::bytes::ByteOpcode; @@ -69,3 +71,64 @@ impl AndOperation { } } } + +/// A set of columns needed to compute the and of two word64s. +#[derive(AlignedBorrow, Default, Debug, Clone, Copy)] +#[repr(C)] +pub struct And64Operation { + /// The result of `x & y`. + pub value: Word64, +} + +impl And64Operation { + pub fn populate( + &mut self, + record: &mut ExecutionRecord, + shard: u32, + channel: u32, + x: u64, + y: u64, + ) -> u64 { + let expected = x & y; + let x_bytes = x.to_le_bytes(); + let y_bytes = y.to_le_bytes(); + for i in 0..WORD64_SIZE { + let and = x_bytes[i] & y_bytes[i]; + self.value[i] = F::from_canonical_u8(and); + + let byte_event = ByteLookupEvent { + shard, + channel, + opcode: ByteOpcode::AND, + a1: u32::from(and), + a2: 0, + b: u32::from(x_bytes[i]), + c: u32::from(y_bytes[i]), + }; + record.add_byte_lookup_event(byte_event); + } + expected + } + + pub fn eval>( + builder: &mut AB, + a: Word64, + b: Word64, + cols: And64Operation, + shard: AB::Var, + channel: impl Into + Copy, + is_real: AB::Var, + ) { + for i in 0..WORD64_SIZE { + builder.send_byte( + AB::F::from_canonical_u32(ByteOpcode::AND as u32), + cols.value[i], + a[i], + b[i], + shard, + channel, + is_real, + ); + } + } +} diff --git a/core/src/operations/not.rs b/core/src/operations/not.rs index 9703e38c6..d72359ae4 100644 --- a/core/src/operations/not.rs +++ b/core/src/operations/not.rs @@ -4,6 +4,8 @@ use sphinx_derive::AlignedBorrow; use crate::air::ByteAirBuilder; use crate::air::Word; +use crate::air::Word64; +use crate::air::WORD64_SIZE; use crate::bytes::event::ByteRecord; use crate::bytes::ByteOpcode; use crate::disassembler::WORD_SIZE; @@ -62,3 +64,58 @@ impl NotOperation { } } } + +/// A set of columns needed to compute the not of a word64. +#[derive(AlignedBorrow, Default, Debug, Clone, Copy)] +#[repr(C)] +pub struct Not64Operation { + /// The result of `!x`. + pub value: Word64, +} + +impl Not64Operation { + pub fn populate( + &mut self, + record: &mut impl ByteRecord, + shard: u32, + channel: u32, + x: u64, + ) -> u64 { + let expected = !x; + let x_bytes = x.to_le_bytes(); + for i in 0..WORD64_SIZE { + self.value[i] = F::from_canonical_u8(!x_bytes[i]); + } + record.add_u8_range_checks(shard, channel, &x_bytes); + expected + } + + pub fn eval>( + builder: &mut AB, + a: Word64, + cols: Not64Operation, + shard: impl Into + Copy, + channel: impl Into + Copy, + is_real: impl Into + Copy, + ) { + for i in (0..WORD64_SIZE).step_by(2) { + builder.send_byte_pair( + AB::F::from_canonical_u32(ByteOpcode::U8Range as u32), + AB::F::zero(), + AB::F::zero(), + a[i], + a[i + 1], + shard, + channel, + is_real, + ); + } + + // For any byte b, b + !b = 0xFF. + for i in 0..WORD64_SIZE { + builder + .when(is_real) + .assert_eq(cols.value[i] + a[i], AB::F::from_canonical_u8(u8::MAX)); + } + } +} diff --git a/core/src/runtime/record.rs b/core/src/runtime/record.rs index a0f195f28..47cd8759a 100644 --- a/core/src/runtime/record.rs +++ b/core/src/runtime/record.rs @@ -14,8 +14,8 @@ use crate::syscall::precompiles::blake2s::{Blake2sRoundChip, Blake2sRoundEvent}; use crate::syscall::precompiles::edwards::EdDecompressEvent; use crate::syscall::precompiles::keccak256::KeccakPermuteEvent; use crate::syscall::precompiles::sha256::{ShaCompressEvent, ShaExtendEvent}; -// use crate::syscall::precompiles::sha512::Sha512CompressChip; 512FIXME -// use crate::syscall::precompiles::sha512::Sha512CompressEvent; 512FIXME +use crate::syscall::precompiles::sha512::Sha512CompressChip; +use crate::syscall::precompiles::sha512::Sha512CompressEvent; use crate::syscall::precompiles::sha512::Sha512ExtendChip; use crate::syscall::precompiles::sha512::Sha512ExtendEvent; use crate::syscall::precompiles::{ECAddEvent, ECDoubleEvent}; @@ -105,7 +105,8 @@ pub struct ExecutionRecord { pub sha512_extend_events: Vec, - // pub sha512_compress_events: Vec, 512FIXME + pub sha512_compress_events: Vec, + pub keccak_permute_events: Vec, pub ed_add_events: Vec, @@ -237,12 +238,11 @@ impl EventLens for ExecutionRecord { } } -// 512FIXME -// impl EventLens for ExecutionRecord { -// fn events(&self) -> >::Events { -// &self.sha512_compress_events -// } -// } +impl EventLens for ExecutionRecord { + fn events(&self) -> >::Events { + &self.sha512_compress_events + } +} impl EventLens for ExecutionRecord { fn events(&self) -> >::Events { @@ -445,10 +445,10 @@ impl MachineRecord for ExecutionRecord { "sha512_extend_events".to_string(), self.sha512_extend_events.len(), ); - // stats.insert( - // "sha512_compress_events".to_string(), - // self.sha512_compress_events.len(), - // ); 512FIXME + stats.insert( + "sha512_compress_events".to_string(), + self.sha512_compress_events.len(), + ); stats.insert( "keccak_permute_events".to_string(), self.keccak_permute_events.len(), @@ -528,8 +528,8 @@ impl MachineRecord for ExecutionRecord { .append(&mut other.sha_compress_events); self.sha512_extend_events .append(&mut other.sha512_extend_events); - // self.sha512_compress_events - // .append(&mut other.sha512_compress_events); 512FIXME + self.sha512_compress_events + .append(&mut other.sha512_compress_events); self.keccak_permute_events .append(&mut other.keccak_permute_events); self.ed_add_events.append(&mut other.ed_add_events); @@ -858,10 +858,10 @@ impl MachineRecord for ExecutionRecord { } // SHA-512 compress events. - // first.sha512_compress_events = take(&mut self.sha512_compress_events); - // for (i, event) in first.sha512_compress_events.iter().enumerate() { - // self.nonce_lookup.insert(event.lookup_id, (i * 80) as u32); - // } 512FIXME + first.sha512_compress_events = take(&mut self.sha512_compress_events); + for (i, event) in first.sha512_compress_events.iter().enumerate() { + self.nonce_lookup.insert(event.lookup_id, i as u32); + } // Edwards curve add events. first.ed_add_events = take(&mut self.ed_add_events); diff --git a/core/src/runtime/syscall.rs b/core/src/runtime/syscall.rs index 7cc711050..a30a03936 100644 --- a/core/src/runtime/syscall.rs +++ b/core/src/runtime/syscall.rs @@ -19,8 +19,7 @@ use crate::syscall::precompiles::quad_field::{ }; use crate::syscall::precompiles::secp256k1::decompress::Secp256k1DecompressChip; use crate::syscall::precompiles::sha256::{ShaCompressChip, ShaExtendChip}; -// use crate::syscall::precompiles::sha512::{Sha512CompressChip, Sha512ExtendChip}; 512FIXME -use crate::syscall::precompiles::sha512::Sha512ExtendChip; +use crate::syscall::precompiles::sha512::{Sha512CompressChip, Sha512ExtendChip}; use crate::syscall::precompiles::weierstrass::{ WeierstrassAddAssignChip, WeierstrassDoubleAssignChip, }; @@ -109,7 +108,7 @@ pub enum SyscallCode { SHA512_EXTEND = 0x00_00_01_C1, /// Executes the `SHA512_COMPRESS` precompile. - SHA512_COMPRESS = 0x00_01_01_C2, + SHA512_COMPRESS = 0x00_00_01_C2, /// Executes the `COMMIT` precompile. COMMIT = 0x00_00_00_10, @@ -165,7 +164,7 @@ impl SyscallCode { 0x00_00_01_81 => SyscallCode::BLS12381_G2_DOUBLE, 0x00_01_01_ED => SyscallCode::BLAKE_2S_ROUND, 0x00_00_01_C1 => SyscallCode::SHA512_EXTEND, - 0x00_01_01_C2 => SyscallCode::SHA512_COMPRESS, + 0x00_00_01_C2 => SyscallCode::SHA512_COMPRESS, _ => panic!("invalid syscall number: {}", value), } } @@ -407,10 +406,10 @@ pub fn default_syscall_map() -> HashMap> { SyscallCode::SHA512_EXTEND, Arc::new(Sha512ExtendChip::new()), ); - // syscall_map.insert( - // SyscallCode::SHA512_COMPRESS, - // Arc::new(Sha512CompressChip::new()), - // ); + syscall_map.insert( + SyscallCode::SHA512_COMPRESS, + Arc::new(Sha512CompressChip::new()), + ); syscall_map.insert( SyscallCode::BLAKE_2S_ROUND, diff --git a/core/src/stark/air.rs b/core/src/stark/air.rs index 41418ee2b..a5c821703 100644 --- a/core/src/stark/air.rs +++ b/core/src/stark/air.rs @@ -33,7 +33,7 @@ pub(crate) mod riscv_chips { pub use crate::syscall::precompiles::keccak256::KeccakPermuteChip; pub use crate::syscall::precompiles::sha256::ShaCompressChip; pub use crate::syscall::precompiles::sha256::ShaExtendChip; - // pub use crate::syscall::precompiles::sha512::Sha512CompressChip; 512FIXME + pub use crate::syscall::precompiles::sha512::Sha512CompressChip; pub use crate::syscall::precompiles::sha512::Sha512ExtendChip; pub use crate::syscall::precompiles::weierstrass::WeierstrassAddAssignChip; pub use crate::syscall::precompiles::weierstrass::WeierstrassDoubleAssignChip; @@ -113,8 +113,8 @@ pub enum RiscvAir { Blake2sRound(Blake2sRoundChip), /// A precompile for sha512 extend. Sha512Extend(Sha512ExtendChip), - // /// A precompile for sha256 compress. - // Sha512Compress(Sha512CompressChip), 512FIXME + /// A precompile for sha256 compress. + Sha512Compress(Sha512CompressChip), } impl RiscvAir { @@ -171,8 +171,8 @@ impl RiscvAir { chips.push(RiscvAir::Blake2sRound(blake_2s_round)); let sha512_extend = Sha512ExtendChip; chips.push(RiscvAir::Sha512Extend(sha512_extend)); - // let sha512_compress = Sha512CompressChip; - // chips.push(RiscvAir::Sha512Compress(sha512_compress)); 512FIXME + let sha512_compress = Sha512CompressChip; + chips.push(RiscvAir::Sha512Compress(sha512_compress)); let div_rem = DivRemChip; chips.push(RiscvAir::DivRem(div_rem)); diff --git a/core/src/syscall/precompiles/sha512/compress/air.rs b/core/src/syscall/precompiles/sha512/compress/air.rs index 53cb84fe5..1cb523804 100644 --- a/core/src/syscall/precompiles/sha512/compress/air.rs +++ b/core/src/syscall/precompiles/sha512/compress/air.rs @@ -6,14 +6,16 @@ use p3_matrix::Matrix; use super::{ columns::{Sha512CompressCols, NUM_SHA512_COMPRESS_COLS}, - Sha512CompressChip, SHA512_COMPRESS_K, + Sha512CompressChip, }; use crate::{ - air::{AluAirBuilder, BaseAirBuilder, MemoryAirBuilder, Word, WordAirBuilder}, + air::{ + AluAirBuilder, BaseAirBuilder, ByteAirBuilder, MemoryAirBuilder, Word64, WordAirBuilder, + }, + bytes::ByteOpcode, memory::MemoryCols, operations::{ - Add5Operation, AddOperation, AndOperation, FixedRotateRightOperation, NotOperation, - XorOperation, + Add64Operation, And64Operation, FixedRotateRight64Operation, Not64Operation, Xor64Operation, }, runtime::SyscallCode, }; @@ -40,18 +42,13 @@ where .when_transition() .assert_eq(local.nonce + AB::Expr::one(), next.nonce); - self.eval_control_flow_flags(builder, local, next); + // Assert that is_real is a bool. + builder.assert_bool(local.is_real); self.eval_memory(builder, local); - self.eval_compression_ops(builder, local, next); - - self.eval_finalize_ops(builder, local); + self.eval_compression_ops(builder, local); - builder.assert_eq( - local.start, - local.is_real * local.octet[0] * local.octet_num[0], - ); builder.receive_syscall( local.shard, local.channel, @@ -60,502 +57,383 @@ where AB::F::from_canonical_u32(SyscallCode::SHA512_COMPRESS.syscall_id()), local.w_ptr, local.h_ptr, - local.start, + local.is_real, ); } } impl Sha512CompressChip { - fn eval_control_flow_flags( + /// Constrains that memory accesses are correct. + fn eval_memory( &self, builder: &mut AB, local: &Sha512CompressCols, - next: &Sha512CompressCols, ) { - // Verify that all of the octet columns are bool. - for i in 0..8 { - builder.assert_bool(local.octet[i]); - } - - // Verify that exactly one of the octet columns is true. - let mut octet_sum = AB::Expr::zero(); - for i in 0..8 { - octet_sum += local.octet[i].into(); - } - builder.assert_one(octet_sum); - - // Verify that the first row's octet value is correct. - builder.when_first_row().assert_one(local.octet[0]); - - // Verify correct transition for octet column. - for i in 0..8 { - builder - .when_transition() - .when(local.octet[i]) - .assert_one(next.octet[(i + 1) % 8]) - } - - // Verify that all of the octet_num columns are bool. - for i in 0..10 { - builder.assert_bool(local.octet_num[i]); - } - - // Verify that exactly one of the octet_num columns is true. - let mut octet_num_sum = AB::Expr::zero(); - for i in 0..10 { - octet_num_sum += local.octet_num[i].into(); - } - builder.assert_one(octet_num_sum); - - // The first row should have octet_num[0] = 1 if it's real. - builder.when_first_row().assert_one(local.octet_num[0]); - - // If current row is not last of an octet and next row is real, octet_num should be the same. - for i in 0..10 { - builder - .when_transition() - .when_not(local.octet[7]) - .assert_eq(local.octet_num[i], next.octet_num[i]); - } - - // If current row is last of an octet and next row is real, octet_num should rotate by 1. - for i in 0..10 { - builder - .when_transition() - .when(local.octet[7]) - .assert_eq(local.octet_num[i], next.octet_num[(i + 1) % 10]); - } - - // Constrain A-H columns - let vars = [ - local.a, local.b, local.c, local.d, local.e, local.f, local.g, local.h, - ]; - let next_vars = [ - next.a, next.b, next.c, next.d, next.e, next.f, next.g, next.h, - ]; - for (i, var) in vars.iter().enumerate() { - // For all initialize and finalize cycles, A-H should be the same in the next row. The - // last cycle is an exception since the next row must be a new 80-cycle loop or nonreal. - builder - .when_transition() - .when(local.octet_num[0] + local.octet_num[9] * (AB::Expr::one() - local.octet[7])) - .assert_word_eq(*var, next_vars[i]); - - // When column is read from memory during init, is should be equal to the memory value. - builder - .when_transition() - .when(local.octet_num[0] * local.octet[i]) - .assert_word_eq(*var, *local.mem.value()); - } - - // Assert that the is_initialize flag is correct. - builder.assert_eq(local.is_initialize, local.octet_num[0] * local.is_real); - - // Assert that the is_compression flag is correct. - builder.assert_eq( - local.is_compression, - (local.octet_num[1] - + local.octet_num[2] - + local.octet_num[3] - + local.octet_num[4] - + local.octet_num[5] - + local.octet_num[6] - + local.octet_num[7] - + local.octet_num[8]) - * local.is_real, - ); - - // Assert that the is_finalize flag is correct. - builder.assert_eq(local.is_finalize, local.octet_num[9] * local.is_real); - - builder.assert_eq( - local.is_last_row.into(), - local.octet[7] * local.octet_num[9], + // Assert `i` was read and written to correctly. + builder.eval_memory_access( + local.shard, + local.channel, + local.clk, + local.h_ptr + AB::F::from_canonical_u32(8 * 8), + &local.i_mem, + local.is_real, ); - - // If this row is real and not the last cycle, then next row should have same inputs - builder - .when_transition() - .when(local.is_real) - .when_not(local.is_last_row) - .assert_eq(local.shard, next.shard); - builder - .when_transition() - .when(local.is_real) - .when_not(local.is_last_row) - .assert_eq(local.clk, next.clk); - builder - .when_transition() - .when_not(local.is_last_row) - .assert_eq(local.channel, next.channel); + let reduced_prev_i = local.i_mem.prev_value().reduce::(); builder - .when_transition() .when(local.is_real) - .when_not(local.is_last_row) - .assert_eq(local.w_ptr, next.w_ptr); + .assert_eq(reduced_prev_i, local.i); + let reduced_next_i = local.i_mem.value().reduce::(); builder - .when_transition() .when(local.is_real) - .when_not(local.is_last_row) - .assert_eq(local.h_ptr, next.h_ptr); - - // Assert that is_real is a bool. - builder.assert_bool(local.is_real); - - // If this row is real and not the last cycle, then next row should also be real. - builder - .when_transition() - .when(local.is_real) - .when_not(local.is_last_row) - .assert_one(next.is_real); - - // Once the is_real flag is changed to false, it should not be changed back. - builder - .when_transition() - .when_not(local.is_real) - .assert_zero(next.is_real); - - // Assert that the table ends in nonreal columns. Since each compress ecall is 80 cycles and - // the table is padded to a power of 2, the last row of the table should always be padding. - builder.when_last_row().assert_zero(local.is_real); - } - - /// Constrains that memory address is correct and that memory is correctly written/read. - fn eval_memory( - &self, - builder: &mut AB, - local: &Sha512CompressCols, - ) { - builder.eval_memory_access( + .assert_eq(reduced_next_i, local.i + AB::Expr::one()); + builder.send_byte( + ByteOpcode::LTU.as_field::(), + AB::F::one(), + local.i, + AB::F::from_canonical_usize(80), local.shard, local.channel, - local.clk + local.is_finalize, - local.mem_addr, - &local.mem, - local.is_initialize + local.is_compression + local.is_finalize, - ); - - // Calculate the current cycle_num. - let mut cycle_num = AB::Expr::zero(); - for i in 0..10 { - cycle_num += local.octet_num[i] * AB::Expr::from_canonical_usize(i); - } - - // Calculate the current step of the cycle 8. - let mut cycle_step = AB::Expr::zero(); - for i in 0..8 { - cycle_step += local.octet[i] * AB::Expr::from_canonical_usize(i); - } - - // Verify correct mem address for initialize phase - builder.when(local.is_initialize).assert_eq( - local.mem_addr, - local.h_ptr + cycle_step.clone() * AB::Expr::from_canonical_u32(4), - ); - - // Verify correct mem address for compression phase - builder.when(local.is_compression).assert_eq( - local.mem_addr, - local.w_ptr - + (((cycle_num - AB::Expr::one()) * AB::Expr::from_canonical_u32(8)) - + cycle_step.clone()) - * AB::Expr::from_canonical_u32(4), - ); - - // Verify correct mem address for finalize phase - builder.when(local.is_finalize).assert_eq( - local.mem_addr, - local.h_ptr + cycle_step.clone() * AB::Expr::from_canonical_u32(4), - ); - - // In the initialize phase, verify that local.a, local.b, ... is correctly read from memory - // and does not change - let vars = [ - local.a, local.b, local.c, local.d, local.e, local.f, local.g, local.h, - ]; - for (i, var) in vars.iter().enumerate() { - builder - .when(local.is_initialize) - .when(local.octet[i]) - .assert_word_eq(*var, *local.mem.prev_value()); - builder - .when(local.is_initialize) - .when(local.octet[i]) - .assert_word_eq(*var, *local.mem.value()); + local.is_real, + ); + + for j in 0..2 { + // Assert `w_i` was read correctly. + builder.eval_memory_access( + local.shard, + local.channel, + local.clk, + local.w_ptr + + local.i * AB::F::from_canonical_u32(8) + + AB::F::from_canonical_u32(j as u32 * 4), + &local.w_i[j], + local.is_real, + ); + // Assert `k_i` was read correctly. + builder.eval_memory_access( + local.shard, + local.channel, + local.clk, + local.h_ptr + + AB::F::from_canonical_u32(9 * 8) + + local.i * AB::F::from_canonical_u32(8) + + AB::F::from_canonical_u32(j as u32 * 4), + &local.k_i[j], + local.is_real, + ); + // Assert `h` was read correctly - the result is checked at the end. + for m in 0..8 { + builder.eval_memory_access( + local.shard, + local.channel, + local.clk, + local.h_ptr + AB::F::from_canonical_u32(m as u32 * 8 + j as u32 * 4), + &local.h[m * 2 + j], + local.is_real, + ); + } } - - // During compression, verify that memory is read only and does not change. - builder - .when(local.is_compression) - .assert_word_eq(*local.mem.prev_value(), *local.mem.value()); - - // In the finalize phase, verify that the correct value is written to memory. - builder - .when(local.is_finalize) - .assert_word_eq(*local.mem.value(), local.finalize_add.value); } fn eval_compression_ops( &self, builder: &mut AB, local: &Sha512CompressCols, - next: &Sha512CompressCols, ) { - // Constrain k column which loops over 64 constant values. - for i in 0..64 { - let octet_num = i / 8; - let inner_index = i % 8; - builder - .when(local.octet_num[octet_num + 1] * local.octet[inner_index]) - .assert_all_eq(local.k, Word::::from(SHA512_COMPRESS_K[i])); + let k_i_lo = local.k_i[0].value(); + let k_i_hi = local.k_i[1].value(); + let k_i: Word64 = k_i_lo.into_iter().chain(*k_i_hi).collect(); + + let w_i_lo = local.w_i[0].value(); + let w_i_hi = local.w_i[1].value(); + let w_i: Word64 = w_i_lo.into_iter().chain(*w_i_hi).collect(); + + // Assemble the loaded state into `Word64`s. + fn helper(local: &Sha512CompressCols, i: usize) -> Word64 { + local.h[i * 2] + .prev_value() + .clone() + .into_iter() + .chain(local.h[i * 2 + 1].prev_value().clone()) + .collect() } - - // S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25). - // Calculate e rightrotate 6. - FixedRotateRightOperation::::eval( + let a = helper(local, 0); + let b = helper(local, 1); + let c = helper(local, 2); + let d = helper(local, 3); + let e = helper(local, 4); + let f = helper(local, 5); + let g = helper(local, 6); + let h = helper(local, 7); + + // S1 := (e rightrotate 14) xor (e rightrotate 18) xor (e rightrotate 41) + // Calculate e rightrotate 14. + FixedRotateRight64Operation::::eval( builder, - local.e, - 6, - local.e_rr_6, + e, + 14, + local.e_rr_14, local.shard, &local.channel, - local.is_compression, + local.is_real, ); - // Calculate e rightrotate 11. - FixedRotateRightOperation::::eval( + // Calculate e rightrotate 18. + FixedRotateRight64Operation::::eval( builder, - local.e, - 11, - local.e_rr_11, + e, + 18, + local.e_rr_18, local.shard, &local.channel, - local.is_compression, + local.is_real, ); - // Calculate e rightrotate 25. - FixedRotateRightOperation::::eval( + // Calculate e rightrotate 41. + FixedRotateRight64Operation::::eval( builder, - local.e, - 25, - local.e_rr_25, + e, + 41, + local.e_rr_41, local.shard, &local.channel, - local.is_compression, + local.is_real, ); - // Calculate (e rightrotate 6) xor (e rightrotate 11). - XorOperation::::eval( + // Calculate (e rightrotate 14) xor (e rightrotate 18). + Xor64Operation::::eval( builder, - local.e_rr_6.value, - local.e_rr_11.value, + local.e_rr_14.value, + local.e_rr_18.value, local.s1_intermediate, local.shard, &local.channel, - local.is_compression, + local.is_real, ); - // Calculate S1 := ((e rightrotate 6) xor (e rightrotate 11)) xor (e rightrotate 25). - XorOperation::::eval( + // Calculate S1 := ((e rightrotate 14) xor (e rightrotate 18)) xor (e rightrotate 41). + Xor64Operation::::eval( builder, local.s1_intermediate.value, - local.e_rr_25.value, + local.e_rr_41.value, local.s1, local.shard, &local.channel, - local.is_compression, + local.is_real, ); // Calculate ch := (e and f) xor ((not e) and g). // Calculate e and f. - AndOperation::::eval( + And64Operation::::eval( builder, - local.e, - local.f, + e, + f, local.e_and_f, local.shard, local.channel, - local.is_compression, + local.is_real, ); // Calculate not e. - NotOperation::::eval( + Not64Operation::::eval( builder, - local.e, + e, local.e_not, local.shard, local.channel, - local.is_compression, + local.is_real, ); // Calculate (not e) and g. - AndOperation::::eval( + And64Operation::::eval( builder, local.e_not.value, - local.g, + g, local.e_not_and_g, local.shard, local.channel, - local.is_compression, + local.is_real, ); // Calculate ch := (e and f) xor ((not e) and g). - XorOperation::::eval( + Xor64Operation::::eval( builder, local.e_and_f.value, local.e_not_and_g.value, local.ch, local.shard, &local.channel, - local.is_compression, + local.is_real, ); // Calculate temp1 := h + S1 + ch + k[i] + w[i]. - Add5Operation::::eval( + Add64Operation::::eval( + builder, + h, + local.s1.value, + local.temp1[0], + local.shard, + local.channel, + local.is_real.into(), + ); + Add64Operation::::eval( + builder, + local.temp1[0].value, + local.ch.value, + local.temp1[1], + local.shard, + local.channel, + local.is_real.into(), + ); + Add64Operation::::eval( + builder, + local.temp1[1].value, + k_i, + local.temp1[2], + local.shard, + local.channel, + local.is_real.into(), + ); + Add64Operation::::eval( builder, - &[ - local.h, - local.s1.value, - local.ch.value, - local.k, - local.mem.access.value, - ], + local.temp1[2].value, + w_i, + local.temp1[3], local.shard, local.channel, - local.is_compression, - local.temp1, + local.is_real.into(), ); - // Calculate S0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22). - // Calculate a rightrotate 2. - FixedRotateRightOperation::::eval( + // Calculate S0 := (a rightrotate 28) xor (a rightrotate 34) xor (a rightrotate 39). + // Calculate a rightrotate 28. + FixedRotateRight64Operation::::eval( builder, - local.a, - 2, - local.a_rr_2, + a, + 28, + local.a_rr_28, local.shard, &local.channel, - local.is_compression, + local.is_real, ); - // Calculate a rightrotate 13. - FixedRotateRightOperation::::eval( + // Calculate a rightrotate 34. + FixedRotateRight64Operation::::eval( builder, - local.a, - 13, - local.a_rr_13, + a, + 34, + local.a_rr_34, local.shard, &local.channel, - local.is_compression, + local.is_real, ); // Calculate a rightrotate 22. - FixedRotateRightOperation::::eval( + FixedRotateRight64Operation::::eval( builder, - local.a, - 22, - local.a_rr_22, + a, + 39, + local.a_rr_39, local.shard, &local.channel, - local.is_compression, + local.is_real, ); - // Calculate (a rightrotate 2) xor (a rightrotate 13). - XorOperation::::eval( + // Calculate (a rightrotate 28) xor (a rightrotate 34). + Xor64Operation::::eval( builder, - local.a_rr_2.value, - local.a_rr_13.value, + local.a_rr_28.value, + local.a_rr_34.value, local.s0_intermediate, local.shard, &local.channel, - local.is_compression, + local.is_real, ); - // Calculate S0 := ((a rightrotate 2) xor (a rightrotate 13)) xor (a rightrotate 22). - XorOperation::::eval( + // Calculate S0 := (a rightrotate 28) xor (a rightrotate 34) xor (a rightrotate 39). + Xor64Operation::::eval( builder, local.s0_intermediate.value, - local.a_rr_22.value, + local.a_rr_39.value, local.s0, local.shard, &local.channel, - local.is_compression, + local.is_real, ); // Calculate maj := (a and b) xor (a and c) xor (b and c). // Calculate a and b. - AndOperation::::eval( + And64Operation::::eval( builder, - local.a, - local.b, + a, + b, local.a_and_b, local.shard, local.channel, - local.is_compression, + local.is_real, ); // Calculate a and c. - AndOperation::::eval( + And64Operation::::eval( builder, - local.a, - local.c, + a, + c, local.a_and_c, local.shard, local.channel, - local.is_compression, + local.is_real, ); // Calculate b and c. - AndOperation::::eval( + And64Operation::::eval( builder, - local.b, - local.c, + b, + c, local.b_and_c, local.shard, local.channel, - local.is_compression, + local.is_real, ); // Calculate (a and b) xor (a and c). - XorOperation::::eval( + Xor64Operation::::eval( builder, local.a_and_b.value, local.a_and_c.value, local.maj_intermediate, local.shard, &local.channel, - local.is_compression, + local.is_real, ); // Calculate maj := ((a and b) xor (a and c)) xor (b and c). - XorOperation::::eval( + Xor64Operation::::eval( builder, local.maj_intermediate.value, local.b_and_c.value, local.maj, local.shard, &local.channel, - local.is_compression, + local.is_real, ); // Calculate temp2 := s0 + maj. - AddOperation::::eval( + Add64Operation::::eval( builder, local.s0.value, local.maj.value, local.temp2, local.shard, local.channel, - local.is_compression.into(), + local.is_real.into(), ); // Calculate d + temp1 for the new value of e. - AddOperation::::eval( + Add64Operation::::eval( builder, - local.d, - local.temp1.value, + d, + local.temp1[3].value, local.d_add_temp1, local.shard, local.channel, - local.is_compression.into(), + local.is_real.into(), ); // Calculate temp1 + temp2 for the new value of a. - AddOperation::::eval( + Add64Operation::::eval( builder, - local.temp1.value, + local.temp1[3].value, local.temp2.value, local.temp1_add_temp2, local.shard, local.channel, - local.is_compression.into(), + local.is_real.into(), ); + // Assert the values were correctly updated according to: // h := g // g := f // f := e @@ -564,75 +442,43 @@ impl Sha512CompressChip { // c := b // b := a // a := temp1 + temp2 - builder - .when_transition() - .when(local.is_compression) - .assert_word_eq(next.h, local.g); - builder - .when_transition() - .when(local.is_compression) - .assert_word_eq(next.g, local.f); - builder - .when_transition() - .when(local.is_compression) - .assert_word_eq(next.f, local.e); - builder - .when_transition() - .when(local.is_compression) - .assert_word_eq(next.e, local.d_add_temp1.value); - builder - .when_transition() - .when(local.is_compression) - .assert_word_eq(next.d, local.c); - builder - .when_transition() - .when(local.is_compression) - .assert_word_eq(next.c, local.b); - builder - .when_transition() - .when(local.is_compression) - .assert_word_eq(next.b, local.a); - builder - .when_transition() - .when(local.is_compression) - .assert_word_eq(next.a, local.temp1_add_temp2.value); - } - fn eval_finalize_ops( - &self, - builder: &mut AB, - local: &Sha512CompressCols, - ) { - // In the finalize phase, need to execute h[0] + a, h[1] + b, ..., h[7] + h, for each of the - // phase's 8 rows. - // We can get the needed operand (a,b,c,...,h) by doing an inner product between octet and - // [a,b,c,...,h] which will act as a selector. - let add_operands = [ - local.a, local.b, local.c, local.d, local.e, local.f, local.g, local.h, - ]; - let zero = AB::Expr::zero(); - let mut filtered_operand = Word([zero.clone(), zero.clone(), zero.clone(), zero]); - for (i, operand) in local.octet.iter().zip(add_operands.iter()) { - for j in 0..4 { - filtered_operand.0[j] += *i * operand.0[j]; - } + fn helper2(local: &Sha512CompressCols, i: usize) -> Word64 { + local.h[i * 2] + .value() + .clone() + .into_iter() + .chain(local.h[i * 2 + 1].value().clone()) + .collect() + } + let next_a = helper2(local, 0); + let next_b = helper2(local, 1); + let next_c = helper2(local, 2); + let next_d = helper2(local, 3); + let next_e = helper2(local, 4); + let next_f = helper2(local, 5); + let next_g = helper2(local, 6); + let next_h = helper2(local, 7); + + fn assert_word64_eq( + builder: &mut AB, + is_real: AB::Var, + left: Word64, + right: Word64, + ) { + let l = left.to_le_words(); + let r = right.to_le_words(); + builder.when(is_real).assert_word_eq(l[0], r[0]); + builder.when(is_real).assert_word_eq(l[1], r[1]); } - builder - .when(local.is_finalize) - .assert_word_eq(filtered_operand, local.finalized_operand.map(|x| x.into())); - - // finalize_add.result = h[i] + finalized_operand - AddOperation::::eval( - builder, - local.mem.prev_value, - local.finalized_operand, - local.finalize_add, - local.shard, - local.channel, - local.is_finalize.into(), - ); - - // Memory write is constrained in constrain_memory. + assert_word64_eq(builder, local.is_real, next_h, g); + assert_word64_eq(builder, local.is_real, next_g, f); + assert_word64_eq(builder, local.is_real, next_f, e); + assert_word64_eq(builder, local.is_real, next_e, local.d_add_temp1.value); + assert_word64_eq(builder, local.is_real, next_d, c); + assert_word64_eq(builder, local.is_real, next_c, b); + assert_word64_eq(builder, local.is_real, next_b, a); + assert_word64_eq(builder, local.is_real, next_a, local.temp1_add_temp2.value); } } diff --git a/core/src/syscall/precompiles/sha512/compress/columns.rs b/core/src/syscall/precompiles/sha512/compress/columns.rs index 5af27822f..ae562b23e 100644 --- a/core/src/syscall/precompiles/sha512/compress/columns.rs +++ b/core/src/syscall/precompiles/sha512/compress/columns.rs @@ -3,11 +3,9 @@ use std::mem::size_of; use sphinx_derive::AlignedBorrow; use crate::{ - air::Word, - memory::MemoryReadWriteCols, + memory::{MemoryReadCols, MemoryWriteCols}, operations::{ - Add5Operation, AddOperation, AndOperation, FixedRotateRightOperation, NotOperation, - XorOperation, + Add64Operation, And64Operation, FixedRotateRight64Operation, Not64Operation, Xor64Operation, }, }; @@ -32,82 +30,50 @@ pub struct Sha512CompressCols { pub w_ptr: T, pub h_ptr: T, - pub start: T, + pub i_mem: MemoryWriteCols, + pub i: T, + pub w_i: [MemoryReadCols; 2], + pub k_i: [MemoryReadCols; 2], - /// Which cycle within the octet we are currently processing. - pub octet: [T; 8], + pub h: [MemoryWriteCols; 16], - /// This will specify which octet we are currently processing. - /// - The first octet is for initialize. - /// - The next 8 octets are for compress. - /// - The last octet is for finalize. - pub octet_num: [T; 10], + pub e_rr_14: FixedRotateRight64Operation, + pub e_rr_18: FixedRotateRight64Operation, + pub e_rr_41: FixedRotateRight64Operation, + pub s1_intermediate: Xor64Operation, + /// `S1 := (e rightrotate 14) xor (e rightrotate 18) xor (e rightrotate 41)`. + pub s1: Xor64Operation, - /// Memory access. During init and compression, this is read only. During finalize, this is - /// used to write the result into memory. - pub mem: MemoryReadWriteCols, - /// Current memory address being written/read. During init and finalize, this is A-H. During - /// compression, this is w[i] being read only. - pub mem_addr: T, - - pub a: Word, - pub b: Word, - pub c: Word, - pub d: Word, - pub e: Word, - pub f: Word, - pub g: Word, - pub h: Word, - - /// Current value of K[i]. This is a constant array that loops around every 64 iterations. - pub k: Word, - - pub e_rr_6: FixedRotateRightOperation, - pub e_rr_11: FixedRotateRightOperation, - pub e_rr_25: FixedRotateRightOperation, - pub s1_intermediate: XorOperation, - /// `S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25)`. - pub s1: XorOperation, - - pub e_and_f: AndOperation, - pub e_not: NotOperation, - pub e_not_and_g: AndOperation, + pub e_and_f: And64Operation, + pub e_not: Not64Operation, + pub e_not_and_g: And64Operation, /// `ch := (e and f) xor ((not e) and g)`. - pub ch: XorOperation, + pub ch: Xor64Operation, /// `temp1 := h + S1 + ch + k[i] + w[i]`. - pub temp1: Add5Operation, - - pub a_rr_2: FixedRotateRightOperation, - pub a_rr_13: FixedRotateRightOperation, - pub a_rr_22: FixedRotateRightOperation, - pub s0_intermediate: XorOperation, - /// `S0 := (a rightrotate 2) xor (a rightrotate 13) xor (a rightrotate 22)`. - pub s0: XorOperation, - - pub a_and_b: AndOperation, - pub a_and_c: AndOperation, - pub b_and_c: AndOperation, - pub maj_intermediate: XorOperation, + pub temp1: [Add64Operation; 4], + + pub a_rr_28: FixedRotateRight64Operation, + pub a_rr_34: FixedRotateRight64Operation, + pub a_rr_39: FixedRotateRight64Operation, + pub s0_intermediate: Xor64Operation, + /// `S0 := (a rightrotate 28) xor (a rightrotate 34) xor (a rightrotate 39)`. + pub s0: Xor64Operation, + + pub a_and_b: And64Operation, + pub a_and_c: And64Operation, + pub b_and_c: And64Operation, + pub maj_intermediate: Xor64Operation, /// `maj := (a and b) xor (a and c) xor (b and c)`. - pub maj: XorOperation, + pub maj: Xor64Operation, /// `temp2 := S0 + maj`. - pub temp2: AddOperation, + pub temp2: Add64Operation, /// The next value of `e` is `d + temp1`. - pub d_add_temp1: AddOperation, + pub d_add_temp1: Add64Operation, /// The next value of `a` is `temp1 + temp2`. - pub temp1_add_temp2: AddOperation, - - /// During finalize, this is one of a-h and is being written into `mem`. - pub finalized_operand: Word, - pub finalize_add: AddOperation, - - pub is_initialize: T, - pub is_compression: T, - pub is_finalize: T, - pub is_last_row: T, + pub temp1_add_temp2: Add64Operation, pub is_real: T, } diff --git a/core/src/syscall/precompiles/sha512/compress/execute.rs b/core/src/syscall/precompiles/sha512/compress/execute.rs index 93d6b2dc6..4fdb95c22 100644 --- a/core/src/syscall/precompiles/sha512/compress/execute.rs +++ b/core/src/syscall/precompiles/sha512/compress/execute.rs @@ -9,7 +9,7 @@ use crate::{ impl Syscall for Sha512CompressChip { fn num_extra_cycles(&self) -> u32 { - 1 + 0 } fn execute(&self, rt: &mut SyscallContext<'_, '_>, arg1: u32, arg2: u32) -> Option { @@ -18,20 +18,39 @@ impl Syscall for Sha512CompressChip { assert_ne!(w_ptr, h_ptr); let start_clk = rt.clk; - let mut h_read_records = Vec::new(); - let mut w_i_read_records = Vec::new(); let mut h_write_records = Vec::new(); + // FIXME + fn u32_vec_to_u64(val: Vec) -> u64 { + u64::from_le_bytes( + val.into_iter() + .flat_map(|x| x.to_le_bytes()) + .collect::>() + .try_into() + .unwrap(), + ) + } + // Execute the "initialize" phase where we read in the h values. - let mut hx = [0u32; 8]; - for i in 0..8 { - let (record, value) = rt.mr(h_ptr + i as u32 * 4); - h_read_records.push(record); - hx[i] = value; + let mut hx = [0u64; 8]; + for j in 0..8 { + let values = rt.slice_unsafe(h_ptr + j * 8, 2); + hx[j as usize] = u32_vec_to_u64(values); } - let mut original_w = Vec::new(); - // Execute the "compress" phase. + // The `i` index is at the end of the `h_ptr` state + let i = rt.word_unsafe(h_ptr + 8 * 8); + assert!(i < 80); + + // The constants `k` are copied by the guest to the end of the state pointer + let (k_i_read_records, k_i) = rt.mr_slice(h_ptr + (9 * 8) + i * 8, 2); + let k_i = u32_vec_to_u64(k_i); + assert_eq!(k_i, SHA512_COMPRESS_K[i as usize]); + + let (w_i_read_records, w_i) = rt.mr_slice(w_ptr + i * 8, 2); + let w_i = u32_vec_to_u64(w_i); + + // Execute the "compress" iteration. let mut a = hx[0]; let mut b = hx[1]; let mut c = hx[2]; @@ -40,40 +59,44 @@ impl Syscall for Sha512CompressChip { let mut f = hx[5]; let mut g = hx[6]; let mut h = hx[7]; - for i in 0..64 { - let s1 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25); - let ch = (e & f) ^ (!e & g); - let (record, w_i) = rt.mr(w_ptr + i * 4); - original_w.push(w_i); - w_i_read_records.push(record); - let temp1 = h - .wrapping_add(s1) - .wrapping_add(ch) - .wrapping_add(SHA512_COMPRESS_K[i as usize]) - .wrapping_add(w_i); - let s0 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22); - let maj = (a & b) ^ (a & c) ^ (b & c); - let temp2 = s0.wrapping_add(maj); - h = g; - g = f; - f = e; - e = d.wrapping_add(temp1); - d = c; - c = b; - b = a; - a = temp1.wrapping_add(temp2); + let s1 = e.rotate_right(14) ^ e.rotate_right(18) ^ e.rotate_right(41); + let ch = (e & f) ^ (!e & g); + let temp1 = h + .wrapping_add(s1) + .wrapping_add(ch) + .wrapping_add(SHA512_COMPRESS_K[i as usize]) + .wrapping_add(w_i); + let s0 = a.rotate_right(28) ^ a.rotate_right(34) ^ a.rotate_right(39); + let maj = (a & b) ^ (a & c) ^ (b & c); + let temp2 = s0.wrapping_add(maj); + + h = g; + g = f; + f = e; + e = d.wrapping_add(temp1); + d = c; + c = b; + b = a; + a = temp1.wrapping_add(temp2); + + // FIXME + fn u64_to_u32x2(n: u64) -> [u32; 2] { + let n = n.to_le_bytes(); + [ + u32::from_le_bytes(n[..4].try_into().unwrap()), + u32::from_le_bytes(n[4..].try_into().unwrap()), + ] } - // Increment the clk by 1 before writing to h, since we've already read h at the start_clk - // during the initialization phase. - rt.clk += 1; - // Execute the "finalize" phase. + // Execute the "finalize" phase of updating the memory. let v = [a, b, c, d, e, f, g, h]; - for i in 0..8 { - let record = rt.mw(h_ptr + i as u32 * 4, hx[i].wrapping_add(v[i])); + let v: Vec = v.into_iter().flat_map(u64_to_u32x2).collect(); + for i in 0..16 { + let record = rt.mw(h_ptr + i as u32 * 4, v[i]); h_write_records.push(record); } + let i_write_record = rt.mw(h_ptr + 8 * 8, i.wrapping_add(1)); // Push the SHA512 extend event. let lookup_id = rt.syscall_lookup_id; @@ -88,11 +111,14 @@ impl Syscall for Sha512CompressChip { clk: start_clk, w_ptr, h_ptr, - w: original_w, + w_i, + i, + k_i, h: hx, - h_read_records: h_read_records.try_into().unwrap(), - w_i_read_records, + w_i_read_records: w_i_read_records.try_into().unwrap(), h_write_records: h_write_records.try_into().unwrap(), + k_i_read_records: k_i_read_records.try_into().unwrap(), + i_write_record, }); None diff --git a/core/src/syscall/precompiles/sha512/compress/mod.rs b/core/src/syscall/precompiles/sha512/compress/mod.rs index 7eb7013aa..e9c903e84 100644 --- a/core/src/syscall/precompiles/sha512/compress/mod.rs +++ b/core/src/syscall/precompiles/sha512/compress/mod.rs @@ -98,11 +98,14 @@ pub struct Sha512CompressEvent { pub clk: u32, pub w_ptr: u32, pub h_ptr: u32, - pub w: Vec, - pub h: [u32; 8], - pub h_read_records: [MemoryReadRecord; 8], - pub w_i_read_records: Vec, - pub h_write_records: [MemoryWriteRecord; 8], + pub i: u32, + pub w_i: u64, + pub k_i: u64, + pub h: [u64; 8], + pub w_i_read_records: [MemoryReadRecord; 2], + pub k_i_read_records: [MemoryReadRecord; 2], + pub h_write_records: [MemoryWriteRecord; 16], + pub i_write_record: MemoryWriteRecord, } /// Implements the SHA compress operation which loops over 0 = [0, 63] and modifies A-H in each @@ -112,6 +115,7 @@ pub struct Sha512CompressEvent { /// In the AIR, each SHA compress syscall takes up 80 rows. The first and last 8 rows are for /// initialization and finalize respectively. The middle 64 rows are for compression. Each row /// operates over a single memory word. +/// FIXME #[derive(Default)] pub struct Sha512CompressChip; @@ -129,20 +133,58 @@ pub mod compress_tests { utils::{run_test, setup_logger, tests::SHA512_COMPRESS_ELF}, }; + use super::SHA512_COMPRESS_K; + + // FIXME + fn u64_to_u32x2(n: u64) -> [u32; 2] { + let n = n.to_le_bytes(); + [ + u32::from_le_bytes(n[..4].try_into().unwrap()), + u32::from_le_bytes(n[4..].try_into().unwrap()), + ] + } + pub fn sha512_compress_program() -> Program { let w_ptr = 100; - let h_ptr = 1000; - let mut instructions = vec![Instruction::new(Opcode::ADD, 29, 0, 5, false, true)]; - for i in 0..64 { + let h_ptr = 100000; + let mut instructions = vec![ + Instruction::new(Opcode::ADD, 29, 0, 5, false, true), + Instruction::new(Opcode::ADD, 28, 0, 0, false, true), + ]; + for i in 0..80 { + instructions.extend(vec![ + Instruction::new(Opcode::ADD, 30, 0, w_ptr + i * 8, false, true), + Instruction::new(Opcode::SW, 29, 30, 0, false, true), + Instruction::new(Opcode::ADD, 30, 0, w_ptr + i * 8 + 4, false, true), + Instruction::new(Opcode::SW, 28, 30, 0, false, true), + ]); + } + // Fill out state and the `i` value after it + for i in 0..9 { instructions.extend(vec![ - Instruction::new(Opcode::ADD, 30, 0, w_ptr + i * 4, false, true), + Instruction::new(Opcode::ADD, 30, 0, h_ptr + i * 8, false, true), Instruction::new(Opcode::SW, 29, 30, 0, false, true), + Instruction::new(Opcode::ADD, 30, 0, h_ptr + i * 8 + 4, false, true), + Instruction::new(Opcode::SW, 28, 30, 0, false, true), ]); } - for i in 0..8 { + // Fill out the constants `k` + for i in 0..80 { + let k_i = u64_to_u32x2(SHA512_COMPRESS_K[i]); instructions.extend(vec![ - Instruction::new(Opcode::ADD, 30, 0, h_ptr + i * 4, false, true), + Instruction::new(Opcode::ADD, 29, 0, k_i[0], false, true), + Instruction::new(Opcode::ADD, 28, 0, k_i[1], false, true), + Instruction::new(Opcode::ADD, 30, 0, h_ptr + 72 + i as u32 * 8, false, true), Instruction::new(Opcode::SW, 29, 30, 0, false, true), + Instruction::new( + Opcode::ADD, + 30, + 0, + h_ptr + 72 + i as u32 * 8 + 4, + false, + true, + ), + Instruction::new(Opcode::SW, 28, 30, 0, false, true), ]); } instructions.extend(vec![ diff --git a/core/src/syscall/precompiles/sha512/compress/trace.rs b/core/src/syscall/precompiles/sha512/compress/trace.rs index 3ec539e1e..220764f85 100644 --- a/core/src/syscall/precompiles/sha512/compress/trace.rs +++ b/core/src/syscall/precompiles/sha512/compress/trace.rs @@ -6,11 +6,11 @@ use p3_matrix::Matrix; use super::{ columns::{Sha512CompressCols, NUM_SHA512_COMPRESS_COLS}, - Sha512CompressChip, Sha512CompressEvent, SHA512_COMPRESS_K, + Sha512CompressChip, Sha512CompressEvent, }; use crate::{ - air::{EventLens, MachineAir, WithEvents, Word}, - bytes::event::ByteRecord, + air::{EventLens, MachineAir, WithEvents}, + bytes::{event::ByteRecord, ByteLookupEvent, ByteOpcode}, runtime::{ExecutionRecord, Program}, utils::pad_rows, }; @@ -36,249 +36,137 @@ impl MachineAir for Sha512CompressChip { let mut rows = Vec::new(); let mut new_byte_lookup_events = Vec::new(); - for i in 0..input.events().len() { - let mut event = input.events()[i].clone(); + for evt_idx in 0..input.events().len() { + let event = input.events()[evt_idx].clone(); let shard = event.shard; let channel = event.channel; - let og_h = event.h; - - let mut octet_num_idx = 0; - - // Load a, b, c, d, e, f, g, h. - for j in 0..8usize { - let mut row = [F::zero(); NUM_SHA512_COMPRESS_COLS]; - let cols: &mut Sha512CompressCols = row.as_mut_slice().borrow_mut(); - - cols.shard = F::from_canonical_u32(event.shard); - cols.channel = F::from_canonical_u32(event.channel); - cols.clk = F::from_canonical_u32(event.clk); - cols.w_ptr = F::from_canonical_u32(event.w_ptr); - cols.h_ptr = F::from_canonical_u32(event.h_ptr); - - cols.octet[j] = F::one(); - cols.octet_num[octet_num_idx] = F::one(); - cols.is_initialize = F::one(); + let mut row = [F::zero(); NUM_SHA512_COMPRESS_COLS]; + let cols: &mut Sha512CompressCols = row.as_mut_slice().borrow_mut(); - cols.mem.populate_read( - channel, - event.h_read_records[j], + cols.shard = F::from_canonical_u32(event.shard); + cols.channel = F::from_canonical_u32(event.channel); + cols.clk = F::from_canonical_u32(event.clk); + cols.w_ptr = F::from_canonical_u32(event.w_ptr); + cols.h_ptr = F::from_canonical_u32(event.h_ptr); + cols.i = F::from_canonical_u32(event.i); + cols.is_real = F::one(); + + // i < 80 + new_byte_lookup_events.push(ByteLookupEvent { + opcode: ByteOpcode::LTU, + shard, + channel: event.channel, + a1: 1, + a2: 0, + b: event.i, + c: 80, + }); + + cols.k_i[0].populate( + event.channel, + event.k_i_read_records[0], + &mut new_byte_lookup_events, + ); + cols.k_i[1].populate( + event.channel, + event.k_i_read_records[1], + &mut new_byte_lookup_events, + ); + + cols.w_i[0].populate( + event.channel, + event.w_i_read_records[0], + &mut new_byte_lookup_events, + ); + cols.w_i[1].populate( + event.channel, + event.w_i_read_records[1], + &mut new_byte_lookup_events, + ); + + cols.i_mem.populate( + event.channel, + event.i_write_record, + &mut new_byte_lookup_events, + ); + + for j in 0..16 { + cols.h[j].populate( + event.channel, + event.h_write_records[j], &mut new_byte_lookup_events, ); - cols.mem_addr = F::from_canonical_u32(event.h_ptr + (j * 4) as u32); - - cols.a = Word::from(event.h_read_records[0].value); - cols.b = Word::from(event.h_read_records[1].value); - cols.c = Word::from(event.h_read_records[2].value); - cols.d = Word::from(event.h_read_records[3].value); - cols.e = Word::from(event.h_read_records[4].value); - cols.f = Word::from(event.h_read_records[5].value); - cols.g = Word::from(event.h_read_records[6].value); - cols.h = Word::from(event.h_read_records[7].value); - - cols.is_real = F::one(); - cols.start = cols.is_real * cols.octet_num[0] * cols.octet[0]; - rows.push(row); } // Performs the compress operation. - for j in 0..64 { - if j % 8 == 0 { - octet_num_idx += 1; - } - let mut row = [F::zero(); NUM_SHA512_COMPRESS_COLS]; - let cols: &mut Sha512CompressCols = row.as_mut_slice().borrow_mut(); - - cols.k = Word::from(SHA512_COMPRESS_K[j]); - cols.is_compression = F::one(); - cols.octet[j % 8] = F::one(); - cols.octet_num[octet_num_idx] = F::one(); - - cols.shard = F::from_canonical_u32(event.shard); - cols.channel = F::from_canonical_u32(event.channel); - cols.clk = F::from_canonical_u32(event.clk); - cols.w_ptr = F::from_canonical_u32(event.w_ptr); - cols.h_ptr = F::from_canonical_u32(event.h_ptr); - cols.mem.populate_read( - channel, - event.w_i_read_records[j], - &mut new_byte_lookup_events, - ); - cols.mem_addr = F::from_canonical_u32(event.w_ptr + (j * 4) as u32); - - let a = event.h[0]; - let b = event.h[1]; - let c = event.h[2]; - let d = event.h[3]; - let e = event.h[4]; - let f = event.h[5]; - let g = event.h[6]; - let h = event.h[7]; - cols.a = Word::from(a); - cols.b = Word::from(b); - cols.c = Word::from(c); - cols.d = Word::from(d); - cols.e = Word::from(e); - cols.f = Word::from(f); - cols.g = Word::from(g); - cols.h = Word::from(h); - - let e_rr_6 = cols.e_rr_6.populate(output, shard, channel, e, 6); - let e_rr_11 = cols.e_rr_11.populate(output, shard, channel, e, 11); - let e_rr_25 = cols.e_rr_25.populate(output, shard, channel, e, 25); - let s1_intermediate = cols - .s1_intermediate - .populate(output, shard, channel, e_rr_6, e_rr_11); - let s1 = cols - .s1 - .populate(output, shard, channel, s1_intermediate, e_rr_25); - - let e_and_f = cols.e_and_f.populate(output, shard, channel, e, f); - let e_not = cols.e_not.populate(output, shard, channel, e); - let e_not_and_g = cols.e_not_and_g.populate(output, shard, channel, e_not, g); - let ch = cols - .ch - .populate(output, shard, channel, e_and_f, e_not_and_g); - - let temp1 = cols.temp1.populate( - output, - shard, - channel, - h, - s1, - ch, - event.w[j], - SHA512_COMPRESS_K[j], - ); - - let a_rr_2 = cols.a_rr_2.populate(output, shard, channel, a, 2); - let a_rr_13 = cols.a_rr_13.populate(output, shard, channel, a, 13); - let a_rr_22 = cols.a_rr_22.populate(output, shard, channel, a, 22); - let s0_intermediate = cols - .s0_intermediate - .populate(output, shard, channel, a_rr_2, a_rr_13); - let s0 = cols - .s0 - .populate(output, shard, channel, s0_intermediate, a_rr_22); - - let a_and_b = cols.a_and_b.populate(output, shard, channel, a, b); - let a_and_c = cols.a_and_c.populate(output, shard, channel, a, c); - let b_and_c = cols.b_and_c.populate(output, shard, channel, b, c); - let maj_intermediate = cols - .maj_intermediate - .populate(output, shard, channel, a_and_b, a_and_c); - let maj = cols - .maj - .populate(output, shard, channel, maj_intermediate, b_and_c); - - let temp2 = cols.temp2.populate(output, shard, channel, s0, maj); - - let d_add_temp1 = cols.d_add_temp1.populate(output, shard, channel, d, temp1); - let temp1_add_temp2 = cols - .temp1_add_temp2 - .populate(output, shard, channel, temp1, temp2); - - event.h[7] = g; - event.h[6] = f; - event.h[5] = e; - event.h[4] = d_add_temp1; - event.h[3] = c; - event.h[2] = b; - event.h[1] = a; - event.h[0] = temp1_add_temp2; - - cols.is_real = F::one(); - cols.start = cols.is_real * cols.octet_num[0] * cols.octet[0]; - - rows.push(row); - } - - let mut v: [u32; 8] = [0, 1, 2, 3, 4, 5, 6, 7].map(|i| event.h[i]); - - octet_num_idx += 1; - // Store a, b, c, d, e, f, g, h. - for j in 0..8usize { - let mut row = [F::zero(); NUM_SHA512_COMPRESS_COLS]; - let cols: &mut Sha512CompressCols = row.as_mut_slice().borrow_mut(); - - cols.shard = F::from_canonical_u32(event.shard); - cols.channel = F::from_canonical_u32(event.channel); - cols.clk = F::from_canonical_u32(event.clk); - cols.w_ptr = F::from_canonical_u32(event.w_ptr); - cols.h_ptr = F::from_canonical_u32(event.h_ptr); - - cols.octet[j] = F::one(); - cols.octet_num[octet_num_idx] = F::one(); - cols.is_finalize = F::one(); - - cols.finalize_add - .populate(output, shard, channel, og_h[j], event.h[j]); - cols.mem.populate_write( - channel, - event.h_write_records[j], - &mut new_byte_lookup_events, - ); - cols.mem_addr = F::from_canonical_u32(event.h_ptr + (j * 4) as u32); - - v[j] = event.h[j]; - cols.a = Word::from(v[0]); - cols.b = Word::from(v[1]); - cols.c = Word::from(v[2]); - cols.d = Word::from(v[3]); - cols.e = Word::from(v[4]); - cols.f = Word::from(v[5]); - cols.g = Word::from(v[6]); - cols.h = Word::from(v[7]); - - match j { - 0 => cols.finalized_operand = cols.a, - 1 => cols.finalized_operand = cols.b, - 2 => cols.finalized_operand = cols.c, - 3 => cols.finalized_operand = cols.d, - 4 => cols.finalized_operand = cols.e, - 5 => cols.finalized_operand = cols.f, - 6 => cols.finalized_operand = cols.g, - 7 => cols.finalized_operand = cols.h, - _ => panic!("unsupported j"), - }; - - cols.is_real = F::one(); - cols.is_last_row = cols.octet[7] * cols.octet_num[9]; - cols.start = cols.is_real * cols.octet_num[0] * cols.octet[0]; - - rows.push(row); - } + let a = event.h[0]; + let b = event.h[1]; + let c = event.h[2]; + let d = event.h[3]; + let e = event.h[4]; + let f = event.h[5]; + let g = event.h[6]; + let h = event.h[7]; + + let e_rr_14 = cols.e_rr_14.populate(output, shard, channel, e, 14); + let e_rr_18 = cols.e_rr_18.populate(output, shard, channel, e, 18); + let e_rr_41 = cols.e_rr_41.populate(output, shard, channel, e, 41); + let s1_intermediate = cols + .s1_intermediate + .populate(output, shard, channel, e_rr_14, e_rr_18); + let s1 = cols + .s1 + .populate(output, shard, channel, s1_intermediate, e_rr_41); + + let e_and_f = cols.e_and_f.populate(output, shard, channel, e, f); + let e_not = cols.e_not.populate(output, shard, channel, e); + let e_not_and_g = cols.e_not_and_g.populate(output, shard, channel, e_not, g); + let ch = cols + .ch + .populate(output, shard, channel, e_and_f, e_not_and_g); + + let temp1_0 = cols.temp1[0].populate(output, shard, channel, h, s1); + let temp1_1 = cols.temp1[1].populate(output, shard, channel, temp1_0, ch); + let temp1_2 = cols.temp1[2].populate(output, shard, channel, temp1_1, event.k_i); + let temp1 = cols.temp1[3].populate(output, shard, channel, temp1_2, event.w_i); + + let a_rr_28 = cols.a_rr_28.populate(output, shard, channel, a, 28); + let a_rr_34 = cols.a_rr_34.populate(output, shard, channel, a, 34); + let a_rr_39 = cols.a_rr_39.populate(output, shard, channel, a, 39); + let s0_intermediate = cols + .s0_intermediate + .populate(output, shard, channel, a_rr_28, a_rr_34); + let s0 = cols + .s0 + .populate(output, shard, channel, s0_intermediate, a_rr_39); + + let a_and_b = cols.a_and_b.populate(output, shard, channel, a, b); + let a_and_c = cols.a_and_c.populate(output, shard, channel, a, c); + let b_and_c = cols.b_and_c.populate(output, shard, channel, b, c); + let maj_intermediate = cols + .maj_intermediate + .populate(output, shard, channel, a_and_b, a_and_c); + let maj = cols + .maj + .populate(output, shard, channel, maj_intermediate, b_and_c); + + let temp2 = cols.temp2.populate(output, shard, channel, s0, maj); + + let d_add_temp1 = cols.d_add_temp1.populate(output, shard, channel, d, temp1); + let temp1_add_temp2 = cols + .temp1_add_temp2 + .populate(output, shard, channel, temp1, temp2); + + let out_h = [temp1_add_temp2, a, b, c, d_add_temp1, e, f, g]; + + rows.push(row); } output.add_byte_lookup_events(new_byte_lookup_events); - let num_real_rows = rows.len(); - pad_rows(&mut rows, || [F::zero(); NUM_SHA512_COMPRESS_COLS]); - // Set the octet_num and octect columns for the padded rows. - let mut octet_num = 0; - let mut octet = 0; - for row in rows[num_real_rows..].iter_mut() { - let cols: &mut Sha512CompressCols = row.as_mut_slice().borrow_mut(); - cols.octet_num[octet_num] = F::one(); - cols.octet[octet] = F::one(); - - // If in the compression phase, set the k value. - if octet_num != 0 && octet_num != 9 { - let compression_idx = octet_num - 1; - let k_idx = compression_idx * 8 + octet; - cols.k = Word::from(SHA512_COMPRESS_K[k_idx]); - } - - octet = (octet + 1) % 8; - if octet == 0 { - octet_num = (octet_num + 1) % 10; - } - - cols.is_last_row = cols.octet[7] * cols.octet_num[9]; - } - // Convert the trace to a row major matrix. let mut trace = RowMajorMatrix::new( rows.into_iter().flatten().collect::>(), diff --git a/core/src/syscall/precompiles/sha512/extend/air.rs b/core/src/syscall/precompiles/sha512/extend/air.rs index 545486077..660758f24 100644 --- a/core/src/syscall/precompiles/sha512/extend/air.rs +++ b/core/src/syscall/precompiles/sha512/extend/air.rs @@ -38,6 +38,9 @@ where .when_transition() .assert_eq(local.nonce + AB::Expr::one(), next.nonce); + // Assert that is_real is a bool. + builder.assert_bool(local.is_real); + let nb_bytes_in_word64 = AB::F::from_canonical_u32(8); // Check that `15 < i < 80` @@ -321,8 +324,5 @@ where local.i, local.is_real, ); - - // Assert that is_real is a bool. - builder.assert_bool(local.is_real); } } diff --git a/core/src/syscall/precompiles/sha512/extend/trace.rs b/core/src/syscall/precompiles/sha512/extend/trace.rs index da9439e8d..b64d29d61 100644 --- a/core/src/syscall/precompiles/sha512/extend/trace.rs +++ b/core/src/syscall/precompiles/sha512/extend/trace.rs @@ -8,6 +8,7 @@ use crate::{ air::{EventLens, MachineAir, WithEvents}, bytes::{event::ByteRecord, ByteLookupEvent, ByteOpcode}, runtime::{ExecutionRecord, Program}, + utils::pad_rows, }; impl<'a> WithEvents<'a> for Sha512ExtendChip { @@ -206,15 +207,7 @@ impl MachineAir for Sha512ExtendChip { output.add_byte_lookup_events(new_byte_lookup_events); - let nb_rows = rows.len(); - let mut padded_nb_rows = nb_rows.next_power_of_two(); - if padded_nb_rows == 2 || padded_nb_rows == 1 { - padded_nb_rows = 4; - } - for _ in nb_rows..padded_nb_rows { - let row = [F::zero(); NUM_SHA512_EXTEND_COLS]; - rows.push(row); - } + pad_rows(&mut rows, || [F::zero(); NUM_SHA512_EXTEND_COLS]); // Convert the trace to a row major matrix. let mut trace = RowMajorMatrix::new( diff --git a/core/src/syscall/precompiles/sha512/mod.rs b/core/src/syscall/precompiles/sha512/mod.rs index 06f94fe88..29d7bd1a5 100644 --- a/core/src/syscall/precompiles/sha512/mod.rs +++ b/core/src/syscall/precompiles/sha512/mod.rs @@ -1,5 +1,5 @@ -// mod compress; +mod compress; mod extend; -// pub use compress::*; +pub use compress::*; pub use extend::*; diff --git a/core/src/utils/programs.rs b/core/src/utils/programs.rs index 7953afac5..9b7266f45 100644 --- a/core/src/utils/programs.rs +++ b/core/src/utils/programs.rs @@ -70,8 +70,8 @@ pub mod tests { pub const SHA2_ELF: &[u8] = include_bytes!("../../../tests/sha2/elf/riscv32im-succinct-zkvm-elf"); - // pub const SHA512_COMPRESS_ELF: &[u8] = 512FIXME - // include_bytes!("../../../tests/sha512-compress/elf/riscv32im-succinct-zkvm-elf"); + pub const SHA512_COMPRESS_ELF: &[u8] = + include_bytes!("../../../tests/sha512-compress/elf/riscv32im-succinct-zkvm-elf"); pub const SHA512_EXTEND_ELF: &[u8] = include_bytes!("../../../tests/sha512-extend/elf/riscv32im-succinct-zkvm-elf"); diff --git a/tests/sha512-compress/Cargo.lock b/tests/sha512-compress/Cargo.lock new file mode 100644 index 000000000..b10e41bb8 --- /dev/null +++ b/tests/sha512-compress/Cargo.lock @@ -0,0 +1,509 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "tap", + "zeroize", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "bitvec", + "rand_core", + "subtle", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "hybrid-array" +version = "0.2.0-rc.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53668f5da5a41d9eaf4bf7064be46d1ebe6a4e1ceed817f387587b18f2b51047" +dependencies = [ + "typenum", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2 0.10.8 (registry+https://github.com/rust-lang/crates.io-index)", + "signature", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "git+https://github.com/sp1-patches/RustCrypto-hashes?branch=patch-v0.10.8#1f224388fdede7cef649bce0d63876d1a9e3f515" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha512-compress-test" +version = "0.1.0" +dependencies = [ + "sphinx-zkvm", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "sphinx-precompiles" +version = "1.0.0" +dependencies = [ + "anyhow", + "bincode", + "cfg-if", + "getrandom", + "hybrid-array", + "k256", + "serde", +] + +[[package]] +name = "sphinx-zkvm" +version = "1.0.0" +dependencies = [ + "bincode", + "cfg-if", + "getrandom", + "k256", + "lazy_static", + "libm", + "once_cell", + "rand", + "sha2 0.10.8 (git+https://github.com/sp1-patches/RustCrypto-hashes?branch=patch-v0.10.8)", + "sphinx-precompiles", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "2.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/tests/sha512-compress/Cargo.toml b/tests/sha512-compress/Cargo.toml new file mode 100644 index 000000000..2ebdd8216 --- /dev/null +++ b/tests/sha512-compress/Cargo.toml @@ -0,0 +1,8 @@ +[workspace] +[package] +version = "0.1.0" +name = "sha512-compress-test" +edition = "2021" + +[dependencies] +sphinx-zkvm = { path = "../../zkvm/entrypoint" } diff --git a/tests/sha512-compress/elf/riscv32im-succinct-zkvm-elf b/tests/sha512-compress/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 000000000..385137272 Binary files /dev/null and b/tests/sha512-compress/elf/riscv32im-succinct-zkvm-elf differ diff --git a/tests/sha512-compress/src/main.rs b/tests/sha512-compress/src/main.rs new file mode 100644 index 000000000..a8f03b6ed --- /dev/null +++ b/tests/sha512-compress/src/main.rs @@ -0,0 +1,103 @@ +#![no_main] +sphinx_zkvm::entrypoint!(main); + +use sphinx_zkvm::syscalls::syscall_sha512_compress; + +const SHA512_COMPRESS_K: [u64; 80] = [ + 0x428a2f98d728ae22, + 0x7137449123ef65cd, + 0xb5c0fbcfec4d3b2f, + 0xe9b5dba58189dbbc, + 0x3956c25bf348b538, + 0x59f111f1b605d019, + 0x923f82a4af194f9b, + 0xab1c5ed5da6d8118, + 0xd807aa98a3030242, + 0x12835b0145706fbe, + 0x243185be4ee4b28c, + 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, + 0x80deb1fe3b1696b1, + 0x9bdc06a725c71235, + 0xc19bf174cf692694, + 0xe49b69c19ef14ad2, + 0xefbe4786384f25e3, + 0x0fc19dc68b8cd5b5, + 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, + 0x4a7484aa6ea6e483, + 0x5cb0a9dcbd41fbd4, + 0x76f988da831153b5, + 0x983e5152ee66dfab, + 0xa831c66d2db43210, + 0xb00327c898fb213f, + 0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2, + 0xd5a79147930aa725, + 0x06ca6351e003826f, + 0x142929670a0e6e70, + 0x27b70a8546d22ffc, + 0x2e1b21385c26c926, + 0x4d2c6dfc5ac42aed, + 0x53380d139d95b3df, + 0x650a73548baf63de, + 0x766a0abb3c77b2a8, + 0x81c2c92e47edaee6, + 0x92722c851482353b, + 0xa2bfe8a14cf10364, + 0xa81a664bbc423001, + 0xc24b8b70d0f89791, + 0xc76c51a30654be30, + 0xd192e819d6ef5218, + 0xd69906245565a910, + 0xf40e35855771202a, + 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, + 0x1e376c085141ab53, + 0x2748774cdf8eeb99, + 0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63, + 0x4ed8aa4ae3418acb, + 0x5b9cca4f7763e373, + 0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc, + 0x78a5636f43172f60, + 0x84c87814a1f0ab72, + 0x8cc702081a6439ec, + 0x90befffa23631e28, + 0xa4506cebde82bde9, + 0xbef9a3f7b2c67915, + 0xc67178f2e372532b, + 0xca273eceea26619c, + 0xd186b8c721c0c207, + 0xeada7dd6cde0eb1e, + 0xf57d4f7fee6ed178, + 0x06f067aa72176fba, + 0x0a637dc5a2c898a6, + 0x113f9804bef90dae, + 0x1b710b35131c471b, + 0x28db77f523047d84, + 0x32caab7b40c72493, + 0x3c9ebe0a15c9bebc, + 0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6, + 0x597f299cfc657e2a, + 0x5fcb6fab3ad6faec, + 0x6c44198c4a475817, +]; + +pub fn main() { + let mut w = [1u64; 80]; + let mut state = [1u64; 89]; + state[8] = 0; // i + for j in 0..80 { + state[9 + j] = SHA512_COMPRESS_K[j]; + } + + for _ in 0..80 { + println!("i: {:?}", state[8]); + syscall_sha512_compress(w.as_mut_ptr(), state.as_mut_ptr()); + } + + println!("{:?}", &state[0..8]); +} diff --git a/zkvm/entrypoint/src/syscalls/mod.rs b/zkvm/entrypoint/src/syscalls/mod.rs index c7cdef289..c43ddccf0 100644 --- a/zkvm/entrypoint/src/syscalls/mod.rs +++ b/zkvm/entrypoint/src/syscalls/mod.rs @@ -6,7 +6,7 @@ mod io; mod keccak_permute; mod memory; mod secp256k1; -// mod sha512_compress; 512FIXME +mod sha512_compress; mod sha512_extend; mod sha_compress; mod sha_extend; @@ -25,7 +25,7 @@ pub use io::*; pub use keccak_permute::*; pub use memory::*; pub use secp256k1::*; -// pub use sha512_compress::*; 512FIXME +pub use sha512_compress::*; pub use sha512_extend::*; pub use sha_compress::*; pub use sha_extend::*; @@ -120,4 +120,4 @@ pub const BLAKE_2S_ROUND: u32 = 0x00_01_01_ED; pub const SHA512_EXTEND: u32 = 0x00_00_01_C1; /// Executes `SHA512_COMPRESS`. -pub const SHA512_COMPRESS: u32 = 0x00_01_01_C2; +pub const SHA512_COMPRESS: u32 = 0x00_00_01_C2; diff --git a/zkvm/entrypoint/src/syscalls/sha512_compress.rs b/zkvm/entrypoint/src/syscalls/sha512_compress.rs new file mode 100644 index 000000000..1b1afac98 --- /dev/null +++ b/zkvm/entrypoint/src/syscalls/sha512_compress.rs @@ -0,0 +1,19 @@ +#[cfg(target_os = "zkvm")] +use core::arch::asm; + +#[allow(unused_variables)] +#[no_mangle] +pub extern "C" fn syscall_sha512_compress(w: *mut u64, state: *mut u64) { + #[cfg(target_os = "zkvm")] + unsafe { + asm!( + "ecall", + in("t0") crate::syscalls::SHA512_COMPRESS, + in("a0") w, + in("a1") state, + ); + } + + #[cfg(not(target_os = "zkvm"))] + unreachable!() +} diff --git a/zkvm/precompiles/src/lib.rs b/zkvm/precompiles/src/lib.rs index 8660944f1..b66dfb199 100644 --- a/zkvm/precompiles/src/lib.rs +++ b/zkvm/precompiles/src/lib.rs @@ -23,7 +23,7 @@ extern "C" { pub fn syscall_sha256_extend(w: *mut u32); pub fn syscall_sha256_compress(w: *mut u32, state: *mut u32); pub fn syscall_sha512_extend(w: *mut u64, i: u32); - // pub fn syscall_sha512_compress(w: *mut u64, state: *mut u32); 512FIXME + pub fn syscall_sha512_compress(w: *mut u64, state: *mut u64); pub fn syscall_ed_add(p: *mut u32, q: *mut u32); pub fn syscall_ed_decompress(point: &mut [u8; 64]); pub fn syscall_secp256k1_add(p: *mut u32, q: *const u32);