Add ecrecover syscall (#17720)
Co-authored-by: Anton Lisanin <lisanin.anton@gmail.com>
This commit is contained in:
parent
92c5cdab62
commit
1f288ce527
|
@ -4344,6 +4344,7 @@ version = "1.8.0"
|
|||
dependencies = [
|
||||
"bincode",
|
||||
"byteorder",
|
||||
"libsecp256k1",
|
||||
"log 0.4.14",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
|
@ -5258,6 +5259,7 @@ dependencies = [
|
|||
"hex",
|
||||
"itertools 0.10.1",
|
||||
"lazy_static",
|
||||
"libsecp256k1",
|
||||
"log 0.4.14",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
|
|
|
@ -2752,6 +2752,7 @@ version = "1.8.0"
|
|||
dependencies = [
|
||||
"bincode",
|
||||
"byteorder 1.4.3",
|
||||
"libsecp256k1",
|
||||
"log",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
|
@ -3018,6 +3019,13 @@ dependencies = [
|
|||
"solana-program 1.8.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-bpf-rust-secp256k1-recover"
|
||||
version = "1.8.0"
|
||||
dependencies = [
|
||||
"solana-program 1.8.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solana-bpf-rust-sha"
|
||||
version = "1.8.0"
|
||||
|
@ -3370,6 +3378,7 @@ dependencies = [
|
|||
"hex",
|
||||
"itertools 0.10.1",
|
||||
"lazy_static",
|
||||
"libsecp256k1",
|
||||
"log",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
|
|
|
@ -73,6 +73,7 @@ members = [
|
|||
"rust/ro_modify",
|
||||
"rust/ro_account_modify",
|
||||
"rust/sanity",
|
||||
"rust/secp256k1_recover",
|
||||
"rust/sha",
|
||||
"rust/spoof1",
|
||||
"rust/spoof1_system",
|
||||
|
|
|
@ -86,6 +86,7 @@ fn main() {
|
|||
"ro_modify",
|
||||
"ro_account_modify",
|
||||
"sanity",
|
||||
"secp256k1_recover",
|
||||
"sha",
|
||||
"spoof1",
|
||||
"spoof1_system",
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* @brief Secp256k1Recover Syscall test
|
||||
*/
|
||||
#include <solana_sdk.h>
|
||||
|
||||
extern uint64_t entrypoint(const uint8_t *input) {
|
||||
|
||||
uint8_t result[SECP256K1_RECOVER_RESULT_LENGTH];
|
||||
uint8_t expected[] = { 0x42, 0xcd, 0x27, 0xe4, 0x0f, 0xdf, 0x7c, 0x97,
|
||||
0x0a, 0xa2, 0xca, 0x0b, 0x88, 0x5b, 0x96, 0x0f,
|
||||
0x8b, 0x62, 0x8a, 0x41, 0xa1, 0x81, 0xe7, 0xe6,
|
||||
0x8e, 0x03, 0xea, 0x0b, 0x84, 0x20, 0x58, 0x9b,
|
||||
0x32, 0x06, 0xbd, 0x66, 0x2f, 0x75, 0x65, 0xd6,
|
||||
0x9d, 0xbd, 0x1d, 0x34, 0x29, 0x6a, 0xd9, 0x35,
|
||||
0x38, 0xed, 0x86, 0x9e, 0x99, 0x20, 0x43, 0xc3,
|
||||
0xeb, 0xad, 0x65, 0x50, 0xa0, 0x11, 0x6e, 0x5d};
|
||||
|
||||
uint8_t hash[] = { 0xde, 0xa5, 0x66, 0xb6, 0x94, 0x3b, 0xe0, 0xe9,
|
||||
0x62, 0x53, 0xc2, 0x21, 0x5b, 0x1b, 0xac, 0x69,
|
||||
0xe7, 0xa8, 0x1e, 0xdb, 0x41, 0xc5, 0x02, 0x8b,
|
||||
0x4f, 0x5c, 0x45, 0xc5, 0x3b, 0x49, 0x54, 0xd0};
|
||||
uint8_t signature[] = { 0x97, 0xa4, 0xee, 0x31, 0xfe, 0x82, 0x65, 0x72,
|
||||
0x9f, 0x4a, 0xa6, 0x7d, 0x24, 0xd4, 0xa7, 0x27,
|
||||
0xf8, 0xc3, 0x15, 0xa4, 0xc8, 0xf9, 0x80, 0xeb,
|
||||
0x4c, 0x4d, 0x4a, 0xfa, 0x6e, 0xc9, 0x42, 0x41,
|
||||
0x5d, 0x10, 0xd9, 0xc2, 0x8a, 0x90, 0xe9, 0x92,
|
||||
0x9c, 0x52, 0x4b, 0x2c, 0xfb, 0x65, 0xdf, 0xbc,
|
||||
0xf6, 0x8c, 0xfd, 0x68, 0xdb, 0x17, 0xf9, 0x5d,
|
||||
0x23, 0x5f, 0x96, 0xd8, 0xf0, 0x72, 0x01, 0x2d};
|
||||
uint64_t recovery_id = 1;
|
||||
|
||||
uint64_t result_code = sol_secp256k1_recover(hash, recovery_id, signature, result);
|
||||
|
||||
sol_assert(0 == result_code);
|
||||
sol_assert(0 == sol_memcmp(result, expected, SHA256_RESULT_LENGTH));
|
||||
|
||||
return SUCCESS;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "solana-bpf-rust-secp256k1-recover"
|
||||
version = "1.8.0"
|
||||
description = "Solana BPF test program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.foundation>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
documentation = "https://docs.rs/solana-bpf-rust-secp256k1-recover"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "=1.8.0" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
|
@ -0,0 +1,44 @@
|
|||
//! @brief Secp256k1Recover Syscall test
|
||||
|
||||
extern crate solana_program;
|
||||
use solana_program::{custom_panic_default, msg};
|
||||
|
||||
fn test_secp256k1_recover() {
|
||||
use solana_program::secp256k1_recover::secp256k1_recover;
|
||||
|
||||
let expected: [u8; 64] = [
|
||||
0x42, 0xcd, 0x27, 0xe4, 0x0f, 0xdf, 0x7c, 0x97, 0x0a, 0xa2, 0xca, 0x0b, 0x88, 0x5b, 0x96,
|
||||
0x0f, 0x8b, 0x62, 0x8a, 0x41, 0xa1, 0x81, 0xe7, 0xe6, 0x8e, 0x03, 0xea, 0x0b, 0x84, 0x20,
|
||||
0x58, 0x9b, 0x32, 0x06, 0xbd, 0x66, 0x2f, 0x75, 0x65, 0xd6, 0x9d, 0xbd, 0x1d, 0x34, 0x29,
|
||||
0x6a, 0xd9, 0x35, 0x38, 0xed, 0x86, 0x9e, 0x99, 0x20, 0x43, 0xc3, 0xeb, 0xad, 0x65, 0x50,
|
||||
0xa0, 0x11, 0x6e, 0x5d,
|
||||
];
|
||||
|
||||
let hash: [u8; 32] = [
|
||||
0xde, 0xa5, 0x66, 0xb6, 0x94, 0x3b, 0xe0, 0xe9, 0x62, 0x53, 0xc2, 0x21, 0x5b, 0x1b, 0xac,
|
||||
0x69, 0xe7, 0xa8, 0x1e, 0xdb, 0x41, 0xc5, 0x02, 0x8b, 0x4f, 0x5c, 0x45, 0xc5, 0x3b, 0x49,
|
||||
0x54, 0xd0,
|
||||
];
|
||||
let recovery_id: u8 = 1;
|
||||
let signature: [u8; 64] = [
|
||||
0x97, 0xa4, 0xee, 0x31, 0xfe, 0x82, 0x65, 0x72, 0x9f, 0x4a, 0xa6, 0x7d, 0x24, 0xd4, 0xa7,
|
||||
0x27, 0xf8, 0xc3, 0x15, 0xa4, 0xc8, 0xf9, 0x80, 0xeb, 0x4c, 0x4d, 0x4a, 0xfa, 0x6e, 0xc9,
|
||||
0x42, 0x41, 0x5d, 0x10, 0xd9, 0xc2, 0x8a, 0x90, 0xe9, 0x92, 0x9c, 0x52, 0x4b, 0x2c, 0xfb,
|
||||
0x65, 0xdf, 0xbc, 0xf6, 0x8c, 0xfd, 0x68, 0xdb, 0x17, 0xf9, 0x5d, 0x23, 0x5f, 0x96, 0xd8,
|
||||
0xf0, 0x72, 0x01, 0x2d,
|
||||
];
|
||||
|
||||
let public_key = secp256k1_recover(&hash[..], recovery_id, &signature[..]).unwrap();
|
||||
assert_eq!(public_key.to_bytes(), expected);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn entrypoint(_input: *mut u8) -> u64 {
|
||||
msg!("secp256k1_recover");
|
||||
|
||||
test_secp256k1_recover();
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
custom_panic_default!();
|
|
@ -432,6 +432,7 @@ fn test_program_bpf_sanity() {
|
|||
("relative_call", true),
|
||||
("sanity", true),
|
||||
("sanity++", true),
|
||||
("secp256k1_recover", true),
|
||||
("sha", true),
|
||||
("struct_pass", true),
|
||||
("struct_ret", true),
|
||||
|
@ -453,6 +454,7 @@ fn test_program_bpf_sanity() {
|
|||
("solana_bpf_rust_param_passing", true),
|
||||
("solana_bpf_rust_rand", true),
|
||||
("solana_bpf_rust_sanity", true),
|
||||
("solana_bpf_rust_secp256k1_recover", true),
|
||||
("solana_bpf_rust_sha", true),
|
||||
]);
|
||||
}
|
||||
|
@ -1283,6 +1285,7 @@ fn assert_instruction_count() {
|
|||
("relative_call", 10),
|
||||
("sanity", 169),
|
||||
("sanity++", 168),
|
||||
("secp256k1_recover", 357),
|
||||
("sha", 1040),
|
||||
("struct_pass", 8),
|
||||
("struct_ret", 22),
|
||||
|
@ -1303,8 +1306,9 @@ fn assert_instruction_count() {
|
|||
("solana_bpf_rust_noop", 478),
|
||||
("solana_bpf_rust_param_passing", 46),
|
||||
("solana_bpf_rust_rand", 481),
|
||||
("solana_bpf_rust_sanity", 873),
|
||||
("solana_bpf_rust_sha", 32301),
|
||||
("solana_bpf_rust_sanity", 900),
|
||||
("solana_bpf_rust_secp256k1_recover", 301),
|
||||
("solana_bpf_rust_sha", 32333),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ log = "0.4.14"
|
|||
num-derive = "0.3"
|
||||
num-traits = "0.2"
|
||||
rand_core = "0.6.3"
|
||||
libsecp256k1 = "0.5.0"
|
||||
sha3 = "0.9.1"
|
||||
solana-measure = { path = "../../measure", version = "=1.8.0" }
|
||||
solana-runtime = { path = "../../runtime", version = "=1.8.0" }
|
||||
|
|
|
@ -20,7 +20,8 @@ use solana_sdk::{
|
|||
epoch_schedule::EpochSchedule,
|
||||
feature_set::{
|
||||
blake3_syscall_enabled, cpi_data_cost, enforce_aligned_host_addrs,
|
||||
keccak256_syscall_enabled, memory_ops_syscalls, sysvar_via_syscall, update_data_on_realloc,
|
||||
keccak256_syscall_enabled, memory_ops_syscalls, secp256k1_recover_syscall_enabled,
|
||||
sysvar_via_syscall, update_data_on_realloc,
|
||||
},
|
||||
hash::{Hasher, HASH_BYTES},
|
||||
ic_msg,
|
||||
|
@ -31,6 +32,9 @@ use solana_sdk::{
|
|||
process_instruction::{self, stable_log, ComputeMeter, InvokeContext, Logger},
|
||||
pubkey::{Pubkey, PubkeyError, MAX_SEEDS},
|
||||
rent::Rent,
|
||||
secp256k1_recover::{
|
||||
Secp256k1RecoverError, SECP256K1_PUBLIC_KEY_LENGTH, SECP256K1_SIGNATURE_LENGTH,
|
||||
},
|
||||
sysvar::{self, fees::Fees, Sysvar, SysvarId},
|
||||
};
|
||||
use std::{
|
||||
|
@ -133,6 +137,11 @@ pub fn register_syscalls(
|
|||
syscall_registry.register_syscall_by_name(b"sol_keccak256", SyscallKeccak256::call)?;
|
||||
}
|
||||
|
||||
if invoke_context.is_feature_active(&secp256k1_recover_syscall_enabled::id()) {
|
||||
syscall_registry
|
||||
.register_syscall_by_name(b"sol_secp256k1_recover", SyscallSecp256k1Recover::call)?;
|
||||
}
|
||||
|
||||
if invoke_context.is_feature_active(&blake3_syscall_enabled::id()) {
|
||||
syscall_registry.register_syscall_by_name(b"sol_blake3", SyscallBlake3::call)?;
|
||||
}
|
||||
|
@ -330,6 +339,16 @@ pub fn bind_syscall_context_objects<'a>(
|
|||
}),
|
||||
);
|
||||
|
||||
bind_feature_gated_syscall_context_object!(
|
||||
vm,
|
||||
invoke_context.is_feature_active(&secp256k1_recover_syscall_enabled::id()),
|
||||
Box::new(SyscallSecp256k1Recover {
|
||||
cost: bpf_compute_budget.secp256k1_recover_cost,
|
||||
compute_meter: invoke_context.get_compute_meter(),
|
||||
loader_id,
|
||||
}),
|
||||
);
|
||||
|
||||
let is_sysvar_via_syscall_active = invoke_context.is_feature_active(&sysvar_via_syscall::id());
|
||||
|
||||
let invoke_context = Rc::new(RefCell::new(invoke_context));
|
||||
|
@ -1342,6 +1361,92 @@ impl<'a> SyscallObject<BpfError> for SyscallMemset<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// secp256k1_recover
|
||||
pub struct SyscallSecp256k1Recover<'a> {
|
||||
cost: u64,
|
||||
compute_meter: Rc<RefCell<dyn ComputeMeter>>,
|
||||
loader_id: &'a Pubkey,
|
||||
}
|
||||
|
||||
impl<'a> SyscallObject<BpfError> for SyscallSecp256k1Recover<'a> {
|
||||
fn call(
|
||||
&mut self,
|
||||
hash_addr: u64,
|
||||
recovery_id_val: u64,
|
||||
signature_addr: u64,
|
||||
result_addr: u64,
|
||||
_arg5: u64,
|
||||
memory_mapping: &MemoryMapping,
|
||||
result: &mut Result<u64, EbpfError<BpfError>>,
|
||||
) {
|
||||
question_mark!(self.compute_meter.consume(self.cost), result);
|
||||
|
||||
let hash = question_mark!(
|
||||
translate_slice::<u8>(
|
||||
memory_mapping,
|
||||
hash_addr,
|
||||
keccak::HASH_BYTES as u64,
|
||||
self.loader_id,
|
||||
true,
|
||||
),
|
||||
result
|
||||
);
|
||||
let signature = question_mark!(
|
||||
translate_slice::<u8>(
|
||||
memory_mapping,
|
||||
signature_addr,
|
||||
SECP256K1_SIGNATURE_LENGTH as u64,
|
||||
self.loader_id,
|
||||
true,
|
||||
),
|
||||
result
|
||||
);
|
||||
let secp256k1_recover_result = question_mark!(
|
||||
translate_slice_mut::<u8>(
|
||||
memory_mapping,
|
||||
result_addr,
|
||||
SECP256K1_PUBLIC_KEY_LENGTH as u64,
|
||||
self.loader_id,
|
||||
true,
|
||||
),
|
||||
result
|
||||
);
|
||||
|
||||
let message = match libsecp256k1::Message::parse_slice(hash) {
|
||||
Ok(msg) => msg,
|
||||
Err(_) => {
|
||||
*result = Ok(Secp256k1RecoverError::InvalidHash.into());
|
||||
return;
|
||||
}
|
||||
};
|
||||
let recovery_id = match libsecp256k1::RecoveryId::parse(recovery_id_val as u8) {
|
||||
Ok(id) => id,
|
||||
Err(_) => {
|
||||
*result = Ok(Secp256k1RecoverError::InvalidRecoveryId.into());
|
||||
return;
|
||||
}
|
||||
};
|
||||
let signature = match libsecp256k1::Signature::parse_standard_slice(signature) {
|
||||
Ok(sig) => sig,
|
||||
Err(_) => {
|
||||
*result = Ok(Secp256k1RecoverError::InvalidSignature.into());
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let public_key = match libsecp256k1::recover(&message, &signature, &recovery_id) {
|
||||
Ok(key) => key.serialize(),
|
||||
Err(_) => {
|
||||
*result = Ok(Secp256k1RecoverError::InvalidSignature.into());
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
secp256k1_recover_result.copy_from_slice(&public_key[1..65]);
|
||||
*result = Ok(SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
// Blake3
|
||||
pub struct SyscallBlake3<'a> {
|
||||
base_cost: u64,
|
||||
|
|
|
@ -457,6 +457,37 @@ uint64_t sol_keccak256(
|
|||
uint8_t *result
|
||||
);
|
||||
|
||||
|
||||
/** Length of a secp256k1 recover input hash */
|
||||
#define SECP256K1_RECOVER_HASH_LENGTH 32
|
||||
/** Length of a secp256k1 input signature */
|
||||
#define SECP256K1_RECOVER_SIGNATURE_LENGTH 64
|
||||
/** Length of a secp256k1 recover result */
|
||||
#define SECP256K1_RECOVER_RESULT_LENGTH 64
|
||||
|
||||
/** The hash provided to a sol_secp256k1_recover is invalid */
|
||||
#define SECP256K1_RECOVER_ERROR_INVALID_HASH 1
|
||||
/** The recovery_id provided to a sol_secp256k1_recover is invalid */
|
||||
#define SECP256K1_RECOVER_ERROR_INVALID_RECOVERY_ID 2
|
||||
/** The signature provided to a sol_secp256k1_recover is invalid */
|
||||
#define SECP256K1_RECOVER_ERROR_INVALID_SIGNATURE 3
|
||||
|
||||
/**
|
||||
* Recover public key from a signed message.
|
||||
*
|
||||
* @param hash Hashed message
|
||||
* @param recovery_id Tag used for public key recovery from signatures. Can be 0 or 1
|
||||
* @param signature An ECDSA signature
|
||||
* @param result 64 byte array to hold the result. A recovered public key
|
||||
* @return 0 if executed successfully
|
||||
*/
|
||||
uint64_t sol_secp256k1_recover(
|
||||
const uint8_t *hash,
|
||||
uint64_t recovery_id,
|
||||
const uint8_t *signature,
|
||||
uint8_t *result
|
||||
);
|
||||
|
||||
/**
|
||||
* Length of a Blake3 hash result
|
||||
*/
|
||||
|
|
|
@ -36,6 +36,7 @@ thiserror = "1.0"
|
|||
|
||||
[target.'cfg(not(target_arch = "bpf"))'.dependencies]
|
||||
curve25519-dalek = "3.0.0"
|
||||
libsecp256k1 = "0.5.0"
|
||||
rand = "0.7.0"
|
||||
solana-logger = { path = "../../logger", version = "=1.8.0" }
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ pub mod pubkey;
|
|||
pub mod rent;
|
||||
pub mod sanitize;
|
||||
pub mod secp256k1_program;
|
||||
pub mod secp256k1_recover;
|
||||
pub mod serialize_utils;
|
||||
pub mod short_vec;
|
||||
pub mod slot_hashes;
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
|
||||
use core::convert::TryFrom;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Error)]
|
||||
pub enum Secp256k1RecoverError {
|
||||
#[error("The hash provided to a secp256k1_recover is invalid")]
|
||||
InvalidHash,
|
||||
#[error("The recovery_id provided to a secp256k1_recover is invalid")]
|
||||
InvalidRecoveryId,
|
||||
#[error("The signature provided to a secp256k1_recover is invalid")]
|
||||
InvalidSignature,
|
||||
}
|
||||
|
||||
impl From<u64> for Secp256k1RecoverError {
|
||||
fn from(v: u64) -> Secp256k1RecoverError {
|
||||
match v {
|
||||
1 => Secp256k1RecoverError::InvalidHash,
|
||||
2 => Secp256k1RecoverError::InvalidRecoveryId,
|
||||
3 => Secp256k1RecoverError::InvalidSignature,
|
||||
_ => panic!("Unsupported Secp256k1RecoverError"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Secp256k1RecoverError> for u64 {
|
||||
fn from(v: Secp256k1RecoverError) -> u64 {
|
||||
match v {
|
||||
Secp256k1RecoverError::InvalidHash => 1,
|
||||
Secp256k1RecoverError::InvalidRecoveryId => 2,
|
||||
Secp256k1RecoverError::InvalidSignature => 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const SECP256K1_SIGNATURE_LENGTH: usize = 64;
|
||||
pub const SECP256K1_PUBLIC_KEY_LENGTH: usize = 64;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(
|
||||
BorshSerialize,
|
||||
BorshDeserialize,
|
||||
BorshSchema,
|
||||
Clone,
|
||||
Copy,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Hash,
|
||||
AbiExample,
|
||||
)]
|
||||
pub struct Secp256k1Pubkey(pub [u8; SECP256K1_PUBLIC_KEY_LENGTH]);
|
||||
|
||||
impl Secp256k1Pubkey {
|
||||
pub fn new(pubkey_vec: &[u8]) -> Self {
|
||||
Self(
|
||||
<[u8; SECP256K1_PUBLIC_KEY_LENGTH]>::try_from(<&[u8]>::clone(&pubkey_vec))
|
||||
.expect("Slice must be the same length as a Pubkey"),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn to_bytes(self) -> [u8; 64] {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn secp256k1_recover(
|
||||
hash: &[u8],
|
||||
recovery_id: u8,
|
||||
signature: &[u8],
|
||||
) -> Result<Secp256k1Pubkey, Secp256k1RecoverError> {
|
||||
#[cfg(target_arch = "bpf")]
|
||||
{
|
||||
extern "C" {
|
||||
fn sol_secp256k1_recover(
|
||||
hash: *const u8,
|
||||
recovery_id: u64,
|
||||
signature: *const u8,
|
||||
result: *mut u8,
|
||||
) -> u64;
|
||||
}
|
||||
|
||||
let mut pubkey_buffer = [0u8; SECP256K1_PUBLIC_KEY_LENGTH];
|
||||
let result = unsafe {
|
||||
sol_secp256k1_recover(
|
||||
hash.as_ptr(),
|
||||
recovery_id as u64,
|
||||
signature.as_ptr(),
|
||||
pubkey_buffer.as_mut_ptr(),
|
||||
)
|
||||
};
|
||||
|
||||
match result {
|
||||
0 => Ok(Secp256k1Pubkey::new(&pubkey_buffer)),
|
||||
error => Err(Secp256k1RecoverError::from(error)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "bpf"))]
|
||||
{
|
||||
let message = libsecp256k1::Message::parse_slice(hash)
|
||||
.map_err(|_| Secp256k1RecoverError::InvalidHash)?;
|
||||
let recovery_id = libsecp256k1::RecoveryId::parse(recovery_id)
|
||||
.map_err(|_| Secp256k1RecoverError::InvalidRecoveryId)?;
|
||||
let signature = libsecp256k1::Signature::parse_standard_slice(signature)
|
||||
.map_err(|_| Secp256k1RecoverError::InvalidSignature)?;
|
||||
|
||||
let secp256k1_key = libsecp256k1::recover(&message, &signature, &recovery_id)
|
||||
.map_err(|_| Secp256k1RecoverError::InvalidSignature)?;
|
||||
Ok(Secp256k1Pubkey::new(&secp256k1_key.serialize()[1..65]))
|
||||
}
|
||||
}
|
|
@ -127,6 +127,10 @@ pub mod memory_ops_syscalls {
|
|||
solana_sdk::declare_id!("ENQi37wsVhTvFz2gUiZAAbqFEWGN2jwFsqdEDTE8A4MU");
|
||||
}
|
||||
|
||||
pub mod secp256k1_recover_syscall_enabled {
|
||||
solana_sdk::declare_id!("6RvdSWHh8oh72Dp7wMTS2DBkf3fRPtChfNrAo3cZZoXJ");
|
||||
}
|
||||
|
||||
pub mod add_missing_program_error_mappings {
|
||||
solana_sdk::declare_id!("3QEUpjhgPEt92nz3Mqf6pABkHPGCQwSvKtyGMq4SuQyL");
|
||||
}
|
||||
|
@ -187,6 +191,7 @@ lazy_static! {
|
|||
(keccak256_syscall_enabled::id(), "keccak256 syscall"),
|
||||
(stake_program_v4::id(), "solana_stake_program v4"),
|
||||
(memory_ops_syscalls::id(), "add syscalls for memory operations"),
|
||||
(secp256k1_recover_syscall_enabled::id(), "secp256k1_recover syscall"),
|
||||
(add_missing_program_error_mappings::id(), "add missing program error mappings"),
|
||||
(system_transfer_zero_check::id(), "perform all checks for transfers of 0 lamports"),
|
||||
(blake3_syscall_enabled::id(), "blake3 syscall"),
|
||||
|
|
|
@ -179,6 +179,8 @@ pub struct BpfComputeBudget {
|
|||
pub cpi_bytes_per_unit: u64,
|
||||
/// Base number of compute units consumed to get a sysvar
|
||||
pub sysvar_base_cost: u64,
|
||||
/// Number of compute units consumed to call secp256k1_recover
|
||||
pub secp256k1_recover_cost: u64,
|
||||
}
|
||||
impl Default for BpfComputeBudget {
|
||||
fn default() -> Self {
|
||||
|
@ -202,6 +204,7 @@ impl BpfComputeBudget {
|
|||
max_cpi_instruction_size: 1280, // IPv6 Min MTU size
|
||||
cpi_bytes_per_unit: 250, // ~50MB at 200,000 units
|
||||
sysvar_base_cost: 100,
|
||||
secp256k1_recover_cost: 25_000,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue