From 02fcab993958031c5bedd671cedfab6f9b1527a9 Mon Sep 17 00:00:00 2001
From: Orion <89707822+iceomatic@users.noreply.github.com>
Date: Wed, 25 Oct 2023 02:38:29 +0200
Subject: [PATCH 01/39] Update and rename
0048-native-program-for-secp256r1-sigverify.md to
0048-precompile-for-secp256r1-sigverify.md
Add specification & detail
Add new security considerations
---
...-native-program-for-secp256r1-sigverify.md | 149 -----------
...0048-precompile-for-secp256r1-sigverify.md | 235 ++++++++++++++++++
2 files changed, 235 insertions(+), 149 deletions(-)
delete mode 100644 proposals/0048-native-program-for-secp256r1-sigverify.md
create mode 100644 proposals/0048-precompile-for-secp256r1-sigverify.md
diff --git a/proposals/0048-native-program-for-secp256r1-sigverify.md b/proposals/0048-native-program-for-secp256r1-sigverify.md
deleted file mode 100644
index 733cf5938..000000000
--- a/proposals/0048-native-program-for-secp256r1-sigverify.md
+++ /dev/null
@@ -1,149 +0,0 @@
----
-simd: "0048"
-title: Native Program for verifying secp256r1 sig.
-authors:
- - Orion (Bunkr)
- - Jstnw (Bunkr)
-category: Standard
-type: Core
-status: Draft
-created: 2023-05-14
-feature: (fill in with feature tracking issues once accepted)
----
-
-## Summary
-
-Adding a Native Program to support the verification of signatures
-generated on the secp256r1 curve.
-Analogous to the support for secp256k1 and ed25519 signatures that already
-exists in form of
-the `KeccakSecp256k11111111111111111111111111111` and
-`Ed25519SigVerify111111111111111111111111111`
-native programs
-
-## Motivation
-
-Solana should have option to secure your funds in a self custodial manner that
-doesn't just airgap your private key with a hardware wallet (which even then
-remains as a single point of failure). Arguably, multi-signature wallets fit
-into this equation as they enable the dependency on multiple private keys.
-However in practice the UX takes too much of a hit, as having to sign a
-transaction a minimum of 3 seperate times and having to write down 3 seed
-phrases is too cumbersome. It would be ideal to have an authetication form that
-relies on a more familiar second factor, such as a users mobile device.
-
-Passkeys & WebAuthn are a standardized implementation of this. They enable users
-to save keypairs associated to different services natively on the secure
-element of their mobile device. To authenticate with those services, the user
-uses their biometrics to sign a message with the stored private key.
-
-And although this is meant to enable password-less logins in web2, it makes for
-an excellent candidate as a second factor of on-chain authentication.
-
-Going past just securing funds, this would support other beneficial account
-abstractions that make use of the simple UX of WebAuthn and Passkeys.
-
-Note:
-
-Although WebAuthn supports the following curves:
-
-- P-256
-- P-384
-- P-521
-- ed25519
-
-P-256 is the only one suported by both Android & IOS (IOS being the more
-restrictive of the two), hence the goal being to implement secp256r1 signature
-verification
-
-General Documentation:
-
-[WebAuthn](https://webauthn.io/)
-
-[Passkeys](https://fidoalliance.org/passkeys/)
-
-## Alternatives Considered
-
-We have discussed the following alternatives:
-
-1.) Realising signature verification with a syscall similar
-to `secp256k1_recover()` instead of a native program. This would ease
-integration for developers, since no instruction introspection would be
-required when utilizing the syscall.
-
-## New Terminology
-
-None
-
-## Detailed Design
-
-Implementation would be as follows:
-
-### Program
-
-ID: `Secp256r1SigVerify1111111111111111111111111`
-
-The program instruction will be composed of the following:
-
-- A first u8 as the count for the number of signatures to check
-- Single byte of padding
-- The following struct serialized, for each signature to verify
-
-
-```rust
-struct Secp256r1SignatureOffsets {
- signature_offset: u16, // offset to secp256r1 signature of 64 bytes
- signature_instruction_index: u16, // instruction index to find signature
- public_key_offset: u16, // offset to public key of 32 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 msg data
-}
-```
-
-Multiple signatures can be verified. If any of the signatures fail to verify,
-an error is returned.
-
-Should be analogous to `KeccakSecp256k11111111111111111111111111111`
-and `Ed25519SigVerify111111111111111111111111111`.
-View reference details at [sdk/src/ed25519_instruction.rs](https://github.com/solana-labs/solana/blob/master/sdk/src/ed25519_instruction.rs)
-
-### Implementation
-
-The crates `ecdsa` and `p256` are a good starting point for the implementation.
-Due to a current dependency version conflict of `zeroize` between
-`curve25519-dalek` and `solana-program`, using these crates will require a
-fix/bump of `zeroize` inside `curve25519-dalek`. See issue [#26688](https://github.com/solana-labs/solana/issues/26688)
-
-### Compute Cost
-
-Once the implementation is finished, benchmarking should take place on a
-sufficiently powerful machine in order to determine average compute time.
-Pricing would be based on the 33ns/CU convention. For
-the sake of ensuring proper efficiency, a comparison to similar implementations
-on polygon/optimism/ethereum would be conducted.
-
-This is in line with how previous native programs for EC group operations and
-arithmetic were evaluated/benchmarked.
-See [PR#27961](https://github.com/solana-labs/solana/pull/27961) & [PR#28503](https://github.com/solana-labs/solana/pull/28503)
-
-## Impact
-
-Would enable the on-chain usage of Passkeys and the WebAuthn Standard.
-
-By extension this would also enable the creation of account abstractions and
-forms of Two-Factor Authentication around those keypairs.
-
-## Security Considerations
-
-- Ensure parity of test results and parameters with those found in
- [SEC2](https://www.secg.org/sec2-v2.pdf) for the secp256r1 curve
-- Ensure signature malleability is prevented/accounted for
-
-## Backwards Compatibility
-
-Transactions using the instruction could not be used on Solana versions which don't
-implement this feature. A Feature gate should be used to enable this feature
-when the majority of the cluster is using the required version. Transactions
-that do not use this feature are not impacted.
diff --git a/proposals/0048-precompile-for-secp256r1-sigverify.md b/proposals/0048-precompile-for-secp256r1-sigverify.md
new file mode 100644
index 000000000..65e0b63e5
--- /dev/null
+++ b/proposals/0048-precompile-for-secp256r1-sigverify.md
@@ -0,0 +1,235 @@
+---
+simd: "0048"
+title: Precompile for verifying secp256r1 sig.
+authors:
+ - Orion (Bunkr)
+ - Jstnw (Bunkr)
+category: Standard
+type: Core
+status: Draft
+created: 2023-05-14
+feature: (fill in with feature tracking issues once accepted)
+---
+
+## Summary
+
+Adding a Precompile to support the verification of signatures
+generated on the secp256r1 curve.
+Analogous to the support for secp256k1 and ed25519 signatures that already
+exists in form of
+the `KeccakSecp256k11111111111111111111111111111` and
+`Ed25519SigVerify111111111111111111111111111`
+precompiles
+
+## Motivation
+
+Solana should have option to secure your funds in a self custodial manner that
+doesn't just airgap your private key with a hardware wallet (which even then
+remains as a single point of failure). Arguably, multi-signature wallets fit
+into this equation as they enable the dependency on multiple private keys.
+However in practice the UX takes too much of a hit, as having to sign a
+transaction a minimum of 3 separate times and having to write down 3 seed
+phrases is too cumbersome. It would be ideal to have an authentication form that
+relies on a more familiar second factor, such as a users mobile device.
+
+Passkeys & WebAuthn are a standardized implementation of this. They enable users
+to save keypairs associated to different services natively on the secure
+element of their mobile device. To authenticate with those services, the user
+uses their biometrics to sign a message with the stored private key.
+
+And although this is meant to enable password-less logins in web2, it makes for
+an excellent candidate as a second factor of on-chain authentication.
+
+Going past just securing funds, this would support other beneficial account
+abstractions that make use of the simple UX of WebAuthn and Passkeys.
+
+Note:
+
+Although WebAuthn supports the following curves:
+
+- P-256
+- P-384
+- P-521
+- ed25519
+
+P-256 is the only one supported by both Android & IOS (IOS being the more
+restrictive of the two), hence the goal being to implement secp256r1 signature
+verification
+
+General Documentation:
+
+[WebAuthn](https://webauthn.io/)
+
+[Passkeys](https://fidoalliance.org/passkeys/)
+
+## Alternatives Considered
+
+We have discussed the following alternatives:
+
+1.) Realising signature verification with a syscall similar
+to `secp256k1_recover()` instead of a precompile. This would ease
+integration for developers, since no instruction introspection would be
+required when utilizing the syscall.
+
+## New Terminology
+
+None
+
+## Detailed Design
+
+The precompile's purpose is to verify signatures using ECDSA-256.
+(denoted in [RFC6460](https://www.ietf.org/rfc/rfc6460.txt) as
+ECDSA using the NIST P-256 curve and the SHA-256 hashing algorithm)
+
+### Curve
+
+The curve parameters for NIST P-256/secp256r1/prime256v1 are
+outlined in the [SEC2](https://www.secg.org/SEC2-Ver-1.0.pdf#page=21)
+document in Section 2.7.2
+
+### Point Encoding/Decoding:
+
+The precompile should accept SEC1 encoded points in compressed form.
+The encoding and decoding of these is outlined in sections
+`2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion`
+and `2.3.4 Octet-String-to-Elliptic-Curve-Point Conversion`
+found in [SEC1](https://www.secg.org/sec1-v2.pdf#page=16).
+
+The SEC1 encoded EC point P = (xp, yp)
+in compressed form consists of 33 bytes (octets).
+The first byte 0216 / 03 16 signifies
+whether the point is compressed or uncompressed as well as
+signifying the odd or even state of yp. The
+remaining 32 bytesrepresent xp converted
+into a 32 octet string.
+
+SEC1 endcoded uncompressed points, which consist of 65 bytes,
+have been deliberately disregarded as yp is not needed
+during signature verification and it seems sensible to save 32
+bytes of transaction space.
+
+**Note:** The existing precompiles for secp256k1 & ed25519 utilize
+just xp encoded as an octet string. This saves one byte
+compared to using a compressed point, but fails to conform to any standard.
+
+### ECDSA / Signature Verification
+
+The precompile should implement the `Verifying Operation` outlined in
+[SEC1](https://www.secg.org/sec1-v2.pdf#page=52)
+in Section 4.1.4 as well as in the
+[Digital Signature Standard (DSS)](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf#page=36)
+document in Section 6.4.2.
+
+A multitude of test vectors to verify correctness can
+be found in [RFC6979 Deterministic DSA and ECDSA](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5)
+in Section A.2.5 as well as at the
+[NIST Cryptographic Algorithm Validation Program](https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/digital-signatures#ecdsa2vs)
+
+
+### Signature Malleability
+
+As any signature `s = (R,S)` generated with ECDSA is malleable
+in regards to the `S` value, the precompile should enforce the usage
+of `lowS` values, in which `S < n/2` where `n` is the order of
+the elliptic curve.
+It should fail on any signatures that include a `highS` value.
+
+This should done to prevent any accidental succeptibility to
+signature malleability attacks.
+
+Note: The existing secp256k1 precompile does not prevent signature malleability
+
+### Program
+
+ID: `Secp256r1SigVerify1111111111111111111111111`
+
+The program instruction will be composed of the following:
+
+- A first u8 as the count for the number of signatures to check
+- Single byte of padding
+- The following struct serialized, for each signature to verify
+
+
+```rust
+struct Secp256r1SignatureOffsets {
+ signature_offset: u16, // offset to 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 msg data
+}
+```
+
+Multiple signatures can be verified. If any of the signatures fail to verify,
+an error is returned.
+
+The program logic will be constructed and built using a `verify`
+function, as outlined in
+[sdk/src/precompiles.rs](https://github.com/solana-labs/solana/blob/9ffbe2afd8ab5b972c4ad87d758866a3e1bb87fb/sdk/src/precompiles.rs).
+
+Apart from the signature verification, the remaining
+logic should be constructed analogously to the existing
+[ed25519](https://github.com/solana-labs/solana/blob/master/sdk/src/ed25519_instruction.rs)
+& [secp256k1](https://github.com/solana-labs/solana/blob/9ffbe2afd8ab5b972c4ad87d758866a3e1bb87fb/sdk/src/secp256k1_instruction.rs#L4)
+precompiles.
+
+### Implementation
+
+The precompile can be implemented using the `p256` crate at version `0.10.1`.
+This crate is part of the `Rust Crypto` library and implements
+the NIST P-256 curve as well as ECDSA.
+It conforms with the test vectors found in [RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5).
+
+The precompile would make use of the following to accomplish signature
+verification:
+
+- `p256::ecdsa::VerifyingKey::from_sec1_bytes()`
+- `p256::ecdsa::Signature::from_scalars()`
+- `p256::arithmetic::Scalar::is_high()`
+- `p256::ecdsa::VerifyingKey::verify()`
+
+Note: The crate is well maintained, but has never been externally audited.
+
+### Compute Cost
+
+Once the implementation is finished, benchmarking should take place on a
+sufficiently powerful machine in order to determine average compute time.
+Pricing would be based on the 33ns/CU convention. For
+the sake of ensuring proper efficiency, a comparison to similar implementations
+on polygon/optimism/ethereum would be conducted.
+
+This is in line with how previous precompiles for EC group operations and
+arithmetic were evaluated/benchmarked.
+See [PR#27961](https://github.com/solana-labs/solana/pull/27961) & [PR#28503](https://github.com/solana-labs/solana/pull/28503)
+
+## Impact
+
+Would enable the on-chain usage of Passkeys and the WebAuthn Standard.
+
+By extension this would also enable the creation of account abstractions and
+forms of Two-Factor Authentication around those keypairs.
+
+## Security Considerations
+
+As [Firedancer](https://github.com/firedancer-io/firedancer) is being developed
+in C, it is imperative that there can be bit-level reproducibility between
+the precompile implementations. Any discrepancy between the two implementations
+could cause a fork and or a chain halt. (Thank you @fd-ripatel for pointing this
+out and advocating for it)
+
+As such we would propose the following:
+
+- Development of a thorough test suite that includes all test vectors as well as tests
+from the [Wycheproof Project](https://github.com/google/wycheproof#project-wycheproof)
+
+- Thorough auditing as well as a formal verification of the arithmetic and
+decoding inside the `p256` crate
+
+## Backwards Compatibility
+
+Transactions using the instruction could not be used on Solana versions which don't
+implement this feature. A Feature gate should be used to enable this feature
+when the majority of the cluster is using the required version. Transactions
+that do not use this feature are not impacted.
From b505749d2dbe3232e212f04ea34249cf43bf6060 Mon Sep 17 00:00:00 2001
From: Orion <89707822+iceomatic@users.noreply.github.com>
Date: Wed, 25 Oct 2023 02:47:34 +0200
Subject: [PATCH 02/39] linting
---
.../0048-precompile-for-secp256r1-sigverify.md | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/proposals/0048-precompile-for-secp256r1-sigverify.md b/proposals/0048-precompile-for-secp256r1-sigverify.md
index 65e0b63e5..cb24039d0 100644
--- a/proposals/0048-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0048-precompile-for-secp256r1-sigverify.md
@@ -95,21 +95,21 @@ The encoding and decoding of these is outlined in sections
and `2.3.4 Octet-String-to-Elliptic-Curve-Point Conversion`
found in [SEC1](https://www.secg.org/sec1-v2.pdf#page=16).
-The SEC1 encoded EC point P = (xp, yp)
+The SEC1 encoded EC point P = (x_p, y_p)
in compressed form consists of 33 bytes (octets).
-The first byte 0216 / 03 16 signifies
+The first byte 02_16 / 03_16 signifies
whether the point is compressed or uncompressed as well as
-signifying the odd or even state of yp. The
-remaining 32 bytesrepresent xp converted
+signifying the odd or even state of y_p. The
+remaining 32 bytesrepresent x_p converted
into a 32 octet string.
SEC1 endcoded uncompressed points, which consist of 65 bytes,
-have been deliberately disregarded as yp is not needed
+have been deliberately disregarded as y_p is not needed
during signature verification and it seems sensible to save 32
bytes of transaction space.
**Note:** The existing precompiles for secp256k1 & ed25519 utilize
-just xp encoded as an octet string. This saves one byte
+just x_p encoded as an octet string. This saves one byte
compared to using a compressed point, but fails to conform to any standard.
### ECDSA / Signature Verification
@@ -121,9 +121,10 @@ in Section 4.1.4 as well as in the
document in Section 6.4.2.
A multitude of test vectors to verify correctness can
-be found in [RFC6979 Deterministic DSA and ECDSA](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5)
+be found in [RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5)
in Section A.2.5 as well as at the
-[NIST Cryptographic Algorithm Validation Program](https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/digital-signatures#ecdsa2vs)
+[NIST CAVP](https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/digital-signatures#ecdsa2vs)
+(Cryptographic Algorithm Validation Program)
### Signature Malleability
From a9aa10d5acbac53a3c48984217b26e08d1ac2978 Mon Sep 17 00:00:00 2001
From: Orion <89707822+iceomatic@users.noreply.github.com>
Date: Wed, 25 Oct 2023 02:50:37 +0200
Subject: [PATCH 03/39] linting
---
proposals/0048-precompile-for-secp256r1-sigverify.md | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/proposals/0048-precompile-for-secp256r1-sigverify.md b/proposals/0048-precompile-for-secp256r1-sigverify.md
index cb24039d0..71eb9c7de 100644
--- a/proposals/0048-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0048-precompile-for-secp256r1-sigverify.md
@@ -121,7 +121,8 @@ in Section 4.1.4 as well as in the
document in Section 6.4.2.
A multitude of test vectors to verify correctness can
-be found in [RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5)
+be found in
+[RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5)
in Section A.2.5 as well as at the
[NIST CAVP](https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/digital-signatures#ecdsa2vs)
(Cryptographic Algorithm Validation Program)
@@ -181,7 +182,8 @@ precompiles.
The precompile can be implemented using the `p256` crate at version `0.10.1`.
This crate is part of the `Rust Crypto` library and implements
the NIST P-256 curve as well as ECDSA.
-It conforms with the test vectors found in [RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5).
+It conforms with the test vectors found in
+[RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5).
The precompile would make use of the following to accomplish signature
verification:
@@ -222,8 +224,9 @@ out and advocating for it)
As such we would propose the following:
-- Development of a thorough test suite that includes all test vectors as well as tests
-from the [Wycheproof Project](https://github.com/google/wycheproof#project-wycheproof)
+- Development of a thorough test suite that includes all test vectors as well
+as tests from the
+[Wycheproof Project](https://github.com/google/wycheproof#project-wycheproof)
- Thorough auditing as well as a formal verification of the arithmetic and
decoding inside the `p256` crate
From 5555370d76a3172d9474b4bb5116a121fbc0c9ff Mon Sep 17 00:00:00 2001
From: Orion <89707822+iceomatic@users.noreply.github.com>
Date: Wed, 25 Oct 2023 02:57:04 +0200
Subject: [PATCH 04/39] spelling
---
proposals/0048-precompile-for-secp256r1-sigverify.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/proposals/0048-precompile-for-secp256r1-sigverify.md b/proposals/0048-precompile-for-secp256r1-sigverify.md
index 71eb9c7de..20c45f157 100644
--- a/proposals/0048-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0048-precompile-for-secp256r1-sigverify.md
@@ -136,7 +136,7 @@ of `lowS` values, in which `S < n/2` where `n` is the order of
the elliptic curve.
It should fail on any signatures that include a `highS` value.
-This should done to prevent any accidental succeptibility to
+This should be done to prevent any accidental succeptibility to
signature malleability attacks.
Note: The existing secp256k1 precompile does not prevent signature malleability
From afd0c4f8b5357232c882810b777637d8bf319a4e Mon Sep 17 00:00:00 2001
From: Orion <89707822+iceomatic@users.noreply.github.com>
Date: Wed, 25 Oct 2023 03:01:16 +0200
Subject: [PATCH 05/39] spelling
---
proposals/0048-precompile-for-secp256r1-sigverify.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/proposals/0048-precompile-for-secp256r1-sigverify.md b/proposals/0048-precompile-for-secp256r1-sigverify.md
index 20c45f157..76bc754d1 100644
--- a/proposals/0048-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0048-precompile-for-secp256r1-sigverify.md
@@ -219,7 +219,7 @@ forms of Two-Factor Authentication around those keypairs.
As [Firedancer](https://github.com/firedancer-io/firedancer) is being developed
in C, it is imperative that there can be bit-level reproducibility between
the precompile implementations. Any discrepancy between the two implementations
-could cause a fork and or a chain halt. (Thank you @fd-ripatel for pointing this
+could cause a fork and or a chain halt. (Thank you @ripatel-fd for pointing this
out and advocating for it)
As such we would propose the following:
From 403625eb431ba50dbc4f2bcb0b214a0d37170465 Mon Sep 17 00:00:00 2001
From: aresastro
Date: Wed, 25 Oct 2023 15:41:44 +0800
Subject: [PATCH 06/39] Fixed wording and technical documentation
---
...0048-precompile-for-secp256r1-sigverify.md | 128 +++++++++++-------
1 file changed, 77 insertions(+), 51 deletions(-)
diff --git a/proposals/0048-precompile-for-secp256r1-sigverify.md b/proposals/0048-precompile-for-secp256r1-sigverify.md
index 76bc754d1..5f791fe4f 100644
--- a/proposals/0048-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0048-precompile-for-secp256r1-sigverify.md
@@ -13,7 +13,7 @@ feature: (fill in with feature tracking issues once accepted)
## Summary
-Adding a Precompile to support the verification of signatures
+Adding a precompile to support the verification of signatures
generated on the secp256r1 curve.
Analogous to the support for secp256k1 and ed25519 signatures that already
exists in form of
@@ -23,25 +23,27 @@ precompiles
## Motivation
-Solana should have option to secure your funds in a self custodial manner that
-doesn't just airgap your private key with a hardware wallet (which even then
-remains as a single point of failure). Arguably, multi-signature wallets fit
-into this equation as they enable the dependency on multiple private keys.
-However in practice the UX takes too much of a hit, as having to sign a
-transaction a minimum of 3 separate times and having to write down 3 seed
-phrases is too cumbersome. It would be ideal to have an authentication form that
-relies on a more familiar second factor, such as a users mobile device.
-
-Passkeys & WebAuthn are a standardized implementation of this. They enable users
-to save keypairs associated to different services natively on the secure
-element of their mobile device. To authenticate with those services, the user
-uses their biometrics to sign a message with the stored private key.
-
-And although this is meant to enable password-less logins in web2, it makes for
-an excellent candidate as a second factor of on-chain authentication.
-
-Going past just securing funds, this would support other beneficial account
-abstractions that make use of the simple UX of WebAuthn and Passkeys.
+Solana has the opportunity to leverage the secure element of users' existing
+mobile devices to support more user-friendly self-custodial security solutions.
+The status quo of air-gapping signing with a hardware wallet currently requires
+specialty hardware and still represents a single point of failure. Multi-signature
+wallets provide enhanced security through multi-party signing, however the UX
+is cumbersome due to the need to sign transactions multiple times and manage
+multiple seed phrases. A much more ergonomic approach combining the best of
+these two solutions on generalised mobile hardware could be achieved by adding
+support for secp256r1 signatures.
+
+There are already several standardised implementations of this, such as Passkeys
+and WebAuthn. These solutions leverage Apple's Secure Enclave and Android Keystore
+to enable users to save keypairs associated to different services natively on
+the secure element of their mobile devices. To authenticate with those services,
+the user uses their biometrics to sign a message with the stored private key.
+
+While originally intended to solve for password-less authentication in Web2
+applications, WebAuthn and Passkeys also make an excellent candidate for on-chain
+second-factor authentication. Beyond simply securing funds, there are also many
+other potential beneficial abstractions that could make use of the simple UX
+they provide.
Note:
@@ -52,7 +54,7 @@ Although WebAuthn supports the following curves:
- P-521
- ed25519
-P-256 is the only one supported by both Android & IOS (IOS being the more
+P-256 is the only one supported by both Android & MacOS/iOS (MacOS/iOS being the more
restrictive of the two), hence the goal being to implement secp256r1 signature
verification
@@ -69,7 +71,14 @@ We have discussed the following alternatives:
1.) Realising signature verification with a syscall similar
to `secp256k1_recover()` instead of a precompile. This would ease
integration for developers, since no instruction introspection would be
-required when utilizing the syscall.
+required when utilizing the syscall. This is still a valid consideration.
+
+2.) Allowing for high-S signatures was considered, however the pitfalls
+of signature malleability are too great to leave open to implementation.
+
+3.) Allowing for uncompressed keys was considered, however as we are already
+taking an opinionated stance on signature malleability, it makes sense to
+also take an opinionated stance on public key encoding.
## New Terminology
@@ -95,22 +104,29 @@ The encoding and decoding of these is outlined in sections
and `2.3.4 Octet-String-to-Elliptic-Curve-Point Conversion`
found in [SEC1](https://www.secg.org/sec1-v2.pdf#page=16).
-The SEC1 encoded EC point P = (x_p, y_p)
-in compressed form consists of 33 bytes (octets).
-The first byte 02_16 / 03_16 signifies
-whether the point is compressed or uncompressed as well as
-signifying the odd or even state of y_p. The
-remaining 32 bytesrepresent x_p converted
-into a 32 octet string.
-
-SEC1 endcoded uncompressed points, which consist of 65 bytes,
-have been deliberately disregarded as y_p is not needed
-during signature verification and it seems sensible to save 32
-bytes of transaction space.
-
-**Note:** The existing precompiles for secp256k1 & ed25519 utilize
-just x_p encoded as an octet string. This saves one byte
-compared to using a compressed point, but fails to conform to any standard.
+The SEC1 encoded EC point P = (x_p, y_p) in compressed form consists
+of 33 bytes (octets). The first byte of 02_16 / 03_16 signifies a
+compressed point, as well as whether y_p is odd or even. The remaining
+32 bytes represent x_p converted into a 32 octet string.
+
+While SEC1 encoded uncompressed points could also be used,
+due to their larger size of 65 bytes, the ease of transformation
+between uncompressed and compressed points, and the vast majority
+of applications exclusively making use of compressed points, it
+seems a reasonable consideration to save 32 bytes of instruction
+data with a protocol that only accepts compressed points.
+
+**Note:** When it comes to public key encoding, the existing
+precompile for `secp256k1` utilizes a vastly different standard,
+accepting a 20 octet Ethereum address and recovery id to recover an
+SEC1 encoded uncompressed point. This is due to the primary aim of the
+program not being to verify ECDSA signatures but to provide parity with
+`ecrecover` on EVM. Conversely, the `ed25519` program, which is
+primarily concerned with verifying ed25519 signatures, utilises the most
+common ed25519 convention of encoding x_p as a single 32 octet string.
+As the goals of the `secp256r1` program are more analogous to those of the
+`ed25519` program, we propose the SEC1 compressed point encoding to conform
+to the most widely-used standard in common ECDSA applications.
### ECDSA / Signature Verification
@@ -130,16 +146,26 @@ in Section A.2.5 as well as at the
### Signature Malleability
-As any signature `s = (R,S)` generated with ECDSA is malleable
-in regards to the `S` value, the precompile should enforce the usage
-of `lowS` values, in which `S < n/2` where `n` is the order of
-the elliptic curve.
-It should fail on any signatures that include a `highS` value.
+Due to X axis symmetry along the elliptic curve, for any ECDSA signature
+`(r, s)`, there also exists a valid signature `(r, n - s)`, where `n` is the
+order of the curve. This introduces "s malleability", allowing an attacker
+to produce an alternative version of `s` without invalidating the signature.
+
+The pitfalls of this in authentication systems can be particularly perilous,
+opening up certain implementations to signature replay attacks over the same
+message by simply flipping the `s` value over the curve.
+
+As the primary goal of the `secp256r1` program is secure signature validation
+for authentication purposes, the precompile should mitigate these attacks
+by enforcing the usage of `lowS` values, in which `s <= n/2`.
-This should be done to prevent any accidental succeptibility to
-signature malleability attacks.
+As such, the program should immediately fail upon the detection of any
+signature that includes a `highS` value. This prevents any accidental
+succeptibility to signature malleability attacks.
-Note: The existing secp256k1 precompile does not prevent signature malleability
+Note: The existing `secp256k1` precompile makes no attempt attempt to mitigate
+s malleability, as doing so would go against its primary goal of achieving
+`ecrecover` parity with EVM.
### Program
@@ -180,9 +206,8 @@ precompiles.
### Implementation
The precompile can be implemented using the `p256` crate at version `0.10.1`.
-This crate is part of the `Rust Crypto` library and implements
-the NIST P-256 curve as well as ECDSA.
-It conforms with the test vectors found in
+This crate is part of the `Rust Crypto` library and implements the NIST P-256
+curve as well as ECDSA. It conforms with the test vectors found in
[RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5).
The precompile would make use of the following to accomplish signature
@@ -209,9 +234,10 @@ See [PR#27961](https://github.com/solana-labs/solana/pull/27961) & [PR#28503](ht
## Impact
-Would enable the on-chain usage of Passkeys and the WebAuthn Standard.
+Would enable the on-chain usage of Passkeys and the WebAuthn Standard, and
+turn the vast majority of modern smartphones into native hardware wallets.
-By extension this would also enable the creation of account abstractions and
+By extension, this would also enable the creation of account abstractions and
forms of Two-Factor Authentication around those keypairs.
## Security Considerations
From 47ab3c8cb7edebd3a847a818ac77b401ab34cdae Mon Sep 17 00:00:00 2001
From: Orion <89707822+iceomatic@users.noreply.github.com>
Date: Wed, 25 Oct 2023 10:03:01 +0200
Subject: [PATCH 07/39] linting
---
...0048-precompile-for-secp256r1-sigverify.md | 21 ++++++++++++-------
1 file changed, 14 insertions(+), 7 deletions(-)
diff --git a/proposals/0048-precompile-for-secp256r1-sigverify.md b/proposals/0048-precompile-for-secp256r1-sigverify.md
index 5f791fe4f..f49d7feaf 100644
--- a/proposals/0048-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0048-precompile-for-secp256r1-sigverify.md
@@ -33,15 +33,20 @@ multiple seed phrases. A much more ergonomic approach combining the best of
these two solutions on generalised mobile hardware could be achieved by adding
support for secp256r1 signatures.
-There are already several standardised implementations of this, such as Passkeys
-and WebAuthn. These solutions leverage Apple's Secure Enclave and Android Keystore
+There are already several standardised implementations of this,
+such as Passkeys
+and WebAuthn. These solutions leverage Apple's Secure Enclave and
+Android Keystore
to enable users to save keypairs associated to different services natively on
-the secure element of their mobile devices. To authenticate with those services,
+the secure element of their mobile devices. To authenticate with
+those services,
the user uses their biometrics to sign a message with the stored private key.
While originally intended to solve for password-less authentication in Web2
-applications, WebAuthn and Passkeys also make an excellent candidate for on-chain
-second-factor authentication. Beyond simply securing funds, there are also many
+applications, WebAuthn and Passkeys also make an excellent
+candidate for on-chain
+second-factor authentication. Beyond simply securing funds,
+there are also many
other potential beneficial abstractions that could make use of the simple UX
they provide.
@@ -54,8 +59,10 @@ Although WebAuthn supports the following curves:
- P-521
- ed25519
-P-256 is the only one supported by both Android & MacOS/iOS (MacOS/iOS being the more
-restrictive of the two), hence the goal being to implement secp256r1 signature
+P-256 is the only one supported by both Android & MacOS/iOS
+(MacOS/iOS being the more
+restrictive of the two), hence the goal being to implement
+secp256r1 signature
verification
General Documentation:
From cbc60a99b8ee73c6d142f71f0868e20a3a0f9724 Mon Sep 17 00:00:00 2001
From: Orion <89707822+iceomatic@users.noreply.github.com>
Date: Thu, 26 Oct 2023 13:29:37 +0200
Subject: [PATCH 08/39] add: author
---
proposals/0048-precompile-for-secp256r1-sigverify.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/proposals/0048-precompile-for-secp256r1-sigverify.md b/proposals/0048-precompile-for-secp256r1-sigverify.md
index f49d7feaf..49733d622 100644
--- a/proposals/0048-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0048-precompile-for-secp256r1-sigverify.md
@@ -4,6 +4,7 @@ title: Precompile for verifying secp256r1 sig.
authors:
- Orion (Bunkr)
- Jstnw (Bunkr)
+ - Dean (Web3 Builders Alliance)
category: Standard
type: Core
status: Draft
From 05bd88c8b9fa002cecc1ead64e1a59aba87bda0c Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Fri, 5 Jan 2024 21:51:57 +0100
Subject: [PATCH 09/39] fix: review changes
---
...0048-precompile-for-secp256r1-sigverify.md | 150 +++++++++---------
1 file changed, 78 insertions(+), 72 deletions(-)
diff --git a/proposals/0048-precompile-for-secp256r1-sigverify.md b/proposals/0048-precompile-for-secp256r1-sigverify.md
index 49733d622..0f2ceabfa 100644
--- a/proposals/0048-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0048-precompile-for-secp256r1-sigverify.md
@@ -18,41 +18,35 @@ Adding a precompile to support the verification of signatures
generated on the secp256r1 curve.
Analogous to the support for secp256k1 and ed25519 signatures that already
exists in form of
-the `KeccakSecp256k11111111111111111111111111111` and
+the `KeccakSecp256k11111111111111111111111111111` and
`Ed25519SigVerify111111111111111111111111111`
precompiles
## Motivation
-Solana has the opportunity to leverage the secure element of users' existing
+Solana has the opportunity to leverage the secure element of users' existing
mobile devices to support more user-friendly self-custodial security solutions.
The status quo of air-gapping signing with a hardware wallet currently requires
specialty hardware and still represents a single point of failure. Multi-signature
wallets provide enhanced security through multi-party signing, however the UX
-is cumbersome due to the need to sign transactions multiple times and manage
-multiple seed phrases. A much more ergonomic approach combining the best of
-these two solutions on generalised mobile hardware could be achieved by adding
+is cumbersome due to the need to sign transactions multiple times and manage
+multiple seed phrases. A much more ergonomic approach combining the best of
+these two solutions on generalised mobile hardware could be achieved by adding
support for secp256r1 signatures.
-There are already several standardised implementations of this,
-such as Passkeys
-and WebAuthn. These solutions leverage Apple's Secure Enclave and
-Android Keystore
-to enable users to save keypairs associated to different services natively on
+There are already several standardised implementations of this, such as Passkeys
+and WebAuthn. These solutions leverage Apple's Secure Enclave and Android Keystore
+to enable users to save keypairs associated to different services natively on
the secure element of their mobile devices. To authenticate with
-those services,
-the user uses their biometrics to sign a message with the stored private key.
+those services, the user uses their biometrics to sign a message with the stored
+private key.
While originally intended to solve for password-less authentication in Web2
-applications, WebAuthn and Passkeys also make an excellent
-candidate for on-chain
-second-factor authentication. Beyond simply securing funds,
-there are also many
+applications, WebAuthn and Passkeys also make an excellent candidate for on-chain
+second-factor authentication. Beyond simply securing funds, there are also many
other potential beneficial abstractions that could make use of the simple UX
they provide.
-Note:
-
Although WebAuthn supports the following curves:
- P-256
@@ -60,10 +54,8 @@ Although WebAuthn supports the following curves:
- P-521
- ed25519
-P-256 is the only one supported by both Android & MacOS/iOS
-(MacOS/iOS being the more
-restrictive of the two), hence the goal being to implement
-secp256r1 signature
+P-256 is the only one supported by both Android & MacOS/iOS (MacOS/iOS being the
+more restrictive of the two), hence the goal being to implement secp256r1 signature
verification
General Documentation:
@@ -72,6 +64,10 @@ General Documentation:
[Passkeys](https://fidoalliance.org/passkeys/)
+**Note: P-256 / secp256r1 / prime256v1 are used interchangably in this document
+as they represent the same elliptic curve. The choice of nomenclature depends on
+what RFC or SEC document is being referenced.**
+
## Alternatives Considered
We have discussed the following alternatives:
@@ -81,10 +77,19 @@ to `secp256k1_recover()` instead of a precompile. This would ease
integration for developers, since no instruction introspection would be
required when utilizing the syscall. This is still a valid consideration.
-2.) Allowing for high-S signatures was considered, however the pitfalls
-of signature malleability are too great to leave open to implementation.
+2.) Realising signature verification through and on-chain sBPF implemenation. On
+a local validator a single signature verification consumes ≈42M compute units.
+A possibility would be to split the verification into multiple transactions.
+This would most probably require off-chain infrastructure to crank the process
+or carry higher transaction fees for the end user. (similar to the current elusiv
+protocol private transfer)
+We feel this alternative directly contradicts and impinges on the main upside of
+passkeys, which is the incredible UX and ease of use to the end user.
+
+3.) Allowing for high-S signatures was considered, however the pitfalls
+of signature malleability are too great to leave open to implementation.
-3.) Allowing for uncompressed keys was considered, however as we are already
+4.) Allowing for uncompressed keys was considered, however as we are already
taking an opinionated stance on signature malleability, it makes sense to
also take an opinionated stance on public key encoding.
@@ -98,65 +103,64 @@ The precompile's purpose is to verify signatures using ECDSA-256.
(denoted in [RFC6460](https://www.ietf.org/rfc/rfc6460.txt) as
ECDSA using the NIST P-256 curve and the SHA-256 hashing algorithm)
-### Curve
+### Curve
-The curve parameters for NIST P-256/secp256r1/prime256v1 are
+The curve parameters for NIST P-256/secp256r1/prime256v1 are
outlined in the [SEC2](https://www.secg.org/SEC2-Ver-1.0.pdf#page=21)
document in Section 2.7.2
-### Point Encoding/Decoding:
+### Point Encoding/Decoding
The precompile should accept SEC1 encoded points in compressed form.
-The encoding and decoding of these is outlined in sections
-`2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion`
+The encoding and decoding of these is outlined in sections
+`2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion`
and `2.3.4 Octet-String-to-Elliptic-Curve-Point Conversion`
found in [SEC1](https://www.secg.org/sec1-v2.pdf#page=16).
The SEC1 encoded EC point P = (x_p, y_p) in compressed form consists
-of 33 bytes (octets). The first byte of 02_16 / 03_16 signifies a
-compressed point, as well as whether y_p is odd or even. The remaining
+of 33 bytes (octets). The first byte of 02_16 / 03_16 signifies a
+compressed point, as well as whether y_p is odd or even. The remaining
32 bytes represent x_p converted into a 32 octet string.
While SEC1 encoded uncompressed points could also be used,
-due to their larger size of 65 bytes, the ease of transformation
-between uncompressed and compressed points, and the vast majority
-of applications exclusively making use of compressed points, it
-seems a reasonable consideration to save 32 bytes of instruction
+due to their larger size of 65 bytes, the ease of transformation
+between uncompressed and compressed points, and the vast majority
+of applications exclusively making use of compressed points, it
+seems a reasonable consideration to save 32 bytes of instruction
data with a protocol that only accepts compressed points.
-**Note:** When it comes to public key encoding, the existing
+**Note:** When it comes to public key encoding, the existing
precompile for `secp256k1` utilizes a vastly different standard,
-accepting a 20 octet Ethereum address and recovery id to recover an
-SEC1 encoded uncompressed point. This is due to the primary aim of the
-program not being to verify ECDSA signatures but to provide parity with
-`ecrecover` on EVM. Conversely, the `ed25519` program, which is
+accepting a 20 octet Ethereum address and recovery id to recover an
+SEC1 encoded uncompressed point. This is due to the primary aim of the
+program not being to verify ECDSA signatures but to provide parity with
+`ecrecover` on EVM. Conversely, the `ed25519` program, which is
primarily concerned with verifying ed25519 signatures, utilises the most
-common ed25519 convention of encoding x_p as a single 32 octet string.
-As the goals of the `secp256r1` program are more analogous to those of the
-`ed25519` program, we propose the SEC1 compressed point encoding to conform
+common ed25519 convention of encoding x_p as a single 32 octet string.
+As the goals of the `secp256r1` program are more analogous to those of the
+`ed25519` program, we propose the SEC1 compressed point encoding to conform
to the most widely-used standard in common ECDSA applications.
### ECDSA / Signature Verification
-The precompile should implement the `Verifying Operation` outlined in
+The precompile should implement the `Verifying Operation` outlined in
[SEC1](https://www.secg.org/sec1-v2.pdf#page=52)
-in Section 4.1.4 as well as in the
+in Section 4.1.4 as well as in the
[Digital Signature Standard (DSS)](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf#page=36)
document in Section 6.4.2.
-A multitude of test vectors to verify correctness can
-be found in
-[RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5)
-in Section A.2.5 as well as at the
+A multitude of test vectors to verify correctness can
+be found in
+[RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5)
+in Section A.2.5 as well as at the
[NIST CAVP](https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/digital-signatures#ecdsa2vs)
(Cryptographic Algorithm Validation Program)
-
### Signature Malleability
-Due to X axis symmetry along the elliptic curve, for any ECDSA signature
-`(r, s)`, there also exists a valid signature `(r, n - s)`, where `n` is the
-order of the curve. This introduces "s malleability", allowing an attacker
+Due to X axis symmetry along the elliptic curve, for any ECDSA signature
+`(r, s)`, there also exists a valid signature `(r, n - s)`, where `n` is the
+order of the curve. This introduces "s malleability", allowing an attacker
to produce an alternative version of `s` without invalidating the signature.
The pitfalls of this in authentication systems can be particularly perilous,
@@ -164,15 +168,15 @@ opening up certain implementations to signature replay attacks over the same
message by simply flipping the `s` value over the curve.
As the primary goal of the `secp256r1` program is secure signature validation
-for authentication purposes, the precompile should mitigate these attacks
+for authentication purposes, the precompile should mitigate these attacks
by enforcing the usage of `lowS` values, in which `s <= n/2`.
-As such, the program should immediately fail upon the detection of any
-signature that includes a `highS` value. This prevents any accidental
+As such, the program should immediately fail upon the detection of any
+signature that includes a `highS` value. This prevents any accidental
succeptibility to signature malleability attacks.
-Note: The existing `secp256k1` precompile makes no attempt attempt to mitigate
-s malleability, as doing so would go against its primary goal of achieving
+Note: The existing `secp256k1` precompile makes no attempt attempt to mitigate
+s malleability, as doing so would go against its primary goal of achieving
`ecrecover` parity with EVM.
### Program
@@ -185,7 +189,6 @@ The program instruction will be composed of the following:
- Single byte of padding
- The following struct serialized, for each signature to verify
-
```rust
struct Secp256r1SignatureOffsets {
signature_offset: u16, // offset to secp256r1 signature of 64 bytes
@@ -205,7 +208,7 @@ The program logic will be constructed and built using a `verify`
function, as outlined in
[sdk/src/precompiles.rs](https://github.com/solana-labs/solana/blob/9ffbe2afd8ab5b972c4ad87d758866a3e1bb87fb/sdk/src/precompiles.rs).
-Apart from the signature verification, the remaining
+Apart from the signature verification, the remaining
logic should be constructed analogously to the existing
[ed25519](https://github.com/solana-labs/solana/blob/master/sdk/src/ed25519_instruction.rs)
& [secp256k1](https://github.com/solana-labs/solana/blob/9ffbe2afd8ab5b972c4ad87d758866a3e1bb87fb/sdk/src/secp256k1_instruction.rs#L4)
@@ -215,7 +218,7 @@ precompiles.
The precompile can be implemented using the `p256` crate at version `0.10.1`.
This crate is part of the `Rust Crypto` library and implements the NIST P-256
-curve as well as ECDSA. It conforms with the test vectors found in
+curve as well as ECDSA. It conforms with the test vectors found in
[RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5).
The precompile would make use of the following to accomplish signature
@@ -228,13 +231,13 @@ verification:
Note: The crate is well maintained, but has never been externally audited.
-### Compute Cost
+### Compute Cost / Efficiency
Once the implementation is finished, benchmarking should take place on a
-sufficiently powerful machine in order to determine average compute time.
-Pricing would be based on the 33ns/CU convention. For
-the sake of ensuring proper efficiency, a comparison to similar implementations
-on polygon/optimism/ethereum would be conducted.
+sufficiently powerful machine in order to determine average compute time per
+signature. Calculation of CUs would be based on the 1 CU / ns convention.
+The secp256k1 ecrecover syscall, which incurs a cost of 25_000 CUs, can be used
+as a reference point.
This is in line with how previous precompiles for EC group operations and
arithmetic were evaluated/benchmarked.
@@ -251,7 +254,7 @@ forms of Two-Factor Authentication around those keypairs.
## Security Considerations
As [Firedancer](https://github.com/firedancer-io/firedancer) is being developed
-in C, it is imperative that there can be bit-level reproducibility between
+in C, it is imperative that there can be bit-level reproducibility between
the precompile implementations. Any discrepancy between the two implementations
could cause a fork and or a chain halt. (Thank you @ripatel-fd for pointing this
out and advocating for it)
@@ -259,11 +262,14 @@ out and advocating for it)
As such we would propose the following:
- Development of a thorough test suite that includes all test vectors as well
-as tests from the
-[Wycheproof Project](https://github.com/google/wycheproof#project-wycheproof)
+ as tests from the
+ [Wycheproof Project](https://github.com/google/wycheproof#project-wycheproof)
+
+- Direct comparison and analysis of `p256` verification routines and group/field
+ with those found in the `prime256v1` OpenSSL implementation
-- Thorough auditing as well as a formal verification of the arithmetic and
-decoding inside the `p256` crate
+- Thorough auditing of the arithmetic and
+ decoding inside the `p256` crate
## Backwards Compatibility
From c1becc5e8fffd3e3a0e1ce7ffdcb07f53f7d0168 Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Fri, 5 Jan 2024 21:56:13 +0100
Subject: [PATCH 10/39] fix: typos
---
.../0048-precompile-for-secp256r1-sigverify.md | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/proposals/0048-precompile-for-secp256r1-sigverify.md b/proposals/0048-precompile-for-secp256r1-sigverify.md
index 0f2ceabfa..1448055fc 100644
--- a/proposals/0048-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0048-precompile-for-secp256r1-sigverify.md
@@ -14,13 +14,11 @@ feature: (fill in with feature tracking issues once accepted)
## Summary
-Adding a precompile to support the verification of signatures
-generated on the secp256r1 curve.
-Analogous to the support for secp256k1 and ed25519 signatures that already
-exists in form of
-the `KeccakSecp256k11111111111111111111111111111` and
-`Ed25519SigVerify111111111111111111111111111`
-precompiles
+Adding a precompile to support the verification of signatures generated on
+the secp256r1 curve. Analogous to the support for secp256k1 and ed25519
+signatures that already exists in form of the
+`KeccakSecp256k11111111111111111111111111111` and
+`Ed25519SigVerify111111111111111111111111111` precompiles.
## Motivation
@@ -266,7 +264,7 @@ As such we would propose the following:
[Wycheproof Project](https://github.com/google/wycheproof#project-wycheproof)
- Direct comparison and analysis of `p256` verification routines and group/field
- with those found in the `prime256v1` OpenSSL implementation
+ operations with those found in the `prime256v1` OpenSSL implementation
- Thorough auditing of the arithmetic and
decoding inside the `p256` crate
From d0d057f1227cfcb772de43dffa0814e4c1c3f971 Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Tue, 27 Feb 2024 18:28:18 -0700
Subject: [PATCH 11/39] refactor: implementation logic argumentation
---
...0048-precompile-for-secp256r1-sigverify.md | 7 +-
...0075-precompile-for-secp256r1-sigverify.md | 343 ++++++++++++++++++
2 files changed, 347 insertions(+), 3 deletions(-)
create mode 100644 proposals/0075-precompile-for-secp256r1-sigverify.md
diff --git a/proposals/0048-precompile-for-secp256r1-sigverify.md b/proposals/0048-precompile-for-secp256r1-sigverify.md
index 1448055fc..99c15ad2d 100644
--- a/proposals/0048-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0048-precompile-for-secp256r1-sigverify.md
@@ -12,6 +12,10 @@ created: 2023-05-14
feature: (fill in with feature tracking issues once accepted)
---
+
+## [DEPRECATED IN FAVOR OF SIMD-0075]
+
+
## Summary
Adding a precompile to support the verification of signatures generated on
@@ -219,9 +223,6 @@ This crate is part of the `Rust Crypto` library and implements the NIST P-256
curve as well as ECDSA. It conforms with the test vectors found in
[RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5).
-The precompile would make use of the following to accomplish signature
-verification:
-
- `p256::ecdsa::VerifyingKey::from_sec1_bytes()`
- `p256::ecdsa::Signature::from_scalars()`
- `p256::arithmetic::Scalar::is_high()`
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
new file mode 100644
index 000000000..d2c4dfbdd
--- /dev/null
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -0,0 +1,343 @@
+---
+simd: "0075"
+title: Precompile for verifying secp256r1 sig (Supercedes SIMD-0048).
+authors:
+ - Orion (Bunkr)
+ - Jstnw (Bunkr)
+ - Dean (Web3 Builders Alliance)
+category: Standard
+type: Core
+status: Draft
+created: 2024-02-27
+feature: (fill in with feature tracking issues once accepted)
+---
+
+## Note
+
+Supercedes SIMD-0048
+
+## Summary
+
+Adding a precompile to support the verification of signatures generated on
+the secp256r1 curve. Analogous to the support for secp256k1 and ed25519
+signatures that already exists in form of the
+`KeccakSecp256k11111111111111111111111111111` and
+`Ed25519SigVerify111111111111111111111111111` precompiles.
+
+## Motivation
+
+Solana has the opportunity to leverage the secure element of users' existing
+mobile devices to support more user-friendly self-custodial security solutions.
+The status quo of air-gapping signing with a hardware wallet currently requires
+specialty hardware and still represents a single point of failure. Multi-signature
+wallets provide enhanced security through multi-party signing, however the UX
+is cumbersome due to the need to sign transactions multiple times and manage
+multiple seed phrases. A much more ergonomic approach combining the best of
+these two solutions on generalised mobile hardware could be achieved by adding
+support for secp256r1 signatures.
+
+There are already several standardised implementations of this, such as Passkeys
+and WebAuthn. These solutions leverage Apple's Secure Enclave and Android Keystore
+to enable users to save keypairs associated to different services natively on
+the secure element of their mobile devices. To authenticate with
+those services, the user uses their biometrics to sign a message with the stored
+private key.
+
+While originally intended to solve for password-less authentication in Web2
+applications, WebAuthn and Passkeys also make an excellent candidate for on-chain
+second-factor authentication. Beyond simply securing funds, there are also many
+other potential beneficial abstractions that could make use of the simple UX
+they provide.
+
+Although WebAuthn supports the following curves:
+
+- P-256
+- P-384
+- P-521
+- ed25519
+
+P-256 is the only one supported by both Android & MacOS/iOS (MacOS/iOS being the
+more restrictive of the two), hence the goal being to implement secp256r1 signature
+verification
+
+General Documentation:
+
+[WebAuthn](https://webauthn.io/)
+
+[Passkeys](https://fidoalliance.org/passkeys/)
+
+**Note: P-256 / secp256r1 / prime256v1 are used interchangably in this document
+as they represent the same elliptic curve. The choice of nomenclature depends on
+what RFC or SEC document is being referenced.**
+
+## Alternatives Considered
+
+We have discussed the following alternatives:
+
+1.) Realising signature verification with a syscall similar
+to `secp256k1_recover()` instead of a precompile. This would ease
+integration for developers, since no instruction introspection would be
+required when utilizing the syscall. This is still a valid consideration.
+
+2.) Realising signature verification through and on-chain sBPF implemenation. On
+a local validator a single signature verification consumes ≈42M compute units.
+A possibility would be to split the verification into multiple transactions.
+This would most probably require off-chain infrastructure to crank the process
+or carry higher transaction fees for the end user. (similar to the current elusiv
+protocol private transfer)
+We feel this alternative directly contradicts and impinges on the main upside of
+passkeys, which is the incredible UX and ease of use to the end user.
+
+3.) Allowing for high-S signatures was considered, however the pitfalls
+of signature malleability are too great to leave open to implementation.
+
+4.) Allowing for uncompressed keys was considered, however as we are already
+taking an opinionated stance on signature malleability, it makes sense to
+also take an opinionated stance on public key encoding.
+
+## New Terminology
+
+None
+
+## Detailed Design
+
+The precompile's purpose is to verify signatures using ECDSA-256.
+(denoted in [RFC6460](https://www.ietf.org/rfc/rfc6460.txt) as
+ECDSA using the NIST P-256 curve and the SHA-256 hashing algorithm)
+
+### Curve
+
+The curve parameters for NIST P-256/secp256r1/prime256v1 are
+outlined in the [SEC2](https://www.secg.org/SEC2-Ver-1.0.pdf#page=21)
+document in Section 2.7.2
+
+### Point Encoding/Decoding
+
+The precompile should accept SEC1 encoded points in compressed form.
+The encoding and decoding of these is outlined in sections
+`2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion`
+and `2.3.4 Octet-String-to-Elliptic-Curve-Point Conversion`
+found in [SEC1](https://www.secg.org/sec1-v2.pdf#page=16).
+
+The SEC1 encoded EC point P = (x_p, y_p) in compressed form consists
+of 33 bytes (octets). The first byte of 02_16 / 03_16 signifies a
+compressed point, as well as whether y_p is odd or even. The remaining
+32 bytes represent x_p converted into a 32 octet string.
+
+While SEC1 encoded uncompressed points could also be used,
+due to their larger size of 65 bytes, the ease of transformation
+between uncompressed and compressed points, and the vast majority
+of applications exclusively making use of compressed points, it
+seems a reasonable consideration to save 32 bytes of instruction
+data with a protocol that only accepts compressed points.
+
+**Note:** When it comes to public key encoding, the existing
+precompile for `secp256k1` utilizes a vastly different standard,
+accepting a 20 octet Ethereum address and recovery id to recover an
+SEC1 encoded uncompressed point. This is due to the primary aim of the
+program not being to verify ECDSA signatures but to provide parity with
+`ecrecover` on EVM. Conversely, the `ed25519` program, which is
+primarily concerned with verifying ed25519 signatures, utilises the most
+common ed25519 convention of encoding x_p as a single 32 octet string.
+As the goals of the `secp256r1` program are more analogous to those of the
+`ed25519` program, we propose the SEC1 compressed point encoding to conform
+to the most widely-used standard in common ECDSA applications.
+
+### ECDSA / Signature Verification
+
+The precompile should implement the `Verifying Operation` outlined in
+[SEC1](https://www.secg.org/sec1-v2.pdf#page=52)
+in Section 4.1.4 as well as in the
+[Digital Signature Standard (DSS)](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf#page=36)
+document in Section 6.4.2.
+
+A multitude of test vectors to verify correctness can
+be found in
+[RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5)
+in Section A.2.5 as well as at the
+[NIST CAVP](https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/digital-signatures#ecdsa2vs)
+(Cryptographic Algorithm Validation Program)
+
+### Signature Malleability
+
+Due to X axis symmetry along the elliptic curve, for any ECDSA signature
+`(r, s)`, there also exists a valid signature `(r, n - s)`, where `n` is the
+order of the curve. This introduces "s malleability", allowing an attacker
+to produce an alternative version of `s` without invalidating the signature.
+
+The pitfalls of this in authentication systems can be particularly perilous,
+opening up certain implementations to signature replay attacks over the same
+message by simply flipping the `s` value over the curve.
+
+As the primary goal of the `secp256r1` program is secure signature validation
+for authentication purposes, the precompile should mitigate these attacks
+by enforcing the usage of `lowS` values, in which `s <= n/2`.
+
+As such, the program should immediately fail upon the detection of any
+signature that includes a `highS` value. This prevents any accidental
+succeptibility to signature malleability attacks.
+
+Note: The existing `secp256k1` precompile makes no attempt attempt to mitigate
+s malleability, as doing so would go against its primary goal of achieving
+`ecrecover` parity with EVM.
+
+### Program
+
+ID: `Secp256r1SigVerify1111111111111111111111111`
+
+The program instruction will be composed of the following:
+
+- A first u8 as the count for the number of signatures to check
+- Single byte of padding
+- The following struct serialized, for each signature to verify
+
+```rust
+struct Secp256r1SignatureOffsets {
+ signature_offset: u16, // offset to 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 msg data
+}
+```
+
+Multiple signatures can be verified. If any of the signatures fail to verify,
+an error is returned.
+
+The program logic will be constructed and built using a `verify`
+function, as outlined in
+[sdk/src/precompiles.rs](https://github.com/solana-labs/solana/blob/9ffbe2afd8ab5b972c4ad87d758866a3e1bb87fb/sdk/src/precompiles.rs).
+
+Apart from the signature verification, the remaining
+logic should be constructed analogously to the existing
+[ed25519](https://github.com/solana-labs/solana/blob/master/sdk/src/ed25519_instruction.rs)
+& [secp256k1](https://github.com/solana-labs/solana/blob/9ffbe2afd8ab5b972c4ad87d758866a3e1bb87fb/sdk/src/secp256k1_instruction.rs#L4)
+precompiles.
+
+### Implementation
+
+#### Previous Consideration in SIMD-0048
+
+The precompile could be implemented using
+the `p256` crate at version `0.10.1`. This crate is part of the `Rust Crypto`
+library and implements the NIST P-256 curve as well as ECDSA in native Rust.
+It conforms with the test vectors found in
+[RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5).
+
+#### SIMD-0075 Update
+
+Due to the unaudited and somewhat unknown nature of the `p256` crate and
+the strict security and reproducibility considerations required to enable
+compatibility with Firedancer, we propose to implement the Precompile utilizing
+the `OpenSSL` [crate](https://crates.io/crates/openssl/0.10.57).
+The `OpenSSL` crate is already a dependency in the Anza client and has
+additionally been heavily scrutinized/tested by the broader public.
+
+Addtionally with regard to the development of Firedancer, the OpenSSL rust crate
+merely wraps and binds to the underlying C implementation of OpenSSL. This eases
+the effort in ensuring reproducibility between the Firedancer and Anza client.
+
+Our benchmarks also show that verifying a signature using the `OpenSSL` crate is ~3x
+faster than using the `p256` crate.
+
+Signature verification using the OpenSSL crate includes the following steps:
+
+1. Getting the curve order using the Nid::X9_62_PRIME256V1 identifier:
+
+ ```rust
+ EcGroup::from_curve_name(Nid::X9_62_PRIME256V1)
+ ```
+
+2. Ensuring the `r` & `s` signature components fall within `curve_order - 1`
+3. Recreating the signature using the `r` & `s` signature components:
+
+ ```rust
+ let ecdsa_sig = openssl::ecdsa::EcdsaSig::from_private_components(r_bignum, s_bignum)
+
+ let der_sig = ecdsa_sig.to_der()
+ ```
+
+4. Computing the `half_order`of the curve and ensuring that `s < half_order`
+ (LowS Check)
+5. Parsing the public key bytes:
+
+ ```rust
+ let ec_point = EcPoint::from_bytes(&group, pubkey, &mut ctx)
+
+ let ec_key = EcKey::from_public_key(&group, &ec_point)
+
+ let pkey = PKey::from_ec_key(ec_key)
+ ```
+
+6. Creating a verfier from the public key and the openSSL SHA-256 hasher:
+
+ ```rust
+ Verifier::new(openssl::hash::MessageDigest::sha256(), &pkey)
+ ```
+
+7. Passing the message bytes to the verifier:
+
+ ```rust
+ verifier.update(message)
+ ```
+
+8. Verify signature across the message:
+
+ ```rust
+ verifier.verify(&der_sig)
+ ```
+
+### Compute Cost / Efficiency
+
+Once the implementation is finished, benchmarking should take place on a
+sufficiently powerful machine in order to determine average compute time per
+signature. Calculation of CUs would be based on the 1 CU / ns convention.
+The secp256k1 ecrecover syscall, which incurs a cost of 25_000 CUs, can be used
+as a reference point.
+
+Since precompiles don't incur a flat compute cost like syscalls, this comparison
+will just serve as a confirmation that the computation inside the precompile is
+sufficiently efficient.
+
+This is in line with how previous precompiles for EC group operations and
+arithmetic were evaluated/benchmarked.
+See [PR#27961](https://github.com/solana-labs/solana/pull/27961) & [PR#28503](https://github.com/solana-labs/solana/pull/28503)
+
+## Impact
+
+Would enable the on-chain usage of Passkeys and the WebAuthn Standard, and
+turn the vast majority of modern smartphones into native hardware wallets.
+
+By extension, this would also enable the creation of account abstractions and
+forms of Two-Factor Authentication around those keypairs.
+
+## Security Considerations
+
+As [Firedancer](https://github.com/firedancer-io/firedancer) is being developed
+in C, it is imperative that there can be bit-level reproducibility between
+the precompile implementations. Any discrepancy between the two implementations
+could cause a fork and or a chain halt. (Thank you @ripatel-fd for pointing this
+out and advocating for it)
+
+As such we would propose the following:
+
+- Development of a thorough test suite that includes all test vectors as well
+ as tests from the
+ [Wycheproof Project](https://github.com/google/wycheproof#project-wycheproof)
+
+- Creating a map of what underlying OpenSSL calls get added to the runtime when
+ using the Rust bindings
+
+
+## Backwards Compatibility
+
+Transactions using the instruction could not be used on Solana versions which don't
+implement this feature. A Feature gate should be used to enable this feature
+when the majority of the cluster is using the required version. Transactions
+that do not use this feature are not impacted.
+
+```
+
+```
From b8dcd3494402f9a1aede4bc70077f28fbbc5b78e Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Tue, 27 Feb 2024 18:30:43 -0700
Subject: [PATCH 12/39] remove: SIMD-0048
---
...0048-precompile-for-secp256r1-sigverify.md | 278 ------------------
1 file changed, 278 deletions(-)
delete mode 100644 proposals/0048-precompile-for-secp256r1-sigverify.md
diff --git a/proposals/0048-precompile-for-secp256r1-sigverify.md b/proposals/0048-precompile-for-secp256r1-sigverify.md
deleted file mode 100644
index 99c15ad2d..000000000
--- a/proposals/0048-precompile-for-secp256r1-sigverify.md
+++ /dev/null
@@ -1,278 +0,0 @@
----
-simd: "0048"
-title: Precompile for verifying secp256r1 sig.
-authors:
- - Orion (Bunkr)
- - Jstnw (Bunkr)
- - Dean (Web3 Builders Alliance)
-category: Standard
-type: Core
-status: Draft
-created: 2023-05-14
-feature: (fill in with feature tracking issues once accepted)
----
-
-
-## [DEPRECATED IN FAVOR OF SIMD-0075]
-
-
-## Summary
-
-Adding a precompile to support the verification of signatures generated on
-the secp256r1 curve. Analogous to the support for secp256k1 and ed25519
-signatures that already exists in form of the
-`KeccakSecp256k11111111111111111111111111111` and
-`Ed25519SigVerify111111111111111111111111111` precompiles.
-
-## Motivation
-
-Solana has the opportunity to leverage the secure element of users' existing
-mobile devices to support more user-friendly self-custodial security solutions.
-The status quo of air-gapping signing with a hardware wallet currently requires
-specialty hardware and still represents a single point of failure. Multi-signature
-wallets provide enhanced security through multi-party signing, however the UX
-is cumbersome due to the need to sign transactions multiple times and manage
-multiple seed phrases. A much more ergonomic approach combining the best of
-these two solutions on generalised mobile hardware could be achieved by adding
-support for secp256r1 signatures.
-
-There are already several standardised implementations of this, such as Passkeys
-and WebAuthn. These solutions leverage Apple's Secure Enclave and Android Keystore
-to enable users to save keypairs associated to different services natively on
-the secure element of their mobile devices. To authenticate with
-those services, the user uses their biometrics to sign a message with the stored
-private key.
-
-While originally intended to solve for password-less authentication in Web2
-applications, WebAuthn and Passkeys also make an excellent candidate for on-chain
-second-factor authentication. Beyond simply securing funds, there are also many
-other potential beneficial abstractions that could make use of the simple UX
-they provide.
-
-Although WebAuthn supports the following curves:
-
-- P-256
-- P-384
-- P-521
-- ed25519
-
-P-256 is the only one supported by both Android & MacOS/iOS (MacOS/iOS being the
-more restrictive of the two), hence the goal being to implement secp256r1 signature
-verification
-
-General Documentation:
-
-[WebAuthn](https://webauthn.io/)
-
-[Passkeys](https://fidoalliance.org/passkeys/)
-
-**Note: P-256 / secp256r1 / prime256v1 are used interchangably in this document
-as they represent the same elliptic curve. The choice of nomenclature depends on
-what RFC or SEC document is being referenced.**
-
-## Alternatives Considered
-
-We have discussed the following alternatives:
-
-1.) Realising signature verification with a syscall similar
-to `secp256k1_recover()` instead of a precompile. This would ease
-integration for developers, since no instruction introspection would be
-required when utilizing the syscall. This is still a valid consideration.
-
-2.) Realising signature verification through and on-chain sBPF implemenation. On
-a local validator a single signature verification consumes ≈42M compute units.
-A possibility would be to split the verification into multiple transactions.
-This would most probably require off-chain infrastructure to crank the process
-or carry higher transaction fees for the end user. (similar to the current elusiv
-protocol private transfer)
-We feel this alternative directly contradicts and impinges on the main upside of
-passkeys, which is the incredible UX and ease of use to the end user.
-
-3.) Allowing for high-S signatures was considered, however the pitfalls
-of signature malleability are too great to leave open to implementation.
-
-4.) Allowing for uncompressed keys was considered, however as we are already
-taking an opinionated stance on signature malleability, it makes sense to
-also take an opinionated stance on public key encoding.
-
-## New Terminology
-
-None
-
-## Detailed Design
-
-The precompile's purpose is to verify signatures using ECDSA-256.
-(denoted in [RFC6460](https://www.ietf.org/rfc/rfc6460.txt) as
-ECDSA using the NIST P-256 curve and the SHA-256 hashing algorithm)
-
-### Curve
-
-The curve parameters for NIST P-256/secp256r1/prime256v1 are
-outlined in the [SEC2](https://www.secg.org/SEC2-Ver-1.0.pdf#page=21)
-document in Section 2.7.2
-
-### Point Encoding/Decoding
-
-The precompile should accept SEC1 encoded points in compressed form.
-The encoding and decoding of these is outlined in sections
-`2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion`
-and `2.3.4 Octet-String-to-Elliptic-Curve-Point Conversion`
-found in [SEC1](https://www.secg.org/sec1-v2.pdf#page=16).
-
-The SEC1 encoded EC point P = (x_p, y_p) in compressed form consists
-of 33 bytes (octets). The first byte of 02_16 / 03_16 signifies a
-compressed point, as well as whether y_p is odd or even. The remaining
-32 bytes represent x_p converted into a 32 octet string.
-
-While SEC1 encoded uncompressed points could also be used,
-due to their larger size of 65 bytes, the ease of transformation
-between uncompressed and compressed points, and the vast majority
-of applications exclusively making use of compressed points, it
-seems a reasonable consideration to save 32 bytes of instruction
-data with a protocol that only accepts compressed points.
-
-**Note:** When it comes to public key encoding, the existing
-precompile for `secp256k1` utilizes a vastly different standard,
-accepting a 20 octet Ethereum address and recovery id to recover an
-SEC1 encoded uncompressed point. This is due to the primary aim of the
-program not being to verify ECDSA signatures but to provide parity with
-`ecrecover` on EVM. Conversely, the `ed25519` program, which is
-primarily concerned with verifying ed25519 signatures, utilises the most
-common ed25519 convention of encoding x_p as a single 32 octet string.
-As the goals of the `secp256r1` program are more analogous to those of the
-`ed25519` program, we propose the SEC1 compressed point encoding to conform
-to the most widely-used standard in common ECDSA applications.
-
-### ECDSA / Signature Verification
-
-The precompile should implement the `Verifying Operation` outlined in
-[SEC1](https://www.secg.org/sec1-v2.pdf#page=52)
-in Section 4.1.4 as well as in the
-[Digital Signature Standard (DSS)](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf#page=36)
-document in Section 6.4.2.
-
-A multitude of test vectors to verify correctness can
-be found in
-[RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5)
-in Section A.2.5 as well as at the
-[NIST CAVP](https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/digital-signatures#ecdsa2vs)
-(Cryptographic Algorithm Validation Program)
-
-### Signature Malleability
-
-Due to X axis symmetry along the elliptic curve, for any ECDSA signature
-`(r, s)`, there also exists a valid signature `(r, n - s)`, where `n` is the
-order of the curve. This introduces "s malleability", allowing an attacker
-to produce an alternative version of `s` without invalidating the signature.
-
-The pitfalls of this in authentication systems can be particularly perilous,
-opening up certain implementations to signature replay attacks over the same
-message by simply flipping the `s` value over the curve.
-
-As the primary goal of the `secp256r1` program is secure signature validation
-for authentication purposes, the precompile should mitigate these attacks
-by enforcing the usage of `lowS` values, in which `s <= n/2`.
-
-As such, the program should immediately fail upon the detection of any
-signature that includes a `highS` value. This prevents any accidental
-succeptibility to signature malleability attacks.
-
-Note: The existing `secp256k1` precompile makes no attempt attempt to mitigate
-s malleability, as doing so would go against its primary goal of achieving
-`ecrecover` parity with EVM.
-
-### Program
-
-ID: `Secp256r1SigVerify1111111111111111111111111`
-
-The program instruction will be composed of the following:
-
-- A first u8 as the count for the number of signatures to check
-- Single byte of padding
-- The following struct serialized, for each signature to verify
-
-```rust
-struct Secp256r1SignatureOffsets {
- signature_offset: u16, // offset to 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 msg data
-}
-```
-
-Multiple signatures can be verified. If any of the signatures fail to verify,
-an error is returned.
-
-The program logic will be constructed and built using a `verify`
-function, as outlined in
-[sdk/src/precompiles.rs](https://github.com/solana-labs/solana/blob/9ffbe2afd8ab5b972c4ad87d758866a3e1bb87fb/sdk/src/precompiles.rs).
-
-Apart from the signature verification, the remaining
-logic should be constructed analogously to the existing
-[ed25519](https://github.com/solana-labs/solana/blob/master/sdk/src/ed25519_instruction.rs)
-& [secp256k1](https://github.com/solana-labs/solana/blob/9ffbe2afd8ab5b972c4ad87d758866a3e1bb87fb/sdk/src/secp256k1_instruction.rs#L4)
-precompiles.
-
-### Implementation
-
-The precompile can be implemented using the `p256` crate at version `0.10.1`.
-This crate is part of the `Rust Crypto` library and implements the NIST P-256
-curve as well as ECDSA. It conforms with the test vectors found in
-[RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5).
-
-- `p256::ecdsa::VerifyingKey::from_sec1_bytes()`
-- `p256::ecdsa::Signature::from_scalars()`
-- `p256::arithmetic::Scalar::is_high()`
-- `p256::ecdsa::VerifyingKey::verify()`
-
-Note: The crate is well maintained, but has never been externally audited.
-
-### Compute Cost / Efficiency
-
-Once the implementation is finished, benchmarking should take place on a
-sufficiently powerful machine in order to determine average compute time per
-signature. Calculation of CUs would be based on the 1 CU / ns convention.
-The secp256k1 ecrecover syscall, which incurs a cost of 25_000 CUs, can be used
-as a reference point.
-
-This is in line with how previous precompiles for EC group operations and
-arithmetic were evaluated/benchmarked.
-See [PR#27961](https://github.com/solana-labs/solana/pull/27961) & [PR#28503](https://github.com/solana-labs/solana/pull/28503)
-
-## Impact
-
-Would enable the on-chain usage of Passkeys and the WebAuthn Standard, and
-turn the vast majority of modern smartphones into native hardware wallets.
-
-By extension, this would also enable the creation of account abstractions and
-forms of Two-Factor Authentication around those keypairs.
-
-## Security Considerations
-
-As [Firedancer](https://github.com/firedancer-io/firedancer) is being developed
-in C, it is imperative that there can be bit-level reproducibility between
-the precompile implementations. Any discrepancy between the two implementations
-could cause a fork and or a chain halt. (Thank you @ripatel-fd for pointing this
-out and advocating for it)
-
-As such we would propose the following:
-
-- Development of a thorough test suite that includes all test vectors as well
- as tests from the
- [Wycheproof Project](https://github.com/google/wycheproof#project-wycheproof)
-
-- Direct comparison and analysis of `p256` verification routines and group/field
- operations with those found in the `prime256v1` OpenSSL implementation
-
-- Thorough auditing of the arithmetic and
- decoding inside the `p256` crate
-
-## Backwards Compatibility
-
-Transactions using the instruction could not be used on Solana versions which don't
-implement this feature. A Feature gate should be used to enable this feature
-when the majority of the cluster is using the required version. Transactions
-that do not use this feature are not impacted.
From 7c22ca0d069ceffb1ef999070f647465ec0d081c Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Tue, 27 Feb 2024 18:32:23 -0700
Subject: [PATCH 13/39] linting
---
proposals/0075-precompile-for-secp256r1-sigverify.md | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index d2c4dfbdd..6981d27b5 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -239,8 +239,8 @@ Addtionally with regard to the development of Firedancer, the OpenSSL rust crate
merely wraps and binds to the underlying C implementation of OpenSSL. This eases
the effort in ensuring reproducibility between the Firedancer and Anza client.
-Our benchmarks also show that verifying a signature using the `OpenSSL` crate is ~3x
-faster than using the `p256` crate.
+Our benchmarks also show that verifying a signature using the `OpenSSL` crate is
+~3x faster than using the `p256` crate.
Signature verification using the OpenSSL crate includes the following steps:
@@ -298,7 +298,7 @@ The secp256k1 ecrecover syscall, which incurs a cost of 25_000 CUs, can be used
as a reference point.
Since precompiles don't incur a flat compute cost like syscalls, this comparison
-will just serve as a confirmation that the computation inside the precompile is
+will just serve as a confirmation that the computation inside the precompile is
sufficiently efficient.
This is in line with how previous precompiles for EC group operations and
@@ -330,7 +330,6 @@ As such we would propose the following:
- Creating a map of what underlying OpenSSL calls get added to the runtime when
using the Rust bindings
-
## Backwards Compatibility
Transactions using the instruction could not be used on Solana versions which don't
From 032c146f676b50890b74778aac1165ae46e065a3 Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Tue, 27 Feb 2024 18:36:20 -0700
Subject: [PATCH 14/39] linting
---
proposals/0075-precompile-for-secp256r1-sigverify.md | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index 6981d27b5..fb197ccfc 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -1,6 +1,6 @@
---
simd: "0075"
-title: Precompile for verifying secp256r1 sig (Supercedes SIMD-0048).
+title: Precompile for verifying secp256r1 sig.
authors:
- Orion (Bunkr)
- Jstnw (Bunkr)
@@ -12,10 +12,6 @@ created: 2024-02-27
feature: (fill in with feature tracking issues once accepted)
---
-## Note
-
-Supercedes SIMD-0048
-
## Summary
Adding a precompile to support the verification of signatures generated on
From cb08c9f6819261573093575ee2d505599ae66d7f Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Tue, 27 Feb 2024 18:39:00 -0700
Subject: [PATCH 15/39] fix: typo
---
proposals/0075-precompile-for-secp256r1-sigverify.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index fb197ccfc..e92b3727a 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -243,7 +243,7 @@ Signature verification using the OpenSSL crate includes the following steps:
1. Getting the curve order using the Nid::X9_62_PRIME256V1 identifier:
```rust
- EcGroup::from_curve_name(Nid::X9_62_PRIME256V1)
+ let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1)
```
2. Ensuring the `r` & `s` signature components fall within `curve_order - 1`
From a22eecc874d76b20b1ed3710a9afc0ce0c0d1ba8 Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Tue, 27 Feb 2024 18:42:41 -0700
Subject: [PATCH 16/39] fix: typo
---
proposals/0075-precompile-for-secp256r1-sigverify.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index e92b3727a..10227290a 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -226,7 +226,7 @@ It conforms with the test vectors found in
Due to the unaudited and somewhat unknown nature of the `p256` crate and
the strict security and reproducibility considerations required to enable
-compatibility with Firedancer, we propose to implement the Precompile utilizing
+compatibility with Firedancer, we propose to implement the precompile utilizing
the `OpenSSL` [crate](https://crates.io/crates/openssl/0.10.57).
The `OpenSSL` crate is already a dependency in the Anza client and has
additionally been heavily scrutinized/tested by the broader public.
@@ -267,7 +267,7 @@ Signature verification using the OpenSSL crate includes the following steps:
let pkey = PKey::from_ec_key(ec_key)
```
-6. Creating a verfier from the public key and the openSSL SHA-256 hasher:
+6. Creating a verfier from the public key and the OpenSSL SHA-256 hashing idendifier:
```rust
Verifier::new(openssl::hash::MessageDigest::sha256(), &pkey)
From 6eed78afd203987d1ddbb1b4a67044c24b52994c Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Tue, 27 Feb 2024 21:17:46 -0700
Subject: [PATCH 17/39] add: supersedes section to header
---
proposals/0075-precompile-for-secp256r1-sigverify.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index 10227290a..38c933218 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -10,6 +10,7 @@ type: Core
status: Draft
created: 2024-02-27
feature: (fill in with feature tracking issues once accepted)
+supersedes: SIMD-0048
---
## Summary
From 0b52b1f36eb50d8d6fc7b0830adc4926531811f5 Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Wed, 28 Feb 2024 16:33:57 -0700
Subject: [PATCH 18/39] Revert "remove: SIMD-0048"
This reverts commit b8dcd3494402f9a1aede4bc70077f28fbbc5b78e.
---
...0048-precompile-for-secp256r1-sigverify.md | 278 ++++++++++++++++++
1 file changed, 278 insertions(+)
create mode 100644 proposals/0048-precompile-for-secp256r1-sigverify.md
diff --git a/proposals/0048-precompile-for-secp256r1-sigverify.md b/proposals/0048-precompile-for-secp256r1-sigverify.md
new file mode 100644
index 000000000..99c15ad2d
--- /dev/null
+++ b/proposals/0048-precompile-for-secp256r1-sigverify.md
@@ -0,0 +1,278 @@
+---
+simd: "0048"
+title: Precompile for verifying secp256r1 sig.
+authors:
+ - Orion (Bunkr)
+ - Jstnw (Bunkr)
+ - Dean (Web3 Builders Alliance)
+category: Standard
+type: Core
+status: Draft
+created: 2023-05-14
+feature: (fill in with feature tracking issues once accepted)
+---
+
+
+## [DEPRECATED IN FAVOR OF SIMD-0075]
+
+
+## Summary
+
+Adding a precompile to support the verification of signatures generated on
+the secp256r1 curve. Analogous to the support for secp256k1 and ed25519
+signatures that already exists in form of the
+`KeccakSecp256k11111111111111111111111111111` and
+`Ed25519SigVerify111111111111111111111111111` precompiles.
+
+## Motivation
+
+Solana has the opportunity to leverage the secure element of users' existing
+mobile devices to support more user-friendly self-custodial security solutions.
+The status quo of air-gapping signing with a hardware wallet currently requires
+specialty hardware and still represents a single point of failure. Multi-signature
+wallets provide enhanced security through multi-party signing, however the UX
+is cumbersome due to the need to sign transactions multiple times and manage
+multiple seed phrases. A much more ergonomic approach combining the best of
+these two solutions on generalised mobile hardware could be achieved by adding
+support for secp256r1 signatures.
+
+There are already several standardised implementations of this, such as Passkeys
+and WebAuthn. These solutions leverage Apple's Secure Enclave and Android Keystore
+to enable users to save keypairs associated to different services natively on
+the secure element of their mobile devices. To authenticate with
+those services, the user uses their biometrics to sign a message with the stored
+private key.
+
+While originally intended to solve for password-less authentication in Web2
+applications, WebAuthn and Passkeys also make an excellent candidate for on-chain
+second-factor authentication. Beyond simply securing funds, there are also many
+other potential beneficial abstractions that could make use of the simple UX
+they provide.
+
+Although WebAuthn supports the following curves:
+
+- P-256
+- P-384
+- P-521
+- ed25519
+
+P-256 is the only one supported by both Android & MacOS/iOS (MacOS/iOS being the
+more restrictive of the two), hence the goal being to implement secp256r1 signature
+verification
+
+General Documentation:
+
+[WebAuthn](https://webauthn.io/)
+
+[Passkeys](https://fidoalliance.org/passkeys/)
+
+**Note: P-256 / secp256r1 / prime256v1 are used interchangably in this document
+as they represent the same elliptic curve. The choice of nomenclature depends on
+what RFC or SEC document is being referenced.**
+
+## Alternatives Considered
+
+We have discussed the following alternatives:
+
+1.) Realising signature verification with a syscall similar
+to `secp256k1_recover()` instead of a precompile. This would ease
+integration for developers, since no instruction introspection would be
+required when utilizing the syscall. This is still a valid consideration.
+
+2.) Realising signature verification through and on-chain sBPF implemenation. On
+a local validator a single signature verification consumes ≈42M compute units.
+A possibility would be to split the verification into multiple transactions.
+This would most probably require off-chain infrastructure to crank the process
+or carry higher transaction fees for the end user. (similar to the current elusiv
+protocol private transfer)
+We feel this alternative directly contradicts and impinges on the main upside of
+passkeys, which is the incredible UX and ease of use to the end user.
+
+3.) Allowing for high-S signatures was considered, however the pitfalls
+of signature malleability are too great to leave open to implementation.
+
+4.) Allowing for uncompressed keys was considered, however as we are already
+taking an opinionated stance on signature malleability, it makes sense to
+also take an opinionated stance on public key encoding.
+
+## New Terminology
+
+None
+
+## Detailed Design
+
+The precompile's purpose is to verify signatures using ECDSA-256.
+(denoted in [RFC6460](https://www.ietf.org/rfc/rfc6460.txt) as
+ECDSA using the NIST P-256 curve and the SHA-256 hashing algorithm)
+
+### Curve
+
+The curve parameters for NIST P-256/secp256r1/prime256v1 are
+outlined in the [SEC2](https://www.secg.org/SEC2-Ver-1.0.pdf#page=21)
+document in Section 2.7.2
+
+### Point Encoding/Decoding
+
+The precompile should accept SEC1 encoded points in compressed form.
+The encoding and decoding of these is outlined in sections
+`2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion`
+and `2.3.4 Octet-String-to-Elliptic-Curve-Point Conversion`
+found in [SEC1](https://www.secg.org/sec1-v2.pdf#page=16).
+
+The SEC1 encoded EC point P = (x_p, y_p) in compressed form consists
+of 33 bytes (octets). The first byte of 02_16 / 03_16 signifies a
+compressed point, as well as whether y_p is odd or even. The remaining
+32 bytes represent x_p converted into a 32 octet string.
+
+While SEC1 encoded uncompressed points could also be used,
+due to their larger size of 65 bytes, the ease of transformation
+between uncompressed and compressed points, and the vast majority
+of applications exclusively making use of compressed points, it
+seems a reasonable consideration to save 32 bytes of instruction
+data with a protocol that only accepts compressed points.
+
+**Note:** When it comes to public key encoding, the existing
+precompile for `secp256k1` utilizes a vastly different standard,
+accepting a 20 octet Ethereum address and recovery id to recover an
+SEC1 encoded uncompressed point. This is due to the primary aim of the
+program not being to verify ECDSA signatures but to provide parity with
+`ecrecover` on EVM. Conversely, the `ed25519` program, which is
+primarily concerned with verifying ed25519 signatures, utilises the most
+common ed25519 convention of encoding x_p as a single 32 octet string.
+As the goals of the `secp256r1` program are more analogous to those of the
+`ed25519` program, we propose the SEC1 compressed point encoding to conform
+to the most widely-used standard in common ECDSA applications.
+
+### ECDSA / Signature Verification
+
+The precompile should implement the `Verifying Operation` outlined in
+[SEC1](https://www.secg.org/sec1-v2.pdf#page=52)
+in Section 4.1.4 as well as in the
+[Digital Signature Standard (DSS)](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf#page=36)
+document in Section 6.4.2.
+
+A multitude of test vectors to verify correctness can
+be found in
+[RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5)
+in Section A.2.5 as well as at the
+[NIST CAVP](https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/digital-signatures#ecdsa2vs)
+(Cryptographic Algorithm Validation Program)
+
+### Signature Malleability
+
+Due to X axis symmetry along the elliptic curve, for any ECDSA signature
+`(r, s)`, there also exists a valid signature `(r, n - s)`, where `n` is the
+order of the curve. This introduces "s malleability", allowing an attacker
+to produce an alternative version of `s` without invalidating the signature.
+
+The pitfalls of this in authentication systems can be particularly perilous,
+opening up certain implementations to signature replay attacks over the same
+message by simply flipping the `s` value over the curve.
+
+As the primary goal of the `secp256r1` program is secure signature validation
+for authentication purposes, the precompile should mitigate these attacks
+by enforcing the usage of `lowS` values, in which `s <= n/2`.
+
+As such, the program should immediately fail upon the detection of any
+signature that includes a `highS` value. This prevents any accidental
+succeptibility to signature malleability attacks.
+
+Note: The existing `secp256k1` precompile makes no attempt attempt to mitigate
+s malleability, as doing so would go against its primary goal of achieving
+`ecrecover` parity with EVM.
+
+### Program
+
+ID: `Secp256r1SigVerify1111111111111111111111111`
+
+The program instruction will be composed of the following:
+
+- A first u8 as the count for the number of signatures to check
+- Single byte of padding
+- The following struct serialized, for each signature to verify
+
+```rust
+struct Secp256r1SignatureOffsets {
+ signature_offset: u16, // offset to 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 msg data
+}
+```
+
+Multiple signatures can be verified. If any of the signatures fail to verify,
+an error is returned.
+
+The program logic will be constructed and built using a `verify`
+function, as outlined in
+[sdk/src/precompiles.rs](https://github.com/solana-labs/solana/blob/9ffbe2afd8ab5b972c4ad87d758866a3e1bb87fb/sdk/src/precompiles.rs).
+
+Apart from the signature verification, the remaining
+logic should be constructed analogously to the existing
+[ed25519](https://github.com/solana-labs/solana/blob/master/sdk/src/ed25519_instruction.rs)
+& [secp256k1](https://github.com/solana-labs/solana/blob/9ffbe2afd8ab5b972c4ad87d758866a3e1bb87fb/sdk/src/secp256k1_instruction.rs#L4)
+precompiles.
+
+### Implementation
+
+The precompile can be implemented using the `p256` crate at version `0.10.1`.
+This crate is part of the `Rust Crypto` library and implements the NIST P-256
+curve as well as ECDSA. It conforms with the test vectors found in
+[RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5).
+
+- `p256::ecdsa::VerifyingKey::from_sec1_bytes()`
+- `p256::ecdsa::Signature::from_scalars()`
+- `p256::arithmetic::Scalar::is_high()`
+- `p256::ecdsa::VerifyingKey::verify()`
+
+Note: The crate is well maintained, but has never been externally audited.
+
+### Compute Cost / Efficiency
+
+Once the implementation is finished, benchmarking should take place on a
+sufficiently powerful machine in order to determine average compute time per
+signature. Calculation of CUs would be based on the 1 CU / ns convention.
+The secp256k1 ecrecover syscall, which incurs a cost of 25_000 CUs, can be used
+as a reference point.
+
+This is in line with how previous precompiles for EC group operations and
+arithmetic were evaluated/benchmarked.
+See [PR#27961](https://github.com/solana-labs/solana/pull/27961) & [PR#28503](https://github.com/solana-labs/solana/pull/28503)
+
+## Impact
+
+Would enable the on-chain usage of Passkeys and the WebAuthn Standard, and
+turn the vast majority of modern smartphones into native hardware wallets.
+
+By extension, this would also enable the creation of account abstractions and
+forms of Two-Factor Authentication around those keypairs.
+
+## Security Considerations
+
+As [Firedancer](https://github.com/firedancer-io/firedancer) is being developed
+in C, it is imperative that there can be bit-level reproducibility between
+the precompile implementations. Any discrepancy between the two implementations
+could cause a fork and or a chain halt. (Thank you @ripatel-fd for pointing this
+out and advocating for it)
+
+As such we would propose the following:
+
+- Development of a thorough test suite that includes all test vectors as well
+ as tests from the
+ [Wycheproof Project](https://github.com/google/wycheproof#project-wycheproof)
+
+- Direct comparison and analysis of `p256` verification routines and group/field
+ operations with those found in the `prime256v1` OpenSSL implementation
+
+- Thorough auditing of the arithmetic and
+ decoding inside the `p256` crate
+
+## Backwards Compatibility
+
+Transactions using the instruction could not be used on Solana versions which don't
+implement this feature. A Feature gate should be used to enable this feature
+when the majority of the cluster is using the required version. Transactions
+that do not use this feature are not impacted.
From 7a7e7737386c4fb101e1fa3c3824c7fb07803409 Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Wed, 28 Feb 2024 16:35:04 -0700
Subject: [PATCH 19/39] change: old SIMD status to withdrawn
---
proposals/0048-precompile-for-secp256r1-sigverify.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/proposals/0048-precompile-for-secp256r1-sigverify.md b/proposals/0048-precompile-for-secp256r1-sigverify.md
index 99c15ad2d..a50988b81 100644
--- a/proposals/0048-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0048-precompile-for-secp256r1-sigverify.md
@@ -7,7 +7,7 @@ authors:
- Dean (Web3 Builders Alliance)
category: Standard
type: Core
-status: Draft
+status: Withdrawn
created: 2023-05-14
feature: (fill in with feature tracking issues once accepted)
---
From af3419469c7aa82b4e7ce6646b4c83a0684986ef Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Wed, 28 Feb 2024 16:38:01 -0700
Subject: [PATCH 20/39] remove: Deprecated note for linting
---
proposals/0048-precompile-for-secp256r1-sigverify.md | 4 ----
1 file changed, 4 deletions(-)
diff --git a/proposals/0048-precompile-for-secp256r1-sigverify.md b/proposals/0048-precompile-for-secp256r1-sigverify.md
index a50988b81..dadaad06d 100644
--- a/proposals/0048-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0048-precompile-for-secp256r1-sigverify.md
@@ -12,10 +12,6 @@ created: 2023-05-14
feature: (fill in with feature tracking issues once accepted)
---
-
-## [DEPRECATED IN FAVOR OF SIMD-0075]
-
-
## Summary
Adding a precompile to support the verification of signatures generated on
From d546c80961ae5519493ad0a125fe3b78cfa6d4b2 Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Thu, 29 Feb 2024 07:31:35 -0700
Subject: [PATCH 21/39] fix: SIMD should be timeless
---
.../0075-precompile-for-secp256r1-sigverify.md | 15 +++++----------
1 file changed, 5 insertions(+), 10 deletions(-)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index 38c933218..cb2ba08a2 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -227,15 +227,11 @@ It conforms with the test vectors found in
Due to the unaudited and somewhat unknown nature of the `p256` crate and
the strict security and reproducibility considerations required to enable
-compatibility with Firedancer, we propose to implement the precompile utilizing
+compatibility with other clients, we propose to implement the precompile utilizing
the `OpenSSL` [crate](https://crates.io/crates/openssl/0.10.57).
The `OpenSSL` crate is already a dependency in the Anza client and has
additionally been heavily scrutinized/tested by the broader public.
-Addtionally with regard to the development of Firedancer, the OpenSSL rust crate
-merely wraps and binds to the underlying C implementation of OpenSSL. This eases
-the effort in ensuring reproducibility between the Firedancer and Anza client.
-
Our benchmarks also show that verifying a signature using the `OpenSSL` crate is
~3x faster than using the `p256` crate.
@@ -312,11 +308,10 @@ forms of Two-Factor Authentication around those keypairs.
## Security Considerations
-As [Firedancer](https://github.com/firedancer-io/firedancer) is being developed
-in C, it is imperative that there can be bit-level reproducibility between
-the precompile implementations. Any discrepancy between the two implementations
-could cause a fork and or a chain halt. (Thank you @ripatel-fd for pointing this
-out and advocating for it)
+As multiple other clients are being developed, it is imperative that there can
+be bit-level reproducibility between the precompile implementations, especially
+with regard to cryptographic operations. Any discrepancy between implementations
+could cause a fork and or a chain halt.
As such we would propose the following:
From 9d3a7a2566782d5c745f7ebc91f1f101fda78d46 Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Thu, 29 Feb 2024 18:20:22 -0700
Subject: [PATCH 22/39] Revert: simd 0048 rename & add superseded-by to header
---
...gverify.md => 0048-native-program-for-secp256r1-sigverify.md} | 1 +
1 file changed, 1 insertion(+)
rename proposals/{0048-precompile-for-secp256r1-sigverify.md => 0048-native-program-for-secp256r1-sigverify.md} (99%)
diff --git a/proposals/0048-precompile-for-secp256r1-sigverify.md b/proposals/0048-native-program-for-secp256r1-sigverify.md
similarity index 99%
rename from proposals/0048-precompile-for-secp256r1-sigverify.md
rename to proposals/0048-native-program-for-secp256r1-sigverify.md
index dadaad06d..d7e40cd88 100644
--- a/proposals/0048-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0048-native-program-for-secp256r1-sigverify.md
@@ -10,6 +10,7 @@ type: Core
status: Withdrawn
created: 2023-05-14
feature: (fill in with feature tracking issues once accepted)
+superseded-by: "0075"
---
## Summary
From 8e210466148de41b9aaa8d9c28725df18b10f8c5 Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Thu, 29 Feb 2024 18:21:23 -0700
Subject: [PATCH 23/39] edit: supersedes field on simd 0075
---
proposals/0075-precompile-for-secp256r1-sigverify.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index cb2ba08a2..f92e6897d 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -10,7 +10,7 @@ type: Core
status: Draft
created: 2024-02-27
feature: (fill in with feature tracking issues once accepted)
-supersedes: SIMD-0048
+supersedes: "0048"
---
## Summary
From 0238317ff596f2d6ead38b6afdabddcb0d39a7af Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Thu, 29 Feb 2024 18:22:41 -0700
Subject: [PATCH 24/39] rm: superfluous/unnecessary note from design section
---
proposals/0075-precompile-for-secp256r1-sigverify.md | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index f92e6897d..7284b5746 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -128,17 +128,7 @@ of applications exclusively making use of compressed points, it
seems a reasonable consideration to save 32 bytes of instruction
data with a protocol that only accepts compressed points.
-**Note:** When it comes to public key encoding, the existing
-precompile for `secp256k1` utilizes a vastly different standard,
-accepting a 20 octet Ethereum address and recovery id to recover an
-SEC1 encoded uncompressed point. This is due to the primary aim of the
-program not being to verify ECDSA signatures but to provide parity with
-`ecrecover` on EVM. Conversely, the `ed25519` program, which is
-primarily concerned with verifying ed25519 signatures, utilises the most
-common ed25519 convention of encoding x_p as a single 32 octet string.
-As the goals of the `secp256r1` program are more analogous to those of the
-`ed25519` program, we propose the SEC1 compressed point encoding to conform
-to the most widely-used standard in common ECDSA applications.
+
### ECDSA / Signature Verification
From a37918e7f245766fdfc9dd883c9a40f8a3e68cc5 Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Tue, 19 Mar 2024 10:33:55 +0100
Subject: [PATCH 25/39] general improvements
- revise language as per rfc2119
- move rfc design details to security considerations
- add language agnostic pseudocode structs
---
...0075-precompile-for-secp256r1-sigverify.md | 242 +++++++-----------
1 file changed, 95 insertions(+), 147 deletions(-)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index 7284b5746..e2dbf16b1 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -21,6 +21,11 @@ signatures that already exists in form of the
`KeccakSecp256k11111111111111111111111111111` and
`Ed25519SigVerify111111111111111111111111111` precompiles.
+The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
+NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and
+"OPTIONAL" in this document are to be interpreted as described in
+RFC 2119.
+
## Motivation
Solana has the opportunity to leverage the secure element of users' existing
@@ -102,48 +107,8 @@ The precompile's purpose is to verify signatures using ECDSA-256.
(denoted in [RFC6460](https://www.ietf.org/rfc/rfc6460.txt) as
ECDSA using the NIST P-256 curve and the SHA-256 hashing algorithm)
-### Curve
-
-The curve parameters for NIST P-256/secp256r1/prime256v1 are
-outlined in the [SEC2](https://www.secg.org/SEC2-Ver-1.0.pdf#page=21)
-document in Section 2.7.2
-
-### Point Encoding/Decoding
-
-The precompile should accept SEC1 encoded points in compressed form.
-The encoding and decoding of these is outlined in sections
-`2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion`
-and `2.3.4 Octet-String-to-Elliptic-Curve-Point Conversion`
-found in [SEC1](https://www.secg.org/sec1-v2.pdf#page=16).
-
-The SEC1 encoded EC point P = (x_p, y_p) in compressed form consists
-of 33 bytes (octets). The first byte of 02_16 / 03_16 signifies a
-compressed point, as well as whether y_p is odd or even. The remaining
-32 bytes represent x_p converted into a 32 octet string.
-
-While SEC1 encoded uncompressed points could also be used,
-due to their larger size of 65 bytes, the ease of transformation
-between uncompressed and compressed points, and the vast majority
-of applications exclusively making use of compressed points, it
-seems a reasonable consideration to save 32 bytes of instruction
-data with a protocol that only accepts compressed points.
-
-
-
-### ECDSA / Signature Verification
-
-The precompile should implement the `Verifying Operation` outlined in
-[SEC1](https://www.secg.org/sec1-v2.pdf#page=52)
-in Section 4.1.4 as well as in the
-[Digital Signature Standard (DSS)](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf#page=36)
-document in Section 6.4.2.
-
-A multitude of test vectors to verify correctness can
-be found in
-[RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5)
-in Section A.2.5 as well as at the
-[NIST CAVP](https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/digital-signatures#ecdsa2vs)
-(Cryptographic Algorithm Validation Program)
+Apart from the RFC mandated implementation the precompile must additionally take
+an opinionated stance on signature malleability.
### Signature Malleability
@@ -157,10 +122,10 @@ opening up certain implementations to signature replay attacks over the same
message by simply flipping the `s` value over the curve.
As the primary goal of the `secp256r1` program is secure signature validation
-for authentication purposes, the precompile should mitigate these attacks
+for authentication purposes, the precompile must mitigate these attacks
by enforcing the usage of `lowS` values, in which `s <= n/2`.
-As such, the program should immediately fail upon the detection of any
+As such, the program must immediately fail upon the detection of any
signature that includes a `highS` value. This prevents any accidental
succeptibility to signature malleability attacks.
@@ -168,135 +133,122 @@ Note: The existing `secp256k1` precompile makes no attempt attempt to mitigate
s malleability, as doing so would go against its primary goal of achieving
`ecrecover` parity with EVM.
+### Implementation
+
### Program
ID: `Secp256r1SigVerify1111111111111111111111111`
-The program instruction will be composed of the following:
+The program instruction must be composed of the following struct:
+
+In Pseudocode:
-- A first u8 as the count for the number of signatures to check
-- Single byte of padding
-- The following struct serialized, for each signature to verify
+```
+struct Secp256r1SigVerifyInstruction {
+ count: uint8 LE, // Number of signatures to check
+ padding: uint8 LE, // Single byte of padding
+ signatureOffsets: Array, // Array of signature offset structs
+}
-```rust
struct Secp256r1SignatureOffsets {
- signature_offset: u16, // offset to 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 msg data
+ signature_offset: uint16 LE, // Offset to secp256r1 signature of 64 bytes
+ signature_instruction_index: uint8 LE, // Instruction index to find signature
+ public_key_offset: uint16 LE, // Offset to compressed public key
+ public_key_instruction_index: uint8 LE, // Instruction index to find public key
+ message_data_offset: uint16 LE, // Offset to start of message data
+ message_data_size: uint16 LE, // Size of message data
+ message_instruction_index: uint8 LE, // Index of instruction data to get message data
}
```
Multiple signatures can be verified. If any of the signatures fail to verify,
-an error is returned.
-
-The program logic will be constructed and built using a `verify`
-function, as outlined in
-[sdk/src/precompiles.rs](https://github.com/solana-labs/solana/blob/9ffbe2afd8ab5b972c4ad87d758866a3e1bb87fb/sdk/src/precompiles.rs).
-
-Apart from the signature verification, the remaining
-logic should be constructed analogously to the existing
-[ed25519](https://github.com/solana-labs/solana/blob/master/sdk/src/ed25519_instruction.rs)
-& [secp256k1](https://github.com/solana-labs/solana/blob/9ffbe2afd8ab5b972c4ad87d758866a3e1bb87fb/sdk/src/secp256k1_instruction.rs#L4)
-precompiles.
-
-### Implementation
-
-#### Previous Consideration in SIMD-0048
-
-The precompile could be implemented using
-the `p256` crate at version `0.10.1`. This crate is part of the `Rust Crypto`
-library and implements the NIST P-256 curve as well as ECDSA in native Rust.
-It conforms with the test vectors found in
-[RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5).
-
-#### SIMD-0075 Update
-
-Due to the unaudited and somewhat unknown nature of the `p256` crate and
-the strict security and reproducibility considerations required to enable
-compatibility with other clients, we propose to implement the precompile utilizing
-the `OpenSSL` [crate](https://crates.io/crates/openssl/0.10.57).
-The `OpenSSL` crate is already a dependency in the Anza client and has
-additionally been heavily scrutinized/tested by the broader public.
-
-Our benchmarks also show that verifying a signature using the `OpenSSL` crate is
-~3x faster than using the `p256` crate.
+an error must be returned.
-Signature verification using the OpenSSL crate includes the following steps:
+Therfore the instruction processing logic must follow the pseudocode below:
-1. Getting the curve order using the Nid::X9_62_PRIME256V1 identifier:
-
- ```rust
- let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1)
- ```
-
-2. Ensuring the `r` & `s` signature components fall within `curve_order - 1`
-3. Recreating the signature using the `r` & `s` signature components:
-
- ```rust
- let ecdsa_sig = openssl::ecdsa::EcdsaSig::from_private_components(r_bignum, s_bignum)
+```
+instructions = transactionInsructions;
+for i in 0..count {
+ signature = instructions[signature_instruction_index].data[signature_offset..signature_offset+64]
+ if signature_S == highS {
+ return Error
+ }
+ publicKey = instructions[public_key_instruction_index].data[public_key_offset..public_key_offset+33]
+ message = instructions[message_instruction_index].data[message_data_offset..message_data_offset+message_data_size]
+ result = secp256verify(publicKey, message, signature)
+ if result != true {
+ return Error
+ }
+}
+return Success
+```
- let der_sig = ecdsa_sig.to_der()
- ```
+Additonally the precompile's core `verify` function must be constructed in accordance with the
+structure outlined in
+[sdk/src/precompiles.rs](https://github.com/solana-labs/solana/blob/9ffbe2afd8ab5b972c4ad87d758866a3e1bb87fb/sdk/src/precompiles.rs).
-4. Computing the `half_order`of the curve and ensuring that `s < half_order`
- (LowS Check)
-5. Parsing the public key bytes:
+### Compute Cost / Efficiency
- ```rust
- let ec_point = EcPoint::from_bytes(&group, pubkey, &mut ctx)
+Benchmarking and compute cost calculations must be done in accordance with [SIMD-0121](https://github.com/solana-foundation/solana-improvement-documents/pull/121)
- let ec_key = EcKey::from_public_key(&group, &ec_point)
+Additionally, comparisons to existing precompiles should be done to check for
+comperable efficiency.
- let pkey = PKey::from_ec_key(ec_key)
- ```
+## Impact
-6. Creating a verfier from the public key and the OpenSSL SHA-256 hashing idendifier:
+Would enable the on-chain usage of Passkeys and the WebAuthn Standard, and
+turn the vast majority of modern smartphones into native hardware wallets.
- ```rust
- Verifier::new(openssl::hash::MessageDigest::sha256(), &pkey)
- ```
+By extension, this would also enable the creation of account abstractions and
+forms of Two-Factor Authentication around those keypairs.
-7. Passing the message bytes to the verifier:
+## Security Considerations
- ```rust
- verifier.update(message)
- ```
+The following security considerations must be made for
+implementation of ECDSA over NIST P-256.
-8. Verify signature across the message:
+### Curve
- ```rust
- verifier.verify(&der_sig)
- ```
+The curve parameters for NIST P-256/secp256r1/prime256v1 are
+outlined in the [SEC2](https://www.secg.org/SEC2-Ver-1.0.pdf#page=21)
+document in Section 2.7.2
-### Compute Cost / Efficiency
+### Point Encoding/Decoding
-Once the implementation is finished, benchmarking should take place on a
-sufficiently powerful machine in order to determine average compute time per
-signature. Calculation of CUs would be based on the 1 CU / ns convention.
-The secp256k1 ecrecover syscall, which incurs a cost of 25_000 CUs, can be used
-as a reference point.
+The precompile must accept SEC1 encoded points in compressed form.
+The encoding and decoding of these is outlined in sections
+`2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion`
+and `2.3.4 Octet-String-to-Elliptic-Curve-Point Conversion`
+found in [SEC1](https://www.secg.org/sec1-v2.pdf#page=16).
-Since precompiles don't incur a flat compute cost like syscalls, this comparison
-will just serve as a confirmation that the computation inside the precompile is
-sufficiently efficient.
+The SEC1 encoded EC point P = (x_p, y_p) in compressed form consists
+of 33 bytes (octets). The first byte of 02_16 / 03_16 signifies a
+compressed point, as well as whether y_p is odd or even. The remaining
+32 bytes represent x_p converted into a 32 octet string.
-This is in line with how previous precompiles for EC group operations and
-arithmetic were evaluated/benchmarked.
-See [PR#27961](https://github.com/solana-labs/solana/pull/27961) & [PR#28503](https://github.com/solana-labs/solana/pull/28503)
+While SEC1 encoded uncompressed points could also be used,
+due to their larger size of 65 bytes, the ease of transformation
+between uncompressed and compressed points, and the vast majority
+of applications exclusively making use of compressed points, it
+seems a reasonable consideration to save 32 bytes of instruction
+data with a protocol that only accepts compressed points.
-## Impact
+### ECDSA / Signature Verification
-Would enable the on-chain usage of Passkeys and the WebAuthn Standard, and
-turn the vast majority of modern smartphones into native hardware wallets.
+The precompile must implement the `Verifying Operation` outlined in
+[SEC1](https://www.secg.org/sec1-v2.pdf#page=52)
+in Section 4.1.4 as well as in the
+[Digital Signature Standard (DSS)](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf#page=36)
+document in Section 6.4.2.
-By extension, this would also enable the creation of account abstractions and
-forms of Two-Factor Authentication around those keypairs.
+A multitude of test vectors to verify correctness can
+be found in
+[RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5)
+in Section A.2.5 as well as at the
+[NIST CAVP](https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/digital-signatures#ecdsa2vs)
+(Cryptographic Algorithm Validation Program)
-## Security Considerations
+### General
As multiple other clients are being developed, it is imperative that there can
be bit-level reproducibility between the precompile implementations, especially
@@ -309,8 +261,8 @@ As such we would propose the following:
as tests from the
[Wycheproof Project](https://github.com/google/wycheproof#project-wycheproof)
-- Creating a map of what underlying OpenSSL calls get added to the runtime when
- using the Rust bindings
+- Maintaining active communication with other clients to ensure parity and to
+support potential changes if they arise.
## Backwards Compatibility
@@ -318,7 +270,3 @@ Transactions using the instruction could not be used on Solana versions which do
implement this feature. A Feature gate should be used to enable this feature
when the majority of the cluster is using the required version. Transactions
that do not use this feature are not impacted.
-
-```
-
-```
From 10fb03fd7f087691be338bc9206f04a602ea509b Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Sun, 31 Mar 2024 22:31:30 -0400
Subject: [PATCH 26/39] fixes
---
...0075-precompile-for-secp256r1-sigverify.md | 43 +++++++++++++++----
1 file changed, 35 insertions(+), 8 deletions(-)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index e2dbf16b1..909ba588b 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -146,7 +146,7 @@ In Pseudocode:
```
struct Secp256r1SigVerifyInstruction {
count: uint8 LE, // Number of signatures to check
- padding: uint8 LE, // Single byte of padding
+ padding: uint8 LE, // Single byte padding
signatureOffsets: Array, // Array of signature offset structs
}
@@ -164,10 +164,37 @@ struct Secp256r1SignatureOffsets {
Multiple signatures can be verified. If any of the signatures fail to verify,
an error must be returned.
-Therfore the instruction processing logic must follow the pseudocode below:
+If the instruction data is empty, the program must return an error.
+
+If `count == 0` and the length of the instruction data > 1, the program must
+return an error.
+
+If `count == 0` and the length of the instruction data is not at least
+`count * Secp256r1SignatureOffsets + 1`, the program must return an error.
+
+The instruction processing logic must follow the pseudocode below:
```
-instructions = transactionInsructions;
+/// `data` is the secp256r1 program's instruction data. `instruction_datas` is
+/// the full slice of instruction datas for all instructions in the transaction,
+/// including the secp256r1 program's instruction data.
+
+/// length_of_data is the length of `data`
+
+/// SERIALIZED_OFFSET_STRUCT_SIZE is the length of the serialized
+/// Secp256r1SignatureOffsets struct
+
+if length_of_data == 0 {
+ return Error
+}
+count = data[0]
+if count == 0 && length_of_data > 1 {
+ return Error
+}
+if length_of_data < (count * SERIALIZED_OFFSET_STRUCT_SIZE + 1) {
+ return Error
+}
+instructions = instruction_datas;
for i in 0..count {
signature = instructions[signature_instruction_index].data[signature_offset..signature_offset+64]
if signature_S == highS {
@@ -204,7 +231,7 @@ forms of Two-Factor Authentication around those keypairs.
## Security Considerations
-The following security considerations must be made for
+The following security considerations must be made for the
implementation of ECDSA over NIST P-256.
### Curve
@@ -250,8 +277,8 @@ in Section A.2.5 as well as at the
### General
-As multiple other clients are being developed, it is imperative that there can
-be bit-level reproducibility between the precompile implementations, especially
+As multiple other clients are being developed, it is imperative that there is
+bit-level reproducibility between the precompile implementations, especially
with regard to cryptographic operations. Any discrepancy between implementations
could cause a fork and or a chain halt.
@@ -261,8 +288,8 @@ As such we would propose the following:
as tests from the
[Wycheproof Project](https://github.com/google/wycheproof#project-wycheproof)
-- Maintaining active communication with other clients to ensure parity and to
-support potential changes if they arise.
+- Maintaining active communication with other clients to ensure parity and to
+ support potential changes if they arise.
## Backwards Compatibility
From 7c923ee9378030b796a60a3f0f3ccae7cd2b5c0f Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Sun, 31 Mar 2024 22:43:03 -0400
Subject: [PATCH 27/39] fix: linting
---
.../0075-precompile-for-secp256r1-sigverify.md | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index 909ba588b..0b66cbc8a 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -147,17 +147,17 @@ In Pseudocode:
struct Secp256r1SigVerifyInstruction {
count: uint8 LE, // Number of signatures to check
padding: uint8 LE, // Single byte padding
- signatureOffsets: Array, // Array of signature offset structs
+ signatureOffsets: Array, // Array of structs
}
struct Secp256r1SignatureOffsets {
- signature_offset: uint16 LE, // Offset to secp256r1 signature of 64 bytes
- signature_instruction_index: uint8 LE, // Instruction index to find signature
- public_key_offset: uint16 LE, // Offset to compressed public key
- public_key_instruction_index: uint8 LE, // Instruction index to find public key
+ signature_offset: uint16 LE, // Offset to signature
+ signature_instruction_index: uint8 LE, // Instruction index to signature
+ public_key_offset: uint16 LE, // Offset to public key
+ public_key_instruction_index: uint8 LE, // Instruction index to public key
message_data_offset: uint16 LE, // Offset to start of message data
message_data_size: uint16 LE, // Size of message data
- message_instruction_index: uint8 LE, // Index of instruction data to get message data
+ message_instruction_index: uint8 LE, // Instruction index to message
}
```
@@ -210,9 +210,8 @@ for i in 0..count {
return Success
```
-Additonally the precompile's core `verify` function must be constructed in accordance with the
-structure outlined in
-[sdk/src/precompiles.rs](https://github.com/solana-labs/solana/blob/9ffbe2afd8ab5b972c4ad87d758866a3e1bb87fb/sdk/src/precompiles.rs).
+Additonally the precompile's core `verify` function must be constructed in
+accordance with the structure outlined in [sdk/src/precompiles.rs](https://github.com/solana-labs/solana/blob/9ffbe2afd8ab5b972c4ad87d758866a3e1bb87fb/sdk/src/precompiles.rs).
### Compute Cost / Efficiency
From e6d160d2d93d4045af4fa59db3693f1846186efa Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Mon, 1 Apr 2024 11:02:04 -0400
Subject: [PATCH 28/39] reset: changes to simd-0048
---
...-native-program-for-secp256r1-sigverify.md | 223 ++++--------------
1 file changed, 46 insertions(+), 177 deletions(-)
diff --git a/proposals/0048-native-program-for-secp256r1-sigverify.md b/proposals/0048-native-program-for-secp256r1-sigverify.md
index 461fdf8a4..c1e2e0e15 100644
--- a/proposals/0048-native-program-for-secp256r1-sigverify.md
+++ b/proposals/0048-native-program-for-secp256r1-sigverify.md
@@ -1,10 +1,9 @@
---
simd: "0048"
-title: Precompile for verifying secp256r1 sig.
+title: Native Program for verifying secp256r1 sig.
authors:
- Orion (Bunkr)
- Jstnw (Bunkr)
- - Dean (Web3 Builders Alliance)
category: Standard
type: Core
status: Withdrawn
@@ -13,7 +12,6 @@ created: 2023-05-14
## Summary
-
Adding a Native Program to support the verification of signatures
generated on the secp256r1 curve.
Analogous to the support for secp256k1 and ed25519 signatures that already
@@ -22,31 +20,29 @@ the `KeccakSecp256k11111111111111111111111111111` and
`Ed25519SigVerify111111111111111111111111111`
native programs
-
## Motivation
-Solana has the opportunity to leverage the secure element of users' existing
-mobile devices to support more user-friendly self-custodial security solutions.
-The status quo of air-gapping signing with a hardware wallet currently requires
-specialty hardware and still represents a single point of failure. Multi-signature
-wallets provide enhanced security through multi-party signing, however the UX
-is cumbersome due to the need to sign transactions multiple times and manage
-multiple seed phrases. A much more ergonomic approach combining the best of
-these two solutions on generalised mobile hardware could be achieved by adding
-support for secp256r1 signatures.
-
-There are already several standardised implementations of this, such as Passkeys
-and WebAuthn. These solutions leverage Apple's Secure Enclave and Android Keystore
-to enable users to save keypairs associated to different services natively on
-the secure element of their mobile devices. To authenticate with
-those services, the user uses their biometrics to sign a message with the stored
-private key.
-
-While originally intended to solve for password-less authentication in Web2
-applications, WebAuthn and Passkeys also make an excellent candidate for on-chain
-second-factor authentication. Beyond simply securing funds, there are also many
-other potential beneficial abstractions that could make use of the simple UX
-they provide.
+Solana should have option to secure your funds in a self custodial manner that
+doesn't just airgap your private key with a hardware wallet (which even then
+remains as a single point of failure). Arguably, multi-signature wallets fit
+into this equation as they enable the dependency on multiple private keys.
+However in practice the UX takes too much of a hit, as having to sign a
+transaction a minimum of 3 seperate times and having to write down 3 seed
+phrases is too cumbersome. It would be ideal to have an authetication form that
+relies on a more familiar second factor, such as a users mobile device.
+
+Passkeys & WebAuthn are a standardized implementation of this. They enable users
+to save keypairs associated to different services natively on the secure
+element of their mobile device. To authenticate with those services, the user
+uses their biometrics to sign a message with the stored private key.
+
+And although this is meant to enable password-less logins in web2, it makes for
+an excellent candidate as a second factor of on-chain authentication.
+
+Going past just securing funds, this would support other beneficial account
+abstractions that make use of the simple UX of WebAuthn and Passkeys.
+
+Note:
Although WebAuthn supports the following curves:
@@ -55,8 +51,8 @@ Although WebAuthn supports the following curves:
- P-521
- ed25519
-P-256 is the only one supported by both Android & MacOS/iOS (MacOS/iOS being the
-more restrictive of the two), hence the goal being to implement secp256r1 signature
+P-256 is the only one suported by both Android & IOS (IOS being the more
+restrictive of the two), hence the goal being to implement secp256r1 signature
verification
General Documentation:
@@ -65,34 +61,14 @@ General Documentation:
[Passkeys](https://fidoalliance.org/passkeys/)
-**Note: P-256 / secp256r1 / prime256v1 are used interchangably in this document
-as they represent the same elliptic curve. The choice of nomenclature depends on
-what RFC or SEC document is being referenced.**
-
## Alternatives Considered
We have discussed the following alternatives:
1.) Realising signature verification with a syscall similar
-to `secp256k1_recover()` instead of a precompile. This would ease
+to `secp256k1_recover()` instead of a native program. This would ease
integration for developers, since no instruction introspection would be
-required when utilizing the syscall. This is still a valid consideration.
-
-2.) Realising signature verification through and on-chain sBPF implemenation. On
-a local validator a single signature verification consumes ≈42M compute units.
-A possibility would be to split the verification into multiple transactions.
-This would most probably require off-chain infrastructure to crank the process
-or carry higher transaction fees for the end user. (similar to the current elusiv
-protocol private transfer)
-We feel this alternative directly contradicts and impinges on the main upside of
-passkeys, which is the incredible UX and ease of use to the end user.
-
-3.) Allowing for high-S signatures was considered, however the pitfalls
-of signature malleability are too great to leave open to implementation.
-
-4.) Allowing for uncompressed keys was considered, however as we are already
-taking an opinionated stance on signature malleability, it makes sense to
-also take an opinionated stance on public key encoding.
+required when utilizing the syscall.
## New Terminology
@@ -100,85 +76,7 @@ None
## Detailed Design
-The precompile's purpose is to verify signatures using ECDSA-256.
-(denoted in [RFC6460](https://www.ietf.org/rfc/rfc6460.txt) as
-ECDSA using the NIST P-256 curve and the SHA-256 hashing algorithm)
-
-### Curve
-
-The curve parameters for NIST P-256/secp256r1/prime256v1 are
-outlined in the [SEC2](https://www.secg.org/SEC2-Ver-1.0.pdf#page=21)
-document in Section 2.7.2
-
-### Point Encoding/Decoding
-
-The precompile should accept SEC1 encoded points in compressed form.
-The encoding and decoding of these is outlined in sections
-`2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion`
-and `2.3.4 Octet-String-to-Elliptic-Curve-Point Conversion`
-found in [SEC1](https://www.secg.org/sec1-v2.pdf#page=16).
-
-The SEC1 encoded EC point P = (x_p, y_p) in compressed form consists
-of 33 bytes (octets). The first byte of 02_16 / 03_16 signifies a
-compressed point, as well as whether y_p is odd or even. The remaining
-32 bytes represent x_p converted into a 32 octet string.
-
-While SEC1 encoded uncompressed points could also be used,
-due to their larger size of 65 bytes, the ease of transformation
-between uncompressed and compressed points, and the vast majority
-of applications exclusively making use of compressed points, it
-seems a reasonable consideration to save 32 bytes of instruction
-data with a protocol that only accepts compressed points.
-
-**Note:** When it comes to public key encoding, the existing
-precompile for `secp256k1` utilizes a vastly different standard,
-accepting a 20 octet Ethereum address and recovery id to recover an
-SEC1 encoded uncompressed point. This is due to the primary aim of the
-program not being to verify ECDSA signatures but to provide parity with
-`ecrecover` on EVM. Conversely, the `ed25519` program, which is
-primarily concerned with verifying ed25519 signatures, utilises the most
-common ed25519 convention of encoding x_p as a single 32 octet string.
-As the goals of the `secp256r1` program are more analogous to those of the
-`ed25519` program, we propose the SEC1 compressed point encoding to conform
-to the most widely-used standard in common ECDSA applications.
-
-### ECDSA / Signature Verification
-
-The precompile should implement the `Verifying Operation` outlined in
-[SEC1](https://www.secg.org/sec1-v2.pdf#page=52)
-in Section 4.1.4 as well as in the
-[Digital Signature Standard (DSS)](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-5.pdf#page=36)
-document in Section 6.4.2.
-
-A multitude of test vectors to verify correctness can
-be found in
-[RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5)
-in Section A.2.5 as well as at the
-[NIST CAVP](https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/digital-signatures#ecdsa2vs)
-(Cryptographic Algorithm Validation Program)
-
-### Signature Malleability
-
-Due to X axis symmetry along the elliptic curve, for any ECDSA signature
-`(r, s)`, there also exists a valid signature `(r, n - s)`, where `n` is the
-order of the curve. This introduces "s malleability", allowing an attacker
-to produce an alternative version of `s` without invalidating the signature.
-
-The pitfalls of this in authentication systems can be particularly perilous,
-opening up certain implementations to signature replay attacks over the same
-message by simply flipping the `s` value over the curve.
-
-As the primary goal of the `secp256r1` program is secure signature validation
-for authentication purposes, the precompile should mitigate these attacks
-by enforcing the usage of `lowS` values, in which `s <= n/2`.
-
-As such, the program should immediately fail upon the detection of any
-signature that includes a `highS` value. This prevents any accidental
-succeptibility to signature malleability attacks.
-
-Note: The existing `secp256k1` precompile makes no attempt attempt to mitigate
-s malleability, as doing so would go against its primary goal of achieving
-`ecrecover` parity with EVM.
+Implementation would be as follows:
### Program
@@ -191,12 +89,11 @@ The program instruction will be composed of the following:
- The following struct serialized, for each signature to verify
-
```rust
struct Secp256r1SignatureOffsets {
signature_offset: u16, // offset to 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_offset: u16, // offset to public key of 32 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
@@ -207,69 +104,41 @@ struct Secp256r1SignatureOffsets {
Multiple signatures can be verified. If any of the signatures fail to verify,
an error is returned.
-The program logic will be constructed and built using a `verify`
-function, as outlined in
-[sdk/src/precompiles.rs](https://github.com/solana-labs/solana/blob/9ffbe2afd8ab5b972c4ad87d758866a3e1bb87fb/sdk/src/precompiles.rs).
-
-Apart from the signature verification, the remaining
-logic should be constructed analogously to the existing
-[ed25519](https://github.com/solana-labs/solana/blob/master/sdk/src/ed25519_instruction.rs)
-& [secp256k1](https://github.com/solana-labs/solana/blob/9ffbe2afd8ab5b972c4ad87d758866a3e1bb87fb/sdk/src/secp256k1_instruction.rs#L4)
-precompiles.
+Should be analogous to `KeccakSecp256k11111111111111111111111111111`
+and `Ed25519SigVerify111111111111111111111111111`.
+View reference details at [sdk/src/ed25519_instruction.rs](https://github.com/solana-labs/solana/blob/master/sdk/src/ed25519_instruction.rs)
### Implementation
-The precompile can be implemented using the `p256` crate at version `0.10.1`.
-This crate is part of the `Rust Crypto` library and implements the NIST P-256
-curve as well as ECDSA. It conforms with the test vectors found in
-[RFC6979](https://datatracker.ietf.org/doc/html/rfc6979#appendix-A.2.5).
-
-- `p256::ecdsa::VerifyingKey::from_sec1_bytes()`
-- `p256::ecdsa::Signature::from_scalars()`
-- `p256::arithmetic::Scalar::is_high()`
-- `p256::ecdsa::VerifyingKey::verify()`
-
-Note: The crate is well maintained, but has never been externally audited.
+The crates `ecdsa` and `p256` are a good starting point for the implementation.
+Due to a current dependency version conflict of `zeroize` between
+`curve25519-dalek` and `solana-program`, using these crates will require a
+fix/bump of `zeroize` inside `curve25519-dalek`. See issue [#26688](https://github.com/solana-labs/solana/issues/26688)
-### Compute Cost / Efficiency
+### Compute Cost
Once the implementation is finished, benchmarking should take place on a
-sufficiently powerful machine in order to determine average compute time per
-signature. Calculation of CUs would be based on the 1 CU / ns convention.
-The secp256k1 ecrecover syscall, which incurs a cost of 25_000 CUs, can be used
-as a reference point.
+sufficiently powerful machine in order to determine average compute time.
+Pricing would be based on the 33ns/CU convention. For
+the sake of ensuring proper efficiency, a comparison to similar implementations
+on polygon/optimism/ethereum would be conducted.
-This is in line with how previous precompiles for EC group operations and
+This is in line with how previous native programs for EC group operations and
arithmetic were evaluated/benchmarked.
See [PR#27961](https://github.com/solana-labs/solana/pull/27961) & [PR#28503](https://github.com/solana-labs/solana/pull/28503)
## Impact
-Would enable the on-chain usage of Passkeys and the WebAuthn Standard, and
-turn the vast majority of modern smartphones into native hardware wallets.
+Would enable the on-chain usage of Passkeys and the WebAuthn Standard.
-By extension, this would also enable the creation of account abstractions and
+By extension this would also enable the creation of account abstractions and
forms of Two-Factor Authentication around those keypairs.
## Security Considerations
-As [Firedancer](https://github.com/firedancer-io/firedancer) is being developed
-in C, it is imperative that there can be bit-level reproducibility between
-the precompile implementations. Any discrepancy between the two implementations
-could cause a fork and or a chain halt. (Thank you @ripatel-fd for pointing this
-out and advocating for it)
-
-As such we would propose the following:
-
-- Development of a thorough test suite that includes all test vectors as well
- as tests from the
- [Wycheproof Project](https://github.com/google/wycheproof#project-wycheproof)
-
-- Direct comparison and analysis of `p256` verification routines and group/field
- operations with those found in the `prime256v1` OpenSSL implementation
-
-- Thorough auditing of the arithmetic and
- decoding inside the `p256` crate
+- Ensure parity of test results and parameters with those found in
+ [SEC2](https://www.secg.org/sec2-v2.pdf) for the secp256r1 curve
+- Ensure signature malleability is prevented/accounted for
## Backwards Compatibility
From 7c420a7cb2b2d2253a4a03787dda222ca5296a3b Mon Sep 17 00:00:00 2001
From: Orion <89707822+iceomatic@users.noreply.github.com>
Date: Thu, 9 May 2024 00:14:38 +0200
Subject: [PATCH 29/39] Update
proposals/0075-precompile-for-secp256r1-sigverify.md
Co-authored-by: Philip Taffet <123486962+ptaffet-jump@users.noreply.github.com>
---
proposals/0075-precompile-for-secp256r1-sigverify.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index 0b66cbc8a..3a09509e7 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -169,8 +169,8 @@ If the instruction data is empty, the program must return an error.
If `count == 0` and the length of the instruction data > 1, the program must
return an error.
-If `count == 0` and the length of the instruction data is not at least
-`count * Secp256r1SignatureOffsets + 1`, the program must return an error.
+If `count > 0` and the length of the instruction data is not at least
+`count * sizeof(Secp256r1SignatureOffsets) + 2`, the program must return an error.
The instruction processing logic must follow the pseudocode below:
From 4ae5c0fa79c029bcc57922d37f0b33fbf97694c7 Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Mon, 20 May 2024 17:24:45 +0200
Subject: [PATCH 30/39] add: length prefix & array padding comment
---
proposals/0075-precompile-for-secp256r1-sigverify.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index 3a09509e7..cb69149f0 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -149,6 +149,8 @@ struct Secp256r1SigVerifyInstruction {
padding: uint8 LE, // Single byte padding
signatureOffsets: Array, // Array of structs
}
+Note: Array does not contain any length prefixes or
+padding between elements.
struct Secp256r1SignatureOffsets {
signature_offset: uint16 LE, // Offset to signature
From 08b671e8798dfb7063ba323f16170224b7b17aa6 Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Mon, 20 May 2024 17:28:41 +0200
Subject: [PATCH 31/39] fix: missing byte of padding in line 196
---
proposals/0075-precompile-for-secp256r1-sigverify.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index cb69149f0..589e4221e 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -193,7 +193,7 @@ count = data[0]
if count == 0 && length_of_data > 1 {
return Error
}
-if length_of_data < (count * SERIALIZED_OFFSET_STRUCT_SIZE + 1) {
+if length_of_data < (count * SERIALIZED_OFFSET_STRUCT_SIZE + 2) {
return Error
}
instructions = instruction_datas;
From 3e2c2f1042ea73728fe86f055a84f834dea77505 Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Mon, 20 May 2024 17:57:25 +0200
Subject: [PATCH 32/39] add: offset & indices checks for signature, message and
publickey
---
...0075-precompile-for-secp256r1-sigverify.md | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index 589e4221e..85ce56be4 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -198,12 +198,34 @@ if length_of_data < (count * SERIALIZED_OFFSET_STRUCT_SIZE + 2) {
}
instructions = instruction_datas;
for i in 0..count {
+ if signature_instruction_index >= instructions.length {
+ return Error
+ }
+ if signature_offset + 64 > instructions[signature_instruction_index].data.length {
+ return Error
+ }
signature = instructions[signature_instruction_index].data[signature_offset..signature_offset+64]
+
if signature_S == highS {
return Error
}
+
+ if public_key_instruction_index >= instructions.length {
+ return Error
+ }
+ if public_key_offset + 33 > instructions[public_key_instruction_index].data.length {
+ return Error
+ }
publicKey = instructions[public_key_instruction_index].data[public_key_offset..public_key_offset+33]
+
+ if message_instruction_index >= instructions.length {
+ return Error
+ }
+ if message_data_offset + message_data_size > instructions[message_instruction_index].data.length {
+ return Error
+ }
message = instructions[message_instruction_index].data[message_data_offset..message_data_offset+message_data_size]
+
result = secp256verify(publicKey, message, signature)
if result != true {
return Error
From cc59debe2fa1a84644c9765cc1ead4a09f6372ce Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Mon, 20 May 2024 18:00:26 +0200
Subject: [PATCH 33/39] fix: linting
---
.../0075-precompile-for-secp256r1-sigverify.md | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index 85ce56be4..ea2523648 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -201,7 +201,8 @@ for i in 0..count {
if signature_instruction_index >= instructions.length {
return Error
}
- if signature_offset + 64 > instructions[signature_instruction_index].data.length {
+ if signature_offset + 64 > instructions[signature_instruction_index]
+ .data.length {
return Error
}
signature = instructions[signature_instruction_index].data[signature_offset..signature_offset+64]
@@ -213,19 +214,22 @@ for i in 0..count {
if public_key_instruction_index >= instructions.length {
return Error
}
- if public_key_offset + 33 > instructions[public_key_instruction_index].data.length {
+ if public_key_offset + 33 > instructions[public_key_instruction_index]
+ .data.length {
return Error
}
- publicKey = instructions[public_key_instruction_index].data[public_key_offset..public_key_offset+33]
+ publicKey = instructions[public_key_instruction_index]
+ .data[public_key_offset..public_key_offset+33]
if message_instruction_index >= instructions.length {
return Error
}
- if message_data_offset + message_data_size > instructions[message_instruction_index].data.length {
+ if message_data_offset + message_data_size > instructions[message_instruction_index]
+ .data.length {
return Error
}
message = instructions[message_instruction_index].data[message_data_offset..message_data_offset+message_data_size]
-
+
result = secp256verify(publicKey, message, signature)
if result != true {
return Error
From 9c14a98e01eaf3af8b8f8d4430f98bb97d84c809 Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Mon, 20 May 2024 18:11:07 +0200
Subject: [PATCH 34/39] fix: indentation
---
proposals/0075-precompile-for-secp256r1-sigverify.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index ea2523648..65dcef7e2 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -201,7 +201,7 @@ for i in 0..count {
if signature_instruction_index >= instructions.length {
return Error
}
- if signature_offset + 64 > instructions[signature_instruction_index]
+ if signature_offset + 64 > instructions[signature_instruction_index]
.data.length {
return Error
}
From dff1156b09097f03da7bb2d240cff7036edcfb1b Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Wed, 19 Jun 2024 01:28:10 +0200
Subject: [PATCH 35/39] refactor: modify pseudocode and data structs to comply
with SIMD 0152
---
...0075-precompile-for-secp256r1-sigverify.md | 166 ++++++++++++------
1 file changed, 111 insertions(+), 55 deletions(-)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index 65dcef7e2..77f881528 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -139,40 +139,67 @@ s malleability, as doing so would go against its primary goal of achieving
ID: `Secp256r1SigVerify1111111111111111111111111`
-The program instruction must be composed of the following struct:
+In accordance with [SIMD
+0152](https://github.com/solana-foundation/solana-improvement-documents/pull/152)
+programs ```verify``` instruction will accept the following data:
In Pseudocode:
```
struct Secp256r1SigVerifyInstruction {
- count: uint8 LE, // Number of signatures to check
+ num_signatures: uint8 LE, // Number of signatures to verify
padding: uint8 LE, // Single byte padding
- signatureOffsets: Array, // Array of structs
+ offsets: Array, // Array of offset structs
+ additionalData?: Bytes, // Optional additional data, e.g.
+ // signatures included in the same
+ // instruction
}
Note: Array does not contain any length prefixes or
padding between elements.
struct Secp256r1SignatureOffsets {
signature_offset: uint16 LE, // Offset to signature
- signature_instruction_index: uint8 LE, // Instruction index to signature
+ signature_instruction_index: uint16 LE, // Instruction index to signature
public_key_offset: uint16 LE, // Offset to public key
- public_key_instruction_index: uint8 LE, // Instruction index to public key
- message_data_offset: uint16 LE, // Offset to start of message data
- message_data_size: uint16 LE, // Size of message data
- message_instruction_index: uint8 LE, // Instruction index to message
+ public_key_instruction_index: uint16 LE, // Instruction index to public key
+ message_offset: uint16 LE, // Offset to start of message data
+ message_length: uint16 LE, // Size of message data
+ message_instruction_index: uint16 LE, // Instruction index to message
}
```
-Multiple signatures can be verified. If any of the signatures fail to verify,
+Up to 8 signatures can be verified. If any of the signatures fail to verify,
an error must be returned.
-If the instruction data is empty, the program must return an error.
+In accordance with [SIMD
+0152](https://github.com/solana-foundation/solana-improvement-documents/pull/152)
+the behavior of the program is as follows:
-If `count == 0` and the length of the instruction data > 1, the program must
-return an error.
+1. If instruction `data` is empty, return error.
+2. The first byte of `data` is the number of signatures `num_signatures`.
+3. If `num_signatures` is 0, return error.
+4. Expect (enough bytes of `data` for) `num_signatures` instances of
+ `Secp256r1SignatureOffsets`.
+5. For each signature:
+ a. Read `offsets`: an instance of `Secp256r1SignatureOffsets`
+ b. Based on the `offsets`, retrieve `signature`, `public_key`, and
+ `message` bytes. If any of the three fails, return error.
+ c. Invoke the actual `sigverify` function. If it fails, return error.
-If `count > 0` and the length of the instruction data is not at least
-`count * sizeof(Secp256r1SignatureOffsets) + 2`, the program must return an error.
+To retrieve `signature`, `public_key`, and `message`:
+
+1. Get the `instruction_index`-th `instruction_data`
+ - The special value `0xFFFF` means "current instruction"
+ - If the index is invalid, return Error
+2. Return `length` bytes starting from `offset`
+ - If this exceeds the `instruction_data` length, return Error
+
+Note that fields (offsets) can overlap, for example the same public key or
+message can be referred to by multiple instances of `Secp256r1SignatureOffsets`.
+
+If the precompile `verify` function returns any error, the whole transaction
+should fail. Therefore, the type of error is irrelevant and is left as an
+implementation detail.
The instruction processing logic must follow the pseudocode below:
@@ -186,56 +213,85 @@ The instruction processing logic must follow the pseudocode below:
/// SERIALIZED_OFFSET_STRUCT_SIZE is the length of the serialized
/// Secp256r1SignatureOffsets struct
-if length_of_data == 0 {
- return Error
-}
-count = data[0]
-if count == 0 && length_of_data > 1 {
- return Error
-}
-if length_of_data < (count * SERIALIZED_OFFSET_STRUCT_SIZE + 2) {
- return Error
-}
-instructions = instruction_datas;
-for i in 0..count {
- if signature_instruction_index >= instructions.length {
- return Error
- }
- if signature_offset + 64 > instructions[signature_instruction_index]
- .data.length {
- return Error
- }
- signature = instructions[signature_instruction_index].data[signature_offset..signature_offset+64]
-
- if signature_S == highS {
- return Error
- }
-
- if public_key_instruction_index >= instructions.length {
+/// SERIALIZED_PUBLIC_KEY_LENGTH and SERIALIZED_SIGNATURE_LENGTH represent the
+/// length of the serialized public key and signature respectively
+
+function verify() {
+ if length_of_data == 0 {
+ return Error
+ }
+ num_signatures = data[0]
+ if num_signatures > 8 {
+ return Error
+ }
+ if num_signatures == 0 && length_of_data > 1 {
+ return Error
+ }
+ if length_of_data < (num_signatures * SERIALIZED_OFFSET_STRUCT_SIZE + 2) {
+ return Error
+ }
+ all_tx_data = { data, instruction_datas }
+ data_start_position = 2
+
+ for i in 0..num_signatures {
+ offsets = (Secp256r1SignatureOffsets)
+ all_tx_data.data[data_start_position..data_start_position + SERIALIZED_OFFSET_STRUCT_SIZE]
+ data_position += SERIALIZED_OFFSET_STRUCT_SIZE
+
+ signature = get_data_slice(all_tx_data,
+ offsets.signature_instruction_index,
+ offsets.signature_offset
+ signature_length)
+ if !signature {
return Error
- }
- if public_key_offset + 33 > instructions[public_key_instruction_index]
- .data.length {
+ }
+ if signature_S == highS {
+ return Error
+ }
+ public_key = get_data_slice(all_tx_data,
+ offsets.public_key_instruction_index,
+ offsets.public_key_offset,
+ SERIALIZED_PUBLIC_KEY_LENGTH)
+ if !public_key {
return Error
- }
- publicKey = instructions[public_key_instruction_index]
- .data[public_key_offset..public_key_offset+33]
+ }
- if message_instruction_index >= instructions.length {
+ message = get_data_slice(all_tx_data,
+ offsets.message_instruction_index,
+ offsets.message_offset
+ offsets.message_length)
+ if !message {
return Error
- }
- if message_data_offset + message_data_size > instructions[message_instruction_index]
- .data.length {
+ }
+
+ // sigverify includes validating signature and public_key
+ result = sigverify(signature, public_key, message)
+ if result != Success {
return Error
+ }
}
- message = instructions[message_instruction_index].data[message_data_offset..message_data_offset+message_data_size]
+ return Success
+}
- result = secp256verify(publicKey, message, signature)
- if result != true {
+fn get_data_slice(all_tx_data, instruction_index, offset, length) {
+ // Get the right instruction_data
+ if instruction_index == 0xFFFF {
+ instruction_data = all_tx_data.data
+ } else {
+ if instruction_index >= num_instructions {
return Error
}
-}
-return Success
+ instruction_data = all_tx_data.instruction_datas[instruction_index]
+ }
+
+ start = offset
+ end = offset + length
+ if end > instruction_data_length {
+ return Error
+ }
+
+ return instruction_data[start..end]
+}
```
Additonally the precompile's core `verify` function must be constructed in
From 711bf4153209624034539e56f110ec165348a836 Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Wed, 19 Jun 2024 01:35:02 +0200
Subject: [PATCH 36/39] formatting
---
proposals/0075-precompile-for-secp256r1-sigverify.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index 77f881528..e5b43d8b0 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -147,8 +147,8 @@ In Pseudocode:
```
struct Secp256r1SigVerifyInstruction {
- num_signatures: uint8 LE, // Number of signatures to verify
- padding: uint8 LE, // Single byte padding
+ num_signatures: uint8 LE, // Number of signatures to verify
+ padding: uint8 LE, // Single byte padding
offsets: Array, // Array of offset structs
additionalData?: Bytes, // Optional additional data, e.g.
// signatures included in the same
@@ -162,8 +162,8 @@ struct Secp256r1SignatureOffsets {
signature_instruction_index: uint16 LE, // Instruction index to signature
public_key_offset: uint16 LE, // Offset to public key
public_key_instruction_index: uint16 LE, // Instruction index to public key
- message_offset: uint16 LE, // Offset to start of message data
- message_length: uint16 LE, // Size of message data
+ message_offset: uint16 LE, // Offset to start of message data
+ message_length: uint16 LE, // Size of message data
message_instruction_index: uint16 LE, // Instruction index to message
}
```
From 13d2f8e165315d7964fa004de2ef994bacda8d22 Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Wed, 19 Jun 2024 01:41:09 +0200
Subject: [PATCH 37/39] linting
---
proposals/0075-precompile-for-secp256r1-sigverify.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index e5b43d8b0..c2e6fd329 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -141,7 +141,7 @@ ID: `Secp256r1SigVerify1111111111111111111111111`
In accordance with [SIMD
0152](https://github.com/solana-foundation/solana-improvement-documents/pull/152)
-programs ```verify``` instruction will accept the following data:
+the programs ```verify``` instruction must accept the following data:
In Pseudocode:
@@ -173,7 +173,7 @@ an error must be returned.
In accordance with [SIMD
0152](https://github.com/solana-foundation/solana-improvement-documents/pull/152)
-the behavior of the program is as follows:
+the behavior of the program must be as follows:
1. If instruction `data` is empty, return error.
2. The first byte of `data` is the number of signatures `num_signatures`.
From d28bc3ea56cc689c1648cb9a24d2ac1d12567050 Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Wed, 19 Jun 2024 01:43:35 +0200
Subject: [PATCH 38/39] formatting
---
proposals/0075-precompile-for-secp256r1-sigverify.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index c2e6fd329..b78884f60 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -248,6 +248,7 @@ function verify() {
if signature_S == highS {
return Error
}
+
public_key = get_data_slice(all_tx_data,
offsets.public_key_instruction_index,
offsets.public_key_offset,
From fbeaef29cfcb3d6db6b459427d736e89d98528e7 Mon Sep 17 00:00:00 2001
From: Iceomatic <89707822+iceomatic@users.noreply.github.com>
Date: Wed, 19 Jun 2024 01:51:30 +0200
Subject: [PATCH 39/39] resolve comments
---
.../0075-precompile-for-secp256r1-sigverify.md | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/proposals/0075-precompile-for-secp256r1-sigverify.md b/proposals/0075-precompile-for-secp256r1-sigverify.md
index b78884f60..086b3df0f 100644
--- a/proposals/0075-precompile-for-secp256r1-sigverify.md
+++ b/proposals/0075-precompile-for-secp256r1-sigverify.md
@@ -221,9 +221,6 @@ function verify() {
return Error
}
num_signatures = data[0]
- if num_signatures > 8 {
- return Error
- }
if num_signatures == 0 && length_of_data > 1 {
return Error
}
@@ -245,10 +242,7 @@ function verify() {
if !signature {
return Error
}
- if signature_S == highS {
- return Error
- }
-
+
public_key = get_data_slice(all_tx_data,
offsets.public_key_instruction_index,
offsets.public_key_offset,
@@ -266,6 +260,10 @@ function verify() {
}
// sigverify includes validating signature and public_key
+ // the additional highS check is done here
+ if signature_S == highS {
+ return Error
+ }
result = sigverify(signature, public_key, message)
if result != Success {
return Error
@@ -273,7 +271,7 @@ function verify() {
}
return Success
}
-
+// This function is re-used across precompiles in accordance with SIMD-0152
fn get_data_slice(all_tx_data, instruction_index, offset, length) {
// Get the right instruction_data
if instruction_index == 0xFFFF {