Skip to content

Restore the P256 native precompile path for TIP-7951 - #150

Open
pepebndc wants to merge 3 commits into
masterfrom
p256-tip7951-native
Open

Restore the P256 native precompile path for TIP-7951#150
pepebndc wants to merge 3 commits into
masterfrom
p256-tip7951-native

Conversation

@pepebndc

@pepebndc pepebndc commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

Note on the included lockfile commits

PR #152 (the npm ci lockfile fix this PR was stacked on) was retargeted and merged into release-v5.6, not master, so master still fails npm ci without it. The first two commits here carry that fix (lockfile refresh + the ethers 6.17 toBeArray test fix) so this PR is self-contained and green against master. They will dedupe whenever release-v5.6 merges back.

Context

The TIP-7951 secp256r1 (P256) precompile is available on the TVM (tronprotocol/tips#916, ALLOW_TVM_OSAKA, chain parameter 96). It follows EIP-7951, which keeps the RIP-7212 call interface, at address(0x100).

Activation status:

  • Nile: active (getAllowTvmOsaka = 1, java-tron 4.8.2.1). Functionally verified on-chain: a valid 160-byte h || r || s || qx || qy input returns 0x...01, an invalid input returns empty output.
  • Mainnet: pending the on-chain vote.

Design decision: the TRON team chose upstream alignment over a precompile-only variant (thread). Measured cost of the upstream structure with the precompile active: ~7.8k vs ~7.2k energy on valid signatures (+8%), ~14.9k vs ~7.2k on invalid ones (2x, from the presence-probe call), against ~355k for the pure-Solidity verification both replace.

Changes

  • contracts/utils/cryptography/P256.sol: restore verifyNative, _tryVerifyNative, and _rip7212 from upstream. verify(...) tries the precompile first and falls back to verifySolidity(...) on networks that have not activated it. Byte-for-byte upstream v5.5 except TRON-specific NatSpec. Callers (WebAuthn, TRC7913P256Verifier, SignerP256) keep using verify(...) unchanged.
  • test/utils/cryptography/P256.test.js: probe for the precompile at runtime (same known-valid small-r/s wycheproof vector the library uses). Native assertions run where the precompile exists and show as pending where it does not.
  • test/utils/cryptography/P256.t.sol: restore the upstream file, including testVerifyNativeUnsupportedRIP7212 (covers the MissingPrecompile revert; Foundry stays on cancun, matching upstream).
  • scripts/run-tests-parallel.sh + scripts/tre-activate-osaka.js: each TRE worker gets a writable fullnode.conf copy with 30 s proposal/maintenance intervals, and a pre-flight that activates ALLOW_TVM_OSAKA with an on-chain proposal from the genesis witness (java-tron has no committee-config mapping for this parameter; the image's preapprove env is a no-op for it). Activation failure is a warning, not fatal: on java-tron < 4.8.2 (the current pinned image) the fallback keeps every suite green and the native tests show as pending.

Validation

  • Hardhat EVM (ships EIP-7951 natively): P256 and TRC7913P256Verifier suites pass with all native assertions running; the 210 wycheproof vectors pass through $verify.
  • Real TVM 4.8.2 (local TRE from the tronbox/tre 2.0.0 image with a 4.8.2-ported -oz-tron jar): activation lands in ~25 s and the P256, TRC7913P256Verifier, SignatureChecker, and TRC7739 suites pass through the real precompile.
  • Real TVM 4.8.1 (current pin): activation fails with the intended clear warning, and the P256 suite passes with the 3 native-gated tests pending.
  • Foundry (cancun): P256 (3 tests, incl. the MissingPrecompile revert) and WebAuthn (9 tests) pass.
  • tron-solc batched compile, prettier, solhint, eslint pass.

Follow-up (no longer a merge blocker)

TRE native-path coverage in CI arrives when the patched jar targets java-tron 4.8.2. The current upstream tronbox/tre 2.0.0 image ships 4.8.2 but no JDK, so hardhat-tron's docker/build-jar.sh must compile the patch in an external JDK 17 container, and its vendored TransactionCapsule.java must be re-vendored from the 4.8.2 tag (a 3-way git merge-file onto the 4.8.2 source merges with zero conflicts; validated locally). Once that ships, this repo bumps the @openzeppelin/hardhat-tron dependency and the digest in scripts/pin-tre-image.sh, and the runtime probe lights the native tests up on TRE with no further changes here.

🤖 Generated with Claude Code

@pepebndc pepebndc changed the title Restore the P256 native precompile path for TIP-7951 Use the TIP-7951 P256 precompile in P256.verify Aug 24, 2026
The @openzeppelin/hardhat-tron git dependency tracks main. Their main
now consumes @openzeppelin/tron-runtime ^0.1.0 from npm and bumps
tronweb to 6.5.0, so npm ci fails against the stale lockfile on every
branch. Re-resolve the lockfile. The jar-patch source pin follows the
lockfile, so TRE jars now build from hardhat-tron 603106cd.

Validated locally: clean npm ci, jar rebuild via build-tre-fork.sh
(tre_version reports v1.0.4-oz-tron), tron-solc compile, and TRE smoke
tests (P256 and Create2 suites) against the rebuilt jar.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@pepebndc
pepebndc force-pushed the p256-tip7951-native branch from 0404370 to 15a1118 Compare August 24, 2026 08:48
@pepebndc
pepebndc changed the base branch from master to refresh-hardhat-tron-lockfile August 24, 2026 08:48
ethers 6.17 adds a width parameter to toBeArray. Array.map passes the
element index as the second argument, so .map(ethers.toBeArray) now
throws a NUMERIC_FAULT overflow for width 0. Call it with the value
only, matching upstream openzeppelin-contracts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@pepebndc
pepebndc force-pushed the p256-tip7951-native branch from 15a1118 to 78872cf Compare August 24, 2026 08:58
@pepebndc pepebndc changed the title Use the TIP-7951 P256 precompile in P256.verify Restore the P256 native precompile path for TIP-7951 Aug 26, 2026
@pepebndc
pepebndc marked this pull request as ready for review August 26, 2026 08:09
@pepebndc
pepebndc changed the base branch from refresh-hardhat-tron-lockfile to master August 26, 2026 09:00
The TVM ships a secp256r1 precompile at address(0x100) per TIP-7951
(chain parameter 96, ALLOW_TVM_OSAKA). It is active on Nile (java-tron
4.8.2) and pending the mainnet vote. Verified on Nile: a valid
signature input returns 32-byte 1, an invalid one returns empty.

Per the TRON team's decision, keep the upstream structure byte-for-byte
(TRON NatSpec aside): verify() tries the precompile and falls back to
verifySolidity(); verifyNative and _tryVerifyNative return. Callers
keep using verify() unchanged and get native verification (~7.8k energy
instead of ~355k) once a network activates the precompile.

Tests probe for the precompile at runtime and skip the native
assertions when it is absent. The TRE runner stages per-worker
fullnode.conf copies with 30 s proposal intervals and activates
ALLOW_TVM_OSAKA per worker with an on-chain proposal from the genesis
witness (java-tron has no committee-config mapping for the parameter).
Activation failure on java-tron < 4.8.2 is a warning; the Solidity
fallback keeps every suite green. The Foundry test covers the
MissingPrecompile revert.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@pepebndc
pepebndc force-pushed the p256-tip7951-native branch from d9f443f to 0cb09e6 Compare August 26, 2026 09:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant