Skip to content

Commit 052e7ce

Browse files
authored
feat: implement kzg data availability hints (#1887)
* feat: kzg data availability hints Context: port of the Starknet OS to Rust. We need an implementation of the hints used by the Starknet OS in KZG commitments for data availability. This hint relies on private primitives in cairo-vm and must be implemented in this repository. * add: PR to CHANGELOG * fix: remove unnecessary clones * lint: cargo fmt
1 parent 404d763 commit 052e7ce

File tree

10 files changed

+170
-3
lines changed

10 files changed

+170
-3
lines changed

.github/workflows/rust.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ jobs:
323323
strategy:
324324
fail-fast: false
325325
matrix:
326-
special_features: ["", "extensive_hints", "mod_builtin", "cairo-0-secp-hints"]
326+
special_features: ["", "extensive_hints", "mod_builtin", "cairo-0-secp-hints", "cairo-0-data-availability-hints"]
327327
target: [ test#1, test#2, test#3, test#4, test-no_std#1, test-no_std#2, test-no_std#3, test-no_std#4, test-wasm ]
328328
name: Run tests
329329
runs-on: ubuntu-22.04

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#### Upcoming Changes
44

5+
* feat: implement `kzg` data availability hints [#1887](https://github.com/lambdaclass/cairo-vm/pull/1887)
6+
57
#### [2.0.0-rc3] - 2024-12-26
68

79
* chore: update cairo-lang dependencies to 2.10.0-rc.0 #[1901](https://github.com/lambdaclass/cairo-vm/pull/1901)

Makefile

+7-2
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ SECP_CAIRO0_HINTS_DIR=cairo_programs/cairo-0-secp-hints-feature
9494
SECP_CAIRO0_HINTS_FILES:=$(wildcard $(SECP_CAIRO0_HINTS_DIR)/*.cairo)
9595
COMPILED_SECP_CAIRO0_HINTS:=$(patsubst $(SECP_CAIRO0_HINTS_DIR)/%.cairo, $(SECP_CAIRO0_HINTS_DIR)/%.json, $(SECP_CAIRO0_HINTS_FILES))
9696

97+
KZG_DA_CAIRO0_HINTS_DIR=cairo_programs/cairo-0-kzg-da-hints
98+
KZG_DA_CAIRO0_HINTS_FILES:=$(wildcard $(KZG_DA_CAIRO0_HINTS_DIR)/*.cairo)
99+
COMPILED_KZG_DA_CAIRO0_HINTS:=$(patsubst $(KZG_DA_CAIRO0_HINTS_DIR)/%.cairo, $(KZG_DA_CAIRO0_HINTS_DIR)/%.json, $(KZG_DA_CAIRO0_HINTS_FILES))
100+
97101
PRINT_TEST_DIR=cairo_programs/print_feature
98102
PRINT_TEST_FILES:=$(wildcard $(PRINT_TEST_DIR)/*.cairo)
99103
COMPILED_PRINT_TESTS:=$(patsubst $(PRINT_TEST_DIR)/%.cairo, $(PRINT_TEST_DIR)/%.json, $(PRINT_TEST_FILES))
@@ -243,7 +247,7 @@ run:
243247
check:
244248
cargo check
245249

246-
cairo_test_programs: $(COMPILED_TESTS) $(COMPILED_BAD_TESTS) $(COMPILED_NORETROCOMPAT_TESTS) $(COMPILED_PRINT_TESTS) $(COMPILED_MOD_BUILTIN_TESTS) $(COMPILED_SECP_CAIRO0_HINTS)
250+
cairo_test_programs: $(COMPILED_TESTS) $(COMPILED_BAD_TESTS) $(COMPILED_NORETROCOMPAT_TESTS) $(COMPILED_PRINT_TESTS) $(COMPILED_MOD_BUILTIN_TESTS) $(COMPILED_SECP_CAIRO0_HINTS) $(COMPILED_KZG_DA_CAIRO0_HINTS)
247251
cairo_proof_programs: $(COMPILED_PROOF_TESTS) $(COMPILED_MOD_BUILTIN_PROOF_TESTS)
248252
cairo_bench_programs: $(COMPILED_BENCHES)
249253
cairo_1_test_contracts: $(CAIRO_1_COMPILED_CASM_CONTRACTS)
@@ -268,7 +272,7 @@ test-wasm: cairo_proof_programs cairo_test_programs
268272
# NOTE: release mode is needed to avoid "too many locals" error
269273
wasm-pack test --release --node vm --no-default-features
270274
test-extensive_hints: cairo_proof_programs cairo_test_programs
271-
$(TEST_COMMAND) --workspace --features "test_utils, cairo-1-hints, cairo-0-secp-hints, extensive_hints"
275+
$(TEST_COMMAND) --workspace --features "test_utils, cairo-1-hints, cairo-0-secp-hints, cairo-0-data-availability-hints, extensive_hints"
272276

273277
check-fmt:
274278
cargo fmt --all -- --check
@@ -349,6 +353,7 @@ clean:
349353
rm -f $(BENCH_DIR)/*.json
350354
rm -f $(BAD_TEST_DIR)/*.json
351355
rm -f $(SECP_CAIRO0_HINTS_DIR)/*.json
356+
rm -f $(KZG_DA_CAIRO0_HINTS_DIR)/*.json
352357
rm -f $(PRINT_TEST_DIR)/*.json
353358
rm -f $(CAIRO_1_CONTRACTS_TEST_DIR)/*.sierra
354359
rm -f $(CAIRO_1_CONTRACTS_TEST_DIR)/*.casm
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
%builtins range_check
2+
3+
from starkware.starknet.core.os.data_availability.bls_field import reduced_mul, BigInt3
4+
5+
func main{range_check_ptr: felt}() {
6+
let x = BigInt3(0, 0, 0);
7+
let y = BigInt3(1, 1, 1);
8+
9+
let res = reduced_mul(x, y);
10+
11+
assert res = BigInt3(0, 0, 0);
12+
13+
let x = BigInt3(100, 99, 98);
14+
let y = BigInt3(10, 9, 8);
15+
16+
let res = reduced_mul(x, y);
17+
18+
assert res = BigInt3(
19+
49091481911800146991175221, 43711329369885800715738617, 405132241597509509195407
20+
);
21+
22+
let x = BigInt3(47503316700827173496989353, 17218105161352860131668522, 527908748911931938599018);
23+
let y = BigInt3(50964737623371959432443726, 60451660835701602854498663, 5043009036652075489876599);
24+
25+
let res = reduced_mul(x, y);
26+
assert res = BigInt3(43476011663489831917914902, 15057238271740518603165849, 1923992965848504555868221);
27+
28+
return ();
29+
}

vm/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ cairo-1-hints = [
3030
tracer = []
3131
mod_builtin = []
3232
cairo-0-secp-hints = []
33+
cairo-0-data-availability-hints = []
3334

3435
# Note that these features are not retro-compatible with the cairo Python VM.
3536
test_utils = ["std", "dep:arbitrary", "starknet-types-core/arbitrary", "starknet-types-core/std"] # This feature will reference every test-oriented feature

vm/src/hint_processor/builtin_hint_processor/builtin_hint_processor_definition.rs

+8
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,14 @@ impl HintProcessorLogic for BuiltinHintProcessor {
966966
&hint_data.ap_tracking,
967967
constants,
968968
),
969+
#[cfg(feature = "cairo-0-data-availability-hints")]
970+
super::kzg_da::WRITE_DIVMOD_SEGMENT => super::kzg_da::write_div_mod_segment(
971+
vm,
972+
exec_scopes,
973+
&hint_data.ids_data,
974+
&hint_data.ap_tracking,
975+
constants,
976+
),
969977

970978
code => Err(HintError::UnknownHint(code.to_string().into_boxed_str())),
971979
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
use core::str::FromStr;
2+
3+
use super::{
4+
hint_utils::get_relocatable_from_var_name,
5+
secp::{bigint_utils::BigInt3, secp_utils::SECP_P},
6+
};
7+
use crate::{
8+
hint_processor::hint_processor_definition::HintReference,
9+
serde::deserialize_program::ApTracking,
10+
types::relocatable::MaybeRelocatable,
11+
vm::{errors::hint_errors::HintError, vm_core::VirtualMachine},
12+
Felt252,
13+
};
14+
use crate::{
15+
stdlib::{collections::HashMap, ops::Deref, prelude::*},
16+
types::exec_scope::ExecutionScopes,
17+
};
18+
use lazy_static::lazy_static;
19+
use num_bigint::BigInt;
20+
use num_integer::Integer;
21+
use num_traits::FromPrimitive;
22+
use num_traits::Zero;
23+
24+
lazy_static! {
25+
static ref BLS_BASE: BigInt = BigInt::from_u64(2).unwrap().pow(86);
26+
static ref BLS_PRIME: BigInt = BigInt::from_str(
27+
"52435875175126190479447740508185965837690552500527637822603658699938581184513"
28+
)
29+
.unwrap();
30+
}
31+
pub const WRITE_DIVMOD_SEGMENT: &str = r#"from starkware.starknet.core.os.data_availability.bls_utils import BLS_PRIME, pack, split
32+
33+
a = pack(ids.a, PRIME)
34+
b = pack(ids.b, PRIME)
35+
36+
q, r = divmod(a * b, BLS_PRIME)
37+
38+
# By the assumption: |a|, |b| < 2**104 * ((2**86) ** 2 + 2**86 + 1) < 2**276.001.
39+
# Therefore |q| <= |ab| / BLS_PRIME < 2**299.
40+
# Hence the absolute value of the high limb of split(q) < 2**127.
41+
segments.write_arg(ids.q.address_, split(q))
42+
segments.write_arg(ids.res.address_, split(r))"#;
43+
44+
pub fn write_div_mod_segment(
45+
vm: &mut VirtualMachine,
46+
_exec_scopes: &mut ExecutionScopes,
47+
ids_data: &HashMap<String, HintReference>,
48+
ap_tracking: &ApTracking,
49+
_constants: &HashMap<String, Felt252>,
50+
) -> Result<(), HintError> {
51+
let a = bls_pack(
52+
&BigInt3::from_var_name("a", vm, ids_data, ap_tracking)?,
53+
&SECP_P,
54+
);
55+
let b = bls_pack(
56+
&BigInt3::from_var_name("b", vm, ids_data, ap_tracking)?,
57+
&SECP_P,
58+
);
59+
let (q, r) = (a * b).div_mod_floor(&BLS_PRIME);
60+
let q_reloc = get_relocatable_from_var_name("q", vm, ids_data, ap_tracking)?;
61+
let res_reloc = get_relocatable_from_var_name("res", vm, ids_data, ap_tracking)?;
62+
63+
let q_arg: Vec<MaybeRelocatable> = bls_split(q)
64+
.into_iter()
65+
.map(|ref n| Felt252::from(n).into())
66+
.collect::<Vec<MaybeRelocatable>>();
67+
let res_arg: Vec<MaybeRelocatable> = bls_split(r)
68+
.into_iter()
69+
.map(|ref n| Felt252::from(n).into())
70+
.collect::<Vec<MaybeRelocatable>>();
71+
vm.write_arg(q_reloc, &q_arg).map_err(HintError::Memory)?;
72+
vm.write_arg(res_reloc, &res_arg)
73+
.map_err(HintError::Memory)?;
74+
Ok(())
75+
}
76+
77+
fn bls_split(mut num: BigInt) -> Vec<BigInt> {
78+
use num_traits::Signed;
79+
let mut a = Vec::new();
80+
for _ in 0..2 {
81+
let residue = &num % BLS_BASE.deref();
82+
num /= BLS_BASE.deref();
83+
a.push(residue);
84+
}
85+
assert!(num.abs() < BigInt::from_u128(1 << 127).unwrap());
86+
a.push(num);
87+
a
88+
}
89+
90+
fn as_int(value: BigInt, prime: &BigInt) -> BigInt {
91+
let half_prime = prime / 2u32;
92+
if value > half_prime {
93+
value - prime
94+
} else {
95+
value
96+
}
97+
}
98+
99+
fn bls_pack(z: &BigInt3, prime: &BigInt) -> BigInt {
100+
let limbs = &z.limbs;
101+
limbs
102+
.iter()
103+
.enumerate()
104+
.fold(BigInt::zero(), |acc, (i, limb)| {
105+
let limb_as_int = as_int(limb.to_bigint(), prime);
106+
acc + limb_as_int * &BLS_BASE.pow(i as u32)
107+
})
108+
}

vm/src/hint_processor/builtin_hint_processor/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,7 @@ pub mod uint384_extension;
3838
pub mod uint_utils;
3939
pub mod usort;
4040
pub mod vrf;
41+
42+
#[cfg(feature = "cairo-0-data-availability-hints")]
43+
#[cfg_attr(docsrs, doc(cfg(feature = "cairo-0-data-availability-hints")))]
44+
pub mod kzg_da;

vm/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
//! - implementations of [`arbitrary::Arbitrary`](https://docs.rs/arbitrary/latest/arbitrary/) for some structs.
1010
//! - `cairo-1-hints`: Enable hints that were introduced in Cairo 1. Not enabled by default.
1111
//! - `cairo-0-secp-hints`: Enable secp hints that were introduced in Cairo 0. Not enabled by default.
12+
//! - `cairo-0-data-availability-hints`: Enable data availability hints that were introduced in Cairo 0. Not enabled by default.
1213
1314
#![cfg_attr(docsrs, feature(doc_cfg))]
1415
#![deny(warnings)]

vm/src/tests/cairo_run_test.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1308,3 +1308,12 @@ fn cairo_run_secp_cairo0_ec_mul_by_uint256() {
13081308
);
13091309
run_program_simple(program_data.as_slice());
13101310
}
1311+
1312+
#[test]
1313+
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
1314+
#[cfg(feature = "cairo-0-data-availability-hints")]
1315+
fn cairo_run_data_availability_reduced_mul() {
1316+
let program_data =
1317+
include_bytes!("../../../cairo_programs/cairo-0-kzg-da-hints/reduced_mul.json");
1318+
run_program_simple(program_data.as_slice());
1319+
}

0 commit comments

Comments
 (0)