Skip to content

Commit

Permalink
Merge branch 'main' of github.com:lambdaclass/cairo-vm.go into uint25…
Browse files Browse the repository at this point in the history
…6-hints
  • Loading branch information
toni-calvin committed Oct 3, 2023
2 parents da80a29 + 76d65f6 commit 0a7cc1e
Show file tree
Hide file tree
Showing 36 changed files with 2,646 additions and 272 deletions.
894 changes: 885 additions & 9 deletions README.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions cairo_programs/cairo_keccak.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ func main{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}() {

return ();
}

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

from starkware.cairo.common.cairo_secp.bigint import BigInt3, nondet_bigint3, BASE, bigint_mul
from starkware.cairo.common.cairo_secp.constants import BETA, N0, N1, N2

// Source: https://github.com/myBraavos/efficient-secp256r1/blob/73cca4d53730cb8b2dcf34e36c7b8f34b96b3230/src/secp256r1/signature.cairo

// Computes a * b^(-1) modulo the size of the elliptic curve (N).
//
// Prover assumptions:
// * All the limbs of a are in the range (-2 ** 210.99, 2 ** 210.99).
// * All the limbs of b are in the range (-2 ** 124.99, 2 ** 124.99).
// * b is in the range [0, 2 ** 256).
//
// Soundness assumptions:
// * The limbs of a are in the range (-2 ** 249, 2 ** 249).
// * The limbs of b are in the range (-2 ** 159.83, 2 ** 159.83).
func div_mod_n{range_check_ptr}(a: BigInt3, b: BigInt3) -> (res: BigInt3) {
%{
from starkware.cairo.common.cairo_secp.secp_utils import N, pack
from starkware.python.math_utils import div_mod, safe_div
a = pack(ids.a, PRIME)
b = pack(ids.b, PRIME)
value = res = div_mod(a, b, N)
%}
let (res) = nondet_bigint3();

%{ value = k_plus_one = safe_div(res * b - a, N) + 1 %}
let (k_plus_one) = nondet_bigint3();
let k = BigInt3(d0=k_plus_one.d0 - 1, d1=k_plus_one.d1, d2=k_plus_one.d2);

let (res_b) = bigint_mul(res, b);
let n = BigInt3(N0, N1, N2);
let (k_n) = bigint_mul(k, n);

// We should now have res_b = k_n + a. Since the numbers are in unreduced form,
// we should handle the carry.

tempvar carry1 = (res_b.d0 - k_n.d0 - a.d0) / BASE;
assert [range_check_ptr + 0] = carry1 + 2 ** 127;

tempvar carry2 = (res_b.d1 - k_n.d1 - a.d1 + carry1) / BASE;
assert [range_check_ptr + 1] = carry2 + 2 ** 127;

tempvar carry3 = (res_b.d2 - k_n.d2 - a.d2 + carry2) / BASE;
assert [range_check_ptr + 2] = carry3 + 2 ** 127;

tempvar carry4 = (res_b.d3 - k_n.d3 + carry3) / BASE;
assert [range_check_ptr + 3] = carry4 + 2 ** 127;

assert res_b.d4 - k_n.d4 + carry4 = 0;

let range_check_ptr = range_check_ptr + 4;

return (res=res);
}

func div_mod_n_alt{range_check_ptr}(a: BigInt3, b: BigInt3) -> (res: BigInt3) {
// just used to import N
%{
from starkware.cairo.common.cairo_secp.secp_utils import N, pack
from starkware.python.math_utils import div_mod, safe_div
a = pack(ids.a, PRIME)
b = pack(ids.b, PRIME)
value = res = div_mod(a, b, N)
%}

%{
from starkware.cairo.common.cairo_secp.secp_utils import pack
from starkware.python.math_utils import div_mod, safe_div
a = pack(ids.a, PRIME)
b = pack(ids.b, PRIME)
value = res = div_mod(a, b, N)
%}
let (res) = nondet_bigint3();

%{ value = k_plus_one = safe_div(res * b - a, N) + 1 %}
let (k_plus_one) = nondet_bigint3();
let k = BigInt3(d0=k_plus_one.d0 - 1, d1=k_plus_one.d1, d2=k_plus_one.d2);

let (res_b) = bigint_mul(res, b);
let n = BigInt3(N0, N1, N2);
let (k_n) = bigint_mul(k, n);

tempvar carry1 = (res_b.d0 - k_n.d0 - a.d0) / BASE;
assert [range_check_ptr + 0] = carry1 + 2 ** 127;

tempvar carry2 = (res_b.d1 - k_n.d1 - a.d1 + carry1) / BASE;
assert [range_check_ptr + 1] = carry2 + 2 ** 127;

tempvar carry3 = (res_b.d2 - k_n.d2 - a.d2 + carry2) / BASE;
assert [range_check_ptr + 2] = carry3 + 2 ** 127;

tempvar carry4 = (res_b.d3 - k_n.d3 + carry3) / BASE;
assert [range_check_ptr + 3] = carry4 + 2 ** 127;

assert res_b.d4 - k_n.d4 + carry4 = 0;

let range_check_ptr = range_check_ptr + 4;

return (res=res);
}

func test_div_mod_n{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 = BigInt3(
3413472211745629263979533, 17305268010345238170172332, 11991751872105858217578135
);

// test alternative hint
let (res_alt) = div_mod_n_alt(a, b);

assert res_alt = res;

return ();
}

func main{range_check_ptr: felt}() {
test_div_mod_n();

return ();
}
32 changes: 32 additions & 0 deletions cairo_programs/ec_double_assign.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
%builtins range_check
from starkware.cairo.common.cairo_secp.bigint import BigInt3, nondet_bigint3
struct EcPoint {
x: BigInt3,
y: BigInt3,
}

func ec_double{range_check_ptr}(point: EcPoint, slope: BigInt3) -> (res: BigInt3) {
%{
from starkware.cairo.common.cairo_secp.secp_utils import pack
SECP_P = 2**255-19
slope = pack(ids.slope, PRIME)
x = pack(ids.point.x, PRIME)
y = pack(ids.point.y, PRIME)
value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P
%}

let (new_x: BigInt3) = nondet_bigint3();
return (res=new_x);
}

func main{range_check_ptr}() {
let p = EcPoint(BigInt3(1,2,3), BigInt3(4,5,6));
let s = BigInt3(7,8,9);
let (res) = ec_double(p, s);
assert res.d0 = 21935;
assert res.d1 = 12420;
assert res.d2 = 184;
return ();
}
1 change: 1 addition & 0 deletions cairo_programs/proof_programs/usort.cairo
22 changes: 22 additions & 0 deletions cairo_programs/usort.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
%builtins range_check
from starkware.cairo.common.usort import usort
from starkware.cairo.common.alloc import alloc

func main{range_check_ptr}() -> () {
alloc_locals;
let (input_array: felt*) = alloc();
assert input_array[0] = 2;
assert input_array[1] = 1;
assert input_array[2] = 0;

let (output_len, output, multiplicities) = usort(input_len=3, input=input_array);

assert output_len = 3;
assert output[0] = 0;
assert output[1] = 1;
assert output[2] = 2;
assert multiplicities[0] = 1;
assert multiplicities[1] = 1;
assert multiplicities[2] = 1;
return ();
}
5 changes: 2 additions & 3 deletions pkg/builtins/ec_op.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"math/big"

"github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks"
"github.com/lambdaclass/cairo-vm.go/pkg/math_utils"
"github.com/lambdaclass/cairo-vm.go/pkg/utils"
"github.com/lambdaclass/cairo-vm.go/pkg/vm/memory"
"github.com/pkg/errors"
Expand Down Expand Up @@ -263,7 +262,7 @@ func LineSlope(point_a PartialSumB, point_b DoublePointB, prime big.Int) (big.In
n := new(big.Int).Sub(&point_a.Y, &point_b.Y)
m := new(big.Int).Sub(&point_a.X, &point_b.X)

z, err := math_utils.DivMod(n, m, &prime)
z, err := utils.DivMod(n, m, &prime)
if err != nil {
return big.Int{}, err
}
Expand Down Expand Up @@ -299,7 +298,7 @@ func EcDoubleSlope(point DoublePointB, alpha big.Int, prime big.Int) (big.Int, e
n.Add(n, &alpha)

m := new(big.Int).Mul(&point.Y, big.NewInt(2))
z, err := math_utils.DivMod(n, m, &prime)
z, err := utils.DivMod(n, m, &prime)

if err != nil {
return big.Int{}, err
Expand Down
43 changes: 43 additions & 0 deletions pkg/hints/ec_hint.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/lambdaclass/cairo-vm.go/pkg/builtins"
"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/types"
. "github.com/lambdaclass/cairo-vm.go/pkg/types"
"github.com/lambdaclass/cairo-vm.go/pkg/vm"
Expand Down Expand Up @@ -184,6 +185,48 @@ func computeSlope(vm *VirtualMachine, execScopes ExecutionScopes, idsData IdsMan
return nil
}

// Implements hint:
// from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
//
// slope = pack(ids.slope, PRIME)
// x = pack(ids.point.x, PRIME)
// y = pack(ids.point.y, PRIME)
//
// value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P
func ecDoubleAssignNewX(vm *VirtualMachine, execScopes ExecutionScopes, ids IdsManager, secpP big.Int) error {
execScopes.AssignOrUpdateVariable("SECP_P", secpP)

slope3, err := BigInt3FromVarName("slope", ids, vm)
if err != nil {
return err
}
packedSlope := slope3.Pack86()
slope := new(big.Int).Mod(&packedSlope, Prime())
point, err := EcPointFromVarName("point", vm, ids)
if err != nil {
return err
}

xPacked := point.X.Pack86()
x := new(big.Int).Mod(&xPacked, Prime())
yPacked := point.Y.Pack86()
y := new(big.Int).Mod(&yPacked, Prime())

value := new(big.Int).Mul(slope, slope)
value = value.Mod(value, &secpP)

value = value.Sub(value, x)
value = value.Sub(value, x)
value = value.Mod(value, &secpP)

execScopes.AssignOrUpdateVariable("slope", slope)
execScopes.AssignOrUpdateVariable("x", x)
execScopes.AssignOrUpdateVariable("y", y)
execScopes.AssignOrUpdateVariable("value", *value)
execScopes.AssignOrUpdateVariable("new_x", *value)
return nil
}

/*
Implements hint:
%{ from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_ALPHA as ALPHA %}
Expand Down
69 changes: 69 additions & 0 deletions pkg/hints/ec_hint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,75 @@ func TestRunComputeSlopeOk(t *testing.T) {
}
}

func TestEcDoubleAssignNewXOk(t *testing.T) {
vm := NewVirtualMachine()
vm.Segments.AddSegment()
idsManager := SetupIdsForTest(
map[string][]*MaybeRelocatable{
"slope": {
NewMaybeRelocatableFelt(FeltFromUint64(3)),
NewMaybeRelocatableFelt(FeltFromUint64(0)),
NewMaybeRelocatableFelt(FeltFromUint64(0)),
},
"point": {
// X
NewMaybeRelocatableFelt(FeltFromUint64(2)),
NewMaybeRelocatableFelt(FeltFromUint64(0)),
NewMaybeRelocatableFelt(FeltFromUint64(0)),
// Y
NewMaybeRelocatableFelt(FeltFromUint64(4)),
NewMaybeRelocatableFelt(FeltFromUint64(0)),
NewMaybeRelocatableFelt(FeltFromUint64(0)),
},
},
vm,
)

hintProcessor := CairoVmHintProcessor{}
hintData := any(HintData{
Ids: idsManager,
Code: EC_DOUBLE_ASSIGN_NEW_X_V1,
})

execScopes := types.NewExecutionScopes()
err := hintProcessor.ExecuteHint(vm, &hintData, nil, execScopes)

if err != nil {
t.Errorf("EC_DOUBLE_ASSIGN_NEW_X hint failed with error: %s", err)
}

slopeUncast, _ := execScopes.Get("slope")
slope := slopeUncast.(*big.Int)
xUncast, _ := execScopes.Get("x")
x := xUncast.(*big.Int)
yUncast, _ := execScopes.Get("y")
y := yUncast.(*big.Int)
valueUncast, _ := execScopes.Get("value")
value := valueUncast.(big.Int)
new_xUncast, _ := execScopes.Get("new_x")
new_x := new_xUncast.(big.Int)

if value.Cmp(&new_x) != 0 {
t.Errorf("EC_DOUBLE_ASSIGN_NEW_X hint failed: new_x != value. %v != %v", new_x, value)
}
expectedRes := big.NewInt(5)
if value.Cmp(expectedRes) != 0 {
t.Errorf("EC_DOUBLE_ASSIGN_NEW_X hint failed: expected value (%v) to be 6", value)
}
expectedSlope := big.NewInt(3)
if slope.Cmp(expectedSlope) != 0 {
t.Errorf("EC_DOUBLE_ASSIGN_NEW_X hint failed: expected slope (%v) to be 3", slope)
}
expectedX := big.NewInt(2)
if x.Cmp(expectedX) != 0 {
t.Errorf("EC_DOUBLE_ASSIGN_NEW_X hint failed: expected x (%v) to be 2", x)
}
expectedY := big.NewInt(4)
if y.Cmp(expectedY) != 0 {
t.Errorf("EC_DOUBLE_ASSIGN_NEW_X hint failed: expected y (%v) to be 4", y)
}
}

func TestRunComputeSlopeV2Ok(t *testing.T) {

vm := NewVirtualMachine()
Expand Down
33 changes: 31 additions & 2 deletions pkg/hints/hint_codes/ec_op_hints.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,39 @@ const EC_NEGATE = "from starkware.cairo.common.cairo_secp.secp_utils import SECP
const EC_NEGATE_EMBEDDED_SECP = "from starkware.cairo.common.cairo_secp.secp_utils import pack\nSECP_P = 2**255-19\n\ny = pack(ids.point.y, PRIME) % SECP_P\n# The modulo operation in python always returns a nonnegative number.\nvalue = (-y) % SECP_P"
const EC_DOUBLE_SLOPE_V1 = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\nfrom starkware.python.math_utils import ec_double_slope\n\n# Compute the slope.\nx = pack(ids.point.x, PRIME)\ny = pack(ids.point.y, PRIME)\nvalue = slope = ec_double_slope(point=(x, y), alpha=0, p=SECP_P)"
const COMPUTE_SLOPE_V1 = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\nfrom starkware.python.math_utils import line_slope\n\n# Compute the slope.\nx0 = pack(ids.point0.x, PRIME)\ny0 = pack(ids.point0.y, PRIME)\nx1 = pack(ids.point1.x, PRIME)\ny1 = pack(ids.point1.y, PRIME)\nvalue = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)"
const EC_DOUBLE_SLOPE_EXTERNAL_CONSTS = "from starkware.cairo.common.cairo_secp.secp_utils import pack\nfrom starkware.python.math_utils import ec_double_slope\n\n# Compute the slope.\nx = pack(ids.point.x, PRIME)\ny = pack(ids.point.y, PRIME)\nvalue = slope = ec_double_slope(point=(x, y), alpha=ALPHA, p=SECP_P)"
const NONDET_BIGINT3_V1 = "from starkware.cairo.common.cairo_secp.secp_utils import split\n\nsegments.write_arg(ids.res.address_, split(value))"
const EC_DOUBLE_ASSIGN_NEW_X_V1 = `from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
slope = pack(ids.slope, PRIME)
x = pack(ids.point.x, PRIME)
y = pack(ids.point.y, PRIME)
value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P`
const EC_DOUBLE_ASSIGN_NEW_X_V2 = `from starkware.cairo.common.cairo_secp.secp_utils import pack
slope = pack(ids.slope, PRIME)
x = pack(ids.point.x, PRIME)
y = pack(ids.point.y, PRIME)
value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P`
const EC_DOUBLE_ASSIGN_NEW_X_V3 = `from starkware.cairo.common.cairo_secp.secp_utils import pack
SECP_P = 2**255-19
slope = pack(ids.slope, PRIME)
x = pack(ids.point.x, PRIME)
y = pack(ids.point.y, PRIME)
value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P`
const EC_DOUBLE_ASSIGN_NEW_X_V4 = `from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
slope = pack(ids.slope, PRIME)
x = pack(ids.pt.x, PRIME)
y = pack(ids.pt.y, PRIME)
value = new_x = (pow(slope, 2, SECP_P) - 2 * x) % SECP_P`
const COMPUTE_SLOPE_V2 = "from starkware.python.math_utils import line_slope\nfrom starkware.cairo.common.cairo_secp.secp_utils import pack\nSECP_P = 2**255-19\n# Compute the slope.\nx0 = pack(ids.point0.x, PRIME)\ny0 = pack(ids.point0.y, PRIME)\nx1 = pack(ids.point1.x, PRIME)\ny1 = pack(ids.point1.y, PRIME)\nvalue = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)"
const COMPUTE_SLOPE_WHITELIST = "from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack\nfrom starkware.python.math_utils import div_mod\n\n# Compute the slope.\nx0 = pack(ids.pt0.x, PRIME)\ny0 = pack(ids.pt0.y, PRIME)\nx1 = pack(ids.pt1.x, PRIME)\ny1 = pack(ids.pt1.y, PRIME)\nvalue = slope = div_mod(y0 - y1, x0 - x1, SECP_P)"
const EC_DOUBLE_SLOPE_EXTERNAL_CONSTS = "from starkware.cairo.common.cairo_secp.secp_utils import pack\nfrom starkware.python.math_utils import ec_double_slope\n\n# Compute the slope.\nx = pack(ids.point.x, PRIME)\ny = pack(ids.point.y, PRIME)\nvalue = slope = ec_double_slope(point=(x, y), alpha=ALPHA, p=SECP_P)"
const NONDET_BIGINT3_V1 = "from starkware.cairo.common.cairo_secp.secp_utils import split\n\nsegments.write_arg(ids.res.address_, split(value))"
const COMPUTE_SLOPE_SECP256R1 = "from starkware.cairo.common.cairo_secp.secp_utils import pack\nfrom starkware.python.math_utils import line_slope\n\n# Compute the slope.\nx0 = pack(ids.point0.x, PRIME)\ny0 = pack(ids.point0.y, PRIME)\nx1 = pack(ids.point1.x, PRIME)\ny1 = pack(ids.point1.y, PRIME)\nvalue = slope = line_slope(point1=(x0, y0), point2=(x1, y1), p=SECP_P)"
const FAST_EC_ADD_ASSIGN_NEW_X = `"from starkware.cairo.common.cairo_secp.secp_utils import SECP_P, pack
Expand Down
Loading

0 comments on commit 0a7cc1e

Please sign in to comment.