Skip to content

Commit 526285c

Browse files
feat: define HashMap of hint groups along with hint strings (#1943)
Signed-off-by: Dori Medini <[email protected]> Co-authored-by: Julian Gonzalez Calderon <[email protected]>
1 parent a24c1b8 commit 526285c

File tree

7 files changed

+466
-588
lines changed

7 files changed

+466
-588
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
* refactor: Limit ret opcode decodeing to Cairo0's standards. [#1925](https://github.com/lambdaclass/cairo-vm/pull/1925)
1616

17+
* feat: define HashMap of hint groups along with hint strings [#1943](https://github.com/lambdaclass/cairo-vm/pull/1943)
18+
1719
#### [2.0.0-rc4] - 2025-01-23
1820

1921
* feat: implement `kzg` data availability hints [#1887](https://github.com/lambdaclass/cairo-vm/pull/1887)

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ starknet-crypto = { version = "0.7.3", default-features = false, features = [
4848
"alloc",
4949
] }
5050
sha3 = { version = "0.10.8", default-features = false }
51+
indoc = { version = "2.0.5", default-features = false }
5152
lazy_static = { version = "1.4.0", default-features = false, features = [
5253
"spin_no_std",
5354
] }

vm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ hex = { workspace = true }
5050
bincode = { workspace = true }
5151
starknet-crypto = { workspace = true }
5252
sha3 = { workspace = true }
53+
indoc = { workspace = true }
5354
lazy_static = { workspace = true }
5455
nom = { workspace = true }
5556
sha2 = { workspace = true }

vm/src/hint_processor/builtin_hint_processor/hint_code.rs

Lines changed: 341 additions & 524 deletions
Large diffs are not rendered by default.

vm/src/hint_processor/builtin_hint_processor/hint_utils.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,61 @@ use crate::types::relocatable::Relocatable;
1515
use crate::vm::errors::hint_errors::HintError;
1616
use crate::vm::vm_core::VirtualMachine;
1717

18+
/// Generates a const string for each hint, and a lazy_static HashMap that maps the const name to
19+
/// the hint string.
20+
/// Allows gating specific hints behind feature gates.
21+
///
22+
/// # Examples
23+
///
24+
/// ```
25+
/// # #[macro_use] extern crate cairo_vm;
26+
/// # use cairo_vm::stdlib::collections::HashMap;
27+
/// cairo_vm::define_hint_string_map!(
28+
/// FOO_HINTS,
29+
/// (FOO_HINT_ADD_X_Y, "x + y"),
30+
/// (FOO_HINT_PRINT_X, "print(x)", "test_utils")
31+
/// );
32+
/// ```
33+
///
34+
/// This will generate the following code:
35+
///
36+
/// ```
37+
/// # use cairo_vm::stdlib::collections::HashMap;
38+
/// pub const FOO_HINT_ADD_X_Y: &str = "x + y";
39+
/// #[cfg(feature = "test_utils")]
40+
/// pub const FOO_HINT_PRINT_X: &str = "print(x)";
41+
///
42+
/// lazy_static::lazy_static! {
43+
/// pub static ref FOO_HINTS: HashMap<&'static str, &'static str> = {
44+
/// let mut map = HashMap::new();
45+
/// map.insert("FOO_HINT_ADD_X_Y", FOO_HINT_ADD_X_Y);
46+
/// #[cfg(feature = "test_utils")]
47+
/// map.insert("FOO_HINT_PRINT_X", FOO_HINT_PRINT_X);
48+
/// map
49+
/// };
50+
/// }
51+
/// ```
52+
#[macro_export]
53+
macro_rules! define_hint_string_map {
54+
($hint_set_name:ident, $(($hint_name:ident, $hint_str:expr $(, $feature_gate:expr)?)),+) => {
55+
$(
56+
$(#[cfg(feature = $feature_gate)])?
57+
pub const $hint_name: &str = $hint_str;
58+
)+
59+
60+
lazy_static::lazy_static! {
61+
pub static ref $hint_set_name: HashMap<&'static str, &'static str> = {
62+
let mut map = HashMap::new();
63+
$(
64+
$(#[cfg(feature = $feature_gate)])?
65+
map.insert(stringify!($hint_name), $hint_name);
66+
)+
67+
map
68+
};
69+
}
70+
}
71+
}
72+
1873
//Inserts value into the address of the given ids variable
1974
pub fn insert_value_from_var_name(
2075
var_name: &str,

vm/src/hint_processor/builtin_hint_processor/secp/cairo0_hints.rs

Lines changed: 65 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::stdlib::{
55
prelude::*,
66
};
77

8+
use crate::define_hint_string_map;
89
use crate::hint_processor::builtin_hint_processor::hint_utils::{
910
get_constant_from_var_name, get_integer_from_var_name, insert_value_from_var_name,
1011
};
@@ -17,6 +18,7 @@ use crate::types::exec_scope::ExecutionScopes;
1718
use crate::vm::errors::hint_errors::HintError;
1819
use crate::vm::vm_core::VirtualMachine;
1920
use crate::Felt252;
21+
use indoc::indoc;
2022
use num_bigint::{BigInt, BigUint};
2123
use num_integer::Integer;
2224
use num_traits::One;
@@ -26,9 +28,70 @@ use super::bigint_utils::{BigInt3, Uint384};
2628
use super::ec_utils::EcPoint;
2729
use super::secp_utils::{SECP256R1_ALPHA, SECP256R1_B, SECP256R1_P};
2830

29-
pub const SECP_REDUCE: &str = r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P
31+
define_hint_string_map! {
32+
CAIRO0_HINT_CODES,
33+
(SECP_REDUCE, indoc! {r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P
3034
from starkware.cairo.common.cairo_secp.secp_utils import pack
31-
value = pack(ids.x, PRIME) % SECP256R1_P"#;
35+
value = pack(ids.x, PRIME) % SECP256R1_P"#}),
36+
(SECP_REDUCE_X, indoc! {r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P
37+
from starkware.cairo.common.cairo_secp.secp_utils import pack
38+
39+
x = pack(ids.x, PRIME) % SECP256R1_P"#}),
40+
(COMPUTE_Q_MOD_PRIME, indoc! {r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P
41+
from starkware.cairo.common.cairo_secp.secp_utils import pack
42+
43+
q, r = divmod(pack(ids.val, PRIME), SECP256R1_P)
44+
assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}."
45+
ids.q = q % PRIME"#}),
46+
(COMPUTE_IDS_HIGH_LOW, indoc! {r#"from starkware.cairo.common.math_utils import as_int
47+
48+
# Correctness check.
49+
value = as_int(ids.value, PRIME) % PRIME
50+
assert value < ids.UPPER_BOUND, f'{value} is outside of the range [0, 2**165).'
51+
52+
# Calculation for the assertion.
53+
ids.high, ids.low = divmod(ids.value, ids.SHIFT)"#}),
54+
(SECP_R1_GET_POINT_FROM_X, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP256R1, pack
55+
from starkware.python.math_utils import y_squared_from_x
56+
57+
y_square_int = y_squared_from_x(
58+
x=pack(ids.x, SECP256R1.prime),
59+
alpha=SECP256R1.alpha,
60+
beta=SECP256R1.beta,
61+
field_prime=SECP256R1.prime,
62+
)
63+
64+
# Note that (y_square_int ** ((SECP256R1.prime + 1) / 4)) ** 2 =
65+
# = y_square_int ** ((SECP256R1.prime + 1) / 2) =
66+
# = y_square_int ** ((SECP256R1.prime - 1) / 2 + 1) =
67+
# = y_square_int * y_square_int ** ((SECP256R1.prime - 1) / 2) = y_square_int * {+/-}1.
68+
y = pow(y_square_int, (SECP256R1.prime + 1) // 4, SECP256R1.prime)
69+
70+
# We need to decide whether to take y or prime - y.
71+
if ids.v % 2 == y % 2:
72+
value = y
73+
else:
74+
value = (-y) % SECP256R1.prime"#}),
75+
(IS_ON_CURVE_2, indoc! {r#"ids.is_on_curve = (y * y) % SECP256R1.prime == y_square_int"#}),
76+
(SECP_DOUBLE_ASSIGN_NEW_X, indoc! {r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P
77+
from starkware.cairo.common.cairo_secp.secp_utils import pack
78+
79+
slope = pack(ids.slope, SECP256R1_P)
80+
x = pack(ids.point.x, SECP256R1_P)
81+
y = pack(ids.point.y, SECP256R1_P)
82+
83+
value = new_x = (pow(slope, 2, SECP256R1_P) - 2 * x) % SECP256R1_P"#}),
84+
(GENERATE_NIBBLES, indoc! {r#"num = (ids.scalar.high << 128) + ids.scalar.low
85+
nibbles = [(num >> i) & 0xf for i in range(0, 256, 4)]
86+
ids.first_nibble = nibbles.pop()
87+
ids.last_nibble = nibbles[0]"#}),
88+
(FAST_SECP_ADD_ASSIGN_NEW_Y, indoc! {r#"value = new_y = (slope * (x - new_x) - y) % SECP256R1_P"#}),
89+
(WRITE_NIBBLES_TO_MEM, indoc! {r#"memory[fp + 0] = to_felt_or_relocatable(nibbles.pop())"#}),
90+
(COMPUTE_VALUE_DIV_MOD, indoc! {r#"from starkware.python.math_utils import div_mod
91+
92+
value = div_mod(1, x, SECP256R1_P)"#})
93+
}
94+
3295
pub fn reduce_value(
3396
vm: &mut VirtualMachine,
3497
exec_scopes: &mut ExecutionScopes,
@@ -41,10 +104,6 @@ pub fn reduce_value(
41104
Ok(())
42105
}
43106

44-
pub const SECP_REDUCE_X: &str = r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P
45-
from starkware.cairo.common.cairo_secp.secp_utils import pack
46-
47-
x = pack(ids.x, PRIME) % SECP256R1_P"#;
48107
pub fn reduce_x(
49108
vm: &mut VirtualMachine,
50109
exec_scopes: &mut ExecutionScopes,
@@ -57,12 +116,6 @@ pub fn reduce_x(
57116
Ok(())
58117
}
59118

60-
pub const COMPUTE_Q_MOD_PRIME: &str = r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P
61-
from starkware.cairo.common.cairo_secp.secp_utils import pack
62-
63-
q, r = divmod(pack(ids.val, PRIME), SECP256R1_P)
64-
assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}."
65-
ids.q = q % PRIME"#;
66119
pub fn compute_q_mod_prime(
67120
vm: &mut VirtualMachine,
68121
_exec_scopes: &mut ExecutionScopes,
@@ -79,14 +132,6 @@ pub fn compute_q_mod_prime(
79132
Ok(())
80133
}
81134

82-
pub const COMPUTE_IDS_HIGH_LOW: &str = r#"from starkware.cairo.common.math_utils import as_int
83-
84-
# Correctness check.
85-
value = as_int(ids.value, PRIME) % PRIME
86-
assert value < ids.UPPER_BOUND, f'{value} is outside of the range [0, 2**165).'
87-
88-
# Calculation for the assertion.
89-
ids.high, ids.low = divmod(ids.value, ids.SHIFT)"#;
90135
pub fn compute_ids_high_low(
91136
vm: &mut VirtualMachine,
92137
exec_scopes: &mut ExecutionScopes,
@@ -121,28 +166,6 @@ pub fn compute_ids_high_low(
121166
Ok(())
122167
}
123168

124-
pub const SECP_R1_GET_POINT_FROM_X: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP256R1, pack
125-
from starkware.python.math_utils import y_squared_from_x
126-
127-
y_square_int = y_squared_from_x(
128-
x=pack(ids.x, SECP256R1.prime),
129-
alpha=SECP256R1.alpha,
130-
beta=SECP256R1.beta,
131-
field_prime=SECP256R1.prime,
132-
)
133-
134-
# Note that (y_square_int ** ((SECP256R1.prime + 1) / 4)) ** 2 =
135-
# = y_square_int ** ((SECP256R1.prime + 1) / 2) =
136-
# = y_square_int ** ((SECP256R1.prime - 1) / 2 + 1) =
137-
# = y_square_int * y_square_int ** ((SECP256R1.prime - 1) / 2) = y_square_int * {+/-}1.
138-
y = pow(y_square_int, (SECP256R1.prime + 1) // 4, SECP256R1.prime)
139-
140-
# We need to decide whether to take y or prime - y.
141-
if ids.v % 2 == y % 2:
142-
value = y
143-
else:
144-
value = (-y) % SECP256R1.prime"#;
145-
146169
pub fn r1_get_point_from_x(
147170
vm: &mut VirtualMachine,
148171
exec_scopes: &mut ExecutionScopes,
@@ -204,8 +227,6 @@ pub fn r1_get_point_from_x(
204227
Ok(())
205228
}
206229

207-
pub const IS_ON_CURVE_2: &str = r#"ids.is_on_curve = (y * y) % SECP256R1.prime == y_square_int"#;
208-
209230
pub fn is_on_curve_2(
210231
vm: &mut VirtualMachine,
211232
exec_scopes: &mut ExecutionScopes,
@@ -228,15 +249,6 @@ pub fn is_on_curve_2(
228249
Ok(())
229250
}
230251

231-
pub const SECP_DOUBLE_ASSIGN_NEW_X: &str = r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P
232-
from starkware.cairo.common.cairo_secp.secp_utils import pack
233-
234-
slope = pack(ids.slope, SECP256R1_P)
235-
x = pack(ids.point.x, SECP256R1_P)
236-
y = pack(ids.point.y, SECP256R1_P)
237-
238-
value = new_x = (pow(slope, 2, SECP256R1_P) - 2 * x) % SECP256R1_P"#;
239-
240252
pub fn secp_double_assign_new_x(
241253
vm: &mut VirtualMachine,
242254
exec_scopes: &mut ExecutionScopes,
@@ -266,10 +278,6 @@ pub fn secp_double_assign_new_x(
266278
Ok(())
267279
}
268280

269-
pub const GENERATE_NIBBLES: &str = r#"num = (ids.scalar.high << 128) + ids.scalar.low
270-
nibbles = [(num >> i) & 0xf for i in range(0, 256, 4)]
271-
ids.first_nibble = nibbles.pop()
272-
ids.last_nibble = nibbles[0]"#;
273281
pub fn generate_nibbles(
274282
vm: &mut VirtualMachine,
275283
exec_scopes: &mut ExecutionScopes,
@@ -298,8 +306,6 @@ pub fn generate_nibbles(
298306
Ok(())
299307
}
300308

301-
pub const FAST_SECP_ADD_ASSIGN_NEW_Y: &str =
302-
r#"value = new_y = (slope * (x - new_x) - y) % SECP256R1_P"#;
303309
pub fn fast_secp_add_assign_new_y(
304310
_vm: &mut VirtualMachine,
305311
exec_scopes: &mut ExecutionScopes,
@@ -322,8 +328,6 @@ pub fn fast_secp_add_assign_new_y(
322328
Ok(())
323329
}
324330

325-
pub const WRITE_NIBBLES_TO_MEM: &str = r#"memory[fp + 0] = to_felt_or_relocatable(nibbles.pop())"#;
326-
327331
pub fn write_nibbles_to_mem(
328332
vm: &mut VirtualMachine,
329333
exec_scopes: &mut ExecutionScopes,
@@ -338,9 +342,6 @@ pub fn write_nibbles_to_mem(
338342
Ok(())
339343
}
340344

341-
pub const COMPUTE_VALUE_DIV_MOD: &str = r#"from starkware.python.math_utils import div_mod
342-
343-
value = div_mod(1, x, SECP256R1_P)"#;
344345
pub fn compute_value_div_mod(
345346
_vm: &mut VirtualMachine,
346347
exec_scopes: &mut ExecutionScopes,

0 commit comments

Comments
 (0)