Skip to content

Commit

Permalink
Implement REDUCE+ & VERIFY_ZERO+ hints (#307)
Browse files Browse the repository at this point in the history
* Add ec hints

* Implement hints

* Add the hints to the processor

* Test pack86 function

* Test hint

* Delete debug info, Test ec negative op

* Second hint test

* Test embedded hint

* Change to Camel case

* Implement slope hints

* Fix format

* Delete github conflict string

* Tests hints

* Tests hints slopes

* Rename misleading name function

* Fix function name

* Fix error in function call

* Delete debug info

* Delete unused import

* Secp hints

* Secpr21

* Add it to the hint processor

* Hints secp

* bigint3 nondet

* Zero verify

* Merge main

* Add hint to hint processor

* Debug info

* Prints

* Test verify with unit test

* Debug unit test

* Test verify zero with debug

* Non det big 3 test

* Modify test to use ids manager

* Add hint codes

* Implement base hint

* Add hints

* Add hints to ExecuteHint

* debug info

* Fix broken test

* Move integration test to cairo_run_test.go

* Move file from hints_utils and rename

* Delete debug

* Return error of IdsData.Insert

* Change to camel case

* Add unit test

* Add unit test

* Add hint codes

* Implement hint

* Add SafeDivBig

* Add generic way to fetch scope variables

* Add generic fetch

* Add generic way to fetch scope variables

* Use more specific error

* Add hints to ExecuteHint

* Add extra hint

* Fix logic, add unit test

* Add unit test

* use boolean flag instead or arg

* Fix scope var name

* Fix scope var name in tests

* Make FetchScopeVar work despite references

* Revert "Make FetchScopeVar work despite references"

This reverts commit 69993be.

* Handle scope variables as big.Int instead of *big.Int

* Fix merge cnflicts

* Fix tests

* Implement Igcdex + add tests

* Implement DivMod

* Use DivMod instead of Div + Mod

* Dont modify the original value in bigint3_split function

* Push test file

* Remove redundant check

* Implement Reduce_V1 hint

* Fix file names

* Add unit test

* Add testing util CheckScopeVar`

* Refactor test

* Merge math_utils/utils & utils/math_utils

* Restore gitignore

* Add hint + tests

* Add test file

* Add REDUCE_V2 hint

* Implement verify_zero hints

* Add verify_zero hints

* Fix fmt

* Implement `GET_POINT_FROM_X` hint (#298)

* Add hint code

* Implement hint

* Add unit test

* Fix test value

* Fix hint logic

* Add unit test

* Add integration test

* fmt

* Fix

* Bump cairo-vm version

---------

Co-authored-by: Milton <[email protected]>
Co-authored-by: mmsc2 <[email protected]>
Co-authored-by: Mariano A. Nicolini <[email protected]>
Co-authored-by: Pedro Fontana <[email protected]>
Co-authored-by: toni-calvin <[email protected]>
  • Loading branch information
6 people authored Oct 25, 2023
1 parent 432dd89 commit c58f01e
Show file tree
Hide file tree
Showing 13 changed files with 616 additions and 7 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
CAIRO_VM_CLI:=cairo-vm/target/release/cairo-vm-cli

$(CAIRO_VM_CLI):
git clone --depth 1 -b v0.8.5 https://github.com/lambdaclass/cairo-vm
git clone --depth 1 -b v0.8.7 https://github.com/lambdaclass/cairo-vm
cd cairo-vm; cargo b --release --bin cairo-vm-cli

# Create proof mode programs.
Expand Down
127 changes: 127 additions & 0 deletions cairo_programs/reduce.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
%builtins range_check

from starkware.cairo.common.cairo_secp.bigint import BigInt3, UnreducedBigInt3, nondet_bigint3

const BASE = 2 ** 86;
const SECP_REM = 19;

func verify_zero{range_check_ptr}(val: UnreducedBigInt3) {
let q = [ap];
%{
from starkware.cairo.common.cairo_secp.secp_utils import pack
SECP_P = 2**255-19
to_assert = pack(ids.val, PRIME)
q, r = divmod(pack(ids.val, PRIME), SECP_P)
assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}."
ids.q = q % PRIME
%}
let q_biased = [ap + 1];
q_biased = q + 2 ** 127, ap++;
[range_check_ptr] = q_biased, ap++;
// This implies that q is in the range [-2**127, 2**127).

tempvar r1 = (val.d0 + q * SECP_REM) / BASE;
assert [range_check_ptr + 1] = r1 + 2 ** 127;
// This implies that r1 is in the range [-2**127, 2**127).
// Therefore, r1 * BASE is in the range [-2**213, 2**213).
// By the soundness assumption, val.d0 is in the range (-2**250, 2**250).
// This implies that r1 * BASE = val.d0 + q * SECP_REM (as integers).

tempvar r2 = (val.d1 + r1) / BASE;
assert [range_check_ptr + 2] = r2 + 2 ** 127;
// Similarly, this implies that r2 * BASE = val.d1 + r1 (as integers).
// Therefore, r2 * BASE**2 = val.d1 * BASE + r1 * BASE.

assert val.d2 = q * (BASE / 8) - r2;
// Similarly, this implies that q * BASE / 4 = val.d2 + r2 (as integers).
// Therefore,
// q * BASE**3 / 4 = val.d2 * BASE**2 + r2 * BASE ** 2 =
// val.d2 * BASE**2 + val.d1 * BASE + r1 * BASE =
// val.d2 * BASE**2 + val.d1 * BASE + val.d0 + q * SECP_REM =
// val + q * SECP_REM.
// Hence, val = q * (BASE**3 / 4 - SECP_REM) = q * (2**256 - SECP_REM) = q * secp256k1_prime.

let range_check_ptr = range_check_ptr + 3;
return ();
}

// Receives an unreduced number, and returns a number that is equal to the original number mod
// Ed25519 prime and in reduced form (meaning every limb is in the range [0, BASE)).
//
// Completeness assumption: x's limbs are in the range (-2**210.99, 2**210.99).
// Soundness assumption: x's limbs are in the range (-2**249.99, 2**249.99).
func reduce_ed25519{range_check_ptr}(x: UnreducedBigInt3) -> (reduced_x: BigInt3) {
%{
from starkware.cairo.common.cairo_secp.secp_utils import pack
SECP_P=2**255-19
value = pack(ids.x, PRIME) % SECP_P
%}
let (reduced_x: BigInt3) = nondet_bigint3();

verify_zero(
UnreducedBigInt3(d0=x.d0 - reduced_x.d0, d1=x.d1 - reduced_x.d1, d2=x.d2 - reduced_x.d2)
);
return (reduced_x=reduced_x);
}

func test_reduce_ed25519{range_check_ptr}() {
let x = UnreducedBigInt3(0, 0, 0);
let (res) = reduce_ed25519(x);
assert res = BigInt3(0, 0, 0);

let x = UnreducedBigInt3(
1113660525233188137217661511617697775365785011829423399545361443,
1243997169368861650657124871657865626433458458266748922940703512,
1484456708474143440067316914074363277495967516029110959982060577,
);
let (res) = reduce_ed25519(x);
assert res = BigInt3(
42193159084937489098474581, 19864776835133205750023223, 916662843592479469328893
);

return ();
}

func reduce_v2{range_check_ptr}(x: UnreducedBigInt3) -> (reduced_x: BigInt3) {
let orig_x = x;
%{ from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P %}
%{
from starkware.cairo.common.cairo_secp.secp_utils import pack
value = pack(ids.x, PRIME) % SECP_P
%}
let (reduced_x: BigInt3) = nondet_bigint3();
verify_zero(
UnreducedBigInt3(
d0=orig_x.d0 - reduced_x.d0,
d1=orig_x.d1 - reduced_x.d1,
d2=orig_x.d2 - reduced_x.d2
)
);
return (reduced_x=reduced_x);
}
func main{range_check_ptr}() {
test_reduce_ed25519();
// reduce_v2 tests
let x = UnreducedBigInt3(0, 0, 0);
let (reduce_v2_a) = reduce_v2(x);
assert reduce_v2_a = BigInt3(
0, 0, 0
);
let y = UnreducedBigInt3(12354, 745634534, 81298789312879123);
let (reduce_v2_b) = reduce_v2(y);
assert reduce_v2_b = BigInt3(
12354, 745634534, 81298789312879123
);
let z = UnreducedBigInt3(12354812987893128791212331231233, 7453123123123123312634534, 8129224990312325879);
let (reduce_v2_c) = reduce_v2(z);
assert reduce_v2_c = BigInt3(
16653320122975184709085185, 7453123123123123312794216, 8129224990312325879
);
return ();
}
24 changes: 24 additions & 0 deletions cairo_programs/signature.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
%builtins range_check

from starkware.cairo.common.cairo_secp.signature import div_mod_n, get_point_from_x
from starkware.cairo.common.cairo_secp.bigint import BigInt3

func main{range_check_ptr: felt}() {
let a: BigInt3 = BigInt3(100, 99, 98);
let b: BigInt3 = BigInt3(10, 9, 8);
let (res) = div_mod_n(a, b);
assert res.d0 = 3413472211745629263979533;
assert res.d1 = 17305268010345238170172332;
assert res.d2 = 11991751872105858217578135;

let x: BigInt3 = BigInt3(100, 99, 98);
let v: felt = 10;
let (point) = get_point_from_x(x, v);
assert point.x.d0 = 100;
assert point.x.d1 = 99;
assert point.x.d2 = 98;
assert point.y.d0 = 50471654703173585387369794;
assert point.y.d1 = 68898944762041070370364387;
assert point.y.d2 = 16932612780945290933872774;
return ();
}
39 changes: 39 additions & 0 deletions pkg/hints/hint_codes/secp_hint_codes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package hint_codes

const IMPORT_SECP256R1_ALPHA = "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_ALPHA as ALPHA"

const IMPORT_SECP256R1_N = "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_N as N"

const IMPORT_SECP256R1_P = "from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P"

const VERIFY_ZERO_EXTERNAL_SECP = "from starkware.cairo.common.cairo_secp.secp_utils import pack\n\nq, r = divmod(pack(ids.val, PRIME), SECP_P)\nassert r == 0, f\"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}.\"\nids.q = q % PRIME"

const REDUCE_V1 = `from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
value = pack(ids.x, PRIME) % SECP_P`

const REDUCE_V2 = `from starkware.cairo.common.cairo_secp.secp_utils import pack
value = pack(ids.x, PRIME) % SECP_P`

const REDUCE_ED25519 = `from starkware.cairo.common.cairo_secp.secp_utils import pack
SECP_P=2**255-19
value = pack(ids.x, PRIME) % SECP_P`

const VERIFY_ZERO_V1 = `from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
q, r = divmod(pack(ids.val, PRIME), SECP_P)
assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}."
ids.q = q % PRIME`

const VERIFY_ZERO_V2 = `from starkware.cairo.common.cairo_secp.secp_utils import SECP_P
q, r = divmod(pack(ids.val, PRIME), SECP_P)
assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}."
ids.q = q % PRIME`

const VERIFY_ZERO_V3 = `from starkware.cairo.common.cairo_secp.secp_utils import pack
SECP_P = 2**255-19
to_assert = pack(ids.val, PRIME)
q, r = divmod(pack(ids.val, PRIME), SECP_P)
assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}."
ids.q = q % PRIME`
6 changes: 0 additions & 6 deletions pkg/hints/hint_codes/secp_p_hint.go

This file was deleted.

12 changes: 12 additions & 0 deletions pkg/hints/hint_codes/signature_hint_codes.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,15 @@ const DIV_MOD_N_SAFE_DIV = "value = k = safe_div(res * b - a, N)"
const DIV_MOD_N_SAFE_DIV_PLUS_ONE = "value = k_plus_one = safe_div(res * b - a, N) + 1"

const XS_SAFE_DIV = "value = k = safe_div(res * s - x, N)"

const GET_POINT_FROM_X = `from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
x_cube_int = pack(ids.x_cube, PRIME) % SECP_P
y_square_int = (x_cube_int + ids.BETA) % SECP_P
y = pow(y_square_int, (SECP_P + 1) // 4, SECP_P)
# We need to decide whether to take y or SECP_P - y.
if ids.v % 2 == y % 2:
value = y
else:
value = (-y) % SECP_P`
13 changes: 13 additions & 0 deletions pkg/hints/hint_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"strings"

. "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/hints/hint_utils"
. "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks"
"github.com/lambdaclass/cairo-vm.go/pkg/parser"
Expand Down Expand Up @@ -218,6 +219,8 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any,
return divModNSafeDiv(data.Ids, execScopes, "a", "b", false)
case DIV_MOD_N_SAFE_DIV_PLUS_ONE:
return divModNSafeDiv(data.Ids, execScopes, "a", "b", true)
case GET_POINT_FROM_X:
return getPointFromX(data.Ids, vm, execScopes, constants)
case VERIFY_ZERO_EXTERNAL_SECP:
return verifyZeroWithExternalConst(*vm, *execScopes, data.Ids)
case FAST_EC_ADD_ASSIGN_NEW_X:
Expand All @@ -228,6 +231,16 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any,
return fastEcAddAssignNewX(data.Ids, vm, execScopes, "pt0", "pt1", SECP_P())
case FAST_EC_ADD_ASSIGN_NEW_Y:
return fastEcAddAssignNewY(execScopes)
case REDUCE_V1:
return reduceV1(data.Ids, vm, execScopes)
case REDUCE_V2:
return reduceV2(data.Ids, vm, execScopes)
case REDUCE_ED25519:
return reduceED25519(data.Ids, vm, execScopes)
case VERIFY_ZERO_V1, VERIFY_ZERO_V2:
return verifyZero(data.Ids, vm, execScopes, hint_utils.SECP_P())
case VERIFY_ZERO_V3:
return verifyZero(data.Ids, vm, execScopes, hint_utils.SECP_P_V2())
case BLAKE2S_COMPUTE:
return blake2sCompute(data.Ids, vm)
default:
Expand Down
64 changes: 64 additions & 0 deletions pkg/hints/secp_hints.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package hints

import (
"math/big"

. "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/types"
. "github.com/lambdaclass/cairo-vm.go/pkg/vm"
"github.com/lambdaclass/cairo-vm.go/pkg/vm/memory"
"github.com/pkg/errors"
)

func reduceV1(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes) error {
secpP := SECP_P()
scopes.AssignOrUpdateVariable("SECP_P", secpP)
value, err := Uint384FromVarName("x", ids, vm)
if err != nil {
return err
}
packedValue := value.Pack86()
scopes.AssignOrUpdateVariable("value", *new(big.Int).Mod(&packedValue, &secpP))
return nil
}

func reduceV2(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes) error {
secpP, err := FetchScopeVar[big.Int]("SECP_P", scopes)
if err != nil {
return err
}
value, err := Uint384FromVarName("x", ids, vm)
if err != nil {
return err
}
packedValue := value.Pack86()
scopes.AssignOrUpdateVariable("value", *new(big.Int).Mod(&packedValue, &secpP))
return nil
}

func reduceED25519(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes) error {
secpP := SECP_P_V2()
scopes.AssignOrUpdateVariable("SECP_P", secpP)
value, err := Uint384FromVarName("x", ids, vm)
if err != nil {
return err
}
packedValue := value.Pack86()
scopes.AssignOrUpdateVariable("value", *new(big.Int).Mod(&packedValue, &secpP))
return nil
}

func verifyZero(ids IdsManager, vm *VirtualMachine, scopes *ExecutionScopes, secpP big.Int) error {
scopes.AssignOrUpdateVariable("SECP_P", secpP)
valUnpacked, err := Uint384FromVarName("val", ids, vm)
if err != nil {
return err
}
val := valUnpacked.Pack86()
q, r := new(big.Int).DivMod(&val, &secpP, new(big.Int))
if r.Cmp(big.NewInt(0)) != 0 {
return errors.Errorf("verify_zero: Invalid input %s", val.Text(10))
}
return ids.Insert("q", memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromBigInt(q)), vm)
}
Loading

0 comments on commit c58f01e

Please sign in to comment.