Skip to content

Commit

Permalink
Added secp256k1 syscalls (#2841)
Browse files Browse the repository at this point in the history
  • Loading branch information
yuvalsw committed Apr 24, 2023
1 parent c7e87d6 commit 61adf84
Show file tree
Hide file tree
Showing 13 changed files with 425 additions and 3 deletions.
3 changes: 3 additions & 0 deletions corelib/src/ec.cairo
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//! This module contains functions and constructs related to elliptic curve operations on the Stark
//! curve.

use array::ArrayTrait;
use zeroable::IsZeroResult;
use traits::Into;
Expand Down
3 changes: 3 additions & 0 deletions corelib/src/starknet.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ use syscalls::call_contract_syscall;
use syscalls::storage_read_syscall;
use syscalls::storage_write_syscall;

// secp256k1
mod secp256k1;

// ContractAddress
mod contract_address;
use contract_address::ContractAddress;
Expand Down
23 changes: 23 additions & 0 deletions corelib/src/starknet/secp256k1.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//! This module contains functions and constructs related to elliptic curve operations on the
//! secp256k1 curve.

use starknet::SyscallResult;

#[derive(Copy, Drop)]
extern type Secp256K1EcPoint;

/// Computes the addition of secp256k1 EC points `p0 + p1`.
extern fn secp256k1_ec_add_syscall(
p0: Secp256K1EcPoint, p1: Secp256K1EcPoint
) -> SyscallResult<Secp256K1EcPoint> implicits(GasBuiltin, System) nopanic;

/// Computes the product of a secp256k1 EC point `p` by the given scalar `m`.
extern fn secp256k1_ec_mul_syscall(
p: Secp256K1EcPoint, m: u256
) -> SyscallResult<Secp256K1EcPoint> implicits(GasBuiltin, System) nopanic;

/// Computes the point on the secp256k1 curve that matches the given `x` coordinate, if such exists.
/// Out of the two possible y's, chooses according to `y_parity`.
extern fn secp256k1_ec_get_point_from_x_syscall(
x: u256, y_parity: bool
) -> SyscallResult<Option<Secp256K1EcPoint>> implicits(GasBuiltin, System) nopanic;
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,8 @@ pub fn core_libfunc_ap_change<InfoProvider: InvocationApChangeInfoProvider>(
| StarkNetConcreteLibfunc::Keccak(_)
| StarkNetConcreteLibfunc::LibraryCall(_)
| StarkNetConcreteLibfunc::ReplaceClass(_)
| StarkNetConcreteLibfunc::SendMessageToL1(_) => {
| StarkNetConcreteLibfunc::SendMessageToL1(_)
| StarkNetConcreteLibfunc::Secp256K1(_) => {
vec![ApChange::Known(2), ApChange::Known(2)]
}
StarkNetConcreteLibfunc::Testing(_) => vec![ApChange::Known(0)],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use cairo_lang_sierra::extensions::starknet::secp256k1::Secp256K1EcConcreteLibfunc;
use cairo_lang_sierra::extensions::starknet::StarkNetConcreteLibfunc;

use crate::objects::ConstCost;
Expand Down Expand Up @@ -41,6 +42,12 @@ pub fn starknet_libfunc_cost_base(libfunc: &StarkNetConcreteLibfunc) -> Vec<Cons
StarkNetConcreteLibfunc::ReplaceClass(_) => syscall_cost(6, 6),
StarkNetConcreteLibfunc::SendMessageToL1(_) => syscall_cost(8, 8),
StarkNetConcreteLibfunc::Testing(_) => vec![steps(1)],
StarkNetConcreteLibfunc::Secp256K1(libfunc) => match libfunc {
Secp256K1EcConcreteLibfunc::Add(_) => syscall_cost(7, 7),
Secp256K1EcConcreteLibfunc::Mul(_) | Secp256K1EcConcreteLibfunc::GetPointFromX(_) => {
syscall_cost(8, 8)
}
},
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use crate::invocations::{

mod testing;

mod secp256k1;
mod storage;

/// Builds instructions for Sierra starknet operations.
Expand Down Expand Up @@ -78,6 +79,7 @@ pub fn build(
build_syscalls(builder, "SendMessageToL1", [1, 2], [])
}
StarkNetConcreteLibfunc::Testing(libfunc) => testing::build(libfunc, builder),
StarkNetConcreteLibfunc::Secp256K1(libfunc) => secp256k1::build(libfunc, builder),
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use cairo_lang_sierra::extensions::starknet::secp256k1::Secp256K1EcConcreteLibfunc;

use super::{build_syscalls, CompiledInvocation, CompiledInvocationBuilder, InvocationError};

/// Builds instructions for Sierra secp256k1 operations.
pub fn build(
libfunc: &Secp256K1EcConcreteLibfunc,
builder: CompiledInvocationBuilder<'_>,
) -> Result<CompiledInvocation, InvocationError> {
match libfunc {
Secp256K1EcConcreteLibfunc::Add(_) => {
build_syscalls(builder, "Secp256K1EcAdd", [1, 1], [1])
}
Secp256K1EcConcreteLibfunc::Mul(_) => {
build_syscalls(builder, "Secp256K1EcMul", [1, 2], [1])
}
Secp256K1EcConcreteLibfunc::GetPointFromX(_) => {
build_syscalls(builder, "Secp256K1EcGetPointFromX", [2, 1], [2])
}
}
}
1 change: 1 addition & 0 deletions crates/cairo-lang-sierra-to-casm/src/type_sizes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub fn get_type_size_map(
| CoreTypeConcrete::StarkNet(StarkNetTypeConcrete::StorageAddress(_))
| CoreTypeConcrete::StarkNet(StarkNetTypeConcrete::ContractAddress(_))
| CoreTypeConcrete::StarkNet(StarkNetTypeConcrete::ClassHash(_))
| CoreTypeConcrete::StarkNet(StarkNetTypeConcrete::Secp256K1EcPoint(_))
| CoreTypeConcrete::Pedersen(_)
| CoreTypeConcrete::Poseidon(_)
| CoreTypeConcrete::Felt252Dict(_)
Expand Down
10 changes: 8 additions & 2 deletions crates/cairo-lang-sierra/src/extensions/modules/starknet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@ use storage::{
pub mod syscalls;
use syscalls::{ReplaceClassLibfunc, SystemType};

pub mod getter;

pub mod emit_event;
use emit_event::EmitEventLibfunc;

pub mod getter;

pub mod secp256k1;
use secp256k1::{Secp256K1EcLibfunc, Secp256K1EcPointType};

pub mod testing;

pub mod interoperability;
Expand Down Expand Up @@ -48,6 +52,7 @@ define_type_hierarchy! {
StorageBaseAddress(StorageBaseAddressType),
StorageAddress(StorageAddressType),
System(SystemType),
Secp256K1EcPoint(Secp256K1EcPointType),
}, StarkNetTypeConcrete
}

Expand Down Expand Up @@ -76,6 +81,7 @@ define_libfunc_hierarchy! {
ReplaceClass(ReplaceClassLibfunc),
SendMessageToL1(SendMessageToL1Libfunc),
Testing(TestingLibfunc),
Secp256K1(Secp256K1EcLibfunc),
}, StarkNetConcreteLibfunc
}

Expand Down
111 changes: 111 additions & 0 deletions crates/cairo-lang-sierra/src/extensions/modules/starknet/secp256k1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
use super::syscalls::SyscallGenericLibfunc;
use crate::define_libfunc_hierarchy;
use crate::extensions::enm::EnumType;
use crate::extensions::lib_func::SignatureSpecializationContext;
use crate::extensions::modules::{get_bool_type, get_u256_type, get_unit_type};
use crate::extensions::{NamedType, NoGenericArgsGenericType, SpecializationError};
use crate::ids::{GenericTypeId, UserTypeId};
use crate::program::GenericArg;

define_libfunc_hierarchy! {
pub enum Secp256K1EcLibfunc {
Add(Secp256K1EcAddLibfunc),
Mul(Secp256K1EcMulLibfunc),
GetPointFromX(Secp256K1EcGetPointFromXLibfunc),
}, Secp256K1EcConcreteLibfunc
}

#[derive(Default)]
pub struct Secp256K1EcPointType {}
impl NoGenericArgsGenericType for Secp256K1EcPointType {
const ID: GenericTypeId = GenericTypeId::new_inline("Secp256K1EcPoint");
const STORABLE: bool = true;
const DUPLICATABLE: bool = true;
const DROPPABLE: bool = true;
const SIZE: i16 = 1;
}

/// Libfunc for a secp256k1 elliptic curve addition system call.
#[derive(Default)]
pub struct Secp256K1EcAddLibfunc {}
impl SyscallGenericLibfunc for Secp256K1EcAddLibfunc {
const STR_ID: &'static str = "secp256k1_ec_add_syscall";

fn input_tys(
context: &dyn SignatureSpecializationContext,
) -> Result<Vec<crate::ids::ConcreteTypeId>, SpecializationError> {
let secp256k1_ec_point_type = context.get_concrete_type(Secp256K1EcPointType::id(), &[])?;

// Point `p0`, point `p1`
Ok(vec![secp256k1_ec_point_type.clone(), secp256k1_ec_point_type])
}

fn success_output_tys(
context: &dyn SignatureSpecializationContext,
) -> Result<Vec<crate::ids::ConcreteTypeId>, SpecializationError> {
Ok(vec![context.get_concrete_type(Secp256K1EcPointType::id(), &[])?])
}
}

/// Libfunc for a secp256k1 elliptic curve multiplication system call.
#[derive(Default)]
pub struct Secp256K1EcMulLibfunc {}
impl SyscallGenericLibfunc for Secp256K1EcMulLibfunc {
const STR_ID: &'static str = "secp256k1_ec_mul_syscall";

fn input_tys(
context: &dyn SignatureSpecializationContext,
) -> Result<Vec<crate::ids::ConcreteTypeId>, SpecializationError> {
Ok(vec![
// Point `p`.
context.get_concrete_type(Secp256K1EcPointType::id(), &[])?,
// Scalar `m`.
get_u256_type(context)?,
])
}

fn success_output_tys(
context: &dyn SignatureSpecializationContext,
) -> Result<Vec<crate::ids::ConcreteTypeId>, SpecializationError> {
Ok(vec![context.get_concrete_type(Secp256K1EcPointType::id(), &[])?])
}
}

/// System call libfunc for getting a point on the secp256k1 elliptic curve, according to the given
/// `x` coordinate and the parity of the relevant y coordinate.
#[derive(Default)]
pub struct Secp256K1EcGetPointFromXLibfunc {}
impl SyscallGenericLibfunc for Secp256K1EcGetPointFromXLibfunc {
const STR_ID: &'static str = "secp256k1_ec_get_point_from_x_syscall";

fn input_tys(
context: &dyn SignatureSpecializationContext,
) -> Result<Vec<crate::ids::ConcreteTypeId>, SpecializationError> {
Ok(vec![
// `x` coordinate.
get_u256_type(context)?,
// `y_parity` - parity of the relevant y coordinate.
get_bool_type(context)?,
])
}

fn success_output_tys(
context: &dyn SignatureSpecializationContext,
) -> Result<Vec<crate::ids::ConcreteTypeId>, SpecializationError> {
let secp256k1_ec_point_type = context.get_concrete_type(Secp256K1EcPointType::id(), &[])?;

let unit_type = get_unit_type(context)?;
// TODO(yuval): add get_option_type to mod.rs and use it here.
let option_secp256k1_ec_point_type = context.get_concrete_type(
EnumType::id(),
&[
GenericArg::UserType(UserTypeId::from_string(
"core::option::Option::<core::starknet::secp256k1::Secp256K1EcPoint>",
)),
GenericArg::Type(secp256k1_ec_point_type),
GenericArg::Type(unit_type),
],
)?;
Ok(vec![option_secp256k1_ec_point_type])
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@
"rename",
"replace_class_syscall",
"revoke_ap_tracking",
"secp256k1_ec_add_syscall",
"secp256k1_ec_get_point_from_x_syscall",
"secp256k1_ec_mul_syscall",
"send_message_to_l1_syscall",
"snapshot_take",
"storage_address_from_base",
Expand Down
1 change: 1 addition & 0 deletions tests/e2e_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ cairo_lang_test_utils::test_file_test_with_runner!(
{
class_hash: "class_hash",
contract_address: "contract_address",
secp256k1: "secp256k1",
storage_address: "storage_address",
syscalls: "syscalls",
},
Expand Down
Loading

0 comments on commit 61adf84

Please sign in to comment.