-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* 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 * debug info * Fix broken test * Move file from hints_utils and rename * Delete debug * Move integration test to cairo_run_test.go * Return error of IdsData.Insert * Change to camel case * Delete merge characters --------- Co-authored-by: Mariano A. Nicolini <[email protected]>
- Loading branch information
1 parent
d638fec
commit 8a6c949
Showing
13 changed files
with
600 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,212 @@ | ||
%builtins range_check | ||
|
||
// Source: https://github.com/rdubois-crypto/efficient-secp256r1/blob/4b74807c5e91f1ed4cb00a1c973be05c63986e61/src/secp256r1/ec.cairo | ||
from starkware.cairo.common.cairo_secp.bigint import BigInt3, UnreducedBigInt3, nondet_bigint3 | ||
from starkware.cairo.common.cairo_secp.ec import EcPoint | ||
|
||
// src.secp256r1.constants | ||
// SECP_REM is defined by the equation: | ||
// secp256r1_prime = 2 ** 256 - SECP_REM. | ||
const SECP_REM = 2 ** 224 - 2 ** 192 - 2 ** 96 + 1; | ||
|
||
const BASE = 2 ** 86; | ||
|
||
// A = 0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc | ||
const A0 = 0x3ffffffffffffffffffffc; | ||
const A1 = 0x3ff; | ||
const A2 = 0xffffffff0000000100000; | ||
|
||
// Constants for unreduced_mul/sqr | ||
const s2 = (-(2 ** 76)) - 2 ** 12; | ||
const s1 = (-(2 ** 66)) + 4; | ||
const s0 = 2 ** 56; | ||
|
||
const r2 = 2 ** 54 - 2 ** 22; | ||
const r1 = -(2 ** 12); | ||
const r0 = 4; | ||
|
||
// src.secp256r1.field | ||
// Adapt from starkware.cairo.common.math's assert_250_bit | ||
func assert_165_bit{range_check_ptr}(value) { | ||
const UPPER_BOUND = 2 ** 165; | ||
const SHIFT = 2 ** 128; | ||
const HIGH_BOUND = UPPER_BOUND / SHIFT; | ||
|
||
let low = [range_check_ptr]; | ||
let high = [range_check_ptr + 1]; | ||
|
||
%{ | ||
from starkware.cairo.common.math_utils import as_int | ||
# Correctness check. | ||
value = as_int(ids.value, PRIME) % PRIME | ||
assert value < ids.UPPER_BOUND, f'{value} is outside of the range [0, 2**250).' | ||
# Calculation for the assertion. | ||
ids.high, ids.low = divmod(ids.value, ids.SHIFT) | ||
%} | ||
|
||
assert [range_check_ptr + 2] = HIGH_BOUND - 1 - high; | ||
|
||
assert value = high * SHIFT + low; | ||
|
||
let range_check_ptr = range_check_ptr + 3; | ||
return (); | ||
} | ||
|
||
// src.secp256r1.field | ||
// Computes the multiplication of two big integers, given in BigInt3 representation, modulo the | ||
// secp256r1 prime. | ||
// | ||
// Arguments: | ||
// x, y - the two BigInt3 to operate on. | ||
// | ||
// Returns: | ||
// x * y in an UnreducedBigInt3 representation (the returned limbs may be above 3 * BASE). | ||
// | ||
// This means that if unreduced_mul is called on the result of nondet_bigint3, or the difference | ||
// between two such results, we have: | ||
// Soundness guarantee: the limbs are in the range (). | ||
// Completeness guarantee: the limbs are in the range (). | ||
func unreduced_mul(a: BigInt3, b: BigInt3) -> (res_low: UnreducedBigInt3) { | ||
tempvar twice_d2 = a.d2 * b.d2; | ||
tempvar d1d2 = a.d2 * b.d1 + a.d1 * b.d2; | ||
return ( | ||
UnreducedBigInt3( | ||
d0=a.d0 * b.d0 + s0 * twice_d2 + r0 * d1d2, | ||
d1=a.d1 * b.d0 + a.d0 * b.d1 + s1 * twice_d2 + r1 * d1d2, | ||
d2=a.d2 * b.d0 + a.d1 * b.d1 + a.d0 * b.d2 + s2 * twice_d2 + r2 * d1d2, | ||
), | ||
); | ||
} | ||
|
||
// src.secp256r1.field | ||
// Computes the square of a big integer, given in BigInt3 representation, modulo the | ||
// secp256r1 prime. | ||
// | ||
// Has the same guarantees as in unreduced_mul(a, a). | ||
func unreduced_sqr(a: BigInt3) -> (res_low: UnreducedBigInt3) { | ||
tempvar twice_d2 = a.d2 * a.d2; | ||
tempvar twice_d1d2 = a.d2 * a.d1 + a.d1 * a.d2; | ||
tempvar d1d0 = a.d1 * a.d0; | ||
return ( | ||
UnreducedBigInt3( | ||
d0=a.d0 * a.d0 + s0 * twice_d2 + r0 * twice_d1d2, | ||
d1=d1d0 + d1d0 + s1 * twice_d2 + r1 * twice_d1d2, | ||
d2=a.d2 * a.d0 + a.d1 * a.d1 + a.d0 * a.d2 + s2 * twice_d2 + r2 * twice_d1d2, | ||
), | ||
); | ||
} | ||
|
||
// src.secp256r1.field | ||
// Verifies that the given unreduced value is equal to zero modulo the secp256r1 prime. | ||
// | ||
// Completeness assumption: val's limbs are in the range (-2**210.99, 2**210.99). | ||
// Soundness assumption: val's limbs are in the range (-2**250, 2**250). | ||
func verify_zero{range_check_ptr}(val: UnreducedBigInt3) { | ||
alloc_locals; | ||
local q; | ||
// local q_sign; | ||
let q_sign = 1; | ||
// original: | ||
// %{ from starkware.cairo.common.cairo_secp.secp_utils import SECP256R1_P as SECP_P %} | ||
// %{ | ||
// from starkware.cairo.common.cairo_secp.secp_utils import 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}." | ||
// if q >= 0: | ||
// ids.q = q % PRIME | ||
// ids.q_sign = 1 | ||
// else: | ||
// ids.q = (0-q) % PRIME | ||
// ids.q_sign = -1 % PRIME | ||
// %} | ||
%{ from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P %} | ||
%{ | ||
from starkware.cairo.common.cairo_secp.secp_utils import 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 | ||
%} | ||
// assert_250_bit(q); // 256K steps | ||
// assert_le_felt(q, 2**165); // 275K steps | ||
assert_165_bit(q); | ||
assert q_sign * (val.d2 + val.d1 / BASE + val.d0 / BASE ** 2) = q * ( | ||
(BASE / 4) - SECP_REM / BASE ** 2 | ||
); | ||
// Multiply by BASE**2 both sides: | ||
// (q_sign) * val = q * (BASE**3 / 4 - SECP_REM) | ||
// = q * (2**256 - SECP_REM) = q * secp256r1_prime = 0 mod secp256r1_prime | ||
return (); | ||
} | ||
// Computes the slope of the elliptic curve at a given point. | ||
// The slope is used to compute point + point. | ||
// | ||
// Arguments: | ||
// point - the point to operate on. | ||
// | ||
// Returns: | ||
// slope - the slope of the curve at point, in BigInt3 representation. | ||
// | ||
// Assumption: point != 0. | ||
func compute_doubling_slope{range_check_ptr}(point: EcPoint) -> (slope: BigInt3) { | ||
// Note that y cannot be zero: assume that it is, then point = -point, so 2 * point = 0, which | ||
// contradicts the fact that the size of the curve is odd. | ||
// originals: | ||
// %{ from starkware.cairo.common.cairo_secp.secp_utils import SECP256R1_P as SECP_P %} | ||
// %{ from starkware.cairo.common.cairo_secp.secp_utils import SECP256R1_ALPHA as ALPHA %} | ||
%{ from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P as SECP_P %} | ||
%{ from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_ALPHA as ALPHA %} | ||
%{ | ||
from starkware.cairo.common.cairo_secp.secp_utils import pack | ||
from starkware.python.math_utils import ec_double_slope | ||
# Compute the slope. | ||
x = pack(ids.point.x, PRIME) | ||
y = pack(ids.point.y, PRIME) | ||
value = slope = ec_double_slope(point=(x, y), alpha=ALPHA, p=SECP_P) | ||
%} | ||
let (slope: BigInt3) = nondet_bigint3(); | ||
let (x_sqr: UnreducedBigInt3) = unreduced_sqr(point.x); | ||
let (slope_y: UnreducedBigInt3) = unreduced_mul(slope, point.y); | ||
verify_zero( | ||
UnreducedBigInt3( | ||
d0=3 * x_sqr.d0 + A0 - 2 * slope_y.d0, | ||
d1=3 * x_sqr.d1 + A1 - 2 * slope_y.d1, | ||
d2=3 * x_sqr.d2 + A2 - 2 * slope_y.d2, | ||
), | ||
); | ||
return (slope=slope); | ||
} | ||
func test_doubling_slope{range_check_ptr}() { | ||
let point = EcPoint(BigInt3(614323, 5456867, 101208), BigInt3(773712524, 77371252, 5298795)); | ||
let (slope) = compute_doubling_slope(point); | ||
assert slope = BigInt3( | ||
64081873649130491683833713, 34843994309543177837008178, 16548672716077616016846383 | ||
); | ||
let point = EcPoint( | ||
BigInt3(51215, 36848548548458, 634734734), BigInt3(26362, 263724839599, 901297012) | ||
); | ||
let (slope) = compute_doubling_slope(point); | ||
assert slope = BigInt3( | ||
71848883893335852660776740, 75644451964360469099209675, 547087410329256463669633 | ||
); | ||
return (); | ||
} | ||
func main{range_check_ptr}() { | ||
test_doubling_slope(); | ||
return (); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package hints | ||
|
||
import ( | ||
"errors" | ||
"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" | ||
) | ||
|
||
/* | ||
Implements hint: | ||
%{ | ||
from starkware.cairo.common.cairo_secp.secp_utils import split | ||
segments.write_arg(ids.res.address_, split(value)) | ||
%} | ||
*/ | ||
|
||
func NondetBigInt3(virtual_machine VirtualMachine, execScopes ExecutionScopes, idsData IdsManager) error { | ||
resRelloc, err := idsData.GetAddr("res", &virtual_machine) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
valueUncast, err := execScopes.Get("value") | ||
if err != nil { | ||
return err | ||
} | ||
value, ok := valueUncast.(big.Int) | ||
if !ok { | ||
return errors.New("Could not cast value into big int") | ||
} | ||
|
||
bigint3Split, err := Bigint3Split(value) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
arg := make([]memory.MaybeRelocatable, 0) | ||
|
||
for i := 0; i < 3; i++ { | ||
m := memory.NewMaybeRelocatableFelt(lambdaworks.FeltFromBigInt(&bigint3Split[i])) | ||
arg = append(arg, *m) | ||
} | ||
|
||
_, loadErr := virtual_machine.Segments.LoadData(resRelloc, &arg) | ||
if loadErr != nil { | ||
return loadErr | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package hints_test | ||
|
||
import ( | ||
"math/big" | ||
"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/types" | ||
. "github.com/lambdaclass/cairo-vm.go/pkg/vm" | ||
. "github.com/lambdaclass/cairo-vm.go/pkg/vm/memory" | ||
) | ||
|
||
func TestNonDetBigInt3Ok(t *testing.T) { | ||
vm := NewVirtualMachine() | ||
|
||
vm.Segments.AddSegment() | ||
vm.Segments.AddSegment() | ||
vm.Segments.AddSegment() | ||
|
||
vm.RunContext.Pc = NewRelocatable(0, 0) | ||
vm.RunContext.Ap = NewRelocatable(1, 6) | ||
vm.RunContext.Fp = NewRelocatable(1, 6) | ||
|
||
value, _ := new(big.Int).SetString("7737125245533626718119526477371252455336267181195264773712524553362", 10) | ||
execScopes := NewExecutionScopes() | ||
|
||
execScopes.AssignOrUpdateVariable("value", *value) | ||
|
||
idsManager := SetupIdsForTest( | ||
map[string][]*MaybeRelocatable{ | ||
"res": {nil}, | ||
}, | ||
vm, | ||
) | ||
|
||
hintProcessor := CairoVmHintProcessor{} | ||
hintData := any(HintData{ | ||
Ids: idsManager, | ||
Code: NONDET_BIGINT3_V1, | ||
}) | ||
err := hintProcessor.ExecuteHint(vm, &hintData, nil, execScopes) | ||
if err != nil { | ||
t.Errorf("Non Det Big Int 3 hint test failed with error: %s", err) | ||
} else { | ||
valueInStruct0, err := idsManager.GetStructFieldFelt("res", 0, vm) | ||
expected0 := lambdaworks.FeltFromDecString("773712524553362") | ||
if err != nil { | ||
t.Errorf("error fetching from ids manager : %s", err) | ||
} | ||
if valueInStruct0 != expected0 { | ||
t.Errorf(" Incorrect field value %s, expected %s", valueInStruct0.ToBigInt().Text(10), expected0.ToBigInt().Text(10)) | ||
} | ||
|
||
valueInStruct1, err := idsManager.GetStructFieldFelt("res", 1, vm) | ||
expected1 := lambdaworks.FeltFromDecString("57408430697461422066401280") | ||
if err != nil { | ||
t.Errorf("error fetching from ids manager : %s", err) | ||
} | ||
if valueInStruct1 != expected1 { | ||
t.Errorf(" Incorrect field value %s, expected %s", valueInStruct1.ToBigInt().Text(10), expected1.ToBigInt().Text(10)) | ||
} | ||
|
||
valueInStruct2, err := idsManager.GetStructFieldFelt("res", 2, vm) | ||
expected2 := lambdaworks.FeltFromDecString("1292469707114105") | ||
if err != nil { | ||
t.Errorf("error fetching from ids manager : %s", err) | ||
} | ||
if valueInStruct2 != expected2 { | ||
t.Errorf(" Incorrect field value %s, expected %s", valueInStruct2.ToBigInt().Text(10), expected2.ToBigInt().Text(10)) | ||
} | ||
} | ||
} |
Oops, something went wrong.