feat(vm-runner): add p256_verify host function (NEP-635)#15588
feat(vm-runner): add p256_verify host function (NEP-635)#15588
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #15588 +/- ##
==========================================
- Coverage 69.38% 69.32% -0.06%
==========================================
Files 942 942
Lines 212994 213123 +129
Branches 212994 213123 +129
==========================================
- Hits 147781 147749 -32
- Misses 59357 59501 +144
- Partials 5856 5873 +17
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Gas calibration lives in the params estimator (icount + estimator-contract), not in cargo bench — no other host function in this crate has a criterion microbench. The bench measured native P-256 rather than the host function, so it didn't feed the calibration flow that produced the yaml numbers.
There was a problem hiding this comment.
Pull request overview
Adds NEP-635 p256_verify as a protocol-gated VM host function (protocol v85) with calibrated gas costs, wiring it through runtime configs / schemas, and validating it via unit, integration, and test-loop e2e coverage.
Changes:
- Implement
env.p256_verify(sig, msg, pubkey) -> u64innear-vm-runner(both NearVM/Wasmtime paths) with newHostError::P256VerifyInvalidInputfor malformed input lengths. - Introduce new ext costs (
p256_verify_base,p256_verify_byte) and integrate them into runtime configs, estimator tooling, profiling, and JSON/OpenAPI views. - Add comprehensive tests (logic unit tests, near-vm-runner integration tests, test-loop e2e test) and update protocol/schema snapshots accordingly.
Reviewed changes
Copilot reviewed 104 out of 105 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/protocol-schema-check/res/protocol_schema.toml | Updates protocol schema hashes to reflect new/changed types due to added costs/config/errors. |
| test-loop-tests/src/tests/p256_verify.rs | New test-loop e2e coverage for deploy/call behavior and error propagation. |
| test-loop-tests/src/tests/mod.rs | Registers the new p256_verify test module. |
| test-loop-tests/Cargo.toml | Adds p256 and wat dependencies for test-loop contract generation and signing. |
| runtime/runtime-params-estimator/src/lib.rs | Adds p256 cost measurement functions to the estimator cost table. |
| runtime/runtime-params-estimator/src/estimator_context.rs | Caches p256_verify_base measurement similarly to ed25519. |
| runtime/runtime-params-estimator/src/costs_to_runtime_config.rs | Maps new ExtCosts::{p256_verify_base,p256_verify_byte} to estimator Cost entries. |
| runtime/runtime-params-estimator/src/cost.rs | Adds Cost::{P256VerifyBase,P256VerifyByte} variants and documentation. |
| runtime/near-vm-runner/src/wasmtime_runner/logic.rs | Implements p256_verify host function in Wasmtime runner path. |
| runtime/near-vm-runner/src/logic/logic.rs | Implements p256_verify host function in VMLogic path. |
| runtime/near-vm-runner/src/logic/errors.rs | Adds HostError::P256VerifyInvalidInput and Display formatting. |
| runtime/near-vm-runner/src/imports.rs | Adds p256_verify import gated behind Config::p256_verify. |
| runtime/near-vm-runner/src/tests/p256_verify_integration.rs | New near-vm-runner integration tests for correctness and gating/link behavior. |
| runtime/near-vm-runner/src/tests.rs | Wires the new integration test module into the test suite. |
| runtime/near-vm-runner/src/logic/tests/p256_verify.rs | New logic-level unit tests, including Wycheproof vectors and gas accounting assertions. |
| runtime/near-vm-runner/src/logic/tests/mod.rs | Registers the new logic test module. |
| runtime/near-vm-runner/src/profile.rs | Updates profiling cost index mapping to include the new ExtCosts entries. |
| runtime/near-vm-runner/Cargo.toml | Adds the p256 dependency to the runner crate. |
| runtime/near-test-contracts/estimator-contract/src/lib.rs | Adds estimator-contract entrypoints for measuring p256_verify_base and p256_verify_byte. |
| cspell.json | Adds cryptography/test terminology words used by the new tests/docs. |
| core/primitives/src/errors.rs | Adds HostError::P256VerifyInvalidInput to stable primitives error enum. |
| core/primitives-core/src/version.rs | Adds ProtocolFeature::P256Verify and sets activation at protocol version 85. |
| core/parameters/src/vm.rs | Adds Config::p256_verify flag and enables it in enable_all_features(). |
| core/parameters/src/view.rs | Exposes p256_verify and p256 cost fields in config views and conversions. |
| core/parameters/src/parameter.rs | Adds parameters for p256 costs and the P256Verify feature flag parameter. |
| core/parameters/src/parameter_table.rs | Plumbs Parameter::P256Verify into RuntimeConfig construction. |
| core/parameters/src/cost.rs | Adds new ExtCosts discriminants and default test cost values for p256. |
| core/parameters/res/runtime_configs/parameters.yaml | Adds default p256 cost params and the p256_verify flag to runtime config template. |
| core/parameters/res/runtime_configs/parameters_testnet.yaml | Adds default p256 cost params and the p256_verify flag to testnet template. |
| core/parameters/res/runtime_configs/parameters.snap | Updates autogenerated runtime config snapshot for new costs/flag. |
| core/parameters/res/runtime_configs/85.yaml | Marks p256_verify toggling on at protocol version 85. |
| core/primitives/src/profile_data_v3.rs | Updates profile cost index mapping to include p256 verify costs. |
| core/primitives/src/snapshots/near_primitives__views__tests__runtime_config_view.snap | Updates runtime config view snapshot with p256 costs/flag. |
| core/primitives/src/snapshots/near_primitives__views__tests__exec_metadata_v2_view.snap | Updates exec-metadata v2 view snapshot with new cost entries. |
| core/primitives/src/snapshots/near_primitives__views__tests__exec_metadata_v3_view.snap | Updates exec-metadata v3 view snapshot with new cost entries. |
| core/parameters/src/snapshots/near_parameters__view__tests__runtime_config_view.snap | Updates parameters view runtime config snapshot with p256 costs/flag. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_0.json.snap | Updates stored config snapshot to include p256 costs/flag defaults for v0. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_42.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_46.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_48.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_49.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_50.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_52.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_53.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_55.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_57.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_59.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_61.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_62.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_63.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_64.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_66.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_67.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_68.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_69.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_70.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_72.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_73.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_74.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_77.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_78.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_79.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_82.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_83.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_84.json.snap | Snapshot update for p256 costs/flag inclusion and gate off at v84. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_85.json.snap | Snapshot update for p256 costs/flag inclusion and gate on at v85. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_129.json.snap | Snapshot update for p256 costs/flag inclusion for higher protocol versions. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__testnet_149.json.snap | Snapshot update for p256 costs/flag inclusion for higher protocol versions. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__0.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__42.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__46.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__48.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__49.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__50.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__52.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__53.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__55.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__57.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__59.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__61.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__62.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__63.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__64.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__66.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__67.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__68.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__69.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__70.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__72.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__73.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__74.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__77.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__78.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__79.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__82.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__83.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__84.json.snap | Snapshot update for p256 costs/flag inclusion and gate off at v84. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__85.json.snap | Snapshot update for p256 costs/flag inclusion and gate on at v85. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__129.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/parameters/src/snapshots/near_parameters__config_store__tests__149.json.snap | Snapshot update for p256 costs/flag inclusion. |
| core/crypto/src/hash.rs | Suppresses generic-array deprecation warnings in blake2 integration until upstream bumps. |
| runtime/near-vm-runner/src/wasmtime_runner/logic.rs | Replaces as_slice() with &[..] per generic-array deprecation behavior. |
| runtime/near-vm-runner/src/logic/logic.rs | Replaces as_slice() with &[..] per generic-array deprecation behavior. |
| chain/jsonrpc/openapi/openrpc.json | Extends OpenRPC schema to expose p256 costs/flag and new HostError variant. |
| chain/jsonrpc/openapi/openapi.json | Extends OpenAPI schema to expose p256 costs/flag and new HostError variant. |
| Cargo.toml | Adds workspace dependency on p256 (RustCrypto) with ecdsa support. |
| Cargo.lock | Locks new transitive dependencies introduced by p256 and bumps generic-array. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// Then call with a tampered message and assert the return value is 0. | ||
| /// Finally, call with an invalid signature length and assert the host error. | ||
| #[test] | ||
| fn test_p256_verify_e2e() { |
There was a problem hiding this comment.
For testing the host functions in test-loop there is a pre-existing pattern, please see if you could adapt it here. It would be part of near-test-contracts::rs_contract, and calling "call_promise"
There was a problem hiding this comment.
Ok I tried the rs_contract route (d51f259) and CI caught something I hadn't realized: adding a latest_protocol-gated import to rs_contract breaks any test that deploys it at a pre-85 protocol version...
Reverted in 1efd4c1 and kept the WAT helper scoped to the test file, (but with Copilot's offset concern actually fixed this time).
Happy to revisit if there's a cleaner home for the contract... maybe a dedicated mini-contract in near-test-contracts alongside estimator-contract? Wanted to avoid that churn in this PR.
| } | ||
|
|
||
| #[test] | ||
| fn test_p256_verify_integration_empty_signature_length_aborts() { |
There was a problem hiding this comment.
I wonder if we can just have unit tests and test-loop tests. The unit tests are thorough, and we can keep test-loop for:
- Signature valid,
- Signature invalid,
- PV disabled.
I'm not against to keep the other cases as test loop either.
There was a problem hiding this comment.
Test-loop is now exactly those three (1efd4c1)
I kept the six with_vm_variants integration tests in near-vm-runner since they're the only thing exercising both NearVm and Wasmtime for this host function, but we could even get rid of that too 🤷
|
@jakmeier Can you have a quick look at it too please? |
The variant docs claimed this abort covers generic "signature cannot be derived from bytes" cases, but parse failures of well-sized inputs return 0 from the host function — this variant only fires on length mismatch (signature != 64 bytes or public key != 33 bytes). Align the docstring with actual behavior in both logic/errors.rs and the stable primitives enum, and regenerate the corresponding OpenAPI/OpenRPC descriptions so downstream clients see the same wording.
The comment claimed ECDSA signing uses a random nonce, so signatures are nondeterministic. Not true for RustCrypto's p256: SigningKey via signature::Signer uses deterministic RFC6979 by default, so a given key+message always produces the same signature. Update the comment so a future reader isn't misled into switching to randomized signing unnecessarily.
The comment on p256_verify_16kib_64 said the per-byte fee is charged regardless of how many bytes participate in verification — misleading, since SHA-256 hashes every byte of the message. Rewrite it to say what the per-byte charge actually covers: the linear, message-dependent cost of marshalling plus hashing.
The generic-array 0.14.9 bump from pulling in `p256` deprecated the `blake2::digest::generic_array` re-export. Instead of carrying two `#[allow(deprecated)]` annotations, write the impl against the `Output<Self>` type alias that `digest` exposes for exactly this purpose — it resolves to the same underlying type but stays on the non-deprecated API surface. Same approach as #14927.
The wycheproof block tests the RustCrypto p256 crate's handling of adversarial signatures, not our own wrapper, so it reads better as a dedicated sibling module than appended to the main test file. Move the eight tests and their `run_wycheproof` helper into `p256_verify_wycheproof.rs` and scope the cryptography-specific vocabulary (`Wycheproof`, `Shamir`, `FIPS`, `Pubkeys`) to that file via a `// cspell:words` directive, removing them from the global cspell.json. Also drop `Microbenchmark`, which was only referenced by the criterion bench removed earlier in this PR.
The test-loop coverage used to build a bespoke WAT module inline, which laid inputs out at fixed offsets (0, 128, 192) — fine for a 32-byte message, but it'd silently overlap the public key for any longer one. Swap it for the pattern reviewers asked for: expose a small `ext_p256_verify` entry point from `rs_contract`, have the test deploy the standard contract and invoke it with a JSON payload of base64-encoded bytes, and forward the host function's `u64` result back out through `value_return`. No more WAT generation in the test harness, and message length stops being a footgun. With the contract in place, collapse the test-loop side to the three scenarios that matter e2e: valid signature returns 1, invalid returns 0, and a contract that imports `env.p256_verify` can't link against a runtime at PV < 85. The PV-disabled case was previously a vm-runner integration test that toggled `Config::p256_verify = false`; the test-loop version exercises the real protocol gate end-to-end, so drop the vm-runner test. Remove `wat` from test-loop-tests and add `base64` for the JSON payload encoding. Addresses the test-organization comments from darioush (#15588) and the Copilot note about fixed-offset WAT layouts.
Follow-up to b2272dc. The wycheproof test file has its own `cspell:words` directive, but the `mod p256_verify_wycheproof;` declaration in the parent mod.rs wasn't covered — and since the global `cspell.json` no longer carries "Wycheproof", CI spellcheck tripped on the lowercase form there. Add a file-level directive.
Adding `ext_p256_verify` to rs_contract put a new `latest_protocol`- gated import into the shared stable test contract. That was fine for every earlier `latest_protocol` host function because each was already available at the oldest supported PV — but `p256_verify` activates at PV 85 (via a runtime Config flag). As soon as rs_contract imports it, any test that deploys rs_contract at a pre-85 protocol version fails to link; CI caught this via `test_yield_resume_across_protocol_upgrade` (runs at PV 82 through 83). Rather than pollute the cross-team contract, revert that pair of additions and build the p256_verify contract inline in the test-loop test file. Reorder the data layout so Copilot's original concern doesn't return: `signature (0..64) | public_key (64..97) | message (97..)`, with fixed-length inputs first. Result is written to the last 8 bytes of the memory page so it can never collide with the message, regardless of length. Also mark the pre-activation test `#[cfg_attr(feature = "protocol_feature_spice", ignore)]` since Spice runs at PROTOCOL_VERSION 200 and rejects test-loop genesis at arbitrary older PVs (spice_core requires non-genesis blocks to carry uncertified chunks).
| ) | ||
| )"#, | ||
| ); | ||
| wat::parse_str(&wat).expect("failed to parse wat") |
There was a problem hiding this comment.
nit: can we use near_test_contracts::wat_contract here and revert the Cargo.toml change?
pugachAG
left a comment
There was a problem hiding this comment.
please remove unused protocol feature, otherwise looks good
| FixDelegateActionDepositWithFunctionCallError, | ||
| /// Enable P-256 ECDSA signature verification host function. | ||
| /// NEP-635: <https://github.com/near/NEPs/pull/635> | ||
| P256Verify, |
There was a problem hiding this comment.
You don't need protocol feature, p256_verify runtime parameter is sufficient
|
|
||
| /// Whether to enable the P-256 ECDSA signature verification host function. | ||
| /// NEP-635: <https://github.com/near/NEPs/pull/635> | ||
| pub p256_verify: bool, |
There was a problem hiding this comment.
nit: p256_verify -> p256_verify_host_fn for consistency
Replaces the inline `wat::parse_str(...).expect(...)` call in the p256_verify test with `near_test_contracts::wat_contract`, which is the existing helper for this pattern. Drops `wat` from test-loop-tests dev-dependencies since it's no longer referenced directly.
…ost_fn The `p256_verify` flag in `VMConfig` (and the corresponding `Parameter::P256Verify` / YAML key) is renamed to `p256_verify_host_fn` for consistency with the other host-function feature flags (`gas_key_host_fns`, `global_contract_host_fns`). Singular `host_fn` since there is only a single P-256 host function. All snapshots, OpenAPI/OpenRPC descriptors, and the `#[p256_verify]` import attribute are updated to match.
The feature flag was only used to look up the activation protocol version in a single test. The runtime config parameter (p256_verify_host_fn) is the authoritative gate for the host function, so a ProtocolFeature variant isn't needed. The test now hardcodes protocol version 84 (activation - 1) with a comment pointing at 85.yaml.
The manual p256_verify -> p256_verify_host_fn rename missed the `required` array in openrpc.json (the field declaration was renamed but the name still appeared in the list of required fields). The manual merge of master's protocol_schema.toml kept master's hashes for the new BlockBatch / BlockBatchV1 types, but my changes transitively affect their hash, so the tool now reports different values. Copied the current hashes reported by check-protocol-schema.
| } | ||
| }; | ||
|
|
||
| match public_key.verify(&message, &signature) { |
There was a problem hiding this comment.
Reposting from here: it should use PrehashVerifier::verify_prehash instead:
| match public_key.verify(&message, &signature) { | |
| match public_key.verify_prehash(&message, &signature) { |
Followup to near#15588, addressing [mitinarseny's review](near#15588 (review)). [NEP-635](near/NEPs#635) says `p256_verify` does not hash — the caller supplies a prehashed digest (e.g. `SHA-256(msg)` for WebAuthn). The merged implementation used `Verifier::verify`, which SHA-256-hashes the message internally, so a contract passing a raw 32-byte prehash would fail to verify. Switches to `PrehashVerifier::verify_prehash` in both host-function copies (`VMLogic::p256_verify` and the wasmtime-runner `p256_verify`), and updates unit / integration / test-loop tests plus the estimator contract's hardcoded signatures accordingly. Wycheproof `ecdsa_secp256r1_sha256_p1363` vectors still expect `SHA-256(msg)` to be signed, so the test helper now hashes the message before handing it to `p256_verify`. Gas model is unchanged.
Summary
Implements the NEP-635
p256_verifyhost function — ECDSA signature verification on the NIST P-256 curve with SHA-256 message hashing. Gated behind protocol version 85.Signature:
p256_verify(sig, msg, pubkey) -> u64returning 1 on success, 0 on verification failure. Takes a raw 64-byter||ssignature, arbitrary-length message, and 33-byte SEC1 compressed public key. Aborts withHostError::P256VerifyInvalidInputon malformed input lengths.Motivated by TEE attestation (DCAP quote verification) and WebAuthn use cases where P-256 is the required curve and today's contracts have to bundle ~120 KB of verification code.
Gas calibration
wasm_p256_verify_base: 1_300_000_000_000(1,300 Bgas)wasm_p256_verify_byte: 13_000_000(13 Mgas)Derived from
--metric icount(hw-agnostic, via Docker+QEMU instrumentation), anchored againsted25519_verify's already-calibrated210 Bgas / 9 Mgasto get a combined hw-correction-plus-safety factor. Cross-checked with--metric timeon a Threadripper 3970X. The icount-derived P-256/Ed25519 ratio of 6.7× matches the time-derived ratio of 6.2×, which matches library-level benchmarks.Design notes
p256crate does not enforce low-s normalization and we pass that through. Changing this later would be protocol-breaking. Documented in tests.ed25519_verify.Testing
logic/tests/p256_verify.rs, including 8 Wycheproof adversarial vectors (r=0, s=0, r=n, modified r, invalid SEC1 tag, high-s, malleability edge cases)tests/p256_verify_integration.rsincluding a feature-gate test that confirms contracts importingenv.p256_verifyfail to link whenConfig::p256_verify = falsetest-loop-tests/src/tests/p256_verify.rscovering the full transaction → receipt → outcome pipeline at protocol version 85Incidental changes
Adding
p256transitively bumpedgeneric-array0.14.5 → 0.14.9, which emits new deprecation warnings. Suppressed the few spots this affects incore/crypto/src/hash.rsand replacedvalue_hash.as_slice()calls with&value_hash[..]innear-vm-runner.