Skip to content

Commit 107388f

Browse files
committed
Added const for EcPoint including non-zero.
Added actual usage of it in ECDSA - blocked by cfg.
1 parent 93e4003 commit 107388f

File tree

4 files changed

+250
-10
lines changed

4 files changed

+250
-10
lines changed

corelib/src/ecdsa.cairo

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,7 @@ pub fn check_ecdsa_signature(
7474
};
7575

7676
// Retrieve the generator point.
77-
let Some(gen_point) = EcPointTrait::new_nz(
78-
ec::stark_curve::GEN_X, ec::stark_curve::GEN_Y,
79-
) else {
77+
let Some(gen_point) = generator_point() else {
8078
return false;
8179
};
8280

@@ -161,7 +159,7 @@ pub fn recover_public_key(
161159
message_hash: felt252, signature_r: felt252, signature_s: felt252, y_parity: bool,
162160
) -> Option<felt252> {
163161
let r_point = EcPointTrait::new_nz_from_x(signature_r)?;
164-
let gen_point = EcPointTrait::new_nz(ec::stark_curve::GEN_X, ec::stark_curve::GEN_Y)?;
162+
let gen_point = generator_point()?;
165163

166164
// a Valid signature should satisfy:
167165
// zG + rQ = sR.
@@ -197,3 +195,49 @@ pub fn recover_public_key(
197195
state.add_mul(r_multiplier, r_point);
198196
Some(state.finalize_nz()?.x())
199197
}
198+
199+
// TODO(orizi): Remove this function on next Sierra release.
200+
/// Returns the generator point of the elliptic curve.
201+
///
202+
/// Note: Cannot actually fail, as the generator point is always valid.
203+
#[cfg(not(sierra: "future"))]
204+
fn generator_point() -> Option<ec::NonZeroEcPoint> {
205+
EcPointTrait::new_nz(ec::stark_curve::GEN_X, ec::stark_curve::GEN_Y)
206+
}
207+
208+
// TODO(orizi): Remove this function and use `generator::value()` directly on next Sierra release.
209+
/// Returns the generator point of the elliptic curve.
210+
///
211+
/// Note: Cannot actually fail, as the generator point is always valid.
212+
#[cfg(sierra: "future")]
213+
fn generator_point() -> Option<ec::NonZeroEcPoint> {
214+
Some(generator::value())
215+
}
216+
217+
#[cfg(sierra: "future")]
218+
mod generator {
219+
use crate::ec;
220+
221+
mod v {
222+
/// Const type variant for the EcPoint type.
223+
pub extern type Const<T, const X: felt252, const Y: felt252>;
224+
}
225+
226+
mod nz {
227+
/// Non-zero const type variant for the EcPoint type.
228+
pub extern type Const<T, C>;
229+
}
230+
231+
/// Extern declaration for fetching the actual value.
232+
extern fn const_as_immediate<T>() -> NonZero<ec::EcPoint> nopanic;
233+
234+
/// Returns the generator point of the elliptic curve.
235+
pub fn value() -> ec::NonZeroEcPoint {
236+
const_as_immediate::<
237+
nz::Const<
238+
ec::NonZeroEcPoint,
239+
v::Const<ec::EcPoint, ec::stark_curve::GEN_X, ec::stark_curve::GEN_Y>,
240+
>,
241+
>()
242+
}
243+
}

crates/cairo-lang-sierra-to-casm/src/compiler.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,13 @@ fn extract_const_value(
394394
}
395395
_ => return Err(CompilationError::ConstDataMismatch),
396396
},
397+
CoreTypeConcrete::EcPoint(_) => match &const_type.inner_data[..] {
398+
[GenericArg::Value(x), GenericArg::Value(y)] => {
399+
values.push(x.clone());
400+
values.push(y.clone());
401+
}
402+
_ => return Err(CompilationError::ConstDataMismatch),
403+
},
397404
_ => match &const_type.inner_data[..] {
398405
[GenericArg::Value(value)] => {
399406
values.push(value.clone());

crates/cairo-lang-sierra/src/extensions/modules/const_type.rs

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use cairo_lang_utils::try_extract_matches;
22
use itertools::Itertools;
3+
use num_bigint::BigInt;
34
use num_traits::{ToPrimitive, Zero};
5+
use starknet_types_core::curve::AffinePoint;
6+
use starknet_types_core::felt::{CAIRO_PRIME_BIGINT, Felt as Felt252};
47

58
use super::boxing::box_ty;
69
use super::consts::ConstGenLibfunc;
@@ -14,6 +17,7 @@ use super::starknet::interoperability::{
1417
use super::structure::StructType;
1518
use super::utils::Range;
1619
use crate::define_libfunc_hierarchy;
20+
use crate::extensions::ec::EcPointType;
1721
use crate::extensions::lib_func::{
1822
DeferredOutputKind, LibfuncSignature, OutputVarInfo, SierraApChange,
1923
SignatureSpecializationContext, SpecializationContext,
@@ -79,6 +83,8 @@ fn validate_const_data(
7983
return validate_const_enum_data(context, &inner_type_info, inner_data);
8084
} else if *inner_generic_id == NonZeroType::ID {
8185
return validate_const_nz_data(context, &inner_type_info, inner_data);
86+
} else if *inner_generic_id == EcPointType::ID {
87+
return validate_const_ec_data(context, inner_data);
8288
}
8389
let type_range = if *inner_generic_id == ContractAddressType::id() {
8490
Range::half_open(0, ContractAddressConstLibfuncWrapped::bound())
@@ -172,12 +178,22 @@ fn validate_const_nz_data(
172178
if wrapped_ty_from_const != wrapped_ty_from_nz {
173179
return Err(SpecializationError::UnsupportedGenericArg);
174180
}
175-
176-
// Check the direct value case.
177-
if matches!(inner_const_data.as_slice(), [GenericArg::Value(value)] if !value.is_zero()) {
178-
// Validate that the inner type is a valid integer type, by calling `from_type_info`.
179-
Range::from_type_info(&context.get_type_info(wrapped_ty_from_nz)?)?;
180-
return Ok(());
181+
// Check the direct value cases.
182+
match inner_const_data.as_slice() {
183+
[GenericArg::Value(value)] if !value.is_zero() => {
184+
// Validate that the inner type is a valid integer type, by calling `from_type_info`.
185+
Range::from_type_info(&context.get_type_info(wrapped_ty_from_nz)?)?;
186+
return Ok(());
187+
}
188+
[GenericArg::Value(_x), GenericArg::Value(y)] if !y.is_zero() => {
189+
// Validate that the inner type is a valid ec point type.
190+
if context.get_type_info(wrapped_ty_from_nz)?.long_id.generic_id == EcPointType::ID {
191+
return Ok(());
192+
} else {
193+
return Err(SpecializationError::UnsupportedGenericArg);
194+
}
195+
}
196+
_ => {}
181197
}
182198
let struct_generic_args =
183199
extract_type_generic_args::<StructType>(context, &wrapped_ty_from_nz)?;
@@ -207,6 +223,28 @@ fn validate_const_nz_data(
207223
if is_non_zero { Ok(()) } else { Err(SpecializationError::UnsupportedGenericArg) }
208224
}
209225

226+
/// Given a
227+
fn validate_const_ec_data(
228+
_context: &dyn TypeSpecializationContext,
229+
inner_data: &[GenericArg],
230+
) -> Result<(), SpecializationError> {
231+
// Assert that the inner data is the `x` and `y` values of the point on the `ec` curve.
232+
let [GenericArg::Value(x), GenericArg::Value(y)] = inner_data else {
233+
return Err(SpecializationError::UnsupportedGenericArg);
234+
};
235+
if x.is_zero() && y.is_zero() {
236+
return Ok(());
237+
}
238+
let prime: &BigInt = &CAIRO_PRIME_BIGINT;
239+
if x < &BigInt::ZERO || x >= prime || y < &BigInt::ZERO || y >= prime {
240+
return Err(SpecializationError::UnsupportedGenericArg);
241+
}
242+
match AffinePoint::new(Felt252::from(x), Felt252::from(y)) {
243+
Ok(_) => Ok(()),
244+
Err(_) => Err(SpecializationError::UnsupportedGenericArg),
245+
}
246+
}
247+
210248
/// Validates the type is a `Const` type, and extracts the inner type and the rest of the generic
211249
/// args of `const_ty`.
212250
fn extract_const_info(

tests/e2e_test_data/libfuncs/consts

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,3 +1036,154 @@ test::foo@F0() -> (Box<NonZero<core::integer::u512>>);
10361036

10371037
//! > function_costs
10381038
test::foo: SmallOrderedMap({Const: 300})
1039+
1040+
//! > ==========================================================================
1041+
1042+
//! > const generator EcPoint.
1043+
1044+
//! > test_runner_name
1045+
WithOptsE2ETestRunner
1046+
1047+
//! > cairo_code
1048+
use core::ec::EcPoint;
1049+
1050+
mod value {
1051+
extern type Const<T, const X: felt252, const Y: felt252>;
1052+
}
1053+
extern fn const_as_box<T, const SEGMENT_INDEX: felt252>() -> Box<EcPoint> nopanic;
1054+
1055+
fn foo() -> Box<EcPoint> {
1056+
const_as_box::<
1057+
value::Const<
1058+
EcPoint,
1059+
0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca,
1060+
0x5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f,
1061+
>,
1062+
0,
1063+
>()
1064+
}
1065+
1066+
//! > casm
1067+
call rel 5;
1068+
[ap + 0] = [ap + -1] + 4, ap++;
1069+
ret;
1070+
ret;
1071+
dw 874739451078007766457464989774322083649278607533249481151382481072868806602;
1072+
dw 152666792071518830868575557812948353041420400780739481342941381225525861407;
1073+
1074+
//! > sierra_code
1075+
type Box<EcPoint> = Box<EcPoint> [storable: true, drop: true, dup: true, zero_sized: false];
1076+
type Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407> = Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407> [storable: false, drop: false, dup: false, zero_sized: false];
1077+
type EcPoint = EcPoint [storable: true, drop: true, dup: true, zero_sized: false];
1078+
1079+
libfunc const_as_box<Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407>, 0> = const_as_box<Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407>, 0>;
1080+
1081+
F0:
1082+
const_as_box<Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407>, 0>() -> ([0]);
1083+
return([0]);
1084+
1085+
test::foo@F0() -> (Box<EcPoint>);
1086+
1087+
//! > function_costs
1088+
test::foo: SmallOrderedMap({Const: 300})
1089+
1090+
//! > ==========================================================================
1091+
1092+
//! > const zero EcPoint.
1093+
1094+
//! > test_runner_name
1095+
WithOptsE2ETestRunner
1096+
1097+
//! > cairo_code
1098+
use core::ec::EcPoint;
1099+
1100+
mod value {
1101+
extern type Const<T, const X: felt252, const Y: felt252>;
1102+
}
1103+
extern fn const_as_box<T, const SEGMENT_INDEX: felt252>() -> Box<EcPoint> nopanic;
1104+
1105+
fn foo() -> Box<EcPoint> {
1106+
const_as_box::<value::Const<EcPoint, 0, 0>, 0>()
1107+
}
1108+
1109+
//! > casm
1110+
call rel 5;
1111+
[ap + 0] = [ap + -1] + 4, ap++;
1112+
ret;
1113+
ret;
1114+
dw 0;
1115+
dw 0;
1116+
1117+
//! > sierra_code
1118+
type Box<EcPoint> = Box<EcPoint> [storable: true, drop: true, dup: true, zero_sized: false];
1119+
type Const<EcPoint, 0, 0> = Const<EcPoint, 0, 0> [storable: false, drop: false, dup: false, zero_sized: false];
1120+
type EcPoint = EcPoint [storable: true, drop: true, dup: true, zero_sized: false];
1121+
1122+
libfunc const_as_box<Const<EcPoint, 0, 0>, 0> = const_as_box<Const<EcPoint, 0, 0>, 0>;
1123+
1124+
F0:
1125+
const_as_box<Const<EcPoint, 0, 0>, 0>() -> ([0]);
1126+
return([0]);
1127+
1128+
test::foo@F0() -> (Box<EcPoint>);
1129+
1130+
//! > function_costs
1131+
test::foo: SmallOrderedMap({Const: 300})
1132+
1133+
//! > ==========================================================================
1134+
1135+
//! > const non-zero generator EcPoint.
1136+
1137+
//! > test_runner_name
1138+
WithOptsE2ETestRunner
1139+
1140+
//! > cairo_code
1141+
use core::ec::EcPoint;
1142+
1143+
mod value {
1144+
extern type Const<T, const X: felt252, const Y: felt252>;
1145+
}
1146+
mod nz {
1147+
extern type Const<T, C>;
1148+
}
1149+
extern fn const_as_box<T, const SEGMENT_INDEX: felt252>() -> Box<NonZero<EcPoint>> nopanic;
1150+
1151+
fn foo() -> Box<NonZero<EcPoint>> {
1152+
const_as_box::<
1153+
nz::Const<
1154+
NonZero<EcPoint>,
1155+
value::Const<
1156+
EcPoint,
1157+
0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca,
1158+
0x5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f,
1159+
>,
1160+
>,
1161+
0,
1162+
>()
1163+
}
1164+
1165+
//! > casm
1166+
call rel 5;
1167+
[ap + 0] = [ap + -1] + 4, ap++;
1168+
ret;
1169+
ret;
1170+
dw 874739451078007766457464989774322083649278607533249481151382481072868806602;
1171+
dw 152666792071518830868575557812948353041420400780739481342941381225525861407;
1172+
1173+
//! > sierra_code
1174+
type Box<NonZero<EcPoint>> = Box<NonZero<EcPoint>> [storable: true, drop: true, dup: true, zero_sized: false];
1175+
type Const<NonZero<EcPoint>, Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407>> = Const<NonZero<EcPoint>, Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407>> [storable: false, drop: false, dup: false, zero_sized: false];
1176+
type EcPoint = EcPoint [storable: true, drop: true, dup: true, zero_sized: false];
1177+
type NonZero<EcPoint> = NonZero<EcPoint> [storable: true, drop: true, dup: true, zero_sized: false];
1178+
type Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407> = Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407> [storable: false, drop: false, dup: false, zero_sized: false];
1179+
1180+
libfunc const_as_box<Const<NonZero<EcPoint>, Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407>>, 0> = const_as_box<Const<NonZero<EcPoint>, Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407>>, 0>;
1181+
1182+
F0:
1183+
const_as_box<Const<NonZero<EcPoint>, Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407>>, 0>() -> ([0]);
1184+
return([0]);
1185+
1186+
test::foo@F0() -> (Box<NonZero<EcPoint>>);
1187+
1188+
//! > function_costs
1189+
test::foo: SmallOrderedMap({Const: 300})

0 commit comments

Comments
 (0)