Skip to content
Open
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
52 changes: 48 additions & 4 deletions corelib/src/ecdsa.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,7 @@ pub fn check_ecdsa_signature(
};

// Retrieve the generator point.
let Some(gen_point) = EcPointTrait::new_nz(
ec::stark_curve::GEN_X, ec::stark_curve::GEN_Y,
) else {
let Some(gen_point) = generator_point() else {
return false;
};

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

// a Valid signature should satisfy:
// zG + rQ = sR.
Expand Down Expand Up @@ -197,3 +195,49 @@ pub fn recover_public_key(
state.add_mul(r_multiplier, r_point);
Some(state.finalize_nz()?.x())
}

// TODO(orizi): Remove this function on next Sierra release.
/// Returns the generator point of the elliptic curve.
///
/// Note: Cannot actually fail, as the generator point is always valid.
#[cfg(not(sierra: "future"))]
fn generator_point() -> Option<ec::NonZeroEcPoint> {
EcPointTrait::new_nz(ec::stark_curve::GEN_X, ec::stark_curve::GEN_Y)
}

// TODO(orizi): Remove this function and use `generator::value()` directly on next Sierra release.
/// Returns the generator point of the elliptic curve.
///
/// Note: Cannot actually fail, as the generator point is always valid.
#[cfg(sierra: "future")]
fn generator_point() -> Option<ec::NonZeroEcPoint> {
Some(generator::value())
}

#[cfg(sierra: "future")]
mod generator {
use crate::ec;

mod v {
/// Const type variant for the EcPoint type.
pub extern type Const<T, const X: felt252, const Y: felt252>;
}

mod nz {
/// Non-zero const type variant for the EcPoint type.
pub extern type Const<T, C>;
}

/// Extern declaration for fetching the actual value.
extern fn const_as_immediate<T>() -> NonZero<ec::EcPoint> nopanic;

/// Returns the generator point of the elliptic curve.
pub fn value() -> ec::NonZeroEcPoint {
const_as_immediate::<
nz::Const<
ec::NonZeroEcPoint,
v::Const<ec::EcPoint, ec::stark_curve::GEN_X, ec::stark_curve::GEN_Y>,
>,
>()
}
}
7 changes: 7 additions & 0 deletions crates/cairo-lang-sierra-to-casm/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,13 @@ fn extract_const_value(
}
_ => return Err(CompilationError::ConstDataMismatch),
},
CoreTypeConcrete::EcPoint(_) => match &const_type.inner_data[..] {
[GenericArg::Value(x), GenericArg::Value(y)] => {
values.push(x.clone());
values.push(y.clone());
}
_ => return Err(CompilationError::ConstDataMismatch),
},
_ => match &const_type.inner_data[..] {
[GenericArg::Value(value)] => {
values.push(value.clone());
Expand Down
63 changes: 63 additions & 0 deletions crates/cairo-lang-sierra-to-casm/src/test_data/errors
Original file line number Diff line number Diff line change
Expand Up @@ -1109,3 +1109,66 @@ type OutOfRange = Const<ClassHash, 361850278866613110698659328152149712041468702

//! > error
Error during type specialization of `OutOfRange`: Could not specialize type

//! > ==========================================================================

//! > EC negative x.

//! > test_runner_name
compiler_errors

//! > sierra_code
type EcPoint = EcPoint;
type ValidPoint = Const<EcPoint, 1, 1130673244253924969006665885121925533155264548256591442770131812330730973800>;
type InvalidPoint = Const<EcPoint, -1, 14985303859878276524652518297008158829868122004499355227972672702239519519>;

//! > error
Error during type specialization of `InvalidPoint`: Could not specialize type

//! > ==========================================================================

//! > EC negative y.

//! > test_runner_name
compiler_errors

//! > sierra_code
type EcPoint = EcPoint;
type ValidPoint = Const<EcPoint, 1, 1130673244253924969006665885121925533155264548256591442770131812330730973800>;
type InvalidPoint = Const<EcPoint, 1, -1130673244253924969006665885121925533155264548256591442770131812330730973800>;

//! > error
Error during type specialization of `InvalidPoint`: Could not specialize type

//! > ==========================================================================

//! > EC invalid point.

//! > test_runner_name
compiler_errors

//! > sierra_code
type EcPoint = EcPoint;
type ValidPoint = Const<EcPoint, 0, 0>;
type InvalidPoint = Const<EcPoint, 1, 1>;

//! > error
Error during type specialization of `InvalidPoint`: Could not specialize type

//! > ==========================================================================

//! > EC invalid non-zero point.

//! > test_runner_name
compiler_errors

//! > sierra_code
type EcPoint = EcPoint;
type NonZeroEcPoint = NonZero<EcPoint>;
type ValidPoint1 = Const<EcPoint, 1, 1130673244253924969006665885121925533155264548256591442770131812330730973800>;
type ValidNonZeroPoint = Const<NonZeroEcPoint, ValidPoint1>;
type ValidPoint2 = Const<EcPoint, 0, 0>;
type InvalidNonZeroPoint = Const<NonZeroEcPoint, ValidPoint2>;

//! > error
Error during type specialization of `InvalidNonZeroPoint`: Could not specialize type
50 changes: 44 additions & 6 deletions crates/cairo-lang-sierra/src/extensions/modules/const_type.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use cairo_lang_utils::try_extract_matches;
use itertools::Itertools;
use num_bigint::BigInt;
use num_traits::{ToPrimitive, Zero};
use starknet_types_core::curve::AffinePoint;
use starknet_types_core::felt::{CAIRO_PRIME_BIGINT, Felt as Felt252};

use super::boxing::box_ty;
use super::consts::ConstGenLibfunc;
Expand All @@ -14,6 +17,7 @@ use super::starknet::interoperability::{
use super::structure::StructType;
use super::utils::Range;
use crate::define_libfunc_hierarchy;
use crate::extensions::ec::EcPointType;
use crate::extensions::lib_func::{
DeferredOutputKind, LibfuncSignature, OutputVarInfo, SierraApChange,
SignatureSpecializationContext, SpecializationContext,
Expand Down Expand Up @@ -79,6 +83,8 @@ fn validate_const_data(
return validate_const_enum_data(context, &inner_type_info, inner_data);
} else if *inner_generic_id == NonZeroType::ID {
return validate_const_nz_data(context, &inner_type_info, inner_data);
} else if *inner_generic_id == EcPointType::ID {
return validate_const_ec_data(context, inner_data);
}
let type_range = if *inner_generic_id == ContractAddressType::id() {
Range::half_open(0, ContractAddressConstLibfuncWrapped::bound())
Expand Down Expand Up @@ -172,12 +178,22 @@ fn validate_const_nz_data(
if wrapped_ty_from_const != wrapped_ty_from_nz {
return Err(SpecializationError::UnsupportedGenericArg);
}

// Check the direct value case.
if matches!(inner_const_data.as_slice(), [GenericArg::Value(value)] if !value.is_zero()) {
// Validate that the inner type is a valid integer type, by calling `from_type_info`.
Range::from_type_info(&context.get_type_info(wrapped_ty_from_nz)?)?;
return Ok(());
// Check the direct value cases.
match inner_const_data.as_slice() {
[GenericArg::Value(value)] if !value.is_zero() => {
// Validate that the inner type is a valid integer type, by calling `from_type_info`.
Range::from_type_info(&context.get_type_info(wrapped_ty_from_nz)?)?;
return Ok(());
}
[GenericArg::Value(_x), GenericArg::Value(y)] if !y.is_zero() => {
// Validate that the inner type is a valid ec point type.
if context.get_type_info(wrapped_ty_from_nz)?.long_id.generic_id == EcPointType::ID {
return Ok(());
} else {
return Err(SpecializationError::UnsupportedGenericArg);
}
}
_ => {}
}
let struct_generic_args =
extract_type_generic_args::<StructType>(context, &wrapped_ty_from_nz)?;
Expand Down Expand Up @@ -207,6 +223,28 @@ fn validate_const_nz_data(
if is_non_zero { Ok(()) } else { Err(SpecializationError::UnsupportedGenericArg) }
}

/// Given a
fn validate_const_ec_data(
_context: &dyn TypeSpecializationContext,
inner_data: &[GenericArg],
) -> Result<(), SpecializationError> {
// Assert that the inner data is the `x` and `y` values of the point on the `ec` curve.
let [GenericArg::Value(x), GenericArg::Value(y)] = inner_data else {
return Err(SpecializationError::UnsupportedGenericArg);
};
if x.is_zero() && y.is_zero() {
return Ok(());
}
let prime: &BigInt = &CAIRO_PRIME_BIGINT;
if x < &BigInt::ZERO || x >= prime || y < &BigInt::ZERO || y >= prime {
return Err(SpecializationError::UnsupportedGenericArg);
}
match AffinePoint::new(Felt252::from(x), Felt252::from(y)) {
Ok(_) => Ok(()),
Err(_) => Err(SpecializationError::UnsupportedGenericArg),
}
}

/// Validates the type is a `Const` type, and extracts the inner type and the rest of the generic
/// args of `const_ty`.
fn extract_const_info(
Expand Down
151 changes: 151 additions & 0 deletions tests/e2e_test_data/libfuncs/consts
Original file line number Diff line number Diff line change
Expand Up @@ -1036,3 +1036,154 @@ test::foo@F0() -> (Box<NonZero<core::integer::u512>>);

//! > function_costs
test::foo: SmallOrderedMap({Const: 300})

//! > ==========================================================================

//! > const generator EcPoint.

//! > test_runner_name
WithOptsE2ETestRunner

//! > cairo_code
use core::ec::EcPoint;

mod value {
extern type Const<T, const X: felt252, const Y: felt252>;
}
extern fn const_as_box<T, const SEGMENT_INDEX: felt252>() -> Box<EcPoint> nopanic;

fn foo() -> Box<EcPoint> {
const_as_box::<
value::Const<
EcPoint,
0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca,
0x5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f,
>,
0,
>()
}

//! > casm
call rel 5;
[ap + 0] = [ap + -1] + 4, ap++;
ret;
ret;
dw 874739451078007766457464989774322083649278607533249481151382481072868806602;
dw 152666792071518830868575557812948353041420400780739481342941381225525861407;

//! > sierra_code
type Box<EcPoint> = Box<EcPoint> [storable: true, drop: true, dup: true, zero_sized: false];
type Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407> = Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407> [storable: false, drop: false, dup: false, zero_sized: false];
type EcPoint = EcPoint [storable: true, drop: true, dup: true, zero_sized: false];

libfunc const_as_box<Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407>, 0> = const_as_box<Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407>, 0>;

F0:
const_as_box<Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407>, 0>() -> ([0]);
return([0]);

test::foo@F0() -> (Box<EcPoint>);

//! > function_costs
test::foo: SmallOrderedMap({Const: 300})

//! > ==========================================================================

//! > const zero EcPoint.

//! > test_runner_name
WithOptsE2ETestRunner

//! > cairo_code
use core::ec::EcPoint;

mod value {
extern type Const<T, const X: felt252, const Y: felt252>;
}
extern fn const_as_box<T, const SEGMENT_INDEX: felt252>() -> Box<EcPoint> nopanic;

fn foo() -> Box<EcPoint> {
const_as_box::<value::Const<EcPoint, 0, 0>, 0>()
}

//! > casm
call rel 5;
[ap + 0] = [ap + -1] + 4, ap++;
ret;
ret;
dw 0;
dw 0;

//! > sierra_code
type Box<EcPoint> = Box<EcPoint> [storable: true, drop: true, dup: true, zero_sized: false];
type Const<EcPoint, 0, 0> = Const<EcPoint, 0, 0> [storable: false, drop: false, dup: false, zero_sized: false];
type EcPoint = EcPoint [storable: true, drop: true, dup: true, zero_sized: false];

libfunc const_as_box<Const<EcPoint, 0, 0>, 0> = const_as_box<Const<EcPoint, 0, 0>, 0>;

F0:
const_as_box<Const<EcPoint, 0, 0>, 0>() -> ([0]);
return([0]);

test::foo@F0() -> (Box<EcPoint>);

//! > function_costs
test::foo: SmallOrderedMap({Const: 300})

//! > ==========================================================================

//! > const non-zero generator EcPoint.

//! > test_runner_name
WithOptsE2ETestRunner

//! > cairo_code
use core::ec::EcPoint;

mod value {
extern type Const<T, const X: felt252, const Y: felt252>;
}
mod nz {
extern type Const<T, C>;
}
extern fn const_as_box<T, const SEGMENT_INDEX: felt252>() -> Box<NonZero<EcPoint>> nopanic;

fn foo() -> Box<NonZero<EcPoint>> {
const_as_box::<
nz::Const<
NonZero<EcPoint>,
value::Const<
EcPoint,
0x1ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca,
0x5668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f,
>,
>,
0,
>()
}

//! > casm
call rel 5;
[ap + 0] = [ap + -1] + 4, ap++;
ret;
ret;
dw 874739451078007766457464989774322083649278607533249481151382481072868806602;
dw 152666792071518830868575557812948353041420400780739481342941381225525861407;

//! > sierra_code
type Box<NonZero<EcPoint>> = Box<NonZero<EcPoint>> [storable: true, drop: true, dup: true, zero_sized: false];
type Const<NonZero<EcPoint>, Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407>> = Const<NonZero<EcPoint>, Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407>> [storable: false, drop: false, dup: false, zero_sized: false];
type EcPoint = EcPoint [storable: true, drop: true, dup: true, zero_sized: false];
type NonZero<EcPoint> = NonZero<EcPoint> [storable: true, drop: true, dup: true, zero_sized: false];
type Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407> = Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407> [storable: false, drop: false, dup: false, zero_sized: false];

libfunc const_as_box<Const<NonZero<EcPoint>, Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407>>, 0> = const_as_box<Const<NonZero<EcPoint>, Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407>>, 0>;

F0:
const_as_box<Const<NonZero<EcPoint>, Const<EcPoint, 874739451078007766457464989774322083649278607533249481151382481072868806602, 152666792071518830868575557812948353041420400780739481342941381225525861407>>, 0>() -> ([0]);
return([0]);

test::foo@F0() -> (Box<NonZero<EcPoint>>);

//! > function_costs
test::foo: SmallOrderedMap({Const: 300})