-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- all precompiles have the same interface as their counter-parts in `sp1`; the `secp256k1` curve ops are backed by the `secp` crate. - integrates appropriate dummy circuits for precompiles into the zkvm - added `utils.rs` with some utilities for safely manipulating memory segments of the VM - tested the compatibility of the syscalls (+ keccak, done previously) with sp1 (see the `syscalls.rs` example file). - extended the docs pasted from sp1 Aurel has reviewed an earlier version of this [here](Inversed-Tech#4).
- Loading branch information
Showing
20 changed files
with
1,316 additions
and
85 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,65 +1,87 @@ | ||
use itertools::{Itertools, izip}; | ||
use itertools::Itertools; | ||
use tiny_keccak::keccakf; | ||
|
||
use crate::{Change, EmuContext, Platform, VMState, WORD_SIZE, WordAddr, WriteOp}; | ||
use crate::{Change, EmuContext, Platform, VMState, Word, WriteOp, utils::MemoryView}; | ||
|
||
use super::{SyscallEffects, SyscallWitness}; | ||
use super::{SyscallEffects, SyscallSpec, SyscallWitness}; | ||
|
||
const KECCAK_CELLS: usize = 25; // u64 cells | ||
pub const KECCAK_WORDS: usize = KECCAK_CELLS * 2; // u32 words | ||
|
||
pub struct KeccakSpec; | ||
|
||
impl SyscallSpec for KeccakSpec { | ||
const NAME: &'static str = "KECCAK"; | ||
|
||
const REG_OPS_COUNT: usize = 2; | ||
const MEM_OPS_COUNT: usize = KECCAK_WORDS; | ||
const CODE: u32 = ceno_rt::syscalls::KECCAK_PERMUTE; | ||
} | ||
|
||
/// Wrapper type for the keccak_permute argument that implements conversions | ||
/// from and to VM word-representations according to the syscall spec | ||
pub struct KeccakState(pub [u64; KECCAK_CELLS]); | ||
|
||
impl From<[Word; KECCAK_WORDS]> for KeccakState { | ||
fn from(words: [Word; KECCAK_WORDS]) -> Self { | ||
KeccakState( | ||
words | ||
.chunks_exact(2) | ||
.map(|chunk| (chunk[0] as u64 | ((chunk[1] as u64) << 32))) | ||
.collect_vec() | ||
.try_into() | ||
.expect("failed to parse words into [u64; 25]"), | ||
) | ||
} | ||
} | ||
|
||
impl From<KeccakState> for [Word; KECCAK_WORDS] { | ||
fn from(state: KeccakState) -> [Word; KECCAK_WORDS] { | ||
state | ||
.0 | ||
.iter() | ||
.flat_map(|&elem| [elem as u32, (elem >> 32) as u32]) | ||
.collect_vec() | ||
.try_into() | ||
.unwrap() | ||
} | ||
} | ||
|
||
/// Trace the execution of a Keccak permutation. | ||
/// | ||
/// Compatible with: | ||
/// https://github.com/succinctlabs/sp1/blob/013c24ea2fa15a0e7ed94f7d11a7ada4baa39ab9/crates/core/executor/src/syscalls/precompiles/keccak256/permute.rs | ||
/// | ||
/// TODO: test compatibility. | ||
pub fn keccak_permute(vm: &VMState) -> SyscallEffects { | ||
let state_ptr = vm.peek_register(Platform::reg_arg0()); | ||
|
||
// Read the argument `state_ptr`. | ||
let reg_ops = vec![WriteOp::new_register_op( | ||
Platform::reg_arg0(), | ||
Change::new(state_ptr, state_ptr), | ||
0, // Cycle set later in finalize(). | ||
)]; | ||
|
||
let addrs = (state_ptr..) | ||
.step_by(WORD_SIZE) | ||
.take(KECCAK_WORDS) | ||
.map(WordAddr::from) | ||
.collect_vec(); | ||
|
||
// Read Keccak state. | ||
let input = addrs | ||
.iter() | ||
.map(|&addr| vm.peek_memory(addr)) | ||
.collect::<Vec<_>>(); | ||
// for compatibility with sp1 spec | ||
assert_eq!(vm.peek_register(Platform::reg_arg1()), 0); | ||
|
||
// Compute Keccak permutation. | ||
let output = { | ||
let mut state = [0_u64; KECCAK_CELLS]; | ||
for (cell, (&lo, &hi)) in izip!(&mut state, input.iter().tuples()) { | ||
*cell = lo as u64 | ((hi as u64) << 32); | ||
} | ||
|
||
keccakf(&mut state); | ||
// Read the argument `state_ptr`. | ||
let reg_ops = vec![ | ||
WriteOp::new_register_op( | ||
Platform::reg_arg0(), | ||
Change::new(state_ptr, state_ptr), | ||
0, // Cycle set later in finalize(). | ||
), | ||
WriteOp::new_register_op( | ||
Platform::reg_arg1(), | ||
Change::new(0, 0), | ||
0, // Cycle set later in finalize(). | ||
), | ||
]; | ||
|
||
state.into_iter().flat_map(|c| [c as u32, (c >> 32) as u32]) | ||
}; | ||
let mut state_view = MemoryView::<KECCAK_WORDS>::new(vm, state_ptr); | ||
let mut state = KeccakState::from(state_view.words()); | ||
keccakf(&mut state.0); | ||
let output_words: [Word; KECCAK_WORDS] = state.into(); | ||
|
||
// Write permuted state. | ||
let mem_ops = izip!(addrs, input, output) | ||
.map(|(addr, before, after)| WriteOp { | ||
addr, | ||
value: Change { before, after }, | ||
previous_cycle: 0, // Cycle set later in finalize(). | ||
}) | ||
.collect_vec(); | ||
state_view.write(output_words); | ||
let mem_ops: Vec<WriteOp> = state_view.mem_ops().to_vec(); | ||
|
||
assert_eq!(mem_ops.len(), KECCAK_WORDS); | ||
SyscallEffects { | ||
witness: SyscallWitness { mem_ops, reg_ops }, | ||
witness: SyscallWitness::new(mem_ops, reg_ops), | ||
next_pc: None, | ||
} | ||
} |
Oops, something went wrong.