Skip to content

Commit

Permalink
Merge branch 'main' into newhint53-u256_add_low
Browse files Browse the repository at this point in the history
  • Loading branch information
MegaRedHand authored Apr 26, 2023
2 parents 32fdc43 + 33690df commit 38e548d
Show file tree
Hide file tree
Showing 8 changed files with 307 additions and 15 deletions.
76 changes: 73 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,34 @@

#### Upcoming Changes

* Implement hint on cairo_blake2s whitelist [#1039](https://github.com/lambdaclass/cairo-rs/pull/1039)

`BuiltinHintProcessor` now supports the following hint:

```python

%{
# 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)
%}

* Implement hint on `assert_le_felt` for versions 0.6.0 and 0.8.2 [#1047](https://github.com/lambdaclass/cairo-rs/pull/1047):

Expand Down Expand Up @@ -372,6 +400,48 @@
ids.res.high = res_split[1]
```

* Implement hint on vrf.json lib [#1049](https://github.com/lambdaclass/cairo-rs/pull/1049)

`BuiltinHintProcessor` now supports the following hint:

```python
def split(num: int, num_bits_shift: int, length: int):
a = []
for _ in range(length):
a.append( num & ((1 << num_bits_shift) - 1) )
num = num >> num_bits_shift
return tuple(a)

def pack(z, num_bits_shift: int) -> int:
limbs = (z.d0, z.d1, z.d2)
return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))

def pack_extended(z, num_bits_shift: int) -> int:
limbs = (z.d0, z.d1, z.d2, z.d3, z.d4, z.d5)
return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))

a = pack_extended(ids.a, num_bits_shift = 128)
div = pack(ids.div, num_bits_shift = 128)

quotient, remainder = divmod(a, div)

quotient_split = split(quotient, num_bits_shift=128, length=6)

ids.quotient.d0 = quotient_split[0]
ids.quotient.d1 = quotient_split[1]
ids.quotient.d2 = quotient_split[2]
ids.quotient.d3 = quotient_split[3]
ids.quotient.d4 = quotient_split[4]
ids.quotient.d5 = quotient_split[5]

remainder_split = split(remainder, num_bits_shift=128, length=3)
ids.remainder.d0 = remainder_split[0]
ids.remainder.d1 = remainder_split[1]
ids.remainder.d2 = remainder_split[2]
```

_Note: this hint is similar to the one in #983, but with some trailing whitespace removed_

* Add missing hint on vrf.json lib [#1030](https://github.com/lambdaclass/cairo-rs/pull/1030):

`BuiltinHintProcessor` now supports the following hint:
Expand Down Expand Up @@ -482,13 +552,13 @@
a = []
for _ in range(length):
a.append( num & ((1 << num_bits_shift) - 1) )
num = num >> num_bits_shift
num = num >> num_bits_shift
return tuple(a)

def pack(z, num_bits_shift: int) -> int:
limbs = (z.d0, z.d1, z.d2)
return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))

def pack_extended(z, num_bits_shift: int) -> int:
limbs = (z.d0, z.d1, z.d2, z.d3, z.d4, z.d5)
return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
Expand Down Expand Up @@ -982,4 +1052,4 @@
* `pub fn from_vm_error(runner: &CairoRunner, error: VirtualMachineError, pc: usize) -> Self` is now `pub fn from_vm_error(runner: &CairoRunner, vm: &VirtualMachine, error: VirtualMachineError) -> Self`
* `pub fn get_location(pc: &usize, runner: &CairoRunner) -> Option<Location>` is now `pub fn get_location(pc: usize, runner: &CairoRunner) -> Option<Location>`
* `pub fn decode_instruction(encoded_instr: i64, mut imm: Option<BigInt>) -> Result<instruction::Instruction, VirtualMachineError>` is now `pub fn decode_instruction(encoded_instr: i64, mut imm: Option<&BigInt>) -> Result<instruction::Instruction, VirtualMachineError>`
* `VmExcepion` field's string format now mirror their cairo-lang conterparts.
* `VmExcepion` field's string format now mirror their cairo-lang conterparts.
68 changes: 68 additions & 0 deletions cairo_programs/finalize_blake2s_v2_hint.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 ();
}
66 changes: 66 additions & 0 deletions cairo_programs/uint384_extension.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,72 @@ namespace u384_ext {

return (quotient=quotient, remainder=remainder);
}

// same as `unsigned_div_rem_uint768_by_uint384` but with different hint
func unsigned_div_rem_uint768_by_uint384_alt{range_check_ptr}(a: Uint768, div: Uint384) -> (
quotient: Uint768, remainder: Uint384
) {
alloc_locals;
local quotient: Uint768;
local remainder: Uint384;

// If div == 0, return (0, 0).
if (div.d0 + div.d1 + div.d2 == 0) {
return (quotient=Uint768(0, 0, 0, 0, 0, 0), remainder=Uint384(0, 0, 0));
}

%{
def split(num: int, num_bits_shift: int, length: int):
a = []
for _ in range(length):
a.append( num & ((1 << num_bits_shift) - 1) )
num = num >> num_bits_shift
return tuple(a)
def pack(z, num_bits_shift: int) -> int:
limbs = (z.d0, z.d1, z.d2)
return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
def pack_extended(z, num_bits_shift: int) -> int:
limbs = (z.d0, z.d1, z.d2, z.d3, z.d4, z.d5)
return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
a = pack_extended(ids.a, num_bits_shift = 128)
div = pack(ids.div, num_bits_shift = 128)
quotient, remainder = divmod(a, div)
quotient_split = split(quotient, num_bits_shift=128, length=6)
ids.quotient.d0 = quotient_split[0]
ids.quotient.d1 = quotient_split[1]
ids.quotient.d2 = quotient_split[2]
ids.quotient.d3 = quotient_split[3]
ids.quotient.d4 = quotient_split[4]
ids.quotient.d5 = quotient_split[5]
remainder_split = split(remainder, num_bits_shift=128, length=3)
ids.remainder.d0 = remainder_split[0]
ids.remainder.d1 = remainder_split[1]
ids.remainder.d2 = remainder_split[2]
%}
check(quotient);
u384.check(remainder);

let (res_mul_low: Uint768, res_mul_high: Uint384) = mul_uint768_by_uint384_d(quotient, div);

assert res_mul_high = Uint384(0, 0, 0);

let (check_val: Uint768, add_carry: felt) = add_uint768_and_uint384(res_mul_low, remainder);

assert add_carry = 0;
assert check_val = a;

let (is_valid) = u384.lt(remainder, div);
assert is_valid = 1;

return (quotient=quotient, remainder=remainder);
}
}

func main() {
Expand Down
19 changes: 19 additions & 0 deletions cairo_programs/uint384_extension_test.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,26 @@ func test_uint384_extension_operations{range_check_ptr}() {
return ();
}

func test_uint384_unsigned_div_rem_alt{range_check_ptr}() {
// Test unsigned_div_rem_uint768_by_uint384
let a = Uint768(1, 2, 3, 4, 5, 6);
let div = Uint384(6, 7, 8);
let (q, r) = u384_ext.unsigned_div_rem_uint768_by_uint384_alt(a, div);
assert q.d0 = 328319314958874220607240343889245110272;
assert q.d1 = 329648542954659136480144150949525454847;
assert q.d2 = 255211775190703847597530955573826158591;
assert q.d3 = 0;
assert q.d4 = 0;
assert q.d5 = 0;

assert r.d0 = 71778311772385457136805581255138607105;
assert r.d1 = 147544307532125661892322583691118247938;
assert r.d2 = 3;
return ();
}

func main{range_check_ptr: felt}() {
test_uint384_extension_operations();
test_uint384_unsigned_div_rem_alt();
return ();
}
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ impl HintProcessor for BuiltinHintProcessor {
hint_code::REDUCE => {
reduce(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking)
}
hint_code::BLAKE2S_FINALIZE => {
hint_code::BLAKE2S_FINALIZE | hint_code::BLAKE2S_FINALIZE_V2 => {
finalize_blake2s(vm, &hint_data.ids_data, &hint_data.ap_tracking)
}
hint_code::BLAKE2S_ADD_UINT256 => {
Expand Down Expand Up @@ -604,7 +604,8 @@ impl HintProcessor for BuiltinHintProcessor {
hint_code::UINT384_SQRT => {
uint384_sqrt(vm, &hint_data.ids_data, &hint_data.ap_tracking)
}
hint_code::UNSIGNED_DIV_REM_UINT768_BY_UINT384 => {
hint_code::UNSIGNED_DIV_REM_UINT768_BY_UINT384
| hint_code::UNSIGNED_DIV_REM_UINT768_BY_UINT384_STRIPPED => {
unsigned_div_rem_uint768_by_uint384(vm, &hint_data.ids_data, &hint_data.ap_tracking)
}
hint_code::GET_SQUARE_ROOT => {
Expand Down
59 changes: 59 additions & 0 deletions src/hint_processor/builtin_hint_processor/hint_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,27 @@ output = blake2s_compress(
padding = (modified_iv + message + [0, 0xffffffff] + output) * (_n_packed_instances - 1)
segments.write_arg(ids.blake2s_ptr_end, padding)"#;

pub const BLAKE2S_FINALIZE_V2: &str = r#"# 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)"#;

pub const BLAKE2S_ADD_UINT256: &str = r#"B = 32
MASK = 2 ** 32 - 1
segments.write_arg(ids.data, [(ids.low >> (B * i)) & MASK for i in range(4)])
Expand Down Expand Up @@ -896,6 +917,7 @@ root_split = split(root, num_bits_shift=128, length=3)
ids.root.d0 = root_split[0]
ids.root.d1 = root_split[1]
ids.root.d2 = root_split[2]";

pub const UNSIGNED_DIV_REM_UINT768_BY_UINT384: &str =
"def split(num: int, num_bits_shift: int, length: int):
a = []
Expand Down Expand Up @@ -930,6 +952,43 @@ remainder_split = split(remainder, num_bits_shift=128, length=3)
ids.remainder.d0 = remainder_split[0]
ids.remainder.d1 = remainder_split[1]
ids.remainder.d2 = remainder_split[2]";

// equal to UNSIGNED_DIV_REM_UINT768_BY_UINT384 but with some whitespace removed
// in the `num = num >> num_bits_shift` and between `pack` and `pack_extended`
pub const UNSIGNED_DIV_REM_UINT768_BY_UINT384_STRIPPED: &str = r#"def split(num: int, num_bits_shift: int, length: int):
a = []
for _ in range(length):
a.append( num & ((1 << num_bits_shift) - 1) )
num = num >> num_bits_shift
return tuple(a)
def pack(z, num_bits_shift: int) -> int:
limbs = (z.d0, z.d1, z.d2)
return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
def pack_extended(z, num_bits_shift: int) -> int:
limbs = (z.d0, z.d1, z.d2, z.d3, z.d4, z.d5)
return sum(limb << (num_bits_shift * i) for i, limb in enumerate(limbs))
a = pack_extended(ids.a, num_bits_shift = 128)
div = pack(ids.div, num_bits_shift = 128)
quotient, remainder = divmod(a, div)
quotient_split = split(quotient, num_bits_shift=128, length=6)
ids.quotient.d0 = quotient_split[0]
ids.quotient.d1 = quotient_split[1]
ids.quotient.d2 = quotient_split[2]
ids.quotient.d3 = quotient_split[3]
ids.quotient.d4 = quotient_split[4]
ids.quotient.d5 = quotient_split[5]
remainder_split = split(remainder, num_bits_shift=128, length=3)
ids.remainder.d0 = remainder_split[0]
ids.remainder.d1 = remainder_split[1]
ids.remainder.d2 = remainder_split[2]"#;

pub const UINT384_SIGNED_NN: &str = "memory[ap] = 1 if 0 <= (ids.a.d2 % PRIME) < 2 ** 127 else 0";

pub(crate) const GET_SQUARE_ROOT: &str =
Expand Down
Loading

0 comments on commit 38e548d

Please sign in to comment.