Skip to content

Commit

Permalink
v2.1: SIMD-0075: Precompile for Secp256r1 (backport of #3152) (#3662)
Browse files Browse the repository at this point in the history
* SIMD-0075: Precompile for Secp256r1 (#3152)

* feat: secp256r1 precompile

* add: num_signatures == 0 check from SIMD-0152

* rm: unnecessary comment

* fix: legacy numeric constant

* CI/fix: compilation for wasm32 target

* Extract secp256r1 crate

* rm: unnecessary import

* update: sbf/Cargo.lock

* rm: unnecesary re-exports

* add: secp256r1 precompile to docs

* add: docs/description to sdk/program/src/lib.rs

* fix: alpha sort deps

* fixes

* docs fixes

* add: solana-instruction std feature to deps

* fix: lockfile from rebase

* fix: target architecture

* fix: workflow for client_target android

* add: sudo to workflow perl install

* fix: Cargo toml workspace member

* modify: ranlib path in client-targets.yaml

* fix: secp256r1/Cargo.toml formatting

* add: openssl feature

* fixes

* add: precompile signature range error

* more adjustments

* change: feature id

* fix: cargo format

* Revert "add: precompile signature range error"

This reverts commit fdf7673.

* fix: cargo sanity

* fix: client target openssl dep

* fix: 31 byte r,s support in new_secp256r1_instruction

* update: Cargo.lock

* fix: unchecked math in new_secp256r1_instruction

* fixes & increased test coverage

* add: solana-sdk/openssl to all release binaries

* update: comment to make openssl feature more clear

* add: solana-sdk/openssl feature to dependencies

* add: solana-sdk/openssl feature to dependencies

* merge: master into secp256r1-precompile

* fix: test-validator formatting

* Revert "add: solana-sdk/openssl to all release binaries"

This reverts commit 5c66b50.

* add: reserved key for secp256r1 program

* modify: client-targets.yaml

* modify: client/Cargo.toml solana-sdk dep

* modify: ledger-tool/Cargo.toml solana-sdk

* modify: test-validator/Cargo.toml solana-sdk dep

* modify: validator/Cargo.toml solana-sdk dep

* change: openssl feature to openssl-vendored

* remove: solana-sdk dep from sdk/program

* refactor: secp256r1 directory name

* fmt

* cargo.lock files

* revert: rustc-demangle bump

* cargo lock sanity

* fix: faulty feature-set merge

* fix: reserved keys pending feature id

---------

Co-authored-by: Iceomatic <[email protected]>
(cherry picked from commit da4f55e)

# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	ledger-tool/Cargo.toml
#	programs/sbf/Cargo.lock
#	sdk/Cargo.toml
#	sdk/feature-set/src/lib.rs
#	sdk/reserved-account-keys/Cargo.toml
#	sdk/src/reserved_account_keys.rs

* Fix merge conflicts

---------

Co-authored-by: Orion <[email protected]>
Co-authored-by: Jon C <[email protected]>
  • Loading branch information
3 people authored Nov 15, 2024
1 parent 34e62d6 commit adeac02
Show file tree
Hide file tree
Showing 15 changed files with 909 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/client-targets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ jobs:
steps:
- uses: actions/checkout@v4

# This can be removed once cargo-ndk >= 3.5.4 is used.
- name: Setup environment for Android NDK
run: |
echo "RANLIB=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-ranlib" >> $GITHUB_ENV
- run: cargo install [email protected]

- name: Setup Rust
Expand Down
15 changes: 15 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 @@ -135,6 +135,7 @@ members = [
"sdk/pubkey",
"sdk/rent",
"sdk/sanitize",
"sdk/secp256r1-program",
"sdk/serde-varint",
"sdk/serialize-utils",
"sdk/sha256-hasher",
Expand Down Expand Up @@ -475,6 +476,7 @@ solana-rayon-threadlimit = { path = "rayon-threadlimit", version = "=2.1.1" }
solana-remote-wallet = { path = "remote-wallet", version = "=2.1.1", default-features = false }
solana-rent = { path = "sdk/rent", version = "=2.1.1", default-features = false }
solana-sanitize = { path = "sdk/sanitize", version = "=2.1.1" }
solana-secp256r1-program = { path = "sdk/secp256r1-program", version = "=2.1.1", default-features = false }
solana-serde-varint = { path = "sdk/serde-varint", version = "=2.1.1" }
solana-serialize-utils = { path = "sdk/serialize-utils", version = "=2.1.1" }
solana-sha256-hasher = { path = "sdk/sha256-hasher", version = "=2.1.1" }
Expand Down
2 changes: 1 addition & 1 deletion client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ solana-quic-client = { workspace = true }
solana-rpc-client = { workspace = true, features = ["default"] }
solana-rpc-client-api = { workspace = true }
solana-rpc-client-nonce-utils = { workspace = true }
solana-sdk = { workspace = true }
solana-sdk = { workspace = true, features = ["openssl-vendored"] }
solana-streamer = { workspace = true }
solana-thin-client = { workspace = true }
solana-tpu-client = { workspace = true, features = ["default"] }
Expand Down
65 changes: 65 additions & 0 deletions docs/src/runtime/programs.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,71 @@ also receive data from the transaction itself.
Cost of the transaction will count the number of signatures to verify multiplied
by the signature cost verify multiplier.

## Secp256r1 Program

The program for verifying secp256r1 signatures. It takes a secp256r1 signature,
a public key, and a message. Up to 8 signatures can be verified. If any of the
signatures fail to verify, an error is returned.

- Program id: `Secp256r1SigVerify1111111111111111111111111`
- Instructions: [secp256r1_instruction](https://docs.rs/solana-secp256r1)

The secp256r1 program processes an instruction. The first `u8` is a count of the number of signatures to check, followed by a single byte padding. After that, the following struct is serialized, one for each signature to check:

```rust
struct Secp256r1SignatureOffsets {
signature_offset: u16, // offset to compact secp256r1 signature of 64 bytes
signature_instruction_index: u16, // instruction index to find signature
public_key_offset: u16, // offset to compressed public key of 33 bytes
public_key_instruction_index: u16, // instruction index to find public key
message_data_offset: u16, // offset to start of message data
message_data_size: u16, // size of message data
message_instruction_index: u16, // index of instruction data to get message data
}

```

The pseudo code of the signature verification:
```
process_instruction() {
if data.len() < SIGNATURE_OFFSETS_START {
return Error
}
num_signatures = data[0] as usize
if num_signatures == 0 || num_signatures > 8 {
return Error
}
expected_data_size = num_signatures * SIGNATURE_OFFSETS_SERIALIZED_SIZE + SIGNATURE_OFFSETS_START
if data.len() < expected_data_size {
return Error
}
for i in 0..num_signatures {
offsets = parse_signature_offsets(data, i)
signature = get_data_slice(data, instruction_datas, offsets.signature_instruction_index, offsets.signature_offset, SIGNATURE_SERIALIZED_SIZE)
if s > half_curve_order {
return Error
}
pubkey = get_data_slice(data, instruction_datas, offsets.public_key_instruction_index, offsets.public_key_offset, COMPRESSED_PUBKEY_SERIALIZED_SIZE)
message = get_data_slice(data, instruction_datas, offsets.message_instruction_index, offsets.message_data_offset, offsets.message_data_size)
if !verify_signature(signature, pubkey, message) {
return Error
}
}
return Success
}
```
Note: Low S values are enforced for all signatures to avoid accidental signature
malleability.

### Optimization notes

The operation will have to take place after (at least partial) deserialization,
Expand Down
2 changes: 1 addition & 1 deletion ledger-tool/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ solana-measure = { workspace = true }
solana-program-runtime = { workspace = true }
solana-rpc = { workspace = true }
solana-runtime = { workspace = true, features = ["dev-context-only-utils"] }
solana-sdk = { workspace = true }
solana-sdk = { workspace = true, features = ["openssl-vendored"] }
solana-stake-program = { workspace = true }
solana-storage-bigtable = { workspace = true }
solana-streamer = { workspace = true }
Expand Down
13 changes: 13 additions & 0 deletions programs/sbf/Cargo.lock

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

3 changes: 3 additions & 0 deletions sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ frozen-abi = [
"solana-signature/frozen-abi",
"solana-transaction-error/frozen-abi"
]
# Enables the "vendored" feature of openssl inside of secp256r1-program
openssl-vendored = ["solana-secp256r1-program/openssl-vendored"]

[dependencies]
bincode = { workspace = true }
Expand Down Expand Up @@ -111,6 +113,7 @@ solana-pubkey = { workspace = true, default-features = false, features = ["std"]
solana-sanitize = { workspace = true }
solana-sdk-macro = { workspace = true }
solana-secp256k1-recover = { workspace = true }
solana-secp256r1-program = { workspace = true, default-features = false }
solana-serde-varint = { workspace = true }
solana-short-vec = { workspace = true }
solana-signature = { workspace = true, features = [
Expand Down
5 changes: 5 additions & 0 deletions sdk/feature-set/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,10 @@ pub mod disable_account_loader_special_case {
solana_pubkey::declare_id!("EQUMpNFr7Nacb1sva56xn1aLfBxppEoSBH8RRVdkcD1x");
}

pub mod enable_secp256r1_precompile {
solana_pubkey::declare_id!("sr11RdZWgbHTHxSroPALe6zgaT5A1K9LcE4nfsZS4gi");
}

lazy_static! {
/// Map of feature identifiers to user-visible description
pub static ref FEATURE_NAMES: HashMap<Pubkey, &'static str> = [
Expand Down Expand Up @@ -1086,6 +1090,7 @@ lazy_static! {
(disable_sbpf_v1_execution::id(), "Disables execution of SBPFv1 programs"),
(reenable_sbpf_v1_execution::id(), "Re-enables execution of SBPFv1 programs"),
(disable_account_loader_special_case::id(), "Disable account loader special case #3513"),
(enable_secp256r1_precompile::id(), "Enable secp256r1 precompile SIMD-0075"),
/*************** ADD NEW FEATURES HERE ***************/
]
.iter()
Expand Down
36 changes: 36 additions & 0 deletions sdk/secp256r1-program/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[package]
name = "solana-secp256r1-program"
description = "Precompile implementation for the secp256r1 elliptic curve."
documentation = "https://docs.rs/solana-secp256r1"
version = { workspace = true }
authors = { workspace = true }
repository = { workspace = true }
homepage = { workspace = true }
license = { workspace = true }
edition = { workspace = true }

[dependencies]
bytemuck = { workspace = true, features = ["derive"] }
solana-feature-set = { workspace = true }
solana-precompile-error = { workspace = true }
solana-pubkey = { workspace = true }

[target.'cfg(all(not(target_arch = "wasm32"), not(target_os = "solana")))'.dependencies]
solana-instruction = { workspace = true, features = ["std"] }
openssl = { workspace = true }

[dev-dependencies]
solana-logger = { workspace = true }
solana-sdk = { path = "../" }

[features]
default = []
openssl-vendored = ["openssl/vendored"]

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
all-features = true
rustdoc-args = ["--cfg=docsrs"]

[lints]
workspace = true
Loading

0 comments on commit adeac02

Please sign in to comment.