Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement IS_QUAD_RESIDUE hint #216

Merged
merged 61 commits into from
Sep 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
30e2e67
EcOp Builtin
mmsc2 Aug 11, 2023
32950cb
Change b for ec in methods
mmsc2 Aug 11, 2023
91695a3
Change name
mmsc2 Aug 11, 2023
96d0a6c
Merge branch 'main' into EcOpBuiltin
mmsc2 Sep 6, 2023
6c3f5ee
implement shift left for felt
mmsc2 Sep 6, 2023
af96293
Implement Decude memory cell
mmsc2 Sep 6, 2023
95e6349
deduced memory cell
mmsc2 Sep 7, 2023
aa3f158
Add pow function
mmsc2 Sep 7, 2023
c2675ea
Add pow tests
mmsc2 Sep 7, 2023
951209c
Add point on curve
mmsc2 Sep 7, 2023
f06e6ba
Merge branch 'main' into EcOpBuiltin
mmsc2 Sep 7, 2023
428bfd8
implement math functions
mmsc2 Sep 7, 2023
a048726
Math functions
mmsc2 Sep 8, 2023
c3fe6a1
Ec double point
mmsc2 Sep 8, 2023
d513194
Test for point on curve
mmsc2 Sep 8, 2023
4bab01d
merge main
mmsc2 Sep 8, 2023
1884435
Test ec on impl
mmsc2 Sep 11, 2023
f0e857f
debug info
mmsc2 Sep 12, 2023
70a99bc
Add DivMod func
Sep 12, 2023
4320a09
Merge branch 'main' of github.com:lambdaclass/cairo-vm.go into implem…
Sep 12, 2023
092e658
make fmt
Sep 12, 2023
368f9d5
Fix and error
mmsc2 Sep 12, 2023
03cdc7d
Merge branch 'implement-div-mod-func' into EcOpBuiltin
mmsc2 Sep 12, 2023
ada0266
Fix ec impl function, add div mod of math utils
mmsc2 Sep 12, 2023
2a702f4
Fix format, delete debug info
mmsc2 Sep 12, 2023
9d7d605
Delete prints in test
mmsc2 Sep 12, 2023
b39dd2f
Add more tests
mmsc2 Sep 13, 2023
2decb87
Merge main
mmsc2 Sep 13, 2023
af19748
Add deduce memory cell tests
mmsc2 Sep 13, 2023
4c6268b
Fix format of tests
mmsc2 Sep 13, 2023
5a043d1
Add failure test
mmsc2 Sep 13, 2023
cbc24e7
Integration test
mmsc2 Sep 13, 2023
0f49b9a
Merge branch 'main' into EcOpBuiltin
mmsc2 Sep 13, 2023
4f2bf46
Fix format
mmsc2 Sep 13, 2023
5d340aa
Comment integration test for now
mmsc2 Sep 13, 2023
0145060
Fix error type across platforms
mmsc2 Sep 13, 2023
dbce897
Delete unused file
mmsc2 Sep 13, 2023
94d7efe
Use constans
mmsc2 Sep 13, 2023
73ed7c4
Add Felt.IsOne()
pefontana Sep 13, 2023
fa55857
Add is_quad_residue hint code
pefontana Sep 13, 2023
819c378
Change string for be bytes
mmsc2 Sep 13, 2023
2f058ad
Error handling
mmsc2 Sep 13, 2023
ccd24b9
Use cached value
mmsc2 Sep 13, 2023
bb9482f
Improve error message
mmsc2 Sep 13, 2023
11e5e4b
Add integration test
pefontana Sep 13, 2023
f050712
Merge branch 'EcOpBuiltin' into hint_is_quad_residue
pefontana Sep 13, 2023
95a0ba6
Add Pow and Sqrt FFII
pefontana Sep 13, 2023
da444ce
implement func is_quad_residue
pefontana Sep 13, 2023
f8d1bc6
Add unit test TestPowFelt
pefontana Sep 14, 2023
b613c7c
Add lambdaworks.SignedMaxValue + fix hint
pefontana Sep 15, 2023
2701f3f
Add lambdaworks.max_value
pefontana Sep 15, 2023
3501a39
minot fix
pefontana Sep 15, 2023
2983d60
typo
pefontana Sep 15, 2023
8a57ece
Merge branch 'main' into hint_is_quad_residue
pefontana Sep 15, 2023
1d17c8a
Remove max value
pefontana Sep 15, 2023
068f2ce
Add sqrt Test
pefontana Sep 15, 2023
1326a92
Add sqrt Test
pefontana Sep 15, 2023
a62126e
Remove unused constant
pefontana Sep 15, 2023
bb08ca6
Merge branch 'main' into hint_is_quad_residue
entropidelic Sep 18, 2023
e764576
Fix merge main conflicts
pefontana Sep 18, 2023
6bf6762
Add integration test TestIsQuadResidueoHintProofMode
pefontana Sep 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions cairo_programs/is_quad_residue.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
%builtins output
from starkware.cairo.common.serialize import serialize_word
from starkware.cairo.common.math import is_quad_residue
from starkware.cairo.common.alloc import alloc

func fill_array(array_start: felt*, iter: felt) -> () {
if (iter == 8) {
return ();
}
assert array_start[iter] = iter;
return fill_array(array_start, iter + 1);
}

func check_quad_res{output_ptr: felt*}(inputs: felt*, expected: felt*, iter: felt) {
if (iter == 8) {
return ();
}
serialize_word(inputs[iter]);
serialize_word(expected[iter]);

assert is_quad_residue(inputs[iter]) = expected[iter];
return check_quad_res(inputs, expected, iter + 1);
}

func main{output_ptr: felt*}() {
alloc_locals;
let (inputs: felt*) = alloc();
fill_array(inputs, 0);

let (expected: felt*) = alloc();
assert expected[0] = 1;
assert expected[1] = 1;
assert expected[2] = 1;
assert expected[3] = 0;
assert expected[4] = 1;
assert expected[5] = 1;
assert expected[6] = 0;
assert expected[7] = 1;

check_quad_res(inputs, expected, 0);

return ();
}
43 changes: 43 additions & 0 deletions cairo_programs/proof_programs/is_quad_residue.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
%builtins output
from starkware.cairo.common.serialize import serialize_word
from starkware.cairo.common.math import is_quad_residue
from starkware.cairo.common.alloc import alloc

func fill_array(array_start: felt*, iter: felt) -> () {
if (iter == 8) {
return ();
}
assert array_start[iter] = iter;
return fill_array(array_start, iter + 1);
}

func check_quad_res{output_ptr: felt*}(inputs: felt*, expected: felt*, iter: felt) {
if (iter == 8) {
return ();
}
serialize_word(inputs[iter]);
serialize_word(expected[iter]);

assert is_quad_residue(inputs[iter]) = expected[iter];
return check_quad_res(inputs, expected, iter + 1);
}

func main{output_ptr: felt*}() {
alloc_locals;
let (inputs: felt*) = alloc();
fill_array(inputs, 0);

let (expected: felt*) = alloc();
assert expected[0] = 1;
assert expected[1] = 1;
assert expected[2] = 1;
assert expected[3] = 0;
assert expected[4] = 1;
assert expected[5] = 1;
assert expected[6] = 0;
assert expected[7] = 1;

check_quad_res(inputs, expected, 0);

return ();
}
2 changes: 2 additions & 0 deletions pkg/hints/hint_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ func (p *CairoVmHintProcessor) ExecuteHint(vm *vm.VirtualMachine, hintData *any,
return is_positive(data.Ids, vm)
case ASSERT_NOT_ZERO:
return assert_not_zero(data.Ids, vm)
case IS_QUAD_RESIDUE:
return is_quad_residue(data.Ids, vm)
case DEFAULT_DICT_NEW:
return defaultDictNew(data.Ids, execScopes, vm)
case DICT_READ:
Expand Down
9 changes: 9 additions & 0 deletions pkg/hints/math_hint_codes.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ const IS_POSITIVE = "from starkware.cairo.common.math_utils import is_positive\n

const ASSERT_NOT_ZERO = "from starkware.cairo.common.math_utils import assert_integer\nassert_integer(ids.value)\nassert ids.value % PRIME != 0, f'assert_not_zero failed: {ids.value} = 0.'"

const IS_QUAD_RESIDUE = `from starkware.crypto.signature.signature import FIELD_PRIME
from starkware.python.math_utils import div_mod, is_quad_residue, sqrt

x = ids.x
if is_quad_residue(x, FIELD_PRIME):
ids.y = sqrt(x, FIELD_PRIME)
else:
ids.y = sqrt(div_mod(x, 3, FIELD_PRIME), FIELD_PRIME)`

const ASSERT_NOT_EQUAL = "from starkware.cairo.lang.vm.relocatable import RelocatableValue\nboth_ints = isinstance(ids.a, int) and isinstance(ids.b, int)\nboth_relocatable = (\n isinstance(ids.a, RelocatableValue) and isinstance(ids.b, RelocatableValue) and\n ids.a.segment_index == ids.b.segment_index)\nassert both_ints or both_relocatable, \\\n f'assert_not_equal failed: non-comparable values: {ids.a}, {ids.b}.'\nassert (ids.a - ids.b) % PRIME != 0, f'assert_not_equal failed: {ids.a} = {ids.b}.'"

const SQRT = "from starkware.python.math_utils import isqrt\nvalue = ids.value % PRIME\nassert value < 2 ** 250, f\"value={value} is outside of the range [0, 2**250).\"\nassert 2 ** 250 < PRIME\nids.root = isqrt(value)"
33 changes: 33 additions & 0 deletions pkg/hints/math_hints.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package hints
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/lambdaworks"
. "github.com/lambdaclass/cairo-vm.go/pkg/lambdaworks"
. "github.com/lambdaclass/cairo-vm.go/pkg/math_utils"
. "github.com/lambdaclass/cairo-vm.go/pkg/vm"
Expand Down Expand Up @@ -65,6 +66,38 @@ func assert_not_zero(ids IdsManager, vm *VirtualMachine) error {
return nil
}

// Implements hint:from starkware.cairo.common.math.cairo
//
// %{
// from starkware.crypto.signature.signature import FIELD_PRIME
// from starkware.python.math_utils import div_mod, is_quad_residue, sqrt
//
// x = ids.x
// if is_quad_residue(x, FIELD_PRIME):
// ids.y = sqrt(x, FIELD_PRIME)
// else:
// ids.y = sqrt(div_mod(x, 3, FIELD_PRIME), FIELD_PRIME)
//
// %}
func is_quad_residue(ids IdsManager, vm *VirtualMachine) error {
x, err := ids.GetFelt("x", vm)
if err != nil {
return err
}
if x.IsZero() || x.IsOne() {
ids.Insert("y", NewMaybeRelocatableFelt(x), vm)

} else if x.Pow(SignedFeltMaxValue()) == FeltOne() {
num := x.Sqrt()
ids.Insert("y", NewMaybeRelocatableFelt(num), vm)

} else {
num := (x.Div(lambdaworks.FeltFromUint64(3))).Sqrt()
ids.Insert("y", NewMaybeRelocatableFelt(num), vm)
}
return nil
}

func assert_not_equal(ids IdsManager, vm *VirtualMachine) error {
// Extract Ids Variables
a, err := ids.Get("a", vm)
Expand Down
28 changes: 28 additions & 0 deletions pkg/lambdaworks/lambdaworks.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,21 @@ func FeltOne() Felt {
return fromC(result)
}

// Gets the Signed Felt max value: 0x400000000000008800000000000000000000000000000000000000000000000
func SignedFeltMaxValue() Felt {
var result C.felt_t
C.signed_felt_max_value(&result[0])
return fromC(result)
}

func (f Felt) IsZero() bool {
return f == FeltZero()
}

func (f Felt) IsOne() bool {
return f == FeltOne()
}

// Writes the result variable with the sum of a and b felts.
func (a Felt) Add(b Felt) Felt {
var result C.felt_t
Expand Down Expand Up @@ -242,6 +253,23 @@ func (a Felt) PowUint(p uint32) Felt {
return fromC(result)
}

func (a Felt) Pow(p Felt) Felt {
var result C.felt_t
var a_c C.felt_t = a.toC()
var p_c C.felt_t = p.toC()

C.felt_pow(&a_c[0], &p_c[0], &result[0])
return fromC(result)
}

func (a Felt) Sqrt() Felt {
var result C.felt_t
var a_c C.felt_t = a.toC()

C.felt_sqrt(&a_c[0], &result[0])
return fromC(result)
}

func (a Felt) Shr(b uint) Felt {
var result C.felt_t
var a_c C.felt_t = a.toC()
Expand Down
134 changes: 134 additions & 0 deletions pkg/lambdaworks/lambdaworks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,128 @@ func TestPow3(t *testing.T) {
}
}

func TestPowFelt(t *testing.T) {
felt_base := lambdaworks.FeltFromUint64(1233)
felt_exp := lambdaworks.FeltFromUint64(1233)

expected := lambdaworks.FeltFromDecString("3418065535446855313238995939000463244303872344528900201124636596003468607918")
result := felt_base.Pow(felt_exp)

if expected != result {
t.Errorf("TestPowFelt Failed, expecte: %v, got %v", expected, result)
}

felt_base = lambdaworks.FeltFromDecString("12383109480418712378780123")
felt_exp = lambdaworks.FeltFromDecString("91872587643897123781098123")

expected = lambdaworks.FeltFromDecString("2088955439096022421017346644949649198425019274657075865926754962561596407882")
result = felt_base.Pow(felt_exp)

if expected != result {
t.Errorf("TestPowFelt Failed, expecte: %v, got %v", expected, result)
}

felt_base = lambdaworks.FeltFromDecString("1480418712378780123123543345665445665445")
felt_exp = lambdaworks.FeltFromDecString("91872587643897345876123781098124353")

expected = lambdaworks.FeltFromDecString("3250055959035395902088721634924698439245455440785258481507488871970708539723")
result = felt_base.Pow(felt_exp)

if expected != result {
t.Errorf("TestPowFelt Failed, expecte: %v, got %v", expected, result)
}

felt_base = lambdaworks.FeltFromDecString("3250055959035395902088721634924698439245455440785258481507488871970708539723")
felt_exp = lambdaworks.FeltFromDecString("2088955439096022421017346644949649198425019274657075865926754962561596407882")

expected = lambdaworks.FeltFromDecString("2222900320242877003674481253396117682567674359625426155657415083745164507492")
result = felt_base.Pow(felt_exp)

if expected != result {
t.Errorf("TestPowFelt Failed, expecte: %v, got %v", expected, result)
}

felt_base = lambdaworks.FeltFromDecString("3")
felt_exp = lambdaworks.FeltFromDecString("1809251394333065606848661391547535052811553607665798349986546028067936010240")

expected = lambdaworks.FeltFromDecString("3618502788666131213697322783095070105623107215331596699973092056135872020480")
result = felt_base.Pow(felt_exp)

if expected != result {
t.Errorf("TestPowFelt Failed, expecte: %v, got %v", expected, result)
}

felt_base = lambdaworks.FeltFromDecString("6")
felt_exp = lambdaworks.FeltFromDecString("1809251394333065606848661391547535052811553607665798349986546028067936010240")

expected = lambdaworks.FeltFromDecString("3618502788666131213697322783095070105623107215331596699973092056135872020480")
result = felt_base.Pow(felt_exp)

if expected != result {
t.Errorf("TestPowFelt Failed, expecte: %v, got %v", expected, result)
}
}

func TestSqrt(t *testing.T) {

sqrt := lambdaworks.FeltFromDecString("1").Sqrt()
expect_res := lambdaworks.FeltFromDecString("1")

if sqrt != expect_res {
t.Errorf("TestSqrt Failed, expecte: %v, got %v", expect_res, sqrt)
}

sqrt = lambdaworks.FeltFromDecString("2").Sqrt()
expect_res = lambdaworks.FeltFromDecString("1120755473020101814179135767224264702961552391386192943129361948990833801454")

if sqrt != expect_res {
t.Errorf("TestSqrt Failed, expecte: %v, got %v", expect_res, sqrt)
}

sqrt = lambdaworks.FeltFromDecString("231354855").Sqrt()
expect_res = lambdaworks.FeltFromDecString("1025311277904211196612478135732240927612998008429122495456758581279557012570")

if sqrt != expect_res {
t.Errorf("TestSqrt Failed, expecte: %v, got %v", expect_res, sqrt)
}

sqrt = lambdaworks.FeltFromDecString("2837690996375263304037947136281").Sqrt()
expect_res = lambdaworks.FeltFromDecString("1518810120662201067233534392916286105989903317885218522014371199182069054395")

if sqrt != expect_res {
t.Errorf("TestSqrt Failed, expecte: %v, got %v", expect_res, sqrt)
}

sqrt = lambdaworks.FeltFromDecString("2412335192444087475798215188730046737082071476887756022673614366244186268173").Sqrt()
expect_res = lambdaworks.FeltFromDecString("1600105265616524426130944162206101590464382512931039575828824593677922684056")

if sqrt != expect_res {
t.Errorf("TestSqrt Failed, expecte: %v, got %v", expect_res, sqrt)
}

sqrt = lambdaworks.FeltFromDecString("836397911567565091").Sqrt()
expect_res = lambdaworks.FeltFromDecString("1471326547166706568879530640427725594549306523774764149866072915947254299525")

if sqrt != expect_res {
t.Errorf("TestSqrt Failed, expecte: %v, got %v", expect_res, sqrt)
}

sqrt = lambdaworks.FeltFromDecString("1206167596222043737899107594365023368541035738443865566657697352047277454118").Sqrt()
expect_res = lambdaworks.FeltFromDecString("1052329372911162474471895538435386694104976874815914718986386439764768300074")

if sqrt != expect_res {
t.Errorf("TestSqrt Failed, expecte: %v, got %v", expect_res, sqrt)
}

sqrt = lambdaworks.FeltFromDecString("1206167596222043737899107594365023368541035738443865566948239979431619043114").Sqrt()
expect_res = lambdaworks.FeltFromDecString("139198744922466627270517589217125805480206233967015957629136270350373167196")

if sqrt != expect_res {
t.Errorf("TestSqrt Failed, expecte: %v, got %v", expect_res, sqrt)
}

}

func TestFeltNeg1ToString(t *testing.T) {
f_neg_1 := lambdaworks.FeltFromDecString("-1")
expected := "-1"
Expand Down Expand Up @@ -520,3 +642,15 @@ func TestRelocatableToString(t *testing.T) {
}

}

func TestSignedMaxValue(t *testing.T) {

signed_max_value := lambdaworks.SignedFeltMaxValue()
str := signed_max_value.ToHexString()
expect_str := "0x400000000000008800000000000000000000000000000000000000000000000"

if signed_max_value.ToHexString() != expect_str {
t.Errorf("TestSignedMaxValue Failed, expecte: %s, got %s", expect_str, str)
}

}
7 changes: 7 additions & 0 deletions pkg/lambdaworks/lib/lambdaworks.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ void zero(felt_t result);
/* Gets a felt_t representing 1 */
void one(felt_t result);

void signed_felt_max_value(felt_t result);

/* Writes the result variable with the sum of a and b felts. */
void add(felt_t a, felt_t b, felt_t result);

Expand Down Expand Up @@ -73,6 +75,11 @@ void felt_shl(felt_t a, uint64_t num, felt_t result);
/* writes the result variable with a.pow(num) */
void felt_pow_uint(felt_t a, uint32_t num, felt_t result);

/* writes the result variable with a.pow(exponent) */
void felt_pow(felt_t a, felt_t p, felt_t result);

void felt_sqrt(felt_t a, felt_t result);

/* returns the representation of a felt to string */
char *to_signed_felt(felt_t value);

Expand Down
Loading