Skip to content

Commit

Permalink
v0.15.3: Honk contract bytecode, calldata & resources optimisations. (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
feltroidprime authored Dec 16, 2024
1 parent 57892e7 commit ea2b7b6
Show file tree
Hide file tree
Showing 24 changed files with 457 additions and 684 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,10 @@ def input_map(self) -> dict:
imap["p_public_inputs"] = (structs.u256Span, self.vk.public_inputs_size)
imap["p_public_inputs_offset"] = structs.u384

for i in range(self.vk.log_circuit_size):
imap[f"sumcheck_univariate_{i}"] = (
structs.u256Span,
hk.BATCHED_RELATION_PARTIAL_LENGTH,
)
imap["sumcheck_univariates_flat"] = (
structs.u256Span,
self.vk.log_circuit_size * hk.BATCHED_RELATION_PARTIAL_LENGTH,
)

imap["sumcheck_evaluations"] = (
structs.u256Span,
Expand Down Expand Up @@ -208,9 +207,16 @@ def _execute_circuit_logic(
vars["p_public_inputs_offset"],
)

sumcheck_univariates_flat = vars["sumcheck_univariates_flat"]
sumcheck_univariates = []
for i in range(self.vk.log_circuit_size):
sumcheck_univariates.append(vars[f"sumcheck_univariate_{i}"])
sumcheck_univariates.append(
sumcheck_univariates_flat[
i
* hk.BATCHED_RELATION_PARTIAL_LENGTH : (i + 1)
* hk.BATCHED_RELATION_PARTIAL_LENGTH
]
)

assert len(sumcheck_univariates) == self.vk.log_circuit_size
assert len(sumcheck_univariates[0]) == hk.BATCHED_RELATION_PARTIAL_LENGTH
Expand Down Expand Up @@ -261,7 +267,7 @@ def input_map(self) -> dict:
imap = {}

imap["p_sumcheck_evaluations"] = (structs.u256Span, hk.NUMBER_OF_ENTITIES)
imap["p_gemini_a_evaluations"] = (structs.u256Span, hk.CONST_PROOF_SIZE_LOG_N)
imap["p_gemini_a_evaluations"] = (structs.u256Span, self.vk.log_circuit_size)
imap["tp_gemini_r"] = structs.u384
imap["tp_rho"] = structs.u384
imap["tp_shplonk_z"] = structs.u384
Expand Down
53 changes: 30 additions & 23 deletions hydra/garaga/precompiled_circuits/honk.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import copy
import math
from dataclasses import dataclass, fields
from enum import Enum, auto

Expand Down Expand Up @@ -58,6 +59,10 @@ class HonkProof:
shplonk_q: G1Point
kzg_quotient: G1Point

@property
def log_circuit_size(self) -> int:
return int(math.log2(self.circuit_size))

def __post_init__(self):
assert len(self.sumcheck_univariates) == CONST_PROOF_SIZE_LOG_N
assert all(
Expand Down Expand Up @@ -243,18 +248,12 @@ def format_array(elements: list, span: bool = False) -> str:
code += f"lookup_read_tags: {g1_to_g1point256(self.lookup_read_tags)},\n"
code += f"lookup_inverses: {g1_to_g1point256(self.lookup_inverses)},\n"

# Format nested arrays for sumcheck_univariates
univariates_arrays = [
format_array(univariate, span=True)
for univariate in self.sumcheck_univariates
]
code += (
f"sumcheck_univariates: array![{','.join(univariates_arrays)}].span(),\n"
)
# Flatten sumcheck_univariates array
code += f"sumcheck_univariates: {format_array(io.flatten(self.sumcheck_univariates)[:self.log_circuit_size * BATCHED_RELATION_PARTIAL_LENGTH], span=True)},\n"

code += f"sumcheck_evaluations: {format_array(self.sumcheck_evaluations, span=True)},\n"
code += f"gemini_fold_comms: array![{', '.join(g1_to_g1point256(comm) for comm in self.gemini_fold_comms)}].span(),\n"
code += f"gemini_a_evaluations: {format_array(self.gemini_a_evaluations, span=True)},\n"
code += f"gemini_fold_comms: array![{', '.join(g1_to_g1point256(comm) for comm in self.gemini_fold_comms[:self.log_circuit_size - 1])}].span(),\n"
code += f"gemini_a_evaluations: {format_array(self.gemini_a_evaluations[:self.log_circuit_size], span=True)},\n"
code += f"shplonk_q: {g1_to_g1point256(self.shplonk_q)},\n"
code += f"kzg_quotient: {g1_to_g1point256(self.kzg_quotient)},\n"
code += "};"
Expand Down Expand Up @@ -283,27 +282,35 @@ def serialize_G1Point256(g1_point: G1Point) -> list[int]:
cd.extend(serialize_G1Point256(self.lookup_read_counts))
cd.extend(serialize_G1Point256(self.lookup_read_tags))
cd.extend(serialize_G1Point256(self.lookup_inverses))
cd.append(len(self.sumcheck_univariates))
for univariate in self.sumcheck_univariates:
cd.extend(
io.bigint_split_array(
x=univariate, n_limbs=2, base=2**128, prepend_length=True
)
cd.extend(
io.bigint_split_array(
x=io.flatten(self.sumcheck_univariates)[
: BATCHED_RELATION_PARTIAL_LENGTH * self.log_circuit_size
], # The rest is 0.
n_limbs=2,
base=2**128,
prepend_length=True,
)
)

cd.extend(
io.bigint_split_array(
x=self.sumcheck_evaluations, n_limbs=2, base=2**128, prepend_length=True
)
)

cd.append(len(self.gemini_fold_comms))
for pt in self.gemini_fold_comms:
cd.append(self.log_circuit_size - 1)
for pt in self.gemini_fold_comms[
: self.log_circuit_size - 1
]: # The rest is G(1, 2)
cd.extend(serialize_G1Point256(pt))

cd.extend(
io.bigint_split_array(
x=self.gemini_a_evaluations, n_limbs=2, base=2**128, prepend_length=True
x=self.gemini_a_evaluations[: self.log_circuit_size],
n_limbs=2,
base=2**128,
prepend_length=True,
)
)
cd.extend(serialize_G1Point256(self.shplonk_q))
Expand Down Expand Up @@ -1685,16 +1692,16 @@ def compute_shplemini_msm_scalars(
batching_challenge, inverse_vanishing_evals[i + 2]
)
scalars[NUMBER_OF_ENTITIES + i + 1] = self.neg(scaling_factor)
constant_term_accumulator = self.add(
constant_term_accumulator,
self.mul(scaling_factor, p_gemini_a_evaluations[i + 1]),
)
else:
# print(
# f"dummy round {i}, index {NUMBER_OF_ENTITIES + i + 1} is set to 0"
# )
pass

constant_term_accumulator = self.add(
constant_term_accumulator,
self.mul(scaling_factor, p_gemini_a_evaluations[i + 1]),
)
# skip last round:
if i < self.log_n - 2:
batching_challenge = self.mul(batching_challenge, tp_shplonk_nu)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from garaga.starknet.cli.utils import create_directory, get_package_version
from garaga.starknet.groth16_contract_generator.parsing_utils import Groth16VerifyingKey

ECIP_OPS_CLASS_HASH = 0xC4B7AA28A27B5FB8D7D43928B2A3EE960CF5B4E06CB9AE1EE3F102400B1700
ECIP_OPS_CLASS_HASH = 0x684D2756A4440C190A5FE54E367C0ABE33AEFA75084DEC2FFFC791B620C80E3


def precompute_lines_from_vk(vk: Groth16VerifyingKey) -> StructArray:
Expand Down
40 changes: 16 additions & 24 deletions hydra/garaga/starknet/honk_contract_generator/generator_honk.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,14 @@ def gen_honk_circuits_code(vk: HonkVk) -> str:
"""
header = """
use core::circuit::{
RangeCheck96, AddMod, MulMod, u384, u96, circuit_add, circuit_sub, circuit_mul, circuit_inverse,
EvalCircuitTrait, CircuitOutputsTrait, CircuitModulus, AddInputResultTrait, CircuitInputs,
u384, circuit_add, circuit_sub, circuit_mul, circuit_inverse,
EvalCircuitTrait, CircuitOutputsTrait, CircuitInputs,
};
use garaga::core::circuit::AddInputResultTrait2;
use garaga::ec_ops::FunctionFelt;
use core::circuit::CircuitElement as CE;
use core::circuit::CircuitInput as CI;
use garaga::definitions::{
get_b, G1Point, u288, get_GRUMPKIN_modulus, get_BN254_modulus};
use garaga::definitions::{G1Point, get_GRUMPKIN_modulus, get_BN254_modulus};
use core::option::Option;\n
"""
code = header
Expand Down Expand Up @@ -121,7 +120,7 @@ def gen_honk_verifier(
precomputed_lines = precompute_lines_honk()

constants_code = f"""
use garaga::definitions::{{G1Point, G2Point, G2Line, u384, u288}};
use garaga::definitions::{{G1Point, G2Line, u384, u288}};
use garaga::utils::noir::HonkVk;
{vk.serialize_to_cairo()}\n
Expand Down Expand Up @@ -156,16 +155,15 @@ def gen_honk_verifier(
#[starknet::contract]
mod UltraKeccakHonkVerifier {{
use garaga::definitions::{{G1Point, G1G2Pair, BN254_G1_GENERATOR, get_a, get_modulus, u384}};
use garaga::definitions::{{G1Point, G1G2Pair, BN254_G1_GENERATOR, get_a, get_modulus}};
use garaga::pairing_check::{{multi_pairing_check_bn254_2P_2F, MPCheckHintBN254}};
use garaga::ec_ops::{{G1PointTrait, ec_safe_add, FunctionFelt,FunctionFeltTrait, DerivePointFromXHint, MSMHintBatched, compute_rhs_ecip, derive_ec_point_from_X, SlopeInterceptOutput}};
use garaga::ec_ops_g2::{{G2PointTrait}};
use garaga::basic_field_ops::{{add_mod_p, mul_mod_p}};
use garaga::ec_ops::{{G1PointTrait, ec_safe_add,FunctionFeltTrait, DerivePointFromXHint, MSMHintBatched, compute_rhs_ecip, derive_ec_point_from_X, SlopeInterceptOutput}};
use garaga::basic_field_ops::{{batch_3_mod_p}};
use garaga::circuits::ec;
use garaga::utils::neg_3;
use super::{{vk, precomputed_lines, {sumcheck_function_name}, {prepare_scalars_function_name}, {lhs_ecip_function_name}}};
use garaga::utils::noir::{{HonkProof, remove_unused_variables_sumcheck_evaluations, G2_POINT_KZG_1, G2_POINT_KZG_2}};
use garaga::utils::noir::keccak_transcript::{{HonkTranscriptTrait, Point256IntoCircuitPoint}};
use garaga::utils::noir::keccak_transcript::{{HonkTranscriptTrait, Point256IntoCircuitPoint, BATCHED_RELATION_PARTIAL_LENGTH}};
use garaga::core::circuit::U64IntoU384;
use core::num::traits::Zero;
use core::poseidon::hades_permutation;
Expand Down Expand Up @@ -202,7 +200,7 @@ def gen_honk_verifier(
let (sum_check_rlc, honk_check) = {sumcheck_function_name}(
p_public_inputs: full_proof.proof.public_inputs,
p_public_inputs_offset: full_proof.proof.public_inputs_offset.into(),
{', '.join([f'sumcheck_univariate_{i}: (*full_proof.proof.sumcheck_univariates.at({i}))' for i in range(vk.log_circuit_size)])},
sumcheck_univariates_flat: full_proof.proof.sumcheck_univariates.slice(0, log_n * BATCHED_RELATION_PARTIAL_LENGTH),
sumcheck_evaluations: remove_unused_variables_sumcheck_evaluations(
full_proof.proof.sumcheck_evaluations
),
Expand Down Expand Up @@ -271,9 +269,8 @@ def gen_honk_verifier(
full_proof.proof.z_perm.into(),
];
let n_gem_comms = vk.log_circuit_size-1;
for i in 0_u32..n_gem_comms {{
_points.append((*full_proof.proof.gemini_fold_comms.at(i)).into());
for gem_comm in full_proof.proof.gemini_fold_comms {{
_points.append((*gem_comm).into());
}};
_points.append(BN254_G1_GENERATOR);
_points.append(full_proof.proof.kzg_quotient.into());
Expand Down Expand Up @@ -383,15 +380,7 @@ def gen_honk_verifier(
);
let mod_bn = get_modulus(0);
let c0: u384 = base_rlc_coeff.into();
let c1: u384 = mul_mod_p(c0, c0, mod_bn);
let c2 = mul_mod_p(c1, c0, mod_bn);
let zk_ecip_batched_rhs = add_mod_p(
add_mod_p(mul_mod_p(rhs_low, c0, mod_bn), mul_mod_p(rhs_high, c1, mod_bn), mod_bn),
mul_mod_p(rhs_high_shifted, c2, mod_bn),
mod_bn
);
let zk_ecip_batched_rhs = batch_3_mod_p(rhs_low, rhs_high, rhs_high_shifted, base_rlc_coeff.into(), mod_bn);
let ecip_check = zk_ecip_batched_lhs == zk_ecip_batched_rhs;
Expand Down Expand Up @@ -456,11 +445,14 @@ def gen_honk_verifier(
VK_PATH = (
"hydra/garaga/starknet/honk_contract_generator/examples/vk_ultra_keccak.bin"
)

VK_LARGE_PATH = (
"hydra/garaga/starknet/honk_contract_generator/examples/vk_large.bin"
)
CONTRACTS_FOLDER = "src/contracts/" # Do not change this

FOLDER_NAME = (
"noir_ultra_keccak_honk_example" # '_curve_id' is appended in the end.
)

gen_honk_verifier(VK_PATH, CONTRACTS_FOLDER, FOLDER_NAME)
# gen_honk_verifier(VK_LARGE_PATH, CONTRACTS_FOLDER, FOLDER_NAME + "_large")
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "maturin"

[project]
name = "garaga"
version = "0.15.2"
version = "0.15.3"
requires-python = ">=3.10,<3.11"
dependencies = [
"fastecdsa",
Expand Down
2 changes: 1 addition & 1 deletion src/Scarb.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "garaga"
version = "0.15.2"
version = "0.15.3"
edition = "2023_10"
licence = "MIT"
keywords = ["zk", "snarks", "curve", "pairing", "groth16", "plonk", "bls", "elliptic", "signature"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mod Groth16VerifierBLS12_381 {
use super::{N_PUBLIC_INPUTS, vk, ic, precomputed_lines};

const ECIP_OPS_CLASS_HASH: felt252 =
0xc4b7aa28a27b5fb8d7d43928b2a3ee960cf5b4e06cb9ae1ee3f102400b1700;
0x684d2756a4440c190a5fe54e367c0abe33aefa75084dec2fffc791b620c80e3;

#[storage]
struct Storage {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mod Groth16VerifierBN254 {
use super::{N_PUBLIC_INPUTS, vk, ic, precomputed_lines};

const ECIP_OPS_CLASS_HASH: felt252 =
0xc4b7aa28a27b5fb8d7d43928b2a3ee960cf5b4e06cb9ae1ee3f102400b1700;
0x684d2756a4440c190a5fe54e367c0abe33aefa75084dec2fffc791b620c80e3;

#[storage]
struct Storage {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,13 @@ trait IUltraKeccakHonkVerifier<TContractState> {

#[starknet::contract]
mod UltraKeccakHonkVerifier {
use garaga::definitions::{G1Point, G1G2Pair, BN254_G1_GENERATOR, get_a, get_modulus, u384};
use garaga::definitions::{G1Point, G1G2Pair, BN254_G1_GENERATOR, get_a, get_modulus};
use garaga::pairing_check::{multi_pairing_check_bn254_2P_2F, MPCheckHintBN254};
use garaga::ec_ops::{
G1PointTrait, ec_safe_add, FunctionFelt, FunctionFeltTrait, DerivePointFromXHint,
MSMHintBatched, compute_rhs_ecip, derive_ec_point_from_X, SlopeInterceptOutput,
G1PointTrait, ec_safe_add, FunctionFeltTrait, DerivePointFromXHint, MSMHintBatched,
compute_rhs_ecip, derive_ec_point_from_X, SlopeInterceptOutput,
};
use garaga::ec_ops_g2::{G2PointTrait};
use garaga::basic_field_ops::{add_mod_p, mul_mod_p};
use garaga::basic_field_ops::{batch_3_mod_p};
use garaga::circuits::ec;
use garaga::utils::neg_3;
use super::{
Expand All @@ -32,7 +31,9 @@ mod UltraKeccakHonkVerifier {
use garaga::utils::noir::{
HonkProof, remove_unused_variables_sumcheck_evaluations, G2_POINT_KZG_1, G2_POINT_KZG_2,
};
use garaga::utils::noir::keccak_transcript::{HonkTranscriptTrait, Point256IntoCircuitPoint};
use garaga::utils::noir::keccak_transcript::{
HonkTranscriptTrait, Point256IntoCircuitPoint, BATCHED_RELATION_PARTIAL_LENGTH,
};
use garaga::core::circuit::U64IntoU384;
use core::num::traits::Zero;
use core::poseidon::hades_permutation;
Expand Down Expand Up @@ -69,11 +70,10 @@ mod UltraKeccakHonkVerifier {
let (sum_check_rlc, honk_check) = run_GRUMPKIN_HONK_SUMCHECK_SIZE_5_PUB_1_circuit(
p_public_inputs: full_proof.proof.public_inputs,
p_public_inputs_offset: full_proof.proof.public_inputs_offset.into(),
sumcheck_univariate_0: (*full_proof.proof.sumcheck_univariates.at(0)),
sumcheck_univariate_1: (*full_proof.proof.sumcheck_univariates.at(1)),
sumcheck_univariate_2: (*full_proof.proof.sumcheck_univariates.at(2)),
sumcheck_univariate_3: (*full_proof.proof.sumcheck_univariates.at(3)),
sumcheck_univariate_4: (*full_proof.proof.sumcheck_univariates.at(4)),
sumcheck_univariates_flat: full_proof
.proof
.sumcheck_univariates
.slice(0, log_n * BATCHED_RELATION_PARTIAL_LENGTH),
sumcheck_evaluations: remove_unused_variables_sumcheck_evaluations(
full_proof.proof.sumcheck_evaluations,
),
Expand Down Expand Up @@ -183,9 +183,8 @@ mod UltraKeccakHonkVerifier {
full_proof.proof.z_perm.into(),
];

let n_gem_comms = vk.log_circuit_size - 1;
for i in 0_u32..n_gem_comms {
_points.append((*full_proof.proof.gemini_fold_comms.at(i)).into());
for gem_comm in full_proof.proof.gemini_fold_comms {
_points.append((*gem_comm).into());
};
_points.append(BN254_G1_GENERATOR);
_points.append(full_proof.proof.kzg_quotient.into());
Expand Down Expand Up @@ -365,14 +364,8 @@ mod UltraKeccakHonkVerifier {
);

let mod_bn = get_modulus(0);
let c0: u384 = base_rlc_coeff.into();
let c1: u384 = mul_mod_p(c0, c0, mod_bn);
let c2 = mul_mod_p(c1, c0, mod_bn);

let zk_ecip_batched_rhs = add_mod_p(
add_mod_p(mul_mod_p(rhs_low, c0, mod_bn), mul_mod_p(rhs_high, c1, mod_bn), mod_bn),
mul_mod_p(rhs_high_shifted, c2, mod_bn),
mod_bn,
let zk_ecip_batched_rhs = batch_3_mod_p(
rhs_low, rhs_high, rhs_high_shifted, base_rlc_coeff.into(), mod_bn,
);

let ecip_check = zk_ecip_batched_lhs == zk_ecip_batched_rhs;
Expand Down
Loading

0 comments on commit ea2b7b6

Please sign in to comment.