diff --git a/Cargo.lock b/Cargo.lock index acc820c0dac1cc..0f09d092d636fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6830,6 +6830,7 @@ dependencies = [ "solana-logger", "solana-sanitize", "solana-sdk-macro", + "solana-secp256k1-recover", "static_assertions", "thiserror", "wasm-bindgen", @@ -7299,6 +7300,7 @@ dependencies = [ "solana-sanitize", "solana-sdk", "solana-sdk-macro", + "solana-secp256k1-recover", "static_assertions", "thiserror", "tiny-bip39", @@ -7316,6 +7318,20 @@ dependencies = [ "syn 2.0.71", ] +[[package]] +name = "solana-secp256k1-recover" +version = "2.1.0" +dependencies = [ + "anyhow", + "borsh 1.5.1", + "libsecp256k1", + "rustc_version 0.4.0", + "solana-define-syscall", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "thiserror", +] + [[package]] name = "solana-security-txt" version = "1.1.1" diff --git a/Cargo.toml b/Cargo.toml index 4de674c8626506..83b14d978974a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -397,6 +397,7 @@ solana-runtime = { path = "runtime", version = "=2.1.0" } solana-runtime-transaction = { path = "runtime-transaction", version = "=2.1.0" } solana-sdk = { path = "sdk", version = "=2.1.0" } solana-sdk-macro = { path = "sdk/macro", version = "=2.1.0" } +solana-secp256k1-recover = { path = "curves/secp256k1-recover", version = "=2.1.0", default-features = false } solana-send-transaction-service = { path = "send-transaction-service", version = "=2.1.0" } solana-stake-program = { path = "programs/stake", version = "=2.1.0" } solana-storage-bigtable = { path = "storage-bigtable", version = "=2.1.0" } diff --git a/curves/secp256k1-recover/Cargo.toml b/curves/secp256k1-recover/Cargo.toml new file mode 100644 index 00000000000000..545fb073e9e6ae --- /dev/null +++ b/curves/secp256k1-recover/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "solana-secp256k1-recover" +description = "Solana SECP256K1 Recover" +documentation = "https://docs.rs/solana-secp256k1-recover" +version = { workspace = true } +authors = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +edition = { workspace = true } + +[dependencies] +borsh = { workspace = true, optional = true } +solana-frozen-abi = { workspace = true, optional = true } +solana-frozen-abi-macro = { workspace = true, optional = true } +thiserror = { workspace = true } + +[target.'cfg(target_os = "solana")'.dependencies] +solana-define-syscall = { workspace = true } + +[target.'cfg(not(target_os = "solana"))'.dependencies] +libsecp256k1 = { workspace = true } + +[dev-dependencies] +anyhow = { workspace = true } +borsh = { workspace = true } + +[target.'cfg(not(target_os = "solana"))'.dev-dependencies] +libsecp256k1 = { workspace = true, features = ["hmac"] } + +[build-dependencies] +rustc_version = { workspace = true } + +[features] +borsh = ["dep:borsh"] +frozen-abi = ["dep:solana-frozen-abi", "dep:solana-frozen-abi-macro"] + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] diff --git a/curves/secp256k1-recover/build.rs b/curves/secp256k1-recover/build.rs new file mode 120000 index 00000000000000..84539eddaa6ded --- /dev/null +++ b/curves/secp256k1-recover/build.rs @@ -0,0 +1 @@ +../../frozen-abi/build.rs \ No newline at end of file diff --git a/sdk/program/src/secp256k1_recover.rs b/curves/secp256k1-recover/src/lib.rs similarity index 95% rename from sdk/program/src/secp256k1_recover.rs rename to curves/secp256k1-recover/src/lib.rs index fca67cf6b33ae8..837f2b8cf3aed3 100644 --- a/sdk/program/src/secp256k1_recover.rs +++ b/curves/secp256k1-recover/src/lib.rs @@ -1,3 +1,4 @@ +#![cfg_attr(RUSTC_WITH_SPECIALIZATION, feature(min_specialization))] //! Public key recovery from [secp256k1] ECDSA signatures. //! //! [secp256k1]: https://en.bitcoin.it/wiki/Secp256k1 @@ -21,7 +22,7 @@ //! also provides the [secp256k1 program][sp], which is more flexible, has lower CPU //! cost, and can validate many signatures at once. //! -//! [sp]: crate::secp256k1_program +//! [sp]: https://docs.rs/solana-program/latest/solana_program/secp256k1_program/ //! [`ecrecover`]: https://docs.soliditylang.org/en/v0.8.14/units-and-global-variables.html?highlight=ecrecover#mathematical-and-cryptographic-functions #[cfg(feature = "borsh")] @@ -63,7 +64,7 @@ pub const SECP256K1_SIGNATURE_LENGTH: usize = 64; pub const SECP256K1_PUBLIC_KEY_LENGTH: usize = 64; #[repr(transparent)] -#[cfg_attr(feature = "frozen-abi", derive(AbiExample))] +#[cfg_attr(feature = "frozen-abi", derive(solana_frozen_abi_macro::AbiExample))] #[cfg_attr( feature = "borsh", derive(BorshSerialize, BorshDeserialize, BorshSchema), @@ -85,6 +86,9 @@ impl Secp256k1Pubkey { } } +#[cfg(target_os = "solana")] +solana_define_syscall::define_syscall!(fn sol_secp256k1_recover(hash: *const u8, recovery_id: u64, signature: *const u8, result: *mut u8) -> u64); + /// Recover the public key from a [secp256k1] ECDSA signature and /// cryptographically-hashed message. /// @@ -110,7 +114,7 @@ impl Secp256k1Pubkey { /// "overflowing" signature, and this function returns an error when parsing /// overflowing signatures. /// -/// [`keccak`]: crate::keccak +/// [`keccak`]: https://docs.rs/solana-program/latest/solana_program/keccak/ /// [`wrapping_sub`]: https://doc.rust-lang.org/std/primitive.u8.html#method.wrapping_sub /// /// On success this function returns a [`Secp256k1Pubkey`], a wrapper around a @@ -123,7 +127,7 @@ impl Secp256k1Pubkey { /// the [secp256k1 program][sp], which is more flexible, has lower CPU cost, and /// can validate many signatures at once. /// -/// [sp]: crate::secp256k1_program +/// [sp]: https://docs.rs/solana-program/latest/solana_program/secp256k1_program/ /// /// The `secp256k1_recover` syscall is implemented with the [`libsecp256k1`] /// crate, which clients may also want to use. @@ -161,7 +165,7 @@ impl Secp256k1Pubkey { /// signatures with high-order `S` values. The following code will accomplish /// this: /// -/// ```rust +/// ```rust,ignore /// # use solana_program::program_error::ProgramError; /// # let signature_bytes = [ /// # 0x83, 0x55, 0x81, 0xDF, 0xB1, 0x02, 0xA7, 0xD2, @@ -257,13 +261,13 @@ impl Secp256k1Pubkey { /// The Solana program. Note that it uses `libsecp256k1` version 0.7.0 to parse /// the secp256k1 signature to prevent malleability. /// -/// ```no_run +/// ```rust,ignore /// use solana_program::{ /// entrypoint::ProgramResult, /// keccak, msg, /// program_error::ProgramError, -/// secp256k1_recover::secp256k1_recover, /// }; +/// use solana_secp256k1_recover::secp256k1_recover; /// /// /// The key we expect to sign secp256k1 messages, /// /// as serialized by `libsecp256k1::PublicKey::serialize`. @@ -327,7 +331,7 @@ impl Secp256k1Pubkey { /// /// The RPC client program: /// -/// ```no_run +/// ```rust,ignore /// # use solana_program::example_mocks::solana_rpc_client; /// # use solana_program::example_mocks::solana_sdk; /// use anyhow::Result; @@ -399,7 +403,7 @@ pub fn secp256k1_recover( { let mut pubkey_buffer = [0u8; SECP256K1_PUBLIC_KEY_LENGTH]; let result = unsafe { - crate::syscalls::sol_secp256k1_recover( + sol_secp256k1_recover( hash.as_ptr(), recovery_id as u64, signature.as_ptr(), diff --git a/programs/sbf/Cargo.lock b/programs/sbf/Cargo.lock index 756b752be4edac..25cd1962b230d8 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -5294,7 +5294,6 @@ dependencies = [ "getrandom 0.2.10", "js-sys", "lazy_static", - "libsecp256k1 0.6.0", "log", "memoffset 0.9.0", "num-bigint 0.4.6", @@ -5312,6 +5311,7 @@ dependencies = [ "solana-define-syscall", "solana-sanitize", "solana-sdk-macro", + "solana-secp256k1-recover", "thiserror", "wasm-bindgen", ] @@ -6041,6 +6041,7 @@ version = "2.1.0" dependencies = [ "libsecp256k1 0.7.0", "solana-program", + "solana-secp256k1-recover", ] [[package]] @@ -6150,6 +6151,7 @@ dependencies = [ "solana-program", "solana-sanitize", "solana-sdk-macro", + "solana-secp256k1-recover", "thiserror", "uriparse", "wasm-bindgen", @@ -6165,6 +6167,17 @@ dependencies = [ "syn 2.0.58", ] +[[package]] +name = "solana-secp256k1-recover" +version = "2.1.0" +dependencies = [ + "borsh 1.5.1", + "libsecp256k1 0.6.0", + "rustc_version", + "solana-define-syscall", + "thiserror", +] + [[package]] name = "solana-security-txt" version = "1.1.1" diff --git a/programs/sbf/Cargo.toml b/programs/sbf/Cargo.toml index 0c8da26f7574ae..390b863872a2ef 100644 --- a/programs/sbf/Cargo.toml +++ b/programs/sbf/Cargo.toml @@ -48,6 +48,7 @@ solana-sbf-rust-param-passing-dep = { path = "rust/param_passing_dep", version = solana-sbf-rust-realloc-dep = { path = "rust/realloc_dep", version = "=2.1.0" } solana-sbf-rust-realloc-invoke-dep = { path = "rust/realloc_invoke_dep", version = "=2.1.0" } solana-sdk = { path = "../../sdk", version = "=2.1.0" } +solana-secp256k1-recover = { path = "../../curves/secp256k1-recover", version = "=2.1.0" } solana-svm = { path = "../../svm", version = "=2.1.0" } solana-timings = { path = "../../timings", version = "=2.1.0" } solana-transaction-status = { path = "../../transaction-status", version = "=2.1.0" } diff --git a/programs/sbf/rust/secp256k1_recover/Cargo.toml b/programs/sbf/rust/secp256k1_recover/Cargo.toml index 8a7e473e5b6a65..199558865c1d24 100644 --- a/programs/sbf/rust/secp256k1_recover/Cargo.toml +++ b/programs/sbf/rust/secp256k1_recover/Cargo.toml @@ -11,6 +11,7 @@ edition = { workspace = true } [dependencies] libsecp256k1 = { workspace = true } solana-program = { workspace = true } +solana-secp256k1-recover = { workspace = true } [lib] crate-type = ["cdylib"] diff --git a/programs/sbf/rust/secp256k1_recover/src/lib.rs b/programs/sbf/rust/secp256k1_recover/src/lib.rs index c954dda4144f05..09b239e090a147 100644 --- a/programs/sbf/rust/secp256k1_recover/src/lib.rs +++ b/programs/sbf/rust/secp256k1_recover/src/lib.rs @@ -2,8 +2,9 @@ //! Secp256k1Recover Syscall test extern crate solana_program; -use solana_program::{ - custom_heap_default, custom_panic_default, msg, secp256k1_recover::secp256k1_recover, +use { + solana_program::{custom_heap_default, custom_panic_default, msg}, + solana_secp256k1_recover::secp256k1_recover, }; fn test_secp256k1_recover() { diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index 71a8d24733f4e5..f2e6cc6d7cc2d3 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -34,7 +34,7 @@ full = [ "sha3", "digest", ] -borsh = ["dep:borsh", "solana-program/borsh"] +borsh = ["dep:borsh", "solana-program/borsh", "solana-secp256k1-recover/borsh"] dev-context-only-utils = [ "qualifier_attr" ] @@ -84,6 +84,7 @@ solana-frozen-abi-macro = { workspace = true, optional = true } solana-program = { workspace = true } solana-sanitize = { workspace = true } solana-sdk-macro = { workspace = true } +solana-secp256k1-recover = { workspace = true } thiserror = { workspace = true } uriparse = { workspace = true } diff --git a/sdk/program/Cargo.toml b/sdk/program/Cargo.toml index 430e7d7badfc05..2d2625322f5667 100644 --- a/sdk/program/Cargo.toml +++ b/sdk/program/Cargo.toml @@ -36,6 +36,7 @@ solana-frozen-abi = { workspace = true, optional = true } solana-frozen-abi-macro = { workspace = true, optional = true } solana-sanitize = { workspace = true } solana-sdk-macro = { workspace = true } +solana-secp256k1-recover = { workspace = true } thiserror = { workspace = true } # This is currently needed to build on-chain programs reliably. @@ -56,7 +57,6 @@ ark-serialize = { workspace = true } base64 = { workspace = true, features = ["alloc", "std"] } bitflags = { workspace = true } curve25519-dalek = { workspace = true } -libsecp256k1 = { workspace = true } num-bigint = { workspace = true } rand = { workspace = true } diff --git a/sdk/program/src/lib.rs b/sdk/program/src/lib.rs index 2862aff1854f74..a23b9dcf3696c7 100644 --- a/sdk/program/src/lib.rs +++ b/sdk/program/src/lib.rs @@ -519,7 +519,6 @@ pub mod program_utils; pub mod pubkey; pub mod rent; pub mod secp256k1_program; -pub mod secp256k1_recover; pub mod serde_varint; pub mod serialize_utils; pub mod short_vec; @@ -537,6 +536,8 @@ pub mod wasm; #[deprecated(since = "2.1.0", note = "Use `solana-sanitize` crate instead")] pub use solana_sanitize as sanitize; +#[deprecated(since = "2.1.0", note = "Use `solana-secp256k1-recover` crate instead")] +pub use solana_secp256k1_recover as secp256k1_recover; #[cfg(target_arch = "wasm32")] pub use wasm_bindgen::prelude::wasm_bindgen; diff --git a/sdk/program/src/syscalls/definitions.rs b/sdk/program/src/syscalls/definitions.rs index 5988cbb76d4073..3f50b9d09866f1 100644 --- a/sdk/program/src/syscalls/definitions.rs +++ b/sdk/program/src/syscalls/definitions.rs @@ -1,5 +1,10 @@ #[cfg(target_feature = "static-syscalls")] pub use solana_define_syscall::sys_hash; +#[deprecated( + since = "2.1.0", + note = "Use `solana_secp256k1_recover::sol_secp256k1_recover` instead" +)] +pub use solana_secp256k1_recover::sol_secp256k1_recover; use { crate::{ instruction::{AccountMeta, ProcessedSiblingInstruction}, @@ -16,7 +21,6 @@ define_syscall!(fn sol_create_program_address(seeds_addr: *const u8, seeds_len: define_syscall!(fn sol_try_find_program_address(seeds_addr: *const u8, seeds_len: u64, program_id_addr: *const u8, address_bytes_addr: *const u8, bump_seed_addr: *const u8) -> u64); define_syscall!(fn sol_sha256(vals: *const u8, val_len: u64, hash_result: *mut u8) -> u64); define_syscall!(fn sol_keccak256(vals: *const u8, val_len: u64, hash_result: *mut u8) -> u64); -define_syscall!(fn sol_secp256k1_recover(hash: *const u8, recovery_id: u64, signature: *const u8, result: *mut u8) -> u64); define_syscall!(fn sol_blake3(vals: *const u8, val_len: u64, hash_result: *mut u8) -> u64); define_syscall!(fn sol_memcpy_(dst: *mut u8, src: *const u8, n: u64)); define_syscall!(fn sol_memmove_(dst: *mut u8, src: *const u8, n: u64)); diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 098da40b821efb..c6fbd2e301e6fb 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -52,10 +52,9 @@ pub use solana_program::{ decode_error, ed25519_program, epoch_rewards, epoch_schedule, fee_calculator, impl_sysvar_get, incinerator, instruction, keccak, lamports, loader_instruction, loader_upgradeable_instruction, loader_v4, loader_v4_instruction, message, msg, native_token, nonce, program, program_error, - program_memory, program_option, program_pack, rent, secp256k1_program, secp256k1_recover, - serde_varint, serialize_utils, short_vec, slot_hashes, slot_history, stable_layout, stake, - stake_history, syscalls, system_instruction, system_program, sysvar, unchecked_div_by_const, - vote, + program_memory, program_option, program_pack, rent, secp256k1_program, serde_varint, + serialize_utils, short_vec, slot_hashes, slot_history, stable_layout, stake, stake_history, + syscalls, system_instruction, system_program, sysvar, unchecked_div_by_const, vote, }; #[cfg(feature = "borsh")] pub use solana_program::{borsh, borsh0_10, borsh1}; @@ -155,6 +154,8 @@ pub use solana_sdk_macro::declare_id; pub use solana_sdk_macro::pubkey; /// Convenience macro to define multiple static public keys. pub use solana_sdk_macro::pubkeys; +#[deprecated(since = "2.1.0", note = "Use `solana-secp256k1-recover` crate instead")] +pub use solana_secp256k1_recover as secp256k1_recover; /// Convenience macro for `AddAssign` with saturating arithmetic. /// Replace by `std::num::Saturating` once stable