Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
Curve25519 point validation syscall (#23771)
Browse files Browse the repository at this point in the history
* zk-token-sdk: add curve25519 basic ops

* zk-token-sdk: add bpf operations for curve25519 ops

* zk-token-sdk: rebase

* zk-token-sdk: add tests for curve25519 opertions

* zk-token-sdk: rustfmt

* zk-token-sdk: organize syscalls by trait

* zk-token-sdk: organize syscalls by trait

* zk-token-sdk: cleaning up

* zk-token-sdk: rename mods

* zk-token-sdk: cargo fmt

* zk-token-sdk: fix tests for edwards and ristretto

* zk-token-sdk: add Syscall object for curve point validation

* zk-token-sdk: docs for curve syscall traits

* zk-token-sdk: fix errors from rebase

* zk-token-sdk: update Vec to slice

Co-authored-by: Trent Nelson <[email protected]>

* zk-token-sdk: use enum with num-derive for curve ids

* zk-token-sdk: update vec to slice

* zk-token-sdk: make curve25519 tests be deterministic

* zk-token-sdk: rebase

* token-2022: re-organizing curve point validation

* token-2022: cargo fmt

* zk-token-sdk: minor

Co-authored-by: Trent Nelson <[email protected]>
  • Loading branch information
samkim-crypto and t-nelson authored May 7, 2022
1 parent c785f1f commit d9deab4
Show file tree
Hide file tree
Showing 10 changed files with 818 additions and 7 deletions.
8 changes: 7 additions & 1 deletion program-runtime/src/compute_budget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ pub struct ComputeBudget {
/// Number of compute units consumed to do a syscall without any work
pub syscall_base_cost: u64,
/// Number of compute units consumed to call zktoken_crypto_op
pub zk_token_elgamal_op_cost: u64,
pub zk_token_elgamal_op_cost: u64, // to be replaced by curve25519 operations
/// Number of compute units consumed to add/sub two edwards points
pub curve25519_edwards_validate_point_cost: u64,
/// Number of compute units consumed to add/sub two ristretto points
pub curve25519_ristretto_validate_point_cost: u64,
/// Optional program heap region size, if `None` then loader default
pub heap_size: Option<usize>,
/// Number of compute units per additional 32k heap above the default (~.5
Expand Down Expand Up @@ -92,6 +96,8 @@ impl ComputeBudget {
secp256k1_recover_cost: 25_000,
syscall_base_cost: 100,
zk_token_elgamal_op_cost: 25_000,
curve25519_edwards_validate_point_cost: 25_000, // TODO: precisely determine cost
curve25519_ristretto_validate_point_cost: 25_000,
heap_size: None,
heap_cost: 8,
mem_op_base_cost: 10,
Expand Down
101 changes: 95 additions & 6 deletions programs/bpf_loader/src/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ use {
entrypoint::{BPF_ALIGN_OF_U128, MAX_PERMITTED_DATA_INCREASE, SUCCESS},
feature_set::{
add_get_processed_sibling_instruction_syscall, blake3_syscall_enabled,
check_physical_overlapping, check_slice_translation_size, disable_fees_sysvar,
do_support_realloc, executables_incur_cpi_data_cost, fixed_memcpy_nonoverlapping_check,
libsecp256k1_0_5_upgrade_enabled, limit_secp256k1_recovery_id,
prevent_calling_precompiles_as_programs, return_data_syscall_enabled,
secp256k1_recover_syscall_enabled, sol_log_data_syscall_enabled,
syscall_saturated_math, update_syscall_base_costs, zk_token_sdk_enabled,
check_physical_overlapping, check_slice_translation_size, curve25519_syscall_enabled,
disable_fees_sysvar, do_support_realloc, executables_incur_cpi_data_cost,
fixed_memcpy_nonoverlapping_check, libsecp256k1_0_5_upgrade_enabled,
limit_secp256k1_recovery_id, prevent_calling_precompiles_as_programs,
return_data_syscall_enabled, secp256k1_recover_syscall_enabled,
sol_log_data_syscall_enabled, syscall_saturated_math, update_syscall_base_costs,
zk_token_sdk_enabled,
},
hash::{Hasher, HASH_BYTES},
instruction::{
Expand Down Expand Up @@ -137,6 +138,9 @@ pub fn register_syscalls(
let zk_token_sdk_enabled = invoke_context
.feature_set
.is_active(&zk_token_sdk_enabled::id());
let curve25519_syscall_enabled = invoke_context
.feature_set
.is_active(&curve25519_syscall_enabled::id());
let disable_fees_sysvar = invoke_context
.feature_set
.is_active(&disable_fees_sysvar::id());
Expand Down Expand Up @@ -247,6 +251,17 @@ pub fn register_syscalls(
SyscallZkTokenElgamalOpWithScalar::call,
)?;

// Elliptic Curve Point Validation
//
// TODO: add group operations and multiscalar multiplications
register_feature_gated_syscall!(
syscall_registry,
curve25519_syscall_enabled,
b"sol_curve25519_point_validation",
SyscallCurvePointValidation::init,
SyscallCurvePointValidation::call,
)?;

// Sysvars
syscall_registry.register_syscall_by_name(
b"sol_get_clock_sysvar",
Expand Down Expand Up @@ -1890,6 +1905,80 @@ declare_syscall!(
}
);

declare_syscall!(
// Elliptic Curve Point Validation
//
// Currently, only curve25519 Edwards and Ristretto representations are supported
SyscallCurvePointValidation,
fn call(
&mut self,
curve_id: u64,
point_addr: u64,
_arg3: u64,
_arg4: u64,
_arg5: u64,
memory_mapping: &MemoryMapping,
result: &mut Result<u64, EbpfError<BpfError>>,
) {
use solana_zk_token_sdk::curve25519::{curve_syscall_traits::*, edwards, ristretto};

let invoke_context = question_mark!(
self.invoke_context
.try_borrow()
.map_err(|_| SyscallError::InvokeContextBorrowFailed),
result
);

match curve_id {
CURVE25519_EDWARDS => {
let cost = invoke_context
.get_compute_budget()
.curve25519_edwards_validate_point_cost;
question_mark!(invoke_context.get_compute_meter().consume(cost), result);

let point = question_mark!(
translate_type::<edwards::PodEdwardsPoint>(
memory_mapping,
point_addr,
invoke_context.get_check_aligned()
),
result
);

if edwards::validate_edwards(point) {
*result = Ok(0);
} else {
*result = Ok(1);
}
}
CURVE25519_RISTRETTO => {
let cost = invoke_context
.get_compute_budget()
.curve25519_ristretto_validate_point_cost;
question_mark!(invoke_context.get_compute_meter().consume(cost), result);

let point = question_mark!(
translate_type::<ristretto::PodRistrettoPoint>(
memory_mapping,
point_addr,
invoke_context.get_check_aligned()
),
result
);

if ristretto::validate_ristretto(point) {
*result = Ok(0);
} else {
*result = Ok(1);
}
}
_ => {
*result = Ok(1);
}
};
}
);

declare_syscall!(
// Blake3
SyscallBlake3,
Expand Down
5 changes: 5 additions & 0 deletions sdk/src/feature_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ pub mod zk_token_sdk_enabled {
solana_sdk::declare_id!("zk1snxsc6Fh3wsGNbbHAJNHiJoYgF29mMnTSusGx5EJ");
}

// TODO: temporary address for now
pub mod curve25519_syscall_enabled {
solana_sdk::declare_id!("curve25519111111111111111111111111111111111");
}

pub mod versioned_tx_message_enabled {
solana_sdk::declare_id!("3KZZ6Ks1885aGBQ45fwRcPXVBCtzUvxhUTkwKMR41Tca");
}
Expand Down
94 changes: 94 additions & 0 deletions zk-token-sdk/src/curve25519/curve_syscall_traits.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//! The traits representing the basic elliptic curve operations.
//!
//! These traits are instantiatable by all the commonly used elliptic curves and should help in
//! organizing syscall support for other curves in the future. more complicated or curve-specific
//! functions that are needed in cryptographic applications should be representable by combining
//! the associated functions of these traits.
//!
//! NOTE: This module temporarily lives in zk_token_sdk/curve25519, but it is independent of
//! zk-token-sdk or curve25519. It should be moved to a more general location in the future.
//!
pub trait PointValidation {
type Point;

/// Verifies if a byte representation of a curve point lies in the curve.
fn validate_point(&self) -> bool;
}

pub trait GroupOperations {
type Point;
type Scalar;

/// Adds two curve points: P_0 + P_1.
fn add(left_point: &Self::Point, right_point: &Self::Point) -> Option<Self::Point>;

/// Subtracts two curve points: P_0 - P_1.
///
/// NOTE: Altneratively, one can consider replacing this with a `negate` function that maps a
/// curve point P -> -P. Then subtraction can be computed by combining `negate` and `add`
/// syscalls. However, `subtract` is a much more widely used function than `negate`.
fn subtract(left_point: &Self::Point, right_point: &Self::Point) -> Option<Self::Point>;

/// Multiplies a scalar S with a curve point P: S*P
fn multiply(scalar: &Self::Scalar, point: &Self::Point) -> Option<Self::Point>;
}

pub trait MultiScalarMultiplication {
type Scalar;
type Point;

/// Given a vector of scalsrs S_1, ..., S_N, and curve points P_1, ..., P_N, computes the
/// "inner product": S_1*P_1 + ... + S_N*P_N.
///
/// NOTE: This operation can be represented by combining `add` and `multiply` functions in
/// `GroupOperations`, but computing it in a single batch is significantly cheaper. Given how
/// commonly used the multiscalar multiplication (MSM) is, it seems to make sense to have a
/// designated trait for MSM support.
///
/// NOTE: The inputs to the function is a non-fixed size vector and hence, there are some
/// complications in computing the cost for the syscall. The computational costs should only
/// depend on the length of the vectors (and the curve), so it would be ideal to support
/// variable length inputs and compute the syscall cost as is done in eip-197:
/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-197.md#gas-costs. If not, then we can
/// consider bounding the length of the input and assigning worst-case cost.
fn multiscalar_multiply(
scalars: &[Self::Scalar],
points: &[Self::Point],
) -> Option<Self::Point>;
}

pub trait Pairing {
type G1Point;
type G2Point;
type GTPoint;

/// Applies the bilinear pairing operation to two curve points P1, P2 -> e(P1, P2). This trait
/// is only relevant for "pairing-friendly" curves such as BN254 and BLS12-381.
fn pairing_map(
left_point: &Self::G1Point,
right_point: &Self::G2Point,
) -> Option<Self::GTPoint>;
}

pub const CURVE25519_EDWARDS: u64 = 0;
pub const CURVE25519_RISTRETTO: u64 = 1;

pub const ADD: u64 = 0;
pub const SUB: u64 = 1;
pub const MUL: u64 = 2;

// Functions are organized by the curve traits, which can be instantiated by multiple curve
// representations. The functions take in a `curve_id` (e.g. `CURVE25519_EDWARDS`) and should run
// the associated functions in the appropriate trait instantiation. The `curve_op` function
// additionally takes in an `op_id` (e.g. `ADD`) that controls which associated functions to run in
// `GroupOperations`.
extern "C" {
pub fn sol_curve_validate_point(curve_id: u64, point: *const u8, result: *mut u8) -> u64;

pub fn sol_curve_op(curve_id: u64, op_id: u64, point: *const u8, result: *mut u8) -> u64;

pub fn sol_curve_multiscalar_mul(curve_id: u64, point: *const u8, result: *mut u8) -> u64;

pub fn sol_curve_pairing_map(curve_id: u64, point: *const u8, result: *mut u8) -> u64;
}
Loading

0 comments on commit d9deab4

Please sign in to comment.