Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract secp256k1-instruction #3331

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
25 changes: 25 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ members = [
"sdk/pubkey",
"sdk/rent",
"sdk/sanitize",
"sdk/secp256k1-instruction",
"sdk/seed-derivable",
"sdk/seed-phrase",
"sdk/serde-varint",
Expand Down Expand Up @@ -514,6 +515,7 @@ solana-runtime = { path = "runtime", version = "=2.2.0" }
solana-runtime-transaction = { path = "runtime-transaction", version = "=2.2.0" }
solana-sdk = { path = "sdk", version = "=2.2.0" }
solana-sdk-macro = { path = "sdk/macro", version = "=2.2.0" }
solana-secp256k1-instruction = { path = "sdk/secp256k1-instruction", version = "=2.2.0" }
solana-secp256k1-recover = { path = "curves/secp256k1-recover", version = "=2.2.0", default-features = false }
solana-send-transaction-service = { path = "send-transaction-service", version = "=2.2.0" }
solana-short-vec = { path = "short-vec", version = "=2.2.0" }
Expand Down
17 changes: 17 additions & 0 deletions programs/sbf/Cargo.lock

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

2 changes: 2 additions & 0 deletions sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ full = [
"dep:solana-keypair",
"dep:solana-precompile-error",
"dep:solana-presigner",
"dep:solana-secp256k1-instruction",
"dep:solana-seed-derivable",
"dep:solana-seed-phrase",
"dep:solana-signer",
Expand Down Expand Up @@ -119,6 +120,7 @@ solana-pubkey = { workspace = true, default-features = false, features = ["std"]
solana-reward-info = { workspace = true, features = ["serde"] }
solana-sanitize = { workspace = true }
solana-sdk-macro = { workspace = true }
solana-secp256k1-instruction = { workspace = true, optional = true, features = ["bincode"] }
solana-secp256k1-recover = { workspace = true }
solana-seed-derivable = { workspace = true, optional = true }
solana-seed-phrase = { workspace = true, optional = true }
Expand Down
42 changes: 42 additions & 0 deletions sdk/secp256k1-instruction/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[package]
name = "solana-secp256k1-instruction"
description = "Instructions for the Solana Secp256k1 native program."
documentation = "https://docs.rs/solana-secp256k1-instruction"
version = { workspace = true }
authors = { workspace = true }
repository = { workspace = true }
homepage = { workspace = true }
license = { workspace = true }
edition = { workspace = true }

[dependencies]
bincode = { workspace = true, optional = true }
digest = { workspace = true }
libsecp256k1 = { workspace = true, features = ["hmac"] }
serde = { workspace = true, optional = true }
serde_derive = { workspace = true, optional = true }
sha3 = { workspace = true }
solana-feature-set = { workspace = true }
solana-instruction = { workspace = true, features = ["std"] }
solana-precompile-error = { workspace = true }
solana-pubkey = { workspace = true, optional = true }

[dev-dependencies]
anyhow = { workspace = true }
hex = { workspace = true }
rand0-7 = { workspace = true }
solana-hash = { workspace = true }
solana-logger = { workspace = true }
solana-program = { path = "../program" }
solana-sdk = { path = ".." }
solana-secp256k1-instruction = { path = ".", features = ["dev-context-only-utils"] }

[features]
bincode = ["dep:bincode", "dep:solana-pubkey", "serde"]
dev-context-only-utils = ["bincode"]
serde = ["dep:serde", "dep:serde_derive"]

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
all-features = true
rustdoc-args = ["--cfg=docsrs"]
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
//! Instructions for the [secp256k1 native program][np].
//!
//! [np]: https://docs.solanalabs.com/runtime/programs#secp256k1-program
Expand All @@ -20,15 +21,15 @@
//! secp256k1 key recovery algorithm. Ethereum address can be created for
//! secp256k1 public keys with the [`construct_eth_pubkey`] function.
//!
//! [`keccak`]: crate::keccak
//! [`keccak`]: https://docs.rs/solana-sdk/latest/solana_sdk/keccak/index.html
//!
//! This instruction does not directly allow for key recovery as in Ethereum's
//! [`ecrecover`] precompile. For that Solana provides the [`secp256k1_recover`]
//! syscall.
//!
//! [secp256k1]: https://en.bitcoin.it/wiki/Secp256k1
//! [`secp256k1_program`]: solana_program::secp256k1_program
//! [`secp256k1_recover`]: solana_program::secp256k1_recover
//! [`secp256k1_program`]: https://docs.rs/solana-program/latest/solana_program/secp256k1_program/index.html
//! [`secp256k1_recover`]: https://docs.rs/solana-secp256k1-recover
//! [`ecrecover`]: https://docs.soliditylang.org/en/v0.8.14/units-and-global-variables.html?highlight=ecrecover#mathematical-and-cryptographic-functions
//!
//! Use cases for the secp256k1 instruction include:
Expand Down Expand Up @@ -58,8 +59,8 @@
//! of one or more additional instructions, as long as those instructions are in
//! the same transaction.
//!
//! [`load_instruction_at_checked`]: crate::sysvar::instructions::load_instruction_at_checked
//! [`get_instruction_relative`]: crate::sysvar::instructions::get_instruction_relative
//! [`load_instruction_at_checked`]: https://docs.rs/solana-program/latest/solana_program/sysvar/instructions/fn.load_instruction_at_checked.html
//! [`get_instruction_relative`]: https://docs.rs/solana-program/latest/solana_program/sysvar/instructions/fn.get_instruction_relative.html
//!
//! Correct use of this program involves multiple steps, in client code and
//! program code:
Expand All @@ -85,7 +86,7 @@
//! - Check that the public keys and messages are the expected values per
//! the program's requirements.
//!
//! [`secp256k1_program::ID`]: crate::secp256k1_program::ID
//! [`secp256k1_program::ID`]: https://docs.rs/solana-program/latest/solana_program/secp256k1_program/constant.ID.html
//!
//! The signature, message, or Ethereum addresses may reside in the secp256k1
//! instruction data itself as additional data, their bytes following the bytes
Expand Down Expand Up @@ -174,13 +175,13 @@
//! [`get_instruction_relative`] functions. Both of these functions check their
//! sysvar argument to ensure it is the known instruction sysvar.
//!
//! [is]: crate::sysvar::instructions
//! [is]: https://docs.rs/solana-program/latest/solana_program/sysvar/instructions/index.html
//!
//! Programs should _always_ verify that the secp256k1 program ID loaded through
//! the instructions sysvar has the same value as in the [`secp256k1_program`]
//! module. Again this prevents imposter programs.
//!
//! [`secp256k1_program`]: crate::secp256k1_program
//! [`secp256k1_program`]: https://docs.rs/solana-program/latest/solana_program/secp256k1_program/index.html
//!
//! # Errors
//!
Expand Down Expand Up @@ -785,27 +786,29 @@
//! }
//! ```

#![cfg(feature = "full")]

use {
digest::Digest,
serde_derive::{Deserialize, Serialize},
solana_feature_set::FeatureSet,
solana_instruction::Instruction,
solana_precompile_error::PrecompileError,
};
use digest::Digest;
#[cfg(feature = "serde")]
use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "bincode")]
use {solana_instruction::Instruction, solana_precompile_error::PrecompileError};

pub const HASHED_PUBKEY_SERIALIZED_SIZE: usize = 20;
pub const SIGNATURE_SERIALIZED_SIZE: usize = 64;
pub const SIGNATURE_OFFSETS_SERIALIZED_SIZE: usize = 11;
pub const DATA_START: usize = SIGNATURE_OFFSETS_SERIALIZED_SIZE + 1;

// inline from solana_sdk::secp256k1_program to avoid solana_sdk dependency
#[cfg(feature = "bincode")]
const SECP256K1_PROGRAM_ID: solana_pubkey::Pubkey =
solana_pubkey::pubkey!("KeccakSecp256k11111111111111111111111111111");

/// Offsets of signature data within a secp256k1 instruction.
///
/// See the [module documentation][md] for a complete description.
///
/// [md]: self
#[derive(Default, Serialize, Deserialize, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[derive(Default, Debug, Eq, PartialEq)]
pub struct SecpSignatureOffsets {
/// Offset to 64-byte signature plus 1-byte recovery ID.
pub signature_offset: u16,
Expand Down Expand Up @@ -838,7 +841,8 @@ pub struct SecpSignatureOffsets {
///
/// `message_arr` is hashed with the [`keccak`] hash function prior to signing.
///
/// [`keccak`]: crate::keccak
/// [`keccak`]: https://docs.rs/solana-sdk/latest/solana_sdk/keccak/index.html
#[cfg(feature = "bincode")]
pub fn new_secp256k1_instruction(
priv_key: &libsecp256k1::SecretKey,
message_arr: &[u8],
Expand Down Expand Up @@ -893,7 +897,7 @@ pub fn new_secp256k1_instruction(
bincode::serialize_into(writer, &offsets).unwrap();

Instruction {
program_id: solana_sdk::secp256k1_program::id(),
program_id: SECP256K1_PROGRAM_ID,
accounts: vec![],
data: instruction_data,
}
Expand Down Expand Up @@ -922,10 +926,11 @@ pub fn construct_eth_pubkey(
/// disable a few minor additional checks that were activated on chain
/// subsequent to the addition of the secp256k1 native program. For many
/// purposes passing `FeatureSet::all_enabled()` is reasonable.
#[cfg(feature = "bincode")]
pub fn verify(
data: &[u8],
instruction_datas: &[&[u8]],
_feature_set: &FeatureSet,
_feature_set: &solana_feature_set::FeatureSet,
) -> Result<(), PrecompileError> {
if data.is_empty() {
return Err(PrecompileError::InvalidInstructionDataSize);
Expand Down Expand Up @@ -1007,6 +1012,7 @@ pub fn verify(
Ok(())
}

#[cfg(feature = "bincode")]
fn get_data_slice<'a>(
instruction_datas: &'a [&[u8]],
instruction_index: u8,
Expand All @@ -1031,16 +1037,14 @@ fn get_data_slice<'a>(
pub mod test {
use {
super::*,
crate::{
hash::Hash,
rand0_7::{thread_rng, Rng},
solana_feature_set::FeatureSet,
solana_hash::Hash,
solana_sdk::{
keccak,
secp256k1_instruction::{
new_secp256k1_instruction, SecpSignatureOffsets, SIGNATURE_OFFSETS_SERIALIZED_SIZE,
},
signature::{Keypair, Signer},
signer::{keypair::Keypair, Signer},
transaction::Transaction,
},
rand0_7::{thread_rng, Rng},
};

fn test_case(
Expand Down Expand Up @@ -1306,4 +1310,9 @@ pub mod test {
)
.unwrap();
}

#[test]
fn test_inlined_program_id() {
assert_eq!(SECP256K1_PROGRAM_ID, solana_sdk::secp256k1_program::id());
}
}
7 changes: 6 additions & 1 deletion sdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ pub mod reward_type {
pub use solana_reward_info::RewardType;
}
pub mod rpc_port;
pub mod secp256k1_instruction;
pub mod shred_version;
pub mod signature;
pub mod signer;
Expand Down Expand Up @@ -177,6 +176,12 @@ pub use solana_sdk_macro::declare_deprecated_id;
pub use solana_sdk_macro::declare_id;
/// Convenience macro to define multiple static public keys.
pub use solana_sdk_macro::pubkeys;
#[deprecated(
since = "2.2.0",
note = "Use `solana-secp256k1-instruction` crate instead"
)]
#[cfg(feature = "full")]
pub use solana_secp256k1_instruction as secp256k1_instruction;
#[deprecated(since = "2.1.0", note = "Use `solana-secp256k1-recover` crate instead")]
pub use solana_secp256k1_recover as secp256k1_recover;
#[deprecated(since = "2.1.0", note = "Use `solana-serde-varint` crate instead")]
Expand Down
Loading