Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: define HashMap of hint groups along with hint strings #1943

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

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

* feat: define HashMap of hint groups along with hint strings [#1943](https://github.com/lambdaclass/cairo-vm/pull/1943)

#### [2.0.0-rc4] - 2025-01-23

* feat: implement `kzg` data availability hints [#1887](https://github.com/lambdaclass/cairo-vm/pull/1887)
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ starknet-crypto = { version = "0.7.3", default-features = false, features = [
"alloc",
] }
sha3 = { version = "0.10.8", default-features = false }
indoc = { version = "2.0.5", default-features = false }
lazy_static = { version = "1.4.0", default-features = false, features = [
"spin_no_std",
] }
Expand Down
1 change: 1 addition & 0 deletions vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ hex = { workspace = true }
bincode = { workspace = true }
starknet-crypto = { workspace = true }
sha3 = { workspace = true }
indoc = { workspace = true }
lazy_static = { workspace = true }
nom = { workspace = true }
sha2 = { workspace = true }
Expand Down
865 changes: 341 additions & 524 deletions vm/src/hint_processor/builtin_hint_processor/hint_code.rs

Large diffs are not rendered by default.

55 changes: 55 additions & 0 deletions vm/src/hint_processor/builtin_hint_processor/hint_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,61 @@ use crate::types::relocatable::Relocatable;
use crate::vm::errors::hint_errors::HintError;
use crate::vm::vm_core::VirtualMachine;

/// Generates a const string for each hint, and a lazy_static HashMap that maps the const name to
/// the hint string.
/// Allows gating specific hints behind feature gates.
///
/// # Examples
///
/// ```
/// # #[macro_use] extern crate cairo_vm;
/// # use cairo_vm::stdlib::collections::HashMap;
/// cairo_vm::define_hint_string_map!(
/// FOO_HINTS,
/// (FOO_HINT_ADD_X_Y, "x + y"),
/// (FOO_HINT_PRINT_X, "print(x)", "test_utils")
/// );
/// ```
///
/// This will generate the following code:
///
/// ```
/// # use cairo_vm::stdlib::collections::HashMap;
/// pub const FOO_HINT_ADD_X_Y: &str = "x + y";
/// #[cfg(feature = "test_utils")]
/// pub const FOO_HINT_PRINT_X: &str = "print(x)";
///
/// lazy_static::lazy_static! {
/// pub static ref FOO_HINTS: HashMap<&'static str, &'static str> = {
/// let mut map = HashMap::new();
/// map.insert("FOO_HINT_ADD_X_Y", FOO_HINT_ADD_X_Y);
/// #[cfg(feature = "test_utils")]
/// map.insert("FOO_HINT_PRINT_X", FOO_HINT_PRINT_X);
/// map
/// };
/// }
/// ```
#[macro_export]
macro_rules! define_hint_string_map {
($hint_set_name:ident, $(($hint_name:ident, $hint_str:expr $(, $feature_gate:expr)?)),+) => {
$(
$(#[cfg(feature = $feature_gate)])?
pub const $hint_name: &str = $hint_str;
)+

lazy_static::lazy_static! {
pub static ref $hint_set_name: HashMap<&'static str, &'static str> = {
let mut map = HashMap::new();
$(
$(#[cfg(feature = $feature_gate)])?
map.insert(stringify!($hint_name), $hint_name);
)+
map
};
}
}
}

//Inserts value into the address of the given ids variable
pub fn insert_value_from_var_name(
var_name: &str,
Expand Down
129 changes: 65 additions & 64 deletions vm/src/hint_processor/builtin_hint_processor/secp/cairo0_hints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::stdlib::{
prelude::*,
};

use crate::define_hint_string_map;
use crate::hint_processor::builtin_hint_processor::hint_utils::{
get_constant_from_var_name, get_integer_from_var_name, insert_value_from_var_name,
};
Expand All @@ -17,6 +18,7 @@ use crate::types::exec_scope::ExecutionScopes;
use crate::vm::errors::hint_errors::HintError;
use crate::vm::vm_core::VirtualMachine;
use crate::Felt252;
use indoc::indoc;
use num_bigint::{BigInt, BigUint};
use num_integer::Integer;
use num_traits::One;
Expand All @@ -26,9 +28,70 @@ use super::bigint_utils::{BigInt3, Uint384};
use super::ec_utils::EcPoint;
use super::secp_utils::{SECP256R1_ALPHA, SECP256R1_B, SECP256R1_P};

pub const SECP_REDUCE: &str = r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P
define_hint_string_map! {
CAIRO0_HINT_CODES,
(SECP_REDUCE, indoc! {r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P
from starkware.cairo.common.cairo_secp.secp_utils import pack
value = pack(ids.x, PRIME) % SECP256R1_P"#;
value = pack(ids.x, PRIME) % SECP256R1_P"#}),
(SECP_REDUCE_X, indoc! {r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P
from starkware.cairo.common.cairo_secp.secp_utils import pack

x = pack(ids.x, PRIME) % SECP256R1_P"#}),
(COMPUTE_Q_MOD_PRIME, indoc! {r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P
from starkware.cairo.common.cairo_secp.secp_utils import pack

q, r = divmod(pack(ids.val, PRIME), SECP256R1_P)
assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}."
ids.q = q % PRIME"#}),
(COMPUTE_IDS_HIGH_LOW, indoc! {r#"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**165).'

# Calculation for the assertion.
ids.high, ids.low = divmod(ids.value, ids.SHIFT)"#}),
(SECP_R1_GET_POINT_FROM_X, indoc! {r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP256R1, pack
from starkware.python.math_utils import y_squared_from_x

y_square_int = y_squared_from_x(
x=pack(ids.x, SECP256R1.prime),
alpha=SECP256R1.alpha,
beta=SECP256R1.beta,
field_prime=SECP256R1.prime,
)

# Note that (y_square_int ** ((SECP256R1.prime + 1) / 4)) ** 2 =
# = y_square_int ** ((SECP256R1.prime + 1) / 2) =
# = y_square_int ** ((SECP256R1.prime - 1) / 2 + 1) =
# = y_square_int * y_square_int ** ((SECP256R1.prime - 1) / 2) = y_square_int * {+/-}1.
y = pow(y_square_int, (SECP256R1.prime + 1) // 4, SECP256R1.prime)

# We need to decide whether to take y or prime - y.
if ids.v % 2 == y % 2:
value = y
else:
value = (-y) % SECP256R1.prime"#}),
(IS_ON_CURVE_2, indoc! {r#"ids.is_on_curve = (y * y) % SECP256R1.prime == y_square_int"#}),
(SECP_DOUBLE_ASSIGN_NEW_X, indoc! {r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P
from starkware.cairo.common.cairo_secp.secp_utils import pack

slope = pack(ids.slope, SECP256R1_P)
x = pack(ids.point.x, SECP256R1_P)
y = pack(ids.point.y, SECP256R1_P)

value = new_x = (pow(slope, 2, SECP256R1_P) - 2 * x) % SECP256R1_P"#}),
(GENERATE_NIBBLES, indoc! {r#"num = (ids.scalar.high << 128) + ids.scalar.low
nibbles = [(num >> i) & 0xf for i in range(0, 256, 4)]
ids.first_nibble = nibbles.pop()
ids.last_nibble = nibbles[0]"#}),
(FAST_SECP_ADD_ASSIGN_NEW_Y, indoc! {r#"value = new_y = (slope * (x - new_x) - y) % SECP256R1_P"#}),
(WRITE_NIBBLES_TO_MEM, indoc! {r#"memory[fp + 0] = to_felt_or_relocatable(nibbles.pop())"#}),
(COMPUTE_VALUE_DIV_MOD, indoc! {r#"from starkware.python.math_utils import div_mod

value = div_mod(1, x, SECP256R1_P)"#})
}

pub fn reduce_value(
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
Expand All @@ -41,10 +104,6 @@ pub fn reduce_value(
Ok(())
}

pub const SECP_REDUCE_X: &str = r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P
from starkware.cairo.common.cairo_secp.secp_utils import pack

x = pack(ids.x, PRIME) % SECP256R1_P"#;
pub fn reduce_x(
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
Expand All @@ -57,12 +116,6 @@ pub fn reduce_x(
Ok(())
}

pub const COMPUTE_Q_MOD_PRIME: &str = r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P
from starkware.cairo.common.cairo_secp.secp_utils import pack

q, r = divmod(pack(ids.val, PRIME), SECP256R1_P)
assert r == 0, f"verify_zero: Invalid input {ids.val.d0, ids.val.d1, ids.val.d2}."
ids.q = q % PRIME"#;
pub fn compute_q_mod_prime(
vm: &mut VirtualMachine,
_exec_scopes: &mut ExecutionScopes,
Expand All @@ -79,14 +132,6 @@ pub fn compute_q_mod_prime(
Ok(())
}

pub const COMPUTE_IDS_HIGH_LOW: &str = r#"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**165).'

# Calculation for the assertion.
ids.high, ids.low = divmod(ids.value, ids.SHIFT)"#;
pub fn compute_ids_high_low(
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
Expand Down Expand Up @@ -121,28 +166,6 @@ pub fn compute_ids_high_low(
Ok(())
}

pub const SECP_R1_GET_POINT_FROM_X: &str = r#"from starkware.cairo.common.cairo_secp.secp_utils import SECP256R1, pack
from starkware.python.math_utils import y_squared_from_x

y_square_int = y_squared_from_x(
x=pack(ids.x, SECP256R1.prime),
alpha=SECP256R1.alpha,
beta=SECP256R1.beta,
field_prime=SECP256R1.prime,
)

# Note that (y_square_int ** ((SECP256R1.prime + 1) / 4)) ** 2 =
# = y_square_int ** ((SECP256R1.prime + 1) / 2) =
# = y_square_int ** ((SECP256R1.prime - 1) / 2 + 1) =
# = y_square_int * y_square_int ** ((SECP256R1.prime - 1) / 2) = y_square_int * {+/-}1.
y = pow(y_square_int, (SECP256R1.prime + 1) // 4, SECP256R1.prime)

# We need to decide whether to take y or prime - y.
if ids.v % 2 == y % 2:
value = y
else:
value = (-y) % SECP256R1.prime"#;

pub fn r1_get_point_from_x(
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
Expand Down Expand Up @@ -204,8 +227,6 @@ pub fn r1_get_point_from_x(
Ok(())
}

pub const IS_ON_CURVE_2: &str = r#"ids.is_on_curve = (y * y) % SECP256R1.prime == y_square_int"#;

pub fn is_on_curve_2(
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
Expand All @@ -228,15 +249,6 @@ pub fn is_on_curve_2(
Ok(())
}

pub const SECP_DOUBLE_ASSIGN_NEW_X: &str = r#"from starkware.cairo.common.cairo_secp.secp256r1_utils import SECP256R1_P
from starkware.cairo.common.cairo_secp.secp_utils import pack

slope = pack(ids.slope, SECP256R1_P)
x = pack(ids.point.x, SECP256R1_P)
y = pack(ids.point.y, SECP256R1_P)

value = new_x = (pow(slope, 2, SECP256R1_P) - 2 * x) % SECP256R1_P"#;

pub fn secp_double_assign_new_x(
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
Expand Down Expand Up @@ -266,10 +278,6 @@ pub fn secp_double_assign_new_x(
Ok(())
}

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

pub const FAST_SECP_ADD_ASSIGN_NEW_Y: &str =
r#"value = new_y = (slope * (x - new_x) - y) % SECP256R1_P"#;
pub fn fast_secp_add_assign_new_y(
_vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
Expand All @@ -322,8 +328,6 @@ pub fn fast_secp_add_assign_new_y(
Ok(())
}

pub const WRITE_NIBBLES_TO_MEM: &str = r#"memory[fp + 0] = to_felt_or_relocatable(nibbles.pop())"#;

pub fn write_nibbles_to_mem(
vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
Expand All @@ -338,9 +342,6 @@ pub fn write_nibbles_to_mem(
Ok(())
}

pub const COMPUTE_VALUE_DIV_MOD: &str = r#"from starkware.python.math_utils import div_mod

value = div_mod(1, x, SECP256R1_P)"#;
pub fn compute_value_div_mod(
_vm: &mut VirtualMachine,
exec_scopes: &mut ExecutionScopes,
Expand Down
Loading