Skip to content

Commit

Permalink
Implement Blake2s hints (Part 4) (#315)
Browse files Browse the repository at this point in the history
* Begin implemneting blake2s

* Finish blake2s impl

* Add unit test

* Add more unit tests

* Add integration test

* Implement BLAKE2S_COMPUTE

* Add unit tests

* Add unit tests

* Add newline

* Add integration test

* Implement BLAKE2S_ADD_UINT256_BIGEND hint

* Add unit test

* Add integration test

* Implement finalize_blake2s hint

* Fix removed line

* Add unit test

* Fix test values

* Add + expand integration test

* Implement hint + add quickfix to makefile

* Add hint + integration test

* Implement finalize v3

* Add integration test

* Implement sha256 input hint

* Add unit tests

* Add exmaple blake compress hint

* Add unit test

* Clone from main branch

* Update cairo version

* fix conflict

* fix conflict

* Update cairo-vm version

---------

Co-authored-by: Pedro Fontana <[email protected]>
  • Loading branch information
fmoletta and pefontana authored Nov 21, 2023
1 parent 17a2ee1 commit 31c3628
Show file tree
Hide file tree
Showing 10 changed files with 1,011 additions and 1 deletion.
654 changes: 654 additions & 0 deletions cairo_programs/example_blake2s.cairo

Large diffs are not rendered by default.

68 changes: 68 additions & 0 deletions cairo_programs/finalize_blake2s_v2.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
%builtins range_check bitwise

from starkware.cairo.common.alloc import alloc
from starkware.cairo.common.cairo_blake2s.blake2s import blake2s, _finalize_blake2s_inner, _get_sigma, INSTANCE_SIZE, INPUT_BLOCK_FELTS
from starkware.cairo.common.cairo_blake2s.packed_blake2s import N_PACKED_INSTANCES, blake2s_compress
from starkware.cairo.common.cairo_builtins import BitwiseBuiltin
from starkware.cairo.common.registers import get_fp_and_pc
from starkware.cairo.common.math import assert_nn_le, split_felt, unsigned_div_rem

const BLAKE2S_INPUT_CHUNK_SIZE_FELTS = INPUT_BLOCK_FELTS;

// Verifies that the results of blake2s() are valid.
func finalize_blake2s{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(
blake2s_ptr_start: felt*, blake2s_ptr_end: felt*
) {
alloc_locals;

let (__fp__, _) = get_fp_and_pc();

let (sigma) = _get_sigma();

tempvar n = (blake2s_ptr_end - blake2s_ptr_start) / INSTANCE_SIZE;
if (n == 0) {
return ();
}

%{
# Add dummy pairs of input and output.
from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress
_n_packed_instances = int(ids.N_PACKED_INSTANCES)
assert 0 <= _n_packed_instances < 20
_blake2s_input_chunk_size_felts = int(ids.BLAKE2S_INPUT_CHUNK_SIZE_FELTS)
assert 0 <= _blake2s_input_chunk_size_felts < 100
message = [0] * _blake2s_input_chunk_size_felts
modified_iv = [IV[0] ^ 0x01010020] + IV[1:]
output = blake2s_compress(
message=message,
h=modified_iv,
t0=0,
t1=0,
f0=0xffffffff,
f1=0,
)
padding = (modified_iv + message + [0, 0xffffffff] + output) * (_n_packed_instances - 1)
segments.write_arg(ids.blake2s_ptr_end, padding)
%}

// Compute the amount of chunks (rounded up).
let (local n_chunks, _) = unsigned_div_rem(n + N_PACKED_INSTANCES - 1, N_PACKED_INSTANCES);
let blake2s_ptr = blake2s_ptr_start;
_finalize_blake2s_inner{blake2s_ptr=blake2s_ptr}(n=n_chunks, sigma=sigma);
return ();
}

func main{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() {
alloc_locals;
let inputs: felt* = alloc();
assert inputs[0] = 'Hell';
assert inputs[1] = 'o Wo';
assert inputs[2] = 'rld';
let (local blake2s_ptr_start) = alloc();
let blake2s_ptr = blake2s_ptr_start;
let (output) = blake2s{range_check_ptr=range_check_ptr, blake2s_ptr=blake2s_ptr}(inputs, 9);
finalize_blake2s(blake2s_ptr_start, blake2s_ptr);
return ();
}
54 changes: 54 additions & 0 deletions pkg/hints/blake2s_hints.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,57 @@ func blake2sFinalize(ids IdsManager, vm *VirtualMachine) error {
_, err = vm.Segments.LoadData(blake2sPtrEnd, &data)
return err
}

func blake2sFinalizeV3(ids IdsManager, vm *VirtualMachine) error {
const N_PACKED_INSTANCES = 7
blake2sPtrEnd, err := ids.GetRelocatable("blake2s_ptr_end", vm)
if err != nil {
return err
}
var message [16]uint32
modifiedIv := IV()
modifiedIv[0] = modifiedIv[0] ^ 0x01010020
output := Blake2sCompress(modifiedIv, message, 0, 0, 0xffffffff, 0)
padding := message[:]
padding = append(padding, modifiedIv[:]...)
padding = append(padding, 0, 0xffffffff)
padding = append(padding, output[:]...)
fullPadding := padding
for i := 2; i < N_PACKED_INSTANCES; i++ {
fullPadding = append(fullPadding, padding...)
}
data := Uint32SliceToMRSlice(fullPadding)
_, err = vm.Segments.LoadData(blake2sPtrEnd, &data)
return err
}

func exampleBlake2sCompress(ids IdsManager, vm *VirtualMachine) error {
// Fetch ids variables
blake2sStart, err := ids.GetRelocatable("blake2s_start", vm)
if err != nil {
return err
}
output, err := ids.GetRelocatable("output", vm)
if err != nil {
return err
}
nBytesFelt, err := ids.GetFelt("n_bytes", vm)
if err != nil {
return err
}
nBytes, err := nBytesFelt.ToU32()
if err != nil {
return err
}
// Hint Logic
message, err := getUint32MemoryRange(blake2sStart, 0, 16, &vm.Segments)
if err != nil {
return err
}
modifiedIv := IV()
modifiedIv[0] = modifiedIv[0] ^ 0x01010020
outputState := Blake2sCompress(modifiedIv, [16]uint32(message), nBytes, 0, 0xffffffff, 0)
outputData := Uint32SliceToMRSlice(outputState)
_, err = vm.Segments.LoadData(output, &outputData)
return err
}
76 changes: 76 additions & 0 deletions pkg/hints/blake2s_hints_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,3 +281,79 @@ func TestBlake2sFinaizeOk(t *testing.T) {
t.Errorf("Wrong/No data loaded.\n Expected: %v.\n Got: %v", expectedDataSegment, dataSegment)
}
}

func TestBlake2sFinaizeV3Ok(t *testing.T) {
vm := NewVirtualMachine()
vm.Segments.AddSegment()
data := vm.Segments.AddSegment()
idsManager := SetupIdsForTest(
map[string][]*MaybeRelocatable{
"blake2s_ptr_end": {NewMaybeRelocatableRelocatable(data)},
},
vm,
)
hintProcessor := CairoVmHintProcessor{}
hintData := any(HintData{
Ids: idsManager,
Code: BLAKE2S_FINALIZE_V3,
})
err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil)
if err != nil {
t.Errorf("BLAKE2S_FINALIZE_V3 hint test failed with error %s", err)
}
// Check the data segment
dataSegment, err := vm.Segments.GetFeltRange(data, 204)

expectedDataSegment := []Felt{
FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(),
FeltFromUint(1795745351), FeltFromUint(3144134277), FeltFromUint(1013904242), FeltFromUint(2773480762), FeltFromUint(1359893119), FeltFromUint(2600822924), FeltFromUint(528734635), FeltFromUint(1541459225), FeltZero(), FeltFromUint(4294967295), FeltFromUint(813310313),
FeltFromUint(2491453561), FeltFromUint(3491828193), FeltFromUint(2085238082), FeltFromUint(1219908895), FeltFromUint(514171180), FeltFromUint(4245497115), FeltFromUint(4193177630),

FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(),
FeltFromUint(1795745351), FeltFromUint(3144134277), FeltFromUint(1013904242), FeltFromUint(2773480762), FeltFromUint(1359893119), FeltFromUint(2600822924), FeltFromUint(528734635), FeltFromUint(1541459225), FeltZero(), FeltFromUint(4294967295), FeltFromUint(813310313),
FeltFromUint(2491453561), FeltFromUint(3491828193), FeltFromUint(2085238082), FeltFromUint(1219908895), FeltFromUint(514171180), FeltFromUint(4245497115), FeltFromUint(4193177630),

FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(),
FeltFromUint(1795745351), FeltFromUint(3144134277), FeltFromUint(1013904242), FeltFromUint(2773480762), FeltFromUint(1359893119), FeltFromUint(2600822924), FeltFromUint(528734635), FeltFromUint(1541459225), FeltZero(), FeltFromUint(4294967295), FeltFromUint(813310313),
FeltFromUint(2491453561), FeltFromUint(3491828193), FeltFromUint(2085238082), FeltFromUint(1219908895), FeltFromUint(514171180), FeltFromUint(4245497115), FeltFromUint(4193177630),

FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(),
FeltFromUint(1795745351), FeltFromUint(3144134277), FeltFromUint(1013904242), FeltFromUint(2773480762), FeltFromUint(1359893119), FeltFromUint(2600822924), FeltFromUint(528734635), FeltFromUint(1541459225), FeltZero(), FeltFromUint(4294967295), FeltFromUint(813310313),
FeltFromUint(2491453561), FeltFromUint(3491828193), FeltFromUint(2085238082), FeltFromUint(1219908895), FeltFromUint(514171180), FeltFromUint(4245497115), FeltFromUint(4193177630),

FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(),
FeltFromUint(1795745351), FeltFromUint(3144134277), FeltFromUint(1013904242), FeltFromUint(2773480762), FeltFromUint(1359893119), FeltFromUint(2600822924), FeltFromUint(528734635), FeltFromUint(1541459225), FeltZero(), FeltFromUint(4294967295), FeltFromUint(813310313),
FeltFromUint(2491453561), FeltFromUint(3491828193), FeltFromUint(2085238082), FeltFromUint(1219908895), FeltFromUint(514171180), FeltFromUint(4245497115), FeltFromUint(4193177630),

FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(), FeltZero(),
FeltFromUint(1795745351), FeltFromUint(3144134277), FeltFromUint(1013904242), FeltFromUint(2773480762), FeltFromUint(1359893119), FeltFromUint(2600822924), FeltFromUint(528734635), FeltFromUint(1541459225), FeltZero(), FeltFromUint(4294967295), FeltFromUint(813310313),
FeltFromUint(2491453561), FeltFromUint(3491828193), FeltFromUint(2085238082), FeltFromUint(1219908895), FeltFromUint(514171180), FeltFromUint(4245497115), FeltFromUint(4193177630),
}
if err != nil || !reflect.DeepEqual(dataSegment, expectedDataSegment) {
t.Errorf("Wrong/No data loaded.\n Expected: %v.\n Got: %v", expectedDataSegment, dataSegment)
}
}

func TestExampleBlake2sCompressEmptyInput(t *testing.T) {
vm := NewVirtualMachine()
vm.Segments.AddSegment()
output := vm.Segments.AddSegment()
blake2sStart := vm.Segments.AddSegment()
idsManager := SetupIdsForTest(
map[string][]*MaybeRelocatable{
"output": {NewMaybeRelocatableRelocatable(output)},
"blake2s_start": {NewMaybeRelocatableRelocatable(blake2sStart)},
"n_bytes": {NewMaybeRelocatableFelt(FeltOne())},
},
vm,
)
hintProcessor := CairoVmHintProcessor{}
hintData := any(HintData{
Ids: idsManager,
Code: EXAMPLE_BLAKE2S_COMPRESS,
})
err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil)
if err == nil {
t.Errorf("EXAMPLE_BLAKE2S_COMPRESS hint test should have failed")
}
}
58 changes: 58 additions & 0 deletions pkg/hints/hint_codes/blake2s_hint_codes.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,61 @@ output = blake2s_compress(
)
padding = (modified_iv + message + [0, 0xffffffff] + output) * (_n_packed_instances - 1)
segments.write_arg(ids.blake2s_ptr_end, padding)`

const BLAKE2S_FINALIZE_V2 = `# Add dummy pairs of input and output.
from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress
_n_packed_instances = int(ids.N_PACKED_INSTANCES)
assert 0 <= _n_packed_instances < 20
_blake2s_input_chunk_size_felts = int(ids.BLAKE2S_INPUT_CHUNK_SIZE_FELTS)
assert 0 <= _blake2s_input_chunk_size_felts < 100
message = [0] * _blake2s_input_chunk_size_felts
modified_iv = [IV[0] ^ 0x01010020] + IV[1:]
output = blake2s_compress(
message=message,
h=modified_iv,
t0=0,
t1=0,
f0=0xffffffff,
f1=0,
)
padding = (modified_iv + message + [0, 0xffffffff] + output) * (_n_packed_instances - 1)
segments.write_arg(ids.blake2s_ptr_end, padding)`

const BLAKE2S_FINALIZE_V3 = `# Add dummy pairs of input and output.
from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress
_n_packed_instances = int(ids.N_PACKED_INSTANCES)
assert 0 <= _n_packed_instances < 20
_blake2s_input_chunk_size_felts = int(ids.BLAKE2S_INPUT_CHUNK_SIZE_FELTS)
assert 0 <= _blake2s_input_chunk_size_felts < 100
message = [0] * _blake2s_input_chunk_size_felts
modified_iv = [IV[0] ^ 0x01010020] + IV[1:]
output = blake2s_compress(
message=message,
h=modified_iv,
t0=0,
t1=0,
f0=0xffffffff,
f1=0,
)
padding = (message + modified_iv + [0, 0xffffffff] + output) * (_n_packed_instances - 1)
segments.write_arg(ids.blake2s_ptr_end, padding)`

const EXAMPLE_BLAKE2S_COMPRESS = `from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress
_blake2s_input_chunk_size_felts = int(ids.BLAKE2S_INPUT_CHUNK_SIZE_FELTS)
assert 0 <= _blake2s_input_chunk_size_felts < 100
new_state = blake2s_compress(
message=memory.get_range(ids.blake2s_start, _blake2s_input_chunk_size_felts),
h=[IV[0] ^ 0x01010020] + IV[1:],
t0=ids.n_bytes,
t1=0,
f0=0xffffffff,
f1=0,
)
segments.write_arg(ids.output, new_state)`
3 changes: 3 additions & 0 deletions pkg/hints/hint_codes/sha256_hint_codes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package hint_codes

const SHA256_INPUT = "ids.full_word = int(ids.n_bytes >= 4)"
8 changes: 7 additions & 1 deletion pkg/hints/hint_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,14 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any,
return verifyZero(data.Ids, vm, execScopes, hint_utils.SECP_P_V2())
case BLAKE2S_ADD_UINT256_BIGEND:
return blake2sAddUint256Bigend(data.Ids, vm)
case BLAKE2S_FINALIZE:
case BLAKE2S_FINALIZE, BLAKE2S_FINALIZE_V2:
return blake2sFinalize(data.Ids, vm)
case BLAKE2S_FINALIZE_V3:
return blake2sFinalizeV3(data.Ids, vm)
case SHA256_INPUT:
return sha256Input(data.Ids, vm)
case EXAMPLE_BLAKE2S_COMPRESS:
return exampleBlake2sCompress(data.Ids, vm)
default:
return errors.Errorf("Unknown Hint: %s", data.Code)
}
Expand Down
19 changes: 19 additions & 0 deletions pkg/hints/sha256_hints.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package hints

import (
. "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils"
. "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks"
. "github.com/lambdaclass/cairo-vm.go/pkg/vm"
. "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory"
)

func sha256Input(ids IdsManager, vm *VirtualMachine) error {
nBytes, err := ids.GetFelt("n_bytes", vm)
if err != nil {
return err
}
if nBytes.Cmp(FeltFromUint(4)) != -1 {
return ids.Insert("full_word", NewMaybeRelocatableFelt(FeltOne()), vm)
}
return ids.Insert("full_word", NewMaybeRelocatableFelt(FeltZero()), vm)
}
64 changes: 64 additions & 0 deletions pkg/hints/sha256_hints_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package hints_test

import (
"testing"

. "github.com/lambdaclass/cairo-vm.go/pkg/hints"
. "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_codes"
. "github.com/lambdaclass/cairo-vm.go/pkg/hints/hint_utils"
. "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks"
. "github.com/lambdaclass/cairo-vm.go/pkg/vm"
. "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory"
)

func TestSha256InputFalse(t *testing.T) {
vm := NewVirtualMachine()
vm.Segments.AddSegment()
idsManager := SetupIdsForTest(
map[string][]*MaybeRelocatable{
"n_bytes": {NewMaybeRelocatableFelt(FeltFromUint64(2))},
"full_word": {nil},
},
vm,
)
hintProcessor := CairoVmHintProcessor{}
hintData := any(HintData{
Ids: idsManager,
Code: SHA256_INPUT,
})
err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil)
if err != nil {
t.Errorf("SHA256_INPUT hint test failed with error %s", err)
}
// Check ids.full_word
fullWord, err := idsManager.GetFelt("full_word", vm)
if err != nil || fullWord.Cmp(FeltZero()) != 0 {
t.Error("Wrong/No value inserted into ids.full_word")
}
}

func TestSha256InputTrue(t *testing.T) {
vm := NewVirtualMachine()
vm.Segments.AddSegment()
idsManager := SetupIdsForTest(
map[string][]*MaybeRelocatable{
"n_bytes": {NewMaybeRelocatableFelt(FeltFromUint64(8))},
"full_word": {nil},
},
vm,
)
hintProcessor := CairoVmHintProcessor{}
hintData := any(HintData{
Ids: idsManager,
Code: SHA256_INPUT,
})
err := hintProcessor.ExecuteHint(vm, &hintData, nil, nil)
if err != nil {
t.Errorf("SHA256_INPUT hint test failed with error %s", err)
}
// Check ids.full_word
fullWord, err := idsManager.GetFelt("full_word", vm)
if err != nil || fullWord.Cmp(FeltOne()) != 0 {
t.Error("Wrong/No value inserted into ids.full_word")
}
}
8 changes: 8 additions & 0 deletions pkg/vm/cairo_run/cairo_run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,14 @@ func TestBlake2sIntegrationTests(t *testing.T) {
testProgram("blake2s_integration_tests", t)
}

func TestFinalizeBlake2sV2(t *testing.T) {
testProgram("finalize_blake2s_v2", t)
}

func TestExampleBlake2s(t *testing.T) {
testProgram("example_blake2s", t)
}

func TestUint256Integration(t *testing.T) {
testProgram("uint256_integration_tests", t)
}
Expand Down

0 comments on commit 31c3628

Please sign in to comment.