Add ecrecover syscall (#17720)

Co-authored-by: Anton Lisanin <lisanin.anton@gmail.com>
This commit is contained in:
s-medvedev
2021-07-07 23:15:14 +03:00
committed by GitHub
parent 92c5cdab62
commit 1f288ce527
16 changed files with 381 additions and 3 deletions

View File

@ -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" }

View File

@ -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,