Skip to content

Commit

Permalink
implement Blake2sLastBlock opcode in runner
Browse files Browse the repository at this point in the history
  • Loading branch information
ohad-nir-starkware committed Feb 5, 2025
1 parent 246904f commit 7b7d956
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 94 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#### Upcoming Changes

* feat: implement `Blake2sLastBlock` opcode in VM [#1932](https://github.com/lambdaclass/cairo-vm/pull/1932)

* feat: implement `Blake2s` opcode in VM [#1927](https://github.com/lambdaclass/cairo-vm/pull/1927)

* feat: add `get_u32_range` to `impl VirtualMachine` add `get_u32` and `get_u32_range` to `impl Memory` [#1936](https://github.com/lambdaclass/cairo-vm/pull/1936)
Expand Down
2 changes: 1 addition & 1 deletion cairo-vm-tracer/src/tracer_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ impl TracerData {
let (instruction_encoding, _) =
get_instruction_encoding(entry.pc, &memory, program.prime())?;

let instruction_encoding = instruction_encoding.to_u64();
let instruction_encoding = instruction_encoding.to_u128();
if instruction_encoding.is_none() {
return Err(TraceDataError::FailedToConvertInstructionEncoding);
}
Expand Down
54 changes: 35 additions & 19 deletions cairo_programs/stwo_exclusive_programs/blake2s_opcode_test.cairo
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
%builtins range_check bitwise

from starkware.cairo.common.alloc import alloc
from starkware.cairo.common.bool import FALSE, TRUE
from starkware.cairo.common.cairo_blake2s.blake2s import STATE_SIZE_FELTS, INPUT_BLOCK_FELTS, _get_sigma
from starkware.cairo.common.cairo_blake2s.packed_blake2s import N_PACKED_INSTANCES, blake2s_compress
from starkware.cairo.common.cairo_builtins import BitwiseBuiltin

const COUNTER = 128;
const U32_MASK = 0xffffffff;

// Tests the Blake2s opcode runner using a preexisting implementation within the repo as reference.
// The initial state, a random message of 64 bytes and counter are used as input.
// Both the opcode and the reference implementation are run on the same inputs and then their outputs are compared.
// Tests the Blake2s and Blake2sLastBlock opcode runners using a preexisting implementation within the repo as reference.
// The initial state, a random message of 64 or 56 bytes respectively (the zeros are treated as padding) and counter are used as input.
// Both the opcode and the reference implementation are run on the same inputs and outputs are compared.
// Before comparing the outputs, it is verified that the opcode runner has written the output to the correct location.
func main{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() {
run_blake_test(is_last_block=FALSE);
run_blake_test(is_last_block=TRUE);
return ();
}
func run_blake_test{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(is_last_block: felt) {
alloc_locals;

let (local random_message) = alloc();
Expand All @@ -30,8 +36,8 @@ func main{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() {
assert random_message[11] = 860971754;
assert random_message[12] = 1822893775;
assert random_message[13] = 2008495810;
assert random_message[14] = 2958962335;
assert random_message[15] = 2340515744;
assert random_message[14] = 2958962335;
assert random_message[15] = 2340515744;

let (local input_state) = alloc();
// Set the initial state to IV (IV[0] is modified).
Expand All @@ -52,7 +58,7 @@ func main{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() {
h=input_state,
message=random_message,
t0=COUNTER,
f0=0,
f0=is_last_block * U32_MASK,
sigma=sigma,
output=cairo_output,
);
Expand All @@ -76,7 +82,8 @@ func main{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() {
assert bitwise_ptr[7].y = U32_MASK;

// Run the blake2s opcode runner on the same inputs and store its output.
let vm_output = run_blake2s(
let vm_output = run_blake2s_last_block(
is_last_block = is_last_block,
dst=COUNTER,
op0=input_state,
op1=random_message,
Expand Down Expand Up @@ -107,7 +114,7 @@ func main{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() {
return ();
}

// Forces the runner to execute the Blake2s with the given operands.
// Forces the runner to execute the Blake2s or Blake2sLastBlock opcode with the given operands.
// op0 is a pointer to an array of 8 felts as u32 integers of the state.
// op1 is a pointer to an array of 16 felts as u32 integers of the messsage.
// dst is a felt representing a u32 of the counter.
Expand All @@ -116,7 +123,8 @@ func main{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() {
// An instruction encoding is built from offsets -5, -4, -3 and flags which are all 0 except for
// those denoting uses of fp as the base for operand addresses and flag_opcode_blake (16th flag).
// The instruction is then written to [pc] and the runner is forced to execute Blake2s.
func run_blake2s(
func run_blake2s_last_block(
is_last_block: felt,
dst: felt,
op0: felt*,
op1: felt*,
Expand Down Expand Up @@ -147,17 +155,25 @@ func run_blake2s(
let flag_opcode_call = 0;
let flag_opcode_ret = 0;
let flag_opcode_assert_eq = 0;
let flag_opcode_blake2s = 1;
// Build the instruction encoding.
let flag_num = flag_dst_base_fp+flag_op0_base_fp*(2**1)+flag_op1_imm*(2**2)+flag_op1_base_fp*(2**3)+flag_opcode_blake2s*(2**15);
let instruction_num = offset0 + offset1*(2**16) + offset2*(2**32) + flag_num*(2**48);
static_assert instruction_num==9226608988349300731;
let flag_num = flag_dst_base_fp+flag_op0_base_fp*(2**1)+flag_op1_imm*(2**2)+flag_op1_base_fp*(2**3);
let blake2s_opcode_extension_num = 1;
let blake2s_last_block_opcode_extension_num =2;
let blake2s_instruction_num = offset0 + offset1*(2**16) + offset2*(2**32) + flag_num*(2**48) + blake2s_opcode_extension_num*(2**63);
let blake2s_last_block_instruction_num = offset0 + offset1*(2**16) + offset2*(2**32) + flag_num*(2**48) + blake2s_last_block_opcode_extension_num*(2**63);
static_assert blake2s_instruction_num==9226608988349300731;
static_assert blake2s_last_block_instruction_num==18449981025204076539;
// Write the instruction to [pc] and point [ap] to the designated output.
// Write the instruction to [pc] and point [ap+1] to the designated output.
let (local vm_output) = alloc();
assert [ap] = cast(vm_output, felt);
dw 9226608988349300731;
return cast([ap], felt*);
assert [ap+1] = cast(vm_output, felt);
if (is_last_block == TRUE) {
dw 18449981025204076539;
let vm_output = cast([ap], felt*);
} else {
dw 9226608988349300731;
let vm_output = cast([ap], felt*);
}

return vm_output;
}
9 changes: 9 additions & 0 deletions vm/src/tests/cairo_run_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,15 @@ fn blake2s_opcode_test() {
run_program_simple(program_data.as_slice());
}

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn blake2s_last_block_opcode_test() {
let program_data = include_bytes!(
"../../../cairo_programs/stwo_exclusive_programs/blake2s_last_block_opcode_test.json"
);
run_program_simple(program_data.as_slice());
}

#[test]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn relocate_segments() {
Expand Down
7 changes: 4 additions & 3 deletions vm/src/types/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ pub enum Opcode {
pub enum OpcodeExtension {
Stone,
Blake,
BlakeFinalize,
}

impl Instruction {
Expand All @@ -94,11 +95,11 @@ impl Instruction {

// Returns True if the given instruction looks like a call instruction
pub(crate) fn is_call_instruction(encoded_instruction: &Felt252) -> bool {
let encoded_i64_instruction = match encoded_instruction.to_u64() {
let encoded_u128_instruction = match encoded_instruction.to_u128() {
Some(num) => num,
None => return false,
};
let instruction = match decode_instruction(encoded_i64_instruction) {
let instruction = match decode_instruction(encoded_u128_instruction) {
Ok(inst) => inst,
Err(_) => return false,
};
Expand Down Expand Up @@ -141,7 +142,7 @@ mod tests {
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
fn instruction_size() {
let encoded_instruction = Felt252::from(1226245742482522112_i64);
let instruction = decode_instruction(encoded_instruction.to_u64().unwrap()).unwrap();
let instruction = decode_instruction(encoded_instruction.to_u128().unwrap()).unwrap();
assert_eq!(instruction.size(), 2);
}
}
Loading

0 comments on commit 7b7d956

Please sign in to comment.