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

v2.1: SIMD-0075: Precompile for Secp256r1 (backport of #3152) #3662

Merged
merged 2 commits into from
Nov 15, 2024
Merged
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
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
Loading