Skip to content

Commit

Permalink
merge main
Browse files Browse the repository at this point in the history
  • Loading branch information
toni-calvin committed Sep 27, 2023
2 parents c1cd05a + 8a6c949 commit 337f1b7
Show file tree
Hide file tree
Showing 25 changed files with 1,659 additions and 11 deletions.
29 changes: 29 additions & 0 deletions cairo_programs/cairo_keccak.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
%builtins range_check bitwise

from starkware.cairo.common.cairo_keccak.keccak import cairo_keccak, finalize_keccak
from starkware.cairo.common.uint256 import Uint256
from starkware.cairo.common.cairo_builtins import BitwiseBuiltin
from starkware.cairo.common.alloc import alloc

func main{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}() {
alloc_locals;

let (keccak_ptr: felt*) = alloc();
let keccak_ptr_start = keccak_ptr;

let (inputs: felt*) = alloc();

assert inputs[0] = 8031924123371070792;
assert inputs[1] = 560229490;

let n_bytes = 16;

let (res: Uint256) = cairo_keccak{keccak_ptr=keccak_ptr}(inputs=inputs, n_bytes=n_bytes);

assert res.low = 293431514620200399776069983710520819074;
assert res.high = 317109767021952548743448767588473366791;

finalize_keccak(keccak_ptr_start=keccak_ptr_start, keccak_ptr_end=keccak_ptr);

return ();
}
212 changes: 212 additions & 0 deletions cairo_programs/ec_double_slope.cairo
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 ();
}
31 changes: 31 additions & 0 deletions cairo_programs/keccak_add_uint256.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
%builtins output range_check bitwise

from starkware.cairo.common.keccak_utils.keccak_utils import keccak_add_uint256
from starkware.cairo.common.uint256 import Uint256
from starkware.cairo.common.cairo_builtins import BitwiseBuiltin
from starkware.cairo.common.alloc import alloc
from starkware.cairo.common.serialize import serialize_word

func main{output_ptr: felt*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() {
alloc_locals;

let (inputs) = alloc();
let inputs_start = inputs;

let num = Uint256(34623634663146736, 598249824422424658356);

keccak_add_uint256{inputs=inputs_start}(num=num, bigend=0);

assert inputs[0] = 34623634663146736;
assert inputs[1] = 0;
assert inputs[2] = 7954014063719006644;
assert inputs[3] = 32;

serialize_word(inputs[0]);
serialize_word(inputs[1]);
serialize_word(inputs[2]);
serialize_word(inputs[3]);

return ();
}

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

from starkware.cairo.common.keccak import unsafe_keccak, unsafe_keccak_finalize, KeccakState
from starkware.cairo.common.cairo_keccak.keccak import cairo_keccak, finalize_keccak
from starkware.cairo.common.keccak_utils.keccak_utils import keccak_add_uint256
from starkware.cairo.common.alloc import alloc
from starkware.cairo.common.uint256 import Uint256
from starkware.cairo.common.cairo_builtins import BitwiseBuiltin
from starkware.cairo.common.math import unsigned_div_rem

func fill_array(array: felt*, base: felt, step: felt, array_length: felt, iter: felt) {
if (iter == array_length) {
return ();
}
assert array[iter] = base + step * iter;
return fill_array(array, base, step, array_length, iter + 1);
}

func test_integration{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}(iter: felt, last: felt) {
alloc_locals;
if (iter == last) {
return ();
}

let (data_1: felt*) = alloc();
let data_len: felt = 15;
let chunk_len: felt = 5;

fill_array(data_1, iter, iter + 1, data_len, 0);

let (low_1: felt, high_1: felt) = unsafe_keccak(data_1, chunk_len);
let (low_2: felt, high_2: felt) = unsafe_keccak(data_1 + chunk_len, chunk_len);
let (low_3: felt, high_3: felt) = unsafe_keccak(data_1 + 2 * chunk_len, chunk_len);

// With the results of unsafe_keccak, create an array to pass to unsafe_keccak_finalize
// through a KeccakState
let (data_2: felt*) = alloc();
assert data_2[0] = low_1;
assert data_2[1] = high_1;
assert data_2[2] = low_2;
assert data_2[3] = high_2;
assert data_2[4] = low_3;
assert data_2[5] = high_3;

let keccak_state: KeccakState = KeccakState(start_ptr=data_2, end_ptr=data_2 + 6);
let res_1: Uint256 = unsafe_keccak_finalize(keccak_state);

let (data_3: felt*) = alloc();

// This is done to make sure that the numbers inserted in data_3
// fit in a u64
let (q, r) = unsigned_div_rem(res_1.low, 18446744073709551615);
assert data_3[0] = q;
let (q, r) = unsigned_div_rem(res_1.high, 18446744073709551615);
assert data_3[1] = q;

let (keccak_ptr: felt*) = alloc();
let keccak_ptr_start = keccak_ptr;

let res_2: Uint256 = cairo_keccak{keccak_ptr=keccak_ptr}(data_3, 16);

finalize_keccak(keccak_ptr_start=keccak_ptr_start, keccak_ptr_end=keccak_ptr);

let (inputs) = alloc();
let inputs_start = inputs;
keccak_add_uint256{inputs=inputs_start}(num=res_2, bigend=0);

// These values are hardcoded for last = 10
// Since we are dealing with hash functions and using the output of one of them
// as the input of the other, asserting only the last results of the iteration
// should be enough
if (iter == last - 1 and last == 10) {
assert res_2.low = 3896836249413878817054429671793519200;
assert res_2.high = 253424239110447628170109510737834198489;
assert inputs[0] = 16681956707691293280;
assert inputs[1] = 211247916371739620;
assert inputs[2] = 6796127878994642393;
assert inputs[3] = 13738155530201662906;
}

// These values are hardcoded for last = 100
// This should be used for benchmarking.
if (iter == last - 1 and last == 100) {
assert res_2.low = 52798800345724801884797411011515944813;
assert res_2.high = 159010026777930121161844734347918361509;
assert inputs[0] = 14656556134934286189;
assert inputs[1] = 2862228701973161639;
assert inputs[2] = 206697371206337445;
assert inputs[3] = 8619950823980503604;
}

return test_integration{range_check_ptr=range_check_ptr, bitwise_ptr=bitwise_ptr}(
iter + 1, last
);
}

func run_test{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}(last: felt) {
test_integration(0, last);
return ();
}

func main{range_check_ptr: felt, bitwise_ptr: BitwiseBuiltin*}() {
run_test(10);
return ();
}
Loading

0 comments on commit 337f1b7

Please sign in to comment.