Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ed25519-program/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ edition = { workspace = true }
bytemuck = { workspace = true }
bytemuck_derive = { workspace = true }
ed25519-dalek = { workspace = true }
solana-feature-set = { workspace = true }
solana-feature-set-interface = { workspace = true }
solana-instruction = { workspace = true, features = ["std"] }
solana-precompile-error = { workspace = true }
solana-sdk-ids = { workspace = true }
Expand Down
24 changes: 12 additions & 12 deletions ed25519-program/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use {
bytemuck::bytes_of,
bytemuck_derive::{Pod, Zeroable},
ed25519_dalek::{ed25519::signature::Signature, Signer, Verifier},
solana_feature_set::{ed25519_precompile_verify_strict, FeatureSet},
solana_feature_set_interface::PrecompileFeatureSet,
solana_instruction::Instruction,
solana_precompile_error::PrecompileError,
};
Expand Down Expand Up @@ -115,7 +115,7 @@ pub fn new_ed25519_instruction(keypair: &ed25519_dalek::Keypair, message: &[u8])
pub fn verify(
data: &[u8],
instruction_datas: &[&[u8]],
feature_set: &FeatureSet,
feature_set: &PrecompileFeatureSet,
) -> Result<(), PrecompileError> {
if data.len() < SIGNATURE_OFFSETS_START {
return Err(PrecompileError::InvalidInstructionDataSize);
Expand Down Expand Up @@ -174,7 +174,7 @@ pub fn verify(
offsets.message_data_size as usize,
)?;

if feature_set.is_active(&ed25519_precompile_verify_strict::id()) {
if feature_set.ed25519_precompile_verify_strict_feature_enabled {
publickey
.verify_strict(message, &signature)
.map_err(|_| PrecompileError::InvalidSignature)?;
Expand Down Expand Up @@ -220,7 +220,7 @@ pub mod test {
ed25519_dalek::Signer as EdSigner,
hex,
rand0_7::{thread_rng, Rng},
solana_feature_set::FeatureSet,
solana_feature_set_interface::PrecompileFeatureSet,
solana_hash::Hash,
solana_keypair::Keypair,
solana_sdk::transaction::Transaction,
Expand Down Expand Up @@ -297,7 +297,7 @@ pub mod test {
verify(
&instruction_data,
&[&[0u8; 100]],
&FeatureSet::all_enabled(),
&PrecompileFeatureSet::all_enabled(),
)
}

Expand All @@ -315,7 +315,7 @@ pub mod test {
verify(
&instruction_data,
&[&[0u8; 100]],
&FeatureSet::all_enabled(),
&PrecompileFeatureSet::all_enabled(),
),
Err(PrecompileError::InvalidInstructionDataSize)
);
Expand Down Expand Up @@ -441,7 +441,7 @@ pub mod test {
let message_arr = b"hello";
let mut instruction = new_ed25519_instruction(&privkey, message_arr);
let mint_keypair = Keypair::new();
let feature_set = FeatureSet::all_enabled();
let feature_set = PrecompileFeatureSet::all_enabled();

let tx = Transaction::new_signed_with_payer(
&[instruction.clone()],
Expand Down Expand Up @@ -512,7 +512,7 @@ pub mod test {
}

let mint_keypair = Keypair::new();
let feature_set = FeatureSet::all_enabled();
let feature_set = PrecompileFeatureSet::all_enabled();

let tx = Transaction::new_signed_with_payer(
&[instruction.clone()],
Expand Down Expand Up @@ -557,10 +557,10 @@ pub mod test {
Hash::default(),
);

let feature_set = FeatureSet::default();
let feature_set = PrecompileFeatureSet::default();
assert!(tx.verify_precompiles(&feature_set).is_ok());

let feature_set = FeatureSet::all_enabled();
let feature_set = PrecompileFeatureSet::all_enabled();
assert!(tx.verify_precompiles(&feature_set).is_ok());

// malleable sig: verify_strict does NOT pass
Expand All @@ -580,10 +580,10 @@ pub mod test {
Hash::default(),
);

let feature_set = FeatureSet::default();
let feature_set = PrecompileFeatureSet::default();
assert!(tx.verify_precompiles(&feature_set).is_ok());

let feature_set = FeatureSet::all_enabled();
let feature_set = PrecompileFeatureSet::all_enabled();
assert!(tx.verify_precompiles(&feature_set).is_err()); // verify_strict does NOT pass
}
}
16 changes: 16 additions & 0 deletions feature-set-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@ impl FeatureSet {
}
}

#[doc(hidden)]
#[derive(Default)]
pub struct PrecompileFeatureSet {
pub secp256r1_precompile_enabled: bool,
pub ed25519_precompile_verify_strict_feature_enabled: bool,
}

impl PrecompileFeatureSet {
pub fn all_enabled() -> Self {
Self {
secp256r1_precompile_enabled: true,
ed25519_precompile_verify_strict_feature_enabled: true,
}
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
2 changes: 1 addition & 1 deletion precompiles/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ edition = { workspace = true }
[dependencies]
lazy_static = { workspace = true }
solana-ed25519-program = { workspace = true }
solana-feature-set = { workspace = true }
solana-feature-set-interface = { workspace = true }
solana-message = { workspace = true }
solana-precompile-error = { workspace = true }
solana-pubkey = { workspace = true }
Expand Down
50 changes: 26 additions & 24 deletions precompiles/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,45 @@
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
use {
lazy_static::lazy_static, solana_feature_set::FeatureSet,
lazy_static::lazy_static, solana_feature_set_interface::PrecompileFeatureSet,
solana_message::compiled_instruction::CompiledInstruction,
solana_precompile_error::PrecompileError, solana_pubkey::Pubkey,
};

/// All precompiled programs must implement the `Verify` function
pub type Verify = fn(&[u8], &[&[u8]], &FeatureSet) -> std::result::Result<(), PrecompileError>;
pub type Verify =
fn(&[u8], &[&[u8]], &PrecompileFeatureSet) -> std::result::Result<(), PrecompileError>;

/// All precompiled programs must implement the `Enabled` function
pub type Enabled = fn(&PrecompileFeatureSet) -> bool;

/// Information on a precompiled program
pub struct Precompile {
/// Program id
pub program_id: Pubkey,
/// Feature to enable on, `None` indicates always enabled
pub feature: Option<Pubkey>,
/// Enabled function
pub enabled_fn: Enabled,
/// Verification function
pub verify_fn: Verify,
}
impl Precompile {
/// Creates a new `Precompile`
pub fn new(program_id: Pubkey, feature: Option<Pubkey>, verify_fn: Verify) -> Self {
pub fn new(program_id: Pubkey, enabled_fn: Enabled, verify_fn: Verify) -> Self {
Precompile {
program_id,
feature,
enabled_fn,
verify_fn,
}
}
/// Check if a program id is this precompiled program
pub fn check_id<F>(&self, program_id: &Pubkey, is_enabled: F) -> bool
where
F: Fn(&Pubkey) -> bool,
{
self.feature
.map_or(true, |ref feature_id| is_enabled(feature_id))
&& self.program_id == *program_id
/// Check if this precompiled program is enabled
pub fn enabled(&self, feature_set: &PrecompileFeatureSet) -> bool {
(self.enabled_fn)(feature_set)
}
/// Verify this precompiled program
pub fn verify(
&self,
data: &[u8],
instruction_datas: &[&[u8]],
feature_set: &FeatureSet,
feature_set: &PrecompileFeatureSet,
) -> std::result::Result<(), PrecompileError> {
(self.verify_fn)(data, instruction_datas, feature_set)
}
Expand All @@ -51,40 +50,43 @@ lazy_static! {
static ref PRECOMPILES: Vec<Precompile> = vec![
Precompile::new(
solana_sdk_ids::secp256k1_program::id(),
None, // always enabled
|_| true, // always enabled
solana_secp256k1_program::verify,
),
Precompile::new(
solana_sdk_ids::ed25519_program::id(),
None, // always enabled
|_| true, // always enabled
solana_ed25519_program::verify,
),
Precompile::new(
solana_sdk_ids::secp256r1_program::id(),
Some(solana_feature_set::enable_secp256r1_precompile::id()),
|feature_set| feature_set.secp256r1_precompile_enabled,
solana_secp256r1_program::verify,
)
];
}

/// Check if a program is a precompiled program
pub fn is_precompile<F>(program_id: &Pubkey, is_enabled: F) -> bool
pub fn is_precompile<F>(program_id: &Pubkey, feature_set: &PrecompileFeatureSet) -> bool
where
F: Fn(&Pubkey) -> bool,
{
PRECOMPILES
.iter()
.any(|precompile| precompile.check_id(program_id, |feature_id| is_enabled(feature_id)))
.any(|precompile| &precompile.program_id == program_id && precompile.enabled(feature_set))
}

/// Find an enabled precompiled program
pub fn get_precompile<F>(program_id: &Pubkey, is_enabled: F) -> Option<&Precompile>
pub fn get_precompile<'a, F>(
program_id: &'a Pubkey,
feature_set: &PrecompileFeatureSet,
) -> Option<&'a Precompile>
where
F: Fn(&Pubkey) -> bool,
{
PRECOMPILES
.iter()
.find(|precompile| precompile.check_id(program_id, |feature_id| is_enabled(feature_id)))
.find(|precompile| &precompile.program_id == program_id && precompile.enabled(feature_set))
}

pub fn get_precompiles<'a>() -> &'a [Precompile] {
Expand All @@ -96,10 +98,10 @@ pub fn verify_if_precompile(
program_id: &Pubkey,
precompile_instruction: &CompiledInstruction,
all_instructions: &[CompiledInstruction],
feature_set: &FeatureSet,
feature_set: &PrecompileFeatureSet,
) -> Result<(), PrecompileError> {
for precompile in PRECOMPILES.iter() {
if precompile.check_id(program_id, |feature_id| feature_set.is_active(feature_id)) {
if &precompile.program_id == program_id && precompile.enabled(feature_set) {
let instruction_datas: Vec<_> = all_instructions
.iter()
.map(|instruction| instruction.data.as_ref())
Expand Down
1 change: 1 addition & 0 deletions sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ openssl = { workspace = true }
rand0-7 = { workspace = true }
serde_derive = { workspace = true }
serde_with = { workspace = true, features = ["macros"] }
solana-feature-set-interface = { workspace = true }
solana-instructions-sysvar = { workspace = true, features = ["dev-context-only-utils"] }
solana-program = { workspace = true, features = ["dev-context-only-utils"] }
solana-sdk = { path = ".", features = ["dev-context-only-utils"] }
Expand Down
10 changes: 5 additions & 5 deletions sdk/benches/ed25519_instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
extern crate test;
use {
rand0_7::{thread_rng, Rng},
solana_feature_set::FeatureSet,
solana_feature_set_interface::PrecompileFeatureSet,
solana_sdk::{
ed25519_instruction::new_ed25519_instruction,
hash::Hash,
Expand Down Expand Up @@ -38,7 +38,7 @@ fn create_test_transactions(message_length: u16) -> Vec<Transaction> {

#[bench]
fn bench_ed25519_len_032(b: &mut Bencher) {
let feature_set = FeatureSet::all_enabled();
let feature_set = PrecompileFeatureSet::all_enabled();
let txs = create_test_transactions(32);
let mut tx_iter = txs.iter().cycle();
b.iter(|| {
Expand All @@ -52,7 +52,7 @@ fn bench_ed25519_len_032(b: &mut Bencher) {

#[bench]
fn bench_ed25519_len_128(b: &mut Bencher) {
let feature_set = FeatureSet::all_enabled();
let feature_set = PrecompileFeatureSet::all_enabled();
let txs = create_test_transactions(128);
let mut tx_iter = txs.iter().cycle();
b.iter(|| {
Expand All @@ -66,7 +66,7 @@ fn bench_ed25519_len_128(b: &mut Bencher) {

#[bench]
fn bench_ed25519_len_32k(b: &mut Bencher) {
let feature_set = FeatureSet::all_enabled();
let feature_set = PrecompileFeatureSet::all_enabled();
let txs = create_test_transactions(32 * 1024);
let mut tx_iter = txs.iter().cycle();
b.iter(|| {
Expand All @@ -81,7 +81,7 @@ fn bench_ed25519_len_32k(b: &mut Bencher) {
#[bench]
fn bench_ed25519_len_max(b: &mut Bencher) {
let required_extra_space = 113_u16; // len for pubkey, sig, and offsets
let feature_set = FeatureSet::all_enabled();
let feature_set = PrecompileFeatureSet::all_enabled();
let txs = create_test_transactions(u16::MAX - required_extra_space);
let mut tx_iter = txs.iter().cycle();
b.iter(|| {
Expand Down
Loading