From 973f0965e1e180ccb1c4d1d99aeaeb2f958cda9d Mon Sep 17 00:00:00 2001 From: Jack May Date: Tue, 6 Oct 2020 23:52:13 -0700 Subject: [PATCH] Add ristretto multiply syscall (#12699) --- Cargo.lock | 26 +++++++++--- programs/bpf/Cargo.lock | 29 +++++++++++-- programs/bpf/Cargo.toml | 1 + programs/bpf/build.rs | 1 + programs/bpf/rust/ristretto/Cargo.toml | 28 +++++++++++++ programs/bpf/rust/ristretto/Xargo.toml | 2 + programs/bpf/rust/ristretto/src/lib.rs | 31 ++++++++++++++ programs/bpf/rust/ristretto/src/ristretto.rs | 33 +++++++++++++++ programs/bpf/tests/programs.rs | 6 ++- programs/bpf_loader/Cargo.toml | 1 + programs/bpf_loader/src/syscalls.rs | 44 +++++++++++++++++++- runtime/src/feature_set.rs | 5 +++ 12 files changed, 195 insertions(+), 12 deletions(-) create mode 100644 programs/bpf/rust/ristretto/Cargo.toml create mode 100644 programs/bpf/rust/ristretto/Xargo.toml create mode 100644 programs/bpf/rust/ristretto/src/lib.rs create mode 100644 programs/bpf/rust/ristretto/src/ristretto.rs diff --git a/Cargo.lock b/Cargo.lock index 699c0754b8..69cb166e52 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -723,6 +723,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "curve25519-dalek" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8492de420e9e60bc9a1d66e2dbb91825390b738a388606600663fc529b4b307" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle 2.2.2", + "zeroize", +] + [[package]] name = "derivative" version = "2.1.1" @@ -857,7 +870,7 @@ version = "1.0.0-pre.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21a8a37f4e8b35af971e6db5e3897e7a6344caa3f92f6544f88125a1f5f0035a" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 2.1.0", "ed25519", "rand 0.7.3", "serde", @@ -3497,6 +3510,7 @@ version = "1.4.0" dependencies = [ "bincode", "byteorder", + "curve25519-dalek 3.0.0", "num-derive", "num-traits", "rand 0.7.3", @@ -3742,7 +3756,7 @@ dependencies = [ "backtrace", "bytes 0.4.12", "cc", - "curve25519-dalek", + "curve25519-dalek 2.1.0", "ed25519-dalek", "either", "failure", @@ -3765,7 +3779,7 @@ dependencies = [ "backtrace", "bytes 0.4.12", "cc", - "curve25519-dalek", + "curve25519-dalek 2.1.0", "ed25519-dalek", "either", "failure", @@ -4191,7 +4205,7 @@ name = "solana-perf" version = "1.4.0" dependencies = [ "bincode", - "curve25519-dalek", + "curve25519-dalek 2.1.0", "dlopen", "dlopen_derive", "lazy_static", @@ -4340,7 +4354,7 @@ dependencies = [ "bv", "byteorder", "chrono", - "curve25519-dalek", + "curve25519-dalek 2.1.0", "ed25519-dalek", "generic-array 0.14.3", "hex", @@ -4377,7 +4391,7 @@ dependencies = [ "bv", "byteorder", "chrono", - "curve25519-dalek", + "curve25519-dalek 2.1.0", "digest 0.9.0", "ed25519-dalek", "generic-array 0.14.3", diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index 0bd268f637..a1c6b5ec0a 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -395,6 +395,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "curve25519-dalek" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8492de420e9e60bc9a1d66e2dbb91825390b738a388606600663fc529b4b307" +dependencies = [ + "byteorder 1.3.4", + "digest 0.9.0", + "rand_core", + "subtle 2.2.2", + "zeroize", +] + [[package]] name = "digest" version = "0.8.1" @@ -444,7 +457,7 @@ version = "1.0.0-pre.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21a8a37f4e8b35af971e6db5e3897e7a6344caa3f92f6544f88125a1f5f0035a" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 2.1.0", "ed25519", "rand", "serde", @@ -1738,6 +1751,7 @@ version = "1.4.0" dependencies = [ "bincode", "byteorder 1.3.4", + "curve25519-dalek 3.0.0", "num-derive 0.3.0", "num-traits", "solana-runtime", @@ -1912,6 +1926,15 @@ dependencies = [ "solana-sdk", ] +[[package]] +name = "solana-bpf-rust-ristretto" +version = "1.4.0" +dependencies = [ + "curve25519-dalek 3.0.0", + "getrandom", + "solana-sdk", +] + [[package]] name = "solana-bpf-rust-sanity" version = "1.4.0" @@ -1952,7 +1975,7 @@ dependencies = [ "backtrace", "bytes 0.4.12", "cc", - "curve25519-dalek", + "curve25519-dalek 2.1.0", "ed25519-dalek", "either", "failure", @@ -2064,7 +2087,7 @@ dependencies = [ "bv", "byteorder 1.3.4", "chrono", - "curve25519-dalek", + "curve25519-dalek 2.1.0", "digest 0.9.0", "ed25519-dalek", "generic-array 0.14.3", diff --git a/programs/bpf/Cargo.toml b/programs/bpf/Cargo.toml index e83a7fe35f..3bfa9ffb42 100644 --- a/programs/bpf/Cargo.toml +++ b/programs/bpf/Cargo.toml @@ -54,6 +54,7 @@ members = [ "rust/param_passing", "rust/param_passing_dep", "rust/rand", + "rust/ristretto", "rust/sanity", "rust/sha256", "rust/sysval", diff --git a/programs/bpf/build.rs b/programs/bpf/build.rs index 41d290aaf8..7a324bc19e 100644 --- a/programs/bpf/build.rs +++ b/programs/bpf/build.rs @@ -82,6 +82,7 @@ fn main() { "panic", "param_passing", "rand", + "ristretto", "sanity", "sha256", "sysval", diff --git a/programs/bpf/rust/ristretto/Cargo.toml b/programs/bpf/rust/ristretto/Cargo.toml new file mode 100644 index 0000000000..18fadaf607 --- /dev/null +++ b/programs/bpf/rust/ristretto/Cargo.toml @@ -0,0 +1,28 @@ + +# Note: This crate must be built using do.sh + +[package] +name = "solana-bpf-rust-ristretto" +version = "1.4.0" +description = "Solana BPF test program written in Rust" +authors = ["Solana Maintainers "] +repository = "https://github.com/solana-labs/solana" +license = "Apache-2.0" +homepage = "https://solana.com/" +edition = "2018" + +[dependencies] +curve25519-dalek = "3" +getrandom = { version = "0.1.14", features = ["dummy"] } +solana-sdk = { path = "../../../../sdk/", version = "1.4.0", default-features = false } + +[features] +program = ["solana-sdk/program"] +default = ["program", "solana-sdk/default"] + +[lib] +name = "solana_bpf_rust_ristretto" +crate-type = ["cdylib"] + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] diff --git a/programs/bpf/rust/ristretto/Xargo.toml b/programs/bpf/rust/ristretto/Xargo.toml new file mode 100644 index 0000000000..1744f098ae --- /dev/null +++ b/programs/bpf/rust/ristretto/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] \ No newline at end of file diff --git a/programs/bpf/rust/ristretto/src/lib.rs b/programs/bpf/rust/ristretto/src/lib.rs new file mode 100644 index 0000000000..162f5acb3f --- /dev/null +++ b/programs/bpf/rust/ristretto/src/lib.rs @@ -0,0 +1,31 @@ +//! @brief Example Rust-based BPF program that performs a ristretto multiply + +pub mod ristretto; + +extern crate solana_sdk; +use crate::ristretto::ristretto_mul; +use curve25519_dalek::{constants::RISTRETTO_BASEPOINT_POINT, scalar::Scalar}; +use solana_sdk::{ + account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, info, pubkey::Pubkey, +}; + +entrypoint!(process_instruction); +fn process_instruction( + _program_id: &Pubkey, + _accounts: &[AccountInfo], + _instruction_data: &[u8], +) -> ProgramResult { + info!("Ristretto multiply"); + + let point = RISTRETTO_BASEPOINT_POINT; + let scalar = Scalar::zero(); + let result = ristretto_mul(&point, &scalar)?; + assert_ne!(point, result); + + let point = RISTRETTO_BASEPOINT_POINT; + let scalar = Scalar::one(); + let result = ristretto_mul(&point, &scalar)?; + assert_eq!(point, result); + + Ok(()) +} diff --git a/programs/bpf/rust/ristretto/src/ristretto.rs b/programs/bpf/rust/ristretto/src/ristretto.rs new file mode 100644 index 0000000000..801cf31788 --- /dev/null +++ b/programs/bpf/rust/ristretto/src/ristretto.rs @@ -0,0 +1,33 @@ +use curve25519_dalek::{ristretto::RistrettoPoint, scalar::Scalar}; +use solana_sdk::{entrypoint::SUCCESS, program_error::ProgramError}; + +/// Multiply a ristretto point with a scalar +/// +/// @param point - Ristretto point +/// @param scalar - Scalar to mulitply against +/// @return - result of the multiplication +#[inline] +pub fn ristretto_mul( + point: &RistrettoPoint, + scalar: &Scalar, +) -> Result { + let mut result = RistrettoPoint::default(); + let status = unsafe { + sol_ristretto_mul( + point as *const _ as *const u8, + scalar as *const _ as *const u8, + &mut result as *const _ as *mut u8, + ) + }; + match status { + SUCCESS => Ok(result), + _ => Err(status.into()), + } +} +extern "C" { + fn sol_ristretto_mul( + point_addr: *const u8, + scalar_addr: *const u8, + result_addr: *mut u8, + ) -> u64; +} diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 495b9dc3fb..3682414e19 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -155,6 +155,7 @@ fn test_program_bpf_sanity() { ("solana_bpf_rust_panic", false), ("solana_bpf_rust_param_passing", true), ("solana_bpf_rust_rand", true), + ("solana_bpf_rust_ristretto", true), ("solana_bpf_rust_sanity", true), ("solana_bpf_rust_sha256", true), ("solana_bpf_rust_sysval", true), @@ -667,9 +668,10 @@ fn assert_instruction_count() { ("solana_bpf_rust_external_spend", 538), ("solana_bpf_rust_iter", 723), ("solana_bpf_rust_many_args", 231), - ("solana_bpf_rust_noop", 512), + ("solana_bpf_rust_noop", 488), ("solana_bpf_rust_param_passing", 46), - ("solana_bpf_rust_sanity", 1989), + ("solana_bpf_rust_ristretto", 19399), + ("solana_bpf_rust_sanity", 1965), ]); } diff --git a/programs/bpf_loader/Cargo.toml b/programs/bpf_loader/Cargo.toml index 8134f7cd60..0fc0bb2de9 100644 --- a/programs/bpf_loader/Cargo.toml +++ b/programs/bpf_loader/Cargo.toml @@ -11,6 +11,7 @@ edition = "2018" [dependencies] bincode = "1.3.1" byteorder = "1.3.4" +curve25519-dalek = "3" num-derive = "0.3" num-traits = "0.2" solana-runtime = { path = "../../runtime", version = "1.4.0" } diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 8349ae8cd2..70fec0c85d 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -1,5 +1,6 @@ use crate::{alloc, BPFError}; use alloc::Alloc; +use curve25519_dalek::{ristretto::RistrettoPoint, scalar::Scalar}; use solana_rbpf::{ ebpf::{ELF_INSN_DUMP_OFFSET, MM_HEAP_START}, error::EbpfError, @@ -7,7 +8,7 @@ use solana_rbpf::{ vm::{EbpfVm, SyscallObject}, }; use solana_runtime::{ - feature_set::sha256_syscall_enabled, + feature_set::{ristretto_mul_syscall_enabled, sha256_syscall_enabled}, message_processor::MessageProcessor, process_instruction::{ComputeMeter, InvokeContext, Logger}, }; @@ -131,6 +132,17 @@ pub fn register_syscalls<'a>( )?; } + if invoke_context.is_feature_active(&ristretto_mul_syscall_enabled::id()) { + vm.register_syscall_with_context_ex( + "sol_ristretto_mul", + Box::new(SyscallRistrettoMul { + cost: 0, + compute_meter: invoke_context.get_compute_meter(), + loader_id, + }), + )?; + } + vm.register_syscall_with_context_ex( "sol_create_program_address", Box::new(SyscallCreateProgramAddress { @@ -161,6 +173,7 @@ pub fn register_syscalls<'a>( )?; // Memory allocator + let heap = vec![0_u8; DEFAULT_HEAP_SIZE]; let heap_region = MemoryRegion::new_from_slice(&heap, MM_HEAP_START); vm.register_syscall_with_context_ex( @@ -513,6 +526,35 @@ impl<'a> SyscallObject for SyscallSha256<'a> { } } +/// Ristretto point multiply +pub struct SyscallRistrettoMul<'a> { + cost: u64, + compute_meter: Rc>, + loader_id: &'a Pubkey, +} +impl<'a> SyscallObject for SyscallRistrettoMul<'a> { + fn call( + &mut self, + point_addr: u64, + scalar_addr: u64, + result_addr: u64, + _arg4: u64, + _arg5: u64, + ro_regions: &[MemoryRegion], + rw_regions: &[MemoryRegion], + ) -> Result> { + self.compute_meter.consume(self.cost)?; + + let point = translate_type!(RistrettoPoint, point_addr, ro_regions, self.loader_id)?; + let scalar = translate_type!(Scalar, scalar_addr, ro_regions, self.loader_id)?; + let result = translate_type_mut!(RistrettoPoint, result_addr, rw_regions, self.loader_id)?; + + *result = point * scalar; + + Ok(0) + } +} + // Cross-program invocation syscalls struct AccountReferences<'a> { diff --git a/runtime/src/feature_set.rs b/runtime/src/feature_set.rs index 25fb78a0f4..729ba0253b 100644 --- a/runtime/src/feature_set.rs +++ b/runtime/src/feature_set.rs @@ -41,6 +41,10 @@ pub mod no_overflow_rent_distribution { solana_sdk::declare_id!("4kpdyrcj5jS47CZb2oJGfVxjYbsMm2Kx97gFyZrxxwXz"); } +pub mod ristretto_mul_syscall_enabled { + solana_sdk::declare_id!("HRe7A6aoxgjKzdjbBv6HTy7tJ4YWqE6tVmYCGho6S9Aq"); +} + lazy_static! { /// Map of feature identifiers to user-visible description pub static ref FEATURE_NAMES: HashMap = [ @@ -53,6 +57,7 @@ lazy_static! { (compute_budget_config2::id(), "1ms compute budget"), (sha256_syscall_enabled::id(), "sha256 syscall"), (no_overflow_rent_distribution::id(), "no overflow rent distribution"), + (ristretto_mul_syscall_enabled::id(), "ristretto multiply syscall"), /*************** ADD NEW FEATURES HERE ***************/ ] .iter()