Skip to content

Commit

Permalink
✨ Garaga BN/BLS pairing interface & tests
Browse files Browse the repository at this point in the history
  • Loading branch information
feltroidprime committed Mar 2, 2024
1 parent 538d48b commit 600cee3
Show file tree
Hide file tree
Showing 9 changed files with 1,021 additions and 273 deletions.
396 changes: 285 additions & 111 deletions src/definitions.cairo

Large diffs are not rendered by default.

28 changes: 28 additions & 0 deletions src/ec_ops.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from src.definitions import is_zero_mod_P, get_P
from src.precompiled_circuits.ec import get_IS_ON_CURVE_G1_G2_circuit
from src.modulo_circuit import run_modulo_circuit, ModuloCircuit
from starkware.cairo.common.cairo_builtins import ModBuiltin, UInt384

func is_on_curve_g1_g2{
range_check_ptr, range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*
}(curve_id: felt, input: felt*) -> (res: felt) {
alloc_locals;
let (P) = get_P(curve_id);

let (circuit) = get_IS_ON_CURVE_G1_G2_circuit(curve_id);
let (output: felt*) = run_modulo_circuit(circuit, input);
let (check_g1: felt) = is_zero_mod_P([cast(output, UInt384*)], P);
let (check_g20: felt) = is_zero_mod_P([cast(output + UInt384.SIZE, UInt384*)], P);
let (check_g21: felt) = is_zero_mod_P([cast(output + 2 * UInt384.SIZE, UInt384*)], P);

if (check_g1 == 0) {
return (res=0);
}
if (check_g20 == 0) {
return (res=0);
}
if (check_g21 == 0) {
return (res=0);
}
return (res=1);
}
308 changes: 252 additions & 56 deletions src/modulo_circuit.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -3,86 +3,282 @@ from starkware.cairo.common.registers import get_fp_and_pc
from starkware.cairo.common.memcpy import memcpy
from starkware.cairo.common.modulo import run_mod_p_circuit

from src.definitions import get_P, BASE, N_LIMBS
from src.precompiled_circuits.sample import get_sample_circuit
from src.utils import (
get_Z_and_RLC_from_transcript,
write_felts_to_value_segment,
assert_limbs_at_index_are_equal,
)
from src.definitions import get_P, BASE, N_LIMBS, is_curve_id_supported, SUPPORTED_CURVE_ID
from src.utils import get_Z_and_RLC_from_transcript, write_felts_to_value_segment, retrieve_output

struct ExtensionFieldModuloCircuit {
constants_ptr: felt*,
add_offsets_ptr: felt*,
mul_offsets_ptr: felt*,
output_offsets_ptr: felt*,
poseidon_indexes_ptr: felt*,
constants_ptr_len: felt,
input_len: felt,
commitments_len: felt,
witnesses_len: felt,
output_len: felt,
continuous_output: felt,
add_mod_n: felt,
mul_mod_n: felt,
n_assert_eq: felt,
N_Euclidean_equations: felt,
name: felt,
curve_id: felt,
}

struct ModuloCircuit {
constants_ptr: felt*,
add_offsets_ptr: felt*,
mul_offsets_ptr: felt*,
output_offsets_ptr: felt*,
constants_ptr_len: felt,
witnesses_len: felt,
input_len: felt,
output_len: felt,
continuous_output: felt,
add_mod_n: felt,
mul_mod_n: felt,
n_assert_eq: felt,
name: felt,
curve_id: felt,
}

func get_void_modulo_circuit() -> (circuit: ModuloCircuit*) {
return (cast(-1, ModuloCircuit*),);
}
func get_void_extension_field_modulo_circuit() -> (circuit: ExtensionFieldModuloCircuit*) {
return (cast(-1, ExtensionFieldModuloCircuit*),);
}

func run_modulo_circuit{
range_check_ptr, range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*
}(circuit: ModuloCircuit*, input: felt*) -> (output: felt*) {
alloc_locals;
let (__fp__, _) = get_fp_and_pc();
let p: UInt384 = get_P(circuit.curve_id);
local values_ptr: UInt384* = cast(range_check96_ptr, UInt384*);
memcpy(
dst=range_check96_ptr, src=circuit.constants_ptr, len=circuit.constants_ptr_len * N_LIMBS
); // write(Constants)
memcpy(
dst=range_check96_ptr + circuit.constants_ptr_len * N_LIMBS,
src=input,
len=circuit.input_len,
); // write(Input)

%{
from src.precompiled_circuits.all_circuits import ALL_EXTF_CIRCUITS, CircuitID
from src.hints.io import pack_bigint_ptr, fill_felt_ptr, flatten
from src.definitions import CURVES, PyFelt
p = CURVES[ids.circuit.curve_id].p
circuit_input = pack_bigint_ptr(memory, ids.input, ids.N_LIMBS, ids.BASE, ids.circuit.input_len//ids.N_LIMBS)
MOD_CIRCUIT = ALL_EXTF_CIRCUITS[CircuitID(ids.circuit.name)](ids.circuit.curve_id, auto_run=False)
MOD_CIRCUIT = MOD_CIRCUIT.run_circuit(circuit_input)
witnesses = flatten([bigint_split(x.value, ids.N_LIMBS, ids.BASE) for x in MOD_CIRCUIT.witnesses])
fill_felt_ptr(x=witnesses, memory=memory, address=ids.range_check96_ptr + ids.circuit.constants_ptr_len * ids.N_LIMBS + ids.circuit.input_len)
#MOD_CIRCUIT.print_value_segment()
%}

run_mod_p_circuit(
p=p,
values_ptr=values_ptr,
add_mod_offsets_ptr=circuit.add_offsets_ptr,
add_mod_n=circuit.add_mod_n,
mul_mod_offsets_ptr=circuit.mul_offsets_ptr,
mul_mod_n=circuit.mul_mod_n,
);

tempvar range_check96_ptr = range_check96_ptr + circuit.input_len + circuit.witnesses_len + (
circuit.constants_ptr_len + circuit.add_mod_n + circuit.mul_mod_n - circuit.n_assert_eq
) * N_LIMBS;

let (output: felt*) = retrieve_output(
values_segment=values_ptr,
output_offsets_ptr=circuit.output_offsets_ptr,
n=circuit.output_len,
continuous_output=circuit.continuous_output,
);
return (output=output);
}

func run_extension_field_modulo_circuit{
range_check_ptr,
poseidon_ptr: PoseidonBuiltin*,
range_check96_ptr: felt*,
add_mod_ptr: ModBuiltin*,
mul_mod_ptr: ModBuiltin*,
}(input: felt*, input_len: felt, curve_id: felt, circuit_id: felt) -> felt {
}(circuit: ExtensionFieldModuloCircuit*, input: felt*) -> (output: felt*, Z: felt) {
alloc_locals;
let (__fp__, _) = get_fp_and_pc();
let p: UInt384 = get_P(curve_id);
let (
constants_ptr: felt*,
add_offsets_ptr: felt*,
mul_offsets_ptr: felt*,
left_assert_eq_offsets_ptr: felt*,
right_assert_eq_offsets_ptr: felt*,
poseidon_indexes_ptr: felt*,
constants_ptr_len: felt,
add_mod_n: felt,
mul_mod_n: felt,
commitments_len: felt,
assert_eq_len: felt,
N_Euclidean_equations: felt,
) = get_sample_circuit(circuit_id);
let (status) = is_curve_id_supported(circuit.curve_id);
if (status != SUPPORTED_CURVE_ID) {
return (cast(-1, felt*), 0);
}
let p: UInt384 = get_P(circuit.curve_id);

local values_ptr: UInt384* = cast(range_check96_ptr, UInt384*);
memcpy(dst=range_check96_ptr, src=constants_ptr, len=constants_ptr_len * N_LIMBS); // write(Constants)
memcpy(dst=range_check96_ptr + constants_ptr_len * N_LIMBS, src=input, len=input_len); // write(Input)
memcpy(
dst=range_check96_ptr, src=circuit.constants_ptr, len=circuit.constants_ptr_len * N_LIMBS
); // write(Constants)

memcpy(
dst=range_check96_ptr + circuit.constants_ptr_len * N_LIMBS,
src=input,
len=circuit.input_len,
); // write(Input)

local commitments: felt*;
%{
from src.precompiled_circuits.sample import get_sample_circuit
from src.hints.io import pack_bigint_ptr, flatten
from src.definitions import CURVES, PyFelt
p = CURVES[ids.curve_id].p
circuit_input = pack_bigint_ptr(memory, ids.input, ids.N_LIMBS, ids.BASE, ids.input_len//ids.N_LIMBS)
circuit_input = [PyFelt(x, p) for x in circuit_input]
EXTF_MOD_CIRCUIT = get_sample_circuit(ids.circuit_id, circuit_input)
from src.precompiled_circuits.all_circuits import ALL_EXTF_CIRCUITS, CircuitID
from src.hints.io import bigint_split, pack_bigint_ptr, fill_felt_ptr, flatten
circuit_input = pack_bigint_ptr(memory, ids.input, ids.N_LIMBS, ids.BASE, ids.circuit.input_len//ids.N_LIMBS)
EXTF_MOD_CIRCUIT = ALL_EXTF_CIRCUITS[CircuitID(ids.circuit.name)](ids.circuit.curve_id, auto_run=False)
EXTF_MOD_CIRCUIT = EXTF_MOD_CIRCUIT.run_circuit(circuit_input)
print(f"\t{ids.circuit.constants_ptr_len} Constants and {ids.circuit.input_len//4} Inputs copied to RC_96 memory segment at position {ids.range_check96_ptr}")
commitments = flatten([bigint_split(x.value, ids.N_LIMBS, ids.BASE) for x in EXTF_MOD_CIRCUIT.commitments])
ids.commitments = segments.gen_arg(commitments)
print(len(commitments), len(commitments)//4)
witnesses = flatten([bigint_split(x.value, ids.N_LIMBS, ids.BASE) for x in EXTF_MOD_CIRCUIT.witnesses])
fill_felt_ptr(x=commitments, memory=memory, address=ids.range_check96_ptr + ids.circuit.constants_ptr_len * ids.N_LIMBS + ids.circuit.input_len)
fill_felt_ptr(x=witnesses, memory=memory, address=ids.range_check96_ptr + ids.circuit.constants_ptr_len * ids.N_LIMBS + ids.circuit.input_len + ids.circuit.commitments_len)
print(f"\t{len(commitments)//4} Commitments & {len(witnesses)//4} witnesses computed and filled in RC_96 memory segment at positions {ids.range_check96_ptr+ids.circuit.constants_ptr_len * ids.N_LIMBS+ids.circuit.input_len} and {ids.range_check96_ptr + ids.circuit.constants_ptr_len * ids.N_LIMBS + ids.circuit.input_len + ids.circuit.commitments_len}")
#EXTF_MOD_CIRCUIT.print_value_segment()
%}

let (local Z: felt, local RLC_coeffs: felt*) = get_Z_and_RLC_from_transcript(
transcript_start=cast(values_ptr, felt*) + circuit.constants_ptr_len * N_LIMBS,
poseidon_indexes_ptr=circuit.poseidon_indexes_ptr,
n_elements_in_transcript=(circuit.commitments_len + circuit.input_len) / N_LIMBS,
n_equations=circuit.N_Euclidean_equations,
init_hash=circuit.name,
);
%{ print(f"\tZ = Hash(Input|Commitments) = Poseidon({(ids.circuit.input_len+ids.circuit.commitments_len)//ids.N_LIMBS} * [Uint384]) computed") %}
%{ print(f"\tN={ids.circuit.N_Euclidean_equations} felt252 from Poseidon transcript retrieved.") %}

%{
# Sanity Check :
assert ids.Z == EXTF_MOD_CIRCUIT.transcript.continuable_hash, f"Z for circuit {EXTF_MOD_CIRCUIT.name} does not match {hex(ids.Z)} {hex(EXTF_MOD_CIRCUIT.transcript.continuable_hash)}"
%}

tempvar range_check96_ptr = range_check96_ptr + circuit.constants_ptr_len * N_LIMBS +
circuit.input_len + circuit.commitments_len + circuit.witnesses_len;

write_felts_to_value_segment(values_start=&Z, n=1);
write_felts_to_value_segment(values_start=RLC_coeffs, n=circuit.N_Euclidean_equations);
%{ print(f"\tZ and felt252 written to value segment") %}
%{ print(f"\tRunning ModuloBuiltin circuit...") %}
run_mod_p_circuit(
p=p,
values_ptr=values_ptr,
add_mod_offsets_ptr=circuit.add_offsets_ptr,
add_mod_n=circuit.add_mod_n,
mul_mod_offsets_ptr=circuit.mul_offsets_ptr,
mul_mod_n=circuit.mul_mod_n,
);

tempvar range_check96_ptr = range_check96_ptr + (
circuit.add_mod_n + circuit.mul_mod_n - circuit.n_assert_eq
) * N_LIMBS;

let (output: felt*) = retrieve_output(
values_segment=values_ptr,
output_offsets_ptr=circuit.output_offsets_ptr,
n=circuit.output_len,
continuous_output=circuit.continuous_output,
);
return (output=output, Z=Z);
}

// Same as run_modulo_circuit, but doesen't hash the inputs and starts with
// an initial hash.
func run_extension_field_modulo_circuit_continuation{
range_check_ptr,
poseidon_ptr: PoseidonBuiltin*,
range_check96_ptr: felt*,
add_mod_ptr: ModBuiltin*,
mul_mod_ptr: ModBuiltin*,
}(circuit: ExtensionFieldModuloCircuit*, input: felt*, init_hash: felt) -> (
output: felt*, Z: felt
) {
alloc_locals;
let (__fp__, _) = get_fp_and_pc();
let (status) = is_curve_id_supported(circuit.curve_id);
if (status != SUPPORTED_CURVE_ID) {
return (cast(-1, felt*), 0);
}
let p: UInt384 = get_P(circuit.curve_id);

local values_ptr: UInt384* = cast(range_check96_ptr, UInt384*);
memcpy(
dst=range_check96_ptr + constants_ptr_len * N_LIMBS + input_len,
src=commitments,
len=commitments_len * N_LIMBS,
); // write(Commitments)
dst=range_check96_ptr, src=circuit.constants_ptr, len=circuit.constants_ptr_len * N_LIMBS
); // write(Constants)

memcpy(
dst=range_check96_ptr + circuit.constants_ptr_len * N_LIMBS,
src=input,
len=circuit.input_len,
); // write(Input)

%{
from src.precompiled_circuits.all_circuits import ALL_EXTF_CIRCUITS, CircuitID
from src.hints.io import bigint_split, pack_bigint_ptr, fill_felt_ptr, flatten
circuit_input = pack_bigint_ptr(memory, ids.input, ids.N_LIMBS, ids.BASE, ids.circuit.input_len//ids.N_LIMBS)
EXTF_MOD_CIRCUIT = ALL_EXTF_CIRCUITS[CircuitID(ids.circuit.name)](ids.circuit.curve_id, auto_run=False, init_hash=ids.init_hash)
EXTF_MOD_CIRCUIT = EXTF_MOD_CIRCUIT.run_circuit(input=circuit_input)
print(f"\t{ids.circuit.constants_ptr_len} Constants and {ids.circuit.input_len//4} Inputs copied to RC_96 memory segment at position {ids.range_check96_ptr}")
commitments = flatten([bigint_split(x.value, ids.N_LIMBS, ids.BASE) for x in EXTF_MOD_CIRCUIT.commitments])
witnesses = flatten([bigint_split(x.value, ids.N_LIMBS, ids.BASE) for x in EXTF_MOD_CIRCUIT.witnesses])
fill_felt_ptr(x=commitments, memory=memory, address=ids.range_check96_ptr + ids.circuit.constants_ptr_len * ids.N_LIMBS + ids.circuit.input_len)
fill_felt_ptr(x=witnesses, memory=memory, address=ids.range_check96_ptr + ids.circuit.constants_ptr_len * ids.N_LIMBS + ids.circuit.input_len + ids.circuit.commitments_len)
# print(f"continuation segment:, init_hash={hex(ids.init_hash)}")
#EXTF_MOD_CIRCUIT.print_value_segment()
print(f"\t{len(commitments)//4} Commitments & {len(witnesses)//4} witnesses computed and filled in RC_96 memory segment at positions {ids.range_check96_ptr+ids.circuit.constants_ptr_len * ids.N_LIMBS+ids.circuit.input_len} and {ids.range_check96_ptr + ids.circuit.constants_ptr_len * ids.N_LIMBS + ids.circuit.input_len + ids.circuit.commitments_len}")
%}

%{ print(f"\tZ = Hash(Init_Hash|Commitments) = Poseidon(Init_Hash, Poseidon({(ids.circuit.commitments_len)//ids.N_LIMBS} * [Uint384])) computed") %}

let (local Z: felt, local RLC_coeffs: felt*) = get_Z_and_RLC_from_transcript(
transcript_start=cast(values_ptr, felt*) + constants_ptr_len,
poseidon_indexes_ptr=poseidon_indexes_ptr,
n_elements_in_transcript=commitments_len,
n_equations=N_Euclidean_equations,
transcript_start=cast(values_ptr, felt*) + circuit.constants_ptr_len * N_LIMBS +
circuit.input_len,
poseidon_indexes_ptr=circuit.poseidon_indexes_ptr,
n_elements_in_transcript=circuit.commitments_len / N_LIMBS,
n_equations=circuit.N_Euclidean_equations,
init_hash=init_hash,
);

tempvar range_check96_ptr = range_check96_ptr + constants_ptr_len * N_LIMBS + input_len +
commitments_len * N_LIMBS;
write_felts_to_value_segment(values=&Z, n=1);
write_felts_to_value_segment(values=RLC_coeffs, n=N_Euclidean_equations);
%{
# Sanity Check :
assert ids.Z == EXTF_MOD_CIRCUIT.transcript.continuable_hash, f"Z for circuit {EXTF_MOD_CIRCUIT.name} does not match {hex(ids.Z)} {hex(EXTF_MOD_CIRCUIT.transcript.continuable_hash)}"
%}

tempvar range_check96_ptr = range_check96_ptr + circuit.constants_ptr_len * N_LIMBS +
circuit.input_len + circuit.commitments_len + circuit.witnesses_len;

write_felts_to_value_segment(values_start=&Z, n=1);
write_felts_to_value_segment(values_start=RLC_coeffs, n=circuit.N_Euclidean_equations);
%{ print(f"\tZ and felt252 written to value segment") %}
%{ print(f"\tRunning ModuloBuiltin circuit...") %}
run_mod_p_circuit(
p=p,
values_ptr=values_ptr,
add_mod_offsets_ptr=add_offsets_ptr,
add_mod_n=add_mod_n,
mul_mod_offsets_ptr=mul_offsets_ptr,
mul_mod_n=mul_mod_n,
add_mod_offsets_ptr=circuit.add_offsets_ptr,
add_mod_n=circuit.add_mod_n,
mul_mod_offsets_ptr=circuit.mul_offsets_ptr,
mul_mod_n=circuit.mul_mod_n,
);
tempvar range_check96_ptr = range_check96_ptr + (
circuit.add_mod_n + circuit.mul_mod_n - circuit.n_assert_eq
) * N_LIMBS;

// assert_limbs_at_index_are_equal(
// values_ptr, left_assert_eq_offsets_ptr, right_assert_eq_offsets_ptr, assert_eq_len
// );

return 0;
let (output: felt*) = retrieve_output(
values_segment=values_ptr,
output_offsets_ptr=circuit.output_offsets_ptr,
n=circuit.output_len,
continuous_output=circuit.continuous_output,
);
return (output=output, Z=Z);
}
Loading

0 comments on commit 600cee3

Please sign in to comment.