Skip to content

Commit

Permalink
feat: New alt_bn128 precompiles for Solana
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrey Trepalin committed May 22, 2022
1 parent 3c651eb commit ee55495
Show file tree
Hide file tree
Showing 11 changed files with 1,150 additions and 5 deletions.
10 changes: 10 additions & 0 deletions program-runtime/src/compute_budget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ pub struct ComputeBudget {
pub heap_cost: u64,
/// Memory operation syscall base cost
pub mem_op_base_cost: u64,
/// Number of compute units consumed to call alt_bn128_addition
pub alt_bn128_addition_cost: u64,
/// Number of compute units consumed to call alt_bn128_multiplication.
pub alt_bn128_multiplication_cost: u64,
/// Number of compute units consumed to pairing one pair of input elements.
/// Total cost will be one_pair_cost * (num_elems - 1)
pub alt_bn128_pairing_one_pair_cost: u64,
}

impl Default for ComputeBudget {
Expand Down Expand Up @@ -92,6 +99,9 @@ impl ComputeBudget {
heap_size: None,
heap_cost: 8,
mem_op_base_cost: 10,
alt_bn128_addition_cost: 120,
alt_bn128_multiplication_cost: 200,
alt_bn128_pairing_one_pair_cost: 110,
}
}

Expand Down
1 change: 1 addition & 0 deletions programs/bpf/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ members = [
"rust/128bit",
"rust/128bit_dep",
"rust/alloc",
"rust/alt_bn128",
"rust/call_depth",
"rust/caller_access",
"rust/custom_heap",
Expand Down
1 change: 1 addition & 0 deletions programs/bpf/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ fn main() {
let rust_programs = [
"128bit",
"alloc",
"alt_bn128",
"call_depth",
"caller_access",
"custom_heap",
Expand Down
1 change: 1 addition & 0 deletions programs/bpf_loader/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ edition = "2021"

[dependencies]
bincode = "1.3.3"
bn-plus = "=0.4"
byteorder = "1.4.3"
log = "0.4.14"
libsecp256k1 = "0.6.0"
Expand Down
248 changes: 243 additions & 5 deletions programs/bpf_loader/src/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,16 @@ use {
solana_sdk::{
account::{AccountSharedData, ReadableAccount, WritableAccount},
account_info::AccountInfo,
alt_bn128::prelude::*,
blake3, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable,
entrypoint::{BPF_ALIGN_OF_U128, MAX_PERMITTED_DATA_INCREASE, SUCCESS},
feature_set::{
add_get_processed_sibling_instruction_syscall, blake3_syscall_enabled,
disable_fees_sysvar, do_support_realloc, fixed_memcpy_nonoverlapping_check,
libsecp256k1_0_5_upgrade_enabled, prevent_calling_precompiles_as_programs,
return_data_syscall_enabled, secp256k1_recover_syscall_enabled,
sol_log_data_syscall_enabled, update_syscall_base_costs,
add_get_processed_sibling_instruction_syscall, alt_bn128_syscall_enabled,
blake3_syscall_enabled, disable_fees_sysvar, do_support_realloc,
fixed_memcpy_nonoverlapping_check, libsecp256k1_0_5_upgrade_enabled,
prevent_calling_precompiles_as_programs, return_data_syscall_enabled,
secp256k1_recover_syscall_enabled, sol_log_data_syscall_enabled,
update_syscall_base_costs,
},
hash::{Hasher, HASH_BYTES},
instruction::{
Expand Down Expand Up @@ -192,6 +194,16 @@ pub fn register_syscalls(
// Memory allocator
syscall_registry.register_syscall_by_name(b"sol_alloc_free_", SyscallAllocFree::call)?;

// alt_bn128
if invoke_context.feature_set.is_active(&alt_bn128_syscall_enabled::id()) {
syscall_registry
.register_syscall_by_name(b"sol_alt_bn128_addition", SyscallAltBn128Addition::call)?;
syscall_registry
.register_syscall_by_name(b"sol_alt_bn128_multiplication", SyscallAltBn128Multiplication::call)?;
syscall_registry
.register_syscall_by_name(b"sol_alt_bn128_pairing", SyscallAltBn128Pairing::call)?;
}

// Return data
if invoke_context
.feature_set
Expand Down Expand Up @@ -257,6 +269,9 @@ pub fn bind_syscall_context_objects<'a, 'b>(
let is_secp256k1_recover_syscall_active = invoke_context
.feature_set
.is_active(&secp256k1_recover_syscall_enabled::id());
let is_alt_bn128_syscall_active = invoke_context
.feature_set
.is_active(&alt_bn128_syscall_enabled::id());
let is_fee_sysvar_via_syscall_active = !invoke_context
.feature_set
.is_active(&disable_fees_sysvar::id());
Expand Down Expand Up @@ -376,6 +391,33 @@ pub fn bind_syscall_context_objects<'a, 'b>(
}),
);

// alt_bn128 addition
bind_feature_gated_syscall_context_object!(
vm,
is_alt_bn128_syscall_active,
Box::new(SyscallAltBn128Addition {
invoke_context: invoke_context.clone(),
}),
);

// alt_bn128 multiplication
bind_feature_gated_syscall_context_object!(
vm,
is_alt_bn128_syscall_active,
Box::new(SyscallAltBn128Multiplication {
invoke_context: invoke_context.clone(),
}),
);

// alt_bn128 pairing
bind_feature_gated_syscall_context_object!(
vm,
is_alt_bn128_syscall_active,
Box::new(SyscallAltBn128Pairing {
invoke_context: invoke_context.clone(),
}),
);

vm.bind_syscall_context_object(
Box::new(SyscallGetClockSysvar {
invoke_context: invoke_context.clone(),
Expand Down Expand Up @@ -1812,6 +1854,202 @@ impl<'a, 'b> SyscallObject<BpfError> for SyscallBlake3<'a, 'b> {
}
}

/// alt_bn128 addition
pub struct SyscallAltBn128Addition<'a, 'b> {
invoke_context: Rc<RefCell<&'a mut InvokeContext<'b>>>,
}

impl<'a, 'b> SyscallObject<BpfError> for SyscallAltBn128Addition<'a, 'b> {
fn call(
&mut self,
input_addr: u64,
input_size: u64,
result_addr: u64,
_arg4: u64,
_arg5: u64,
memory_mapping: &MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>,
) {
let invoke_context = question_mark!(
self.invoke_context
.try_borrow()
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
result
);
let cost = invoke_context.get_compute_budget().alt_bn128_addition_cost;
question_mark!(invoke_context.get_compute_meter().consume(cost), result);

let loader_id = question_mark!(
invoke_context
.get_loader()
.map_err(SyscallError::InstructionError),
result
);
let input = question_mark!(
translate_slice::<u8>(memory_mapping, input_addr, input_size, &loader_id),
result
);
let call_result = question_mark!(
translate_slice_mut::<u8>(
memory_mapping,
result_addr,
ALT_BN128_ADDITION_OUTPUT_LEN as u64,
&loader_id,
),
result
);

let result_point = match alt_bn128_addition(input) {
Ok(result_point) => result_point,
Err(e) => {
*result = Ok(e.into());
return;
}
};

if result_point.len() != ALT_BN128_ADDITION_OUTPUT_LEN {
*result = Ok(AltBn128Error::SliceOutOfBounds.into());
return;
}

call_result.copy_from_slice(&result_point);
*result = Ok(SUCCESS);
}
}

/// alt_bn128 scalar multiplication
pub struct SyscallAltBn128Multiplication<'a, 'b> {
invoke_context: Rc<RefCell<&'a mut InvokeContext<'b>>>,
}

impl<'a, 'b> SyscallObject<BpfError> for SyscallAltBn128Multiplication<'a, 'b> {
fn call(
&mut self,
input_addr: u64,
input_size: u64,
result_addr: u64,
_arg4: u64,
_arg5: u64,
memory_mapping: &MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>,
) {
let invoke_context = question_mark!(
self.invoke_context
.try_borrow()
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
result
);
let cost = invoke_context.get_compute_budget().alt_bn128_multiplication_cost;
question_mark!(invoke_context.get_compute_meter().consume(cost), result);

let loader_id = question_mark!(
invoke_context
.get_loader()
.map_err(SyscallError::InstructionError),
result
);
let input = question_mark!(
translate_slice::<u8>(memory_mapping, input_addr, input_size, &loader_id),
result
);
let call_result = question_mark!(
translate_slice_mut::<u8>(
memory_mapping,
result_addr,
ALT_BN128_MULTIPLICATION_OUTPUT_LEN as u64,
&loader_id,
),
result
);

let result_point = match alt_bn128_multiplication(input) {
Ok(result_point) => result_point,
Err(e) => {
*result = Ok(e.into());
return;
}
};

if result_point.len() != ALT_BN128_MULTIPLICATION_OUTPUT_LEN {
*result = Ok(AltBn128Error::SliceOutOfBounds.into());
return;
}

call_result.copy_from_slice(&result_point);
*result = Ok(SUCCESS);
}
}

/// alt_bn128 pairing equation
#[allow(dead_code)]
pub struct SyscallAltBn128Pairing<'a, 'b> {
invoke_context: Rc<RefCell<&'a mut InvokeContext<'b>>>,
}

impl<'a, 'b> SyscallObject<BpfError> for SyscallAltBn128Pairing<'a, 'b> {
fn call(
&mut self,
input_addr: u64,
input_size: u64,
result_addr: u64,
_arg4: u64,
_arg5: u64,
memory_mapping: &MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>,
) {
let invoke_context = question_mark!(
self.invoke_context
.try_borrow()
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
result
);
let ele_len = input_size / ALT_BN128_PAIRING_ELEMENT_LEN as u64;
let cost = invoke_context.get_compute_budget().mem_op_base_cost.max(
invoke_context
.get_compute_budget()
.alt_bn128_pairing_one_pair_cost
.saturating_mul(ele_len - 1),
);
question_mark!(invoke_context.get_compute_meter().consume(cost), result);

let loader_id = question_mark!(
invoke_context
.get_loader()
.map_err(SyscallError::InstructionError),
result
);
let input = question_mark!(
translate_slice::<u8>(memory_mapping, input_addr, input_size, &loader_id),
result
);
let call_result = question_mark!(
translate_slice_mut::<u8>(
memory_mapping,
result_addr,
ALT_BN128_PAIRING_OUTPUT_LEN as u64,
&loader_id,
),
result
);

let result_point = match alt_bn128_pairing(input) {
Ok(result_point) => result_point,
Err(e) => {
*result = Ok(e.into());
return;
}
};

if result_point.len() != ALT_BN128_PAIRING_OUTPUT_LEN {
*result = Ok(AltBn128Error::SliceOutOfBounds.into());
return;
}

call_result.copy_from_slice(&result_point);
*result = Ok(SUCCESS);
}
}

// Cross-program invocation syscalls

struct CallerAccount<'a> {
Expand Down
58 changes: 58 additions & 0 deletions sdk/bpf/c/inc/sol/alt_bn128.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#pragma once
/**
* @brief Solana alt_bn128 system calls
*/

#include <sol/types.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* Addition on elliptic curves alt_bn128
*
* @param input ...
* @param input_size ...
* @param result 64 byte array to hold the result. ...
* @return 0 if executed successfully
*/
uint64_t sol_alt_bn128_addition(
const uint8_t *input,
const unit64_t input_size,
uint8_t *result
);

/**
* Multiplication on elliptic curves alt_bn128
*
* @param input ...
* @param input_size ...
* @param result 64 byte array to hold the result. ...
* @return 0 if executed successfully
*/
uint64_t sol_alt_bn128_multiplication(
const uint8_t *input,
const unit64_t input_size,
uint8_t *result
);

/**
* Pairing on elliptic curves alt_bn128
*
* @param input ...
* @param input_size ...
* @param result 64 byte array to hold the result. ...
* @return 0 if executed successfully
*/
uint64_t sol_alt_bn128_pairing(
const uint8_t *input,
const unit64_t input_size,
uint8_t *result
);

#ifdef __cplusplus
}
#endif

/**@}*/
Loading

0 comments on commit ee55495

Please sign in to comment.