agave_precompiles/
lib.rs

1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
2use {
3    agave_feature_set::{enable_secp256r1_precompile, FeatureSet},
4    lazy_static::lazy_static,
5    solana_message::compiled_instruction::CompiledInstruction,
6    solana_precompile_error::PrecompileError,
7    solana_pubkey::Pubkey,
8};
9
10pub mod ed25519;
11pub mod secp256k1;
12pub mod secp256r1;
13
14/// All precompiled programs must implement the `Verify` function
15pub type Verify = fn(&[u8], &[&[u8]], &FeatureSet) -> std::result::Result<(), PrecompileError>;
16
17/// Information on a precompiled program
18pub struct Precompile {
19    /// Program id
20    pub program_id: Pubkey,
21    /// Feature to enable on, `None` indicates always enabled
22    pub feature: Option<Pubkey>,
23    /// Verification function
24    pub verify_fn: Verify,
25}
26impl Precompile {
27    /// Creates a new `Precompile`
28    pub fn new(program_id: Pubkey, feature: Option<Pubkey>, verify_fn: Verify) -> Self {
29        Precompile {
30            program_id,
31            feature,
32            verify_fn,
33        }
34    }
35    /// Check if a program id is this precompiled program
36    pub fn check_id<F>(&self, program_id: &Pubkey, is_enabled: F) -> bool
37    where
38        F: Fn(&Pubkey) -> bool,
39    {
40        self.feature
41            .is_none_or(|ref feature_id| is_enabled(feature_id))
42            && self.program_id == *program_id
43    }
44    /// Verify this precompiled program
45    pub fn verify(
46        &self,
47        data: &[u8],
48        instruction_datas: &[&[u8]],
49        feature_set: &FeatureSet,
50    ) -> std::result::Result<(), PrecompileError> {
51        (self.verify_fn)(data, instruction_datas, feature_set)
52    }
53}
54
55lazy_static! {
56    /// The list of all precompiled programs
57    static ref PRECOMPILES: Vec<Precompile> = vec![
58        Precompile::new(
59            solana_sdk_ids::secp256k1_program::id(),
60            None, // always enabled
61            secp256k1::verify,
62        ),
63        Precompile::new(
64            solana_sdk_ids::ed25519_program::id(),
65            None, // always enabled
66            ed25519::verify,
67        ),
68        Precompile::new(
69            solana_sdk_ids::secp256r1_program::id(),
70            Some(enable_secp256r1_precompile::id()),
71            secp256r1::verify,
72        )
73    ];
74}
75
76/// Check if a program is a precompiled program
77pub fn is_precompile<F>(program_id: &Pubkey, is_enabled: F) -> bool
78where
79    F: Fn(&Pubkey) -> bool,
80{
81    PRECOMPILES
82        .iter()
83        .any(|precompile| precompile.check_id(program_id, |feature_id| is_enabled(feature_id)))
84}
85
86/// Find an enabled precompiled program
87pub fn get_precompile<F>(program_id: &Pubkey, is_enabled: F) -> Option<&Precompile>
88where
89    F: Fn(&Pubkey) -> bool,
90{
91    PRECOMPILES
92        .iter()
93        .find(|precompile| precompile.check_id(program_id, |feature_id| is_enabled(feature_id)))
94}
95
96pub fn get_precompiles<'a>() -> &'a [Precompile] {
97    &PRECOMPILES
98}
99
100/// Check that a program is precompiled and if so verify it
101pub fn verify_if_precompile(
102    program_id: &Pubkey,
103    precompile_instruction: &CompiledInstruction,
104    all_instructions: &[CompiledInstruction],
105    feature_set: &FeatureSet,
106) -> Result<(), PrecompileError> {
107    for precompile in PRECOMPILES.iter() {
108        if precompile.check_id(program_id, |feature_id| feature_set.is_active(feature_id)) {
109            let instruction_datas: Vec<_> = all_instructions
110                .iter()
111                .map(|instruction| instruction.data.as_ref())
112                .collect();
113            return precompile.verify(
114                &precompile_instruction.data,
115                &instruction_datas,
116                feature_set,
117            );
118        }
119    }
120    Ok(())
121}
122
123#[cfg(test)]
124pub(crate) fn test_verify_with_alignment(
125    verify: Verify,
126    instruction_data: &[u8],
127    instruction_datas: &[&[u8]],
128    feature_set: &FeatureSet,
129) -> Result<(), PrecompileError> {
130    // Copy instruction data.
131    let mut instruction_data_copy = vec![0u8; instruction_data.len().checked_add(1).unwrap()];
132    instruction_data_copy[0..instruction_data.len()].copy_from_slice(instruction_data);
133    // Verify the instruction data.
134    let result = verify(
135        &instruction_data_copy[..instruction_data.len()],
136        instruction_datas,
137        feature_set,
138    );
139
140    // Shift alignment by 1 to test `verify` does not rely on alignment.
141    instruction_data_copy[1..].copy_from_slice(instruction_data);
142    let result_shifted = verify(&instruction_data_copy[1..], instruction_datas, feature_set);
143    assert_eq!(result, result_shifted);
144    result
145}