simplify ripe md test

This commit is contained in:
Dmitry Vagner 2023-02-15 18:18:26 -08:00
parent f3946f75bf
commit bce867188c
10 changed files with 200 additions and 256 deletions

View File

@ -57,7 +57,6 @@ pub(crate) fn combined_kernel() -> Kernel {
include_str!("asm/hash/ripemd/constants.asm"),
include_str!("asm/hash/ripemd/functions.asm"),
include_str!("asm/hash/ripemd/main.asm"),
include_str!("asm/hash/ripemd/memory.asm"),
include_str!("asm/hash/ripemd/update.asm"),
include_str!("asm/hash/sha2/compression.asm"),
include_str!("asm/hash/sha2/constants.asm"),

View File

@ -7,40 +7,47 @@
/// STATE, count, _buffer = ripemd_update(STATE, count, _buffer, 8, bytes = size(len(_input)))
/// return process(STATE)
///
/// ripemd is called on a stack with ADDR and length
/// ripemd_stack is called on a stack with length, followed by the input bytes
/// ripemd is called on
/// // stack: length
///
/// ripemd_update receives and return the stack in the form:
/// stack: STATE, count, length, virt
/// where virt is the virtual address of the bytes argument
global ripemd_stack:
// stack: length, INPUT
%stack (length) -> (64, length, 0x80, 63, length, length)
// stack: 64, length, 0x80, 63, length, length, INPUT
%jump(ripemd_storage) // stores the following into memory
// init _buffer at virt 0 [consumes 64]
// store _size at virt 64 [consumes length]
// store _padding at virt 72 [consumes 0x80, 63]
// store _input at virt 136 [consumes length]
global ripemd:
// stack: ADDR, length
%stack (ADDR: 3, length) -> (64, length, 0x80, 63, length, ADDR, length)
// stack: 64, length, 0x80, 63, length, ADDR, length
%jump(ripemd_storage) // stores the following into memory
// init _buffer at virt 0 [consumes 64]
// store _size at virt 64 [consumes length]
// store _padding at virt 72 [consumes 0x80, 63]
// store _input at virt 136 [consumes ADDR, length]
// stack: virt, length
%stack (virt, length) -> (length, 0x80, virt, length)
// stack: length, 0x80, virt, length
global ripemd_init:
// stack: length
%stack (length) -> ( 0, length, 136, ripemd_1, ripemd_2, process)
// stack: count = 0, length, virt = 136, ripemd_1, ripemd_2, process
%shl_const(3)
// stack: abcdefgh
%extract_and_store_byte(64)
// stack: abcdefg
%extract_and_store_byte(65)
// stack: abcdef
%extract_and_store_byte(66)
// stack: abcde
%extract_and_store_byte(67)
// stack: abcd
%extract_and_store_byte(68)
// stack: abc
%extract_and_store_byte(69)
// stack: ab
%extract_and_store_byte(70)
// stack: a
%mstore_kernel_general(71)
// stack: 0x80
%mstore_kernel_general(72)
// stack: virt, length
%stack (virt, length) -> ( 0, length, virt, ripemd_1, ripemd_2, process)
// stack: count = 0, length, virt, ripemd_1, ripemd_2, process
%stack () -> (0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0)
// stack: 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0, count, length, virt, LABELS
%jump(ripemd_update)
ripemd_1:
// stack: STATE, count, length , virt , LABELS
DUP7
@ -105,3 +112,20 @@ global process:
// stack: 56 + 64*(t > 55), t
SUB
%endmacro
%macro extract_and_store_byte(offset)
// stack: xsy
PUSH 0x100
DUP2
MOD
// stack: y, xsy
%stack (y, xsy) -> (xsy, y, 0x100, y)
// stack: xsy, y, 0x100, y
SUB
DIV
SWAP1
// stack: y, xs
%mstore_kernel_general($offset)
// stack: xs
%endmacro

View File

@ -1,137 +0,0 @@
global ripemd_storage: // starts by initializing buffer
// stack: i [init: 64]
%store_zeros(64, ripemd_storage)
// stack: (empty)
%jump(store_size)
store_size:
// stack: length
%shl_const(3)
// stack: abcdefgh
%extract_and_store_byte(64)
// stack: abcdefg
%extract_and_store_byte(65)
// stack: abcdef
%extract_and_store_byte(66)
// stack: abcde
%extract_and_store_byte(67)
// stack: abcd
%extract_and_store_byte(68)
// stack: abc
%extract_and_store_byte(69)
// stack: ab
%extract_and_store_byte(70)
// stack: a
%mstore_kernel_general(71)
// stack: 0x80 // padding has 0x80 in first position and zeros elsewhere
%mstore_kernel_general(72) // store first padding term here so as to avoid extra label
%jump(store_padding)
store_padding:
// stack: i [init 63], length
%store_zeros(136, store_padding)
// stack: length
DUP1
%jumpi(store_input_stack)
POP
%jump(ripemd_init)
store_input_stack:
// stack: rem, length, REM_INP
%stack (rem, length, head) -> (length, rem, 136, head, rem, length)
SUB
ADD
// stack: offset, byte, rem, length, REM_INP
%mstore_kernel_general
// stack: rem, length, REM_INP
%decrement
DUP1
// stack: rem - 1, rem - 1, length, REM_INP
%jumpi(store_input_stack)
// stack: 0, length
POP
%jump(ripemd_init)
store_input:
// stack: rem , ADDR , length
DUP4
DUP4
DUP4
MLOAD_GENERAL
// stack: byte, rem , ADDR , length
DUP2
DUP7
SUB
%add_const(136)
// stack: offset, byte, rem , ADDR , length
%mstore_kernel_general
// stack: rem , ADDR , length
%decrement
// stack: rem-1, ADDR , length
SWAP3
%increment
SWAP3
// stack: rem-1, ADDR+1, length
DUP1
%jumpi(store_input)
// stack: 0 , ADDR , length
%pop4
// stack: length
%jump(ripemd_init)
/// def buffer_update(get, set, times):
/// for i in range(times):
/// buffer[set+i] = bytestring[get+i]
global buffer_update:
// stack: get , set , times , retdest
DUP2
DUP2
// stack: get, set, get , set , times , retdest
%mupdate_kernel_general
// stack: get , set , times , retdest
%increment
SWAP1
%increment
SWAP1
SWAP2
%decrement
SWAP2
// stack: get+1, set+1, times-1, retdest
DUP3
%jumpi(buffer_update)
// stack: get , set , 0 , retdest
%pop3
JUMP
%macro store_zeros(N, label)
// stack: i
%stack (i) -> ($N, i, 0, i)
SUB
// stack: offset = N-i, 0, i
%mstore_kernel_general
// stack: i
%decrement
DUP1
// stack: i-1, i-1
%jumpi($label)
// stack: 0
POP
%endmacro
%macro extract_and_store_byte(offset)
// stack: xsy
PUSH 0x100
DUP2
MOD
// stack: y, xsy
%stack (y, xsy) -> (xsy, y, 0x100, y)
// stack: xsy, y, 0x100, y
SUB
DIV
SWAP1
// stack: y, xs
%mstore_kernel_general($offset)
// stack: xs
%endmacro

View File

@ -106,3 +106,29 @@ update_2:
%stack (offset, STATE: 5) -> (STATE, offset, update_2)
// stack: STATE, offset, update_2, shift, need, have, count, length, virt, retdest
%jump(compress)
/// def buffer_update(get, set, times):
/// for i in range(times):
/// buffer[set+i] = bytestring[get+i]
buffer_update:
// stack: get , set , times , retdest
DUP2
DUP2
// stack: get, set, get , set , times , retdest
%mupdate_kernel_general
// stack: get , set , times , retdest
%increment
SWAP1
%increment
SWAP1
SWAP2
%decrement
SWAP2
// stack: get+1, set+1, times-1, retdest
DUP3
%jumpi(buffer_update)
// stack: get , set , 0 , retdest
%pop3
JUMP

View File

@ -65,6 +65,32 @@ pub fn run_interpreter(
)
}
pub struct InterpreterSetup {
pub label: String,
pub stack: Vec<U256>,
pub segment: Segment,
pub memory: Vec<(usize, Vec<U256>)>,
}
impl InterpreterSetup {
pub fn run(self) -> anyhow::Result<Interpreter<'static>> {
let label = KERNEL.global_labels[&self.label];
let mut stack = self.stack;
stack.reverse();
let mut interpreter = Interpreter::new_with_kernel(label, stack);
for (pointer, data) in self.memory {
for (i, term) in data.iter().enumerate() {
interpreter
.generation_state
.memory
.set(MemoryAddress::new(0, self.segment, pointer + i), *term)
}
}
interpreter.run()?;
Ok(interpreter)
}
}
pub fn run<'a>(
code: &'a [u8],
initial_offset: usize,
@ -223,6 +249,15 @@ impl<'a> Interpreter<'a> {
.content
}
pub fn extract_kernel_memory(self, locs: Vec<MemoryAddress>) -> Vec<U256> {
let mut output: Vec<U256> = vec![];
for loc in locs {
let term = self.generation_state.memory.get(loc);
output.push(term);
}
output
}
pub(crate) fn push(&mut self, x: U256) {
self.stack_mut().push(x);
self.generation_state.registers.stack_len += 1;

View File

@ -1,5 +1,3 @@
use std::str::FromStr;
use anyhow::Result;
use blake2::Blake2b512;
use ethereum_types::{U256, U512};
@ -7,14 +5,14 @@ use rand::{thread_rng, Rng};
use ripemd::{Digest, Ripemd160};
use sha2::Sha256;
use crate::cpu::kernel::aggregator::KERNEL;
use crate::cpu::kernel::interpreter::run_interpreter;
use crate::cpu::kernel::interpreter::InterpreterSetup;
use crate::memory::segments::Segment::KernelGeneral;
/// Standard Sha2 implementation.
fn sha2(input: Vec<u8>) -> U256 {
let mut hasher = Sha256::new();
/// Standard Blake2b implementation.
fn blake2b(input: Vec<u8>) -> U512 {
let mut hasher = Blake2b512::new();
hasher.update(input);
U256::from(&hasher.finalize()[..])
U512::from(&hasher.finalize()[..])
}
/// Standard RipeMD implementation.
@ -24,11 +22,11 @@ fn ripemd(input: Vec<u8>) -> U256 {
U256::from(&hasher.finalize()[..])
}
/// Standard Blake2b implementation.
fn blake2b(input: Vec<u8>) -> U512 {
let mut hasher = Blake2b512::new();
/// Standard Sha2 implementation.
fn sha2(input: Vec<u8>) -> U256 {
let mut hasher = Sha256::new();
hasher.update(input);
U512::from(&hasher.finalize()[..])
U256::from(&hasher.finalize()[..])
}
fn make_random_input() -> Vec<u8> {
@ -47,15 +45,6 @@ fn make_custom_input() -> Vec<u8> {
]
}
fn make_input_stack(message: Vec<u8>) -> Vec<U256> {
let mut initial_stack = vec![U256::from(message.len())];
let bytes: Vec<U256> = message.iter().map(|&x| U256::from(x as u32)).collect();
initial_stack.extend(bytes);
initial_stack.push(U256::from_str("0xdeadbeef").unwrap());
initial_stack.reverse();
initial_stack
}
fn combine_u256s(hi: U256, lo: U256) -> U512 {
let mut result = U512::from(hi);
result <<= 256;
@ -75,16 +64,46 @@ fn prepare_test<T>(
let expected_random = standard_implementation(message_random.clone());
let expected_custom = standard_implementation(message_custom.clone());
// Load the message onto the stack.
let initial_stack_random = make_input_stack(message_random);
let initial_stack_custom = make_input_stack(message_custom);
let inp: usize = 136;
// Make the kernel.
let kernel_function = KERNEL.global_labels[hash_fn_label];
// Load the message into the kernel.
let interpreter_setup_random = InterpreterSetup {
label: hash_fn_label.to_string(),
stack: vec![
U256::from(inp),
U256::from(message_random.len()),
U256::from(0xdeadbeefu32),
],
segment: KernelGeneral,
memory: vec![(
inp,
message_random
.iter()
.map(|&x| U256::from(x as u32))
.collect(),
)],
};
let interpreter_setup_custom = InterpreterSetup {
label: hash_fn_label.to_string(),
stack: vec![
U256::from(inp),
U256::from(message_custom.len()),
U256::from(0xdeadbeefu32),
],
segment: KernelGeneral,
memory: vec![(
inp,
message_custom
.iter()
.map(|&x| U256::from(x as u32))
.collect(),
)],
};
// Run the kernel code.
let result_random = run_interpreter(kernel_function, initial_stack_random)?;
let result_custom = run_interpreter(kernel_function, initial_stack_custom)?;
let result_random = interpreter_setup_random.run().unwrap();
let result_custom = interpreter_setup_custom.run().unwrap();
Ok((
expected_random,
@ -130,17 +149,17 @@ fn test_hash_512(
Ok(())
}
#[test]
fn test_sha2() -> Result<()> {
test_hash_256("sha2", &sha2)
}
// #[test]
// fn test_blake2b() -> Result<()> {
// test_hash_512("blake2b", &blake2b)
// }
#[test]
fn test_ripemd() -> Result<()> {
test_hash_256("ripemd_stack", &ripemd)
test_hash_256("ripemd", &ripemd)
}
#[test]
fn test_blake2b() -> Result<()> {
test_hash_512("blake2b", &blake2b)
}
// #[test]
// fn test_sha2() -> Result<()> {
// test_hash_256("sha2", &sha2)
// }

View File

@ -7,7 +7,6 @@ mod fields;
mod hash;
mod mpt;
mod packing;
mod ripemd;
mod rlp;
mod transaction_parsing;

View File

@ -1,56 +0,0 @@
use anyhow::Result;
use ethereum_types::U256;
use itertools::Itertools;
use crate::cpu::kernel::aggregator::KERNEL;
use crate::cpu::kernel::interpreter::run_interpreter;
fn make_input(word: &str) -> Vec<u32> {
let mut input: Vec<u32> = vec![word.len().try_into().unwrap()];
input.append(&mut word.as_bytes().iter().map(|&x| x as u32).collect_vec());
input.push(u32::from_str_radix("deadbeef", 16).unwrap());
input
}
#[test]
fn test_ripemd_reference() -> Result<()> {
let reference = vec![
("", "0x9c1185a5c5e9fc54612808977ee8f548b2258d31"),
("a", "0x0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"),
("abc", "0x8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"),
(
"message digest",
"0x5d0689ef49d2fae572b881b123a85ffa21595f36",
),
(
"abcdefghijklmnopqrstuvwxyz",
"0xf71c27109c692c1b56bbdceb5b9d2865b3708dbc",
),
(
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
"0x12a053384a9c0c88e405a06c27dcf49ada62eb2b",
),
(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
"0xb0e20b6e3116640286ed3a87a5713079b21f5189",
),
(
"12345678901234567890123456789012345678901234567890123456789012345678901234567890",
"0x9b752e45573d4b39f4dbd3323cab82bf63326bfb",
),
];
for (x, y) in reference {
let input: Vec<u32> = make_input(x);
let expected = U256::from(y);
let initial_offset = KERNEL.global_labels["ripemd_stack"];
let initial_stack: Vec<U256> = input.iter().map(|&x| U256::from(x)).rev().collect();
let final_stack: Vec<U256> = run_interpreter(initial_offset, initial_stack)?
.stack()
.to_vec();
let actual = final_stack[0];
assert_eq!(actual, expected);
}
Ok(())
}

View File

@ -0,0 +1,35 @@
use std::ops::Range;
use anyhow::Result;
use ethereum_types::U256;
use crate::cpu::kernel::aggregator::KERNEL;
use crate::cpu::kernel::interpreter::Interpreter;
use crate::memory::segments::Segment;
use crate::witness::memory::MemoryAddress;
pub struct InterpreterSetup {
pub label: String,
pub stack: Vec<U256>,
pub segment: Segment,
pub memory: Vec<(usize, Vec<U256>)>,
}
impl InterpreterSetup {
pub fn run(self) -> Result<Interpreter<'static>> {
let label = KERNEL.global_labels[&self.label];
let mut stack = self.stack;
stack.reverse();
let mut interpreter = Interpreter::new_with_kernel(label, stack);
for (pointer, data) in self.memory {
for (i, term) in data.iter().enumerate() {
interpreter
.generation_state
.memory
.set(MemoryAddress::new(0, self.segment, pointer + i), *term)
}
}
interpreter.run()?;
Ok(interpreter)
}
}

View File

@ -1,6 +1,6 @@
#[allow(dead_code)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
pub(crate) enum Segment {
pub enum Segment {
/// Contains EVM bytecode.
Code = 0,
/// The program stack.