Skip to content

Commit

Permalink
ec ops
Browse files Browse the repository at this point in the history
  • Loading branch information
ClementWalter committed Jan 23, 2025
1 parent aa3f1af commit 2f42253
Show file tree
Hide file tree
Showing 7 changed files with 661 additions and 934 deletions.
196 changes: 185 additions & 11 deletions cairo/src/curve/secp256k1.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ from starkware.cairo.common.registers import get_label_location
from starkware.cairo.common.modulo import run_mod_p_circuit

from src.curve.g1_point import G1Point
from src.utils.uint384 import felt_to_uint384
from src.utils.uint384 import felt_to_uint384, uint384_is_neg_mod_p, uint384_eq_mod_p

namespace secp256k1 {
const CURVE_ID = 2;
Expand Down Expand Up @@ -180,26 +180,200 @@ func try_get_point_from_x{
}

// @notice Get a random point from x
func get_point_from_x{
func get_random_point{
range_check96_ptr: felt*,
add_mod_ptr: ModBuiltin*,
mul_mod_ptr: ModBuiltin*,
poseidon_ptr: PoseidonBuiltin*,
}(x: felt, attempt: felt) -> G1Point {
}(seed: felt) -> G1Point {
alloc_locals;
let x_384 = felt_to_uint384(x);
let x_384 = felt_to_uint384(seed);

let (y, is_on_curve) = try_get_point_from_x(x=x_384, v=0);

if (is_on_curve != 0) {
let point = G1Point(x=x_384, y=y);
return point;
} else {
assert poseidon_ptr[0].input.s0 = x;
assert poseidon_ptr[0].input.s1 = attempt;
assert poseidon_ptr[0].input.s2 = 2;
let new_x = poseidon_ptr[0].output.s0;
tempvar poseidon_ptr = poseidon_ptr + PoseidonBuiltin.SIZE;
return get_point_from_x(x=new_x, attempt=attempt + 1);
}

assert poseidon_ptr[0].input.s0 = seed;
assert poseidon_ptr[0].input.s1 = y.d0; // salt
assert poseidon_ptr[0].input.s2 = 2;
let seed = poseidon_ptr[0].output.s0;
tempvar poseidon_ptr = poseidon_ptr + PoseidonBuiltin.SIZE;

return get_random_point(seed=seed);
}

// Add Double an EC point. Doesn't check if the input is on curve nor if it's the point at infinity.
func ec_double{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}(
p: G1Point
) -> G1Point {
alloc_locals;

let add_mod_n = 6;
let (add_offsets_ptr) = get_label_location(ec_double_add_offsets_label);
let mul_mod_n = 5;
let (mul_offsets_ptr) = get_label_location(ec_double_mul_offsets_label);

let input: UInt384* = cast(range_check96_ptr, UInt384*);
assert input[0] = UInt384(3, 0, 0, 0);
assert input[1] = p.x;
assert input[2] = p.y;
assert input[3] = UInt384(secp256k1.A0, secp256k1.A1, secp256k1.A2, secp256k1.A3);

let modulus = UInt384(secp256k1.P0, secp256k1.P1, secp256k1.P2, secp256k1.P3);
assert add_mod_ptr[0] = ModBuiltin(
p=modulus, values_ptr=input, offsets_ptr=add_offsets_ptr, n=add_mod_n
);
assert mul_mod_ptr[0] = ModBuiltin(
p=modulus, values_ptr=input, offsets_ptr=mul_offsets_ptr, n=mul_mod_n
);

%{
from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner
assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1
assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1
ModBuiltinRunner.fill_memory(
memory=memory,
add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], ids.add_mod_n),
mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], ids.mul_mod_n),
)
%}

let add_mod_ptr = &add_mod_ptr[add_mod_n];
let mul_mod_ptr = &mul_mod_ptr[mul_mod_n];
let res = G1Point(
x=[cast(range_check96_ptr + 44, UInt384*)], y=[cast(range_check96_ptr + 56, UInt384*)]
);
let range_check96_ptr = range_check96_ptr + 60; // 56 is the last start index in the offset_ptr array

return res;

ec_double_add_offsets_label:
dw 20;
dw 12;
dw 24;
dw 8;
dw 8;
dw 28;
dw 4;
dw 40;
dw 36;
dw 4;
dw 44;
dw 40;
dw 44;
dw 48;
dw 4;
dw 8;
dw 56;
dw 52;

ec_double_mul_offsets_label:
dw 4;
dw 4;
dw 16;
dw 0;
dw 16;
dw 20;
dw 28;
dw 32;
dw 24;
dw 32;
dw 32;
dw 36;
dw 32;
dw 48;
dw 52;
}

// Add two EC points. Doesn't check if the inputs are on curve nor if they are the point at infinity.
func ec_add{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}(
p: G1Point, q: G1Point
) -> G1Point {
alloc_locals;
let modulus = UInt384(secp256k1.P0, secp256k1.P1, secp256k1.P2, secp256k1.P3);
let same_x = uint384_eq_mod_p(p.x, q.x, modulus);

if (same_x != 0) {
let opposite_y = uint384_is_neg_mod_p(p.y, q.y, modulus);
if (opposite_y != 0) {
// p + (-p) = O (point at infinity)
let res = G1Point(UInt384(0, 0, 0, 0), UInt384(0, 0, 0, 0));
return res;
}

return ec_double(p);
}

let add_mod_n = 6;
let (add_offsets_ptr) = get_label_location(ec_add_add_offsets_label);
let mul_mod_n = 3;
let (mul_offsets_ptr) = get_label_location(ec_add_mul_offsets_label);
let input: UInt384* = cast(range_check96_ptr, UInt384*);
assert input[0] = p.x;
assert input[1] = p.y;
assert input[2] = q.x;
assert input[3] = q.y;

assert add_mod_ptr[0] = ModBuiltin(
p=modulus, values_ptr=input, offsets_ptr=add_offsets_ptr, n=add_mod_n
);
assert mul_mod_ptr[0] = ModBuiltin(
p=modulus, values_ptr=input, offsets_ptr=mul_offsets_ptr, n=mul_mod_n
);

%{
from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner
assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1
assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1
ModBuiltinRunner.fill_memory(
memory=memory,
add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], ids.add_mod_n),
mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], ids.mul_mod_n),
)
%}

let add_mod_ptr = &add_mod_ptr[add_mod_n];
let mul_mod_ptr = &mul_mod_ptr[mul_mod_n];
let range_check96_ptr = range_check96_ptr + 52; // 48 is the last start index in the offset_ptr array

let res = G1Point(
x=[cast(cast(input, felt*) + 36, UInt384*)], y=[cast(cast(input, felt*) + 48, UInt384*)]
);
return res;

ec_add_add_offsets_label:
dw 12;
dw 16;
dw 4;
dw 8;
dw 20;
dw 0;
dw 0;
dw 32;
dw 28;
dw 8;
dw 36;
dw 32;
dw 36;
dw 40;
dw 0;
dw 4;
dw 48;
dw 44;

ec_add_mul_offsets_label:
dw 20;
dw 24;
dw 16;
dw 24;
dw 24;
dw 28;
dw 24;
dw 40;
dw 44;
}
Loading

0 comments on commit 2f42253

Please sign in to comment.