feat: expose native keccak256 implementation - #8580
feat: expose native keccak256 implementation#8580ChristopherDedominici wants to merge 10 commits into
Conversation
🦋 Changeset detectedLatest commit: 3896067 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
Pull request overview
This PR exposes EDR’s native Keccak-256 implementation from Hardhat internals and wires it into @nomicfoundation/hardhat-ethers by registering it via ethers v6’s keccak256.register hook, with a graceful fallback when the native implementation can’t be loaded.
Changes:
- Added
hardhat/internal/edrexport surface withgetNativeKeccak256()(+ caching) to load EDR’s native keccak when available. - Registered the native keccak implementation into ethers during
hardhat-ethersinitialization (once per process), and added coverage for degraded scenarios (EDR missing / ethers keccak locked). - Added documentation and changesets/peer-bump metadata to reflect the new Hardhat internal export dependency.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
packages/hardhat/src/internal/edr/keccak.ts |
Adds a cached async loader for EDR’s native keccak256, returning undefined on any load failure. |
packages/hardhat/src/internal/edr/exports.ts |
Exposes getNativeKeccak256 + Keccak256 type via a single internal export entrypoint. |
packages/hardhat/package.json |
Exports new subpath ./internal/edr so downstream packages can import hardhat/internal/edr. |
packages/hardhat/test/internal/edr/keccak.ts |
Validates native keccak availability, stability (same instance), known vectors, and parity vs JS implementation. |
packages/hardhat/test/internal/edr/keccak-unavailable.ts |
Tests that getNativeKeccak256() safely degrades to undefined across failure modes. |
packages/hardhat/test/internal/edr/edr-unavailable-loader-hooks.mjs |
Node loader hook to simulate EDR missing/old behavior for degradation tests. |
packages/hardhat-ethers/src/internal/native-keccak256.ts |
Implements memoized registration of native keccak into ethers, swallowing failures and logging under DEBUG. |
packages/hardhat-ethers/src/internal/initialization.ts |
Invokes native keccak registration as part of ethers initialization (before provider creation). |
packages/hardhat-ethers/test/native-keccak256.ts |
Tests correct registration behavior, non-repeat registration semantics, pooled-Buffer handling, and a known signature digest. |
packages/hardhat-ethers/test/native-keccak256-initialization.ts |
Ensures registration happens via the normal “network connection creation” path. |
packages/hardhat-ethers/test/native-keccak256-degraded.ts |
Ensures ethers remains functional when EDR is missing or ethers keccak is locked (child-process isolated). |
packages/hardhat-ethers/test/helpers/native-keccak256-child.mjs |
Child runner for degraded tests; optionally hides EDR and/or locks ethers keccak before registration attempt. |
packages/hardhat-ethers/test/helpers/hide-edr-loader-hooks.mjs |
Node loader hook to simulate EDR missing in the child process. |
packages/hardhat-ethers/README.md |
Documents the native Keccak-256 behavior and limitations (module-instance scoping, overwrite behavior, lock behavior). |
.peer-bumps.json |
Records that hardhat-ethers now requires the next Hardhat version due to hardhat/internal/edr subpath. |
.changeset/native-keccak-in-hardhat-ethers.md |
Declares minor bumps for hardhat and @nomicfoundation/hardhat-ethers for this feature. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated 4 comments.
Suppressed comments (1)
packages/hardhat-ethers/README.md:301
- The fallback sentence is grammatically incomplete: “isn't available” cannot take “an unsupported platform” as a parallel complement. Rephrase it so the platform and old-version cases explain why the native implementation is unavailable.
When you connect to a network, this plugin replaces that implementation with EDR's native one through ethers' `keccak256.register` hook. The results are identical; only the speed differs. If the native implementation isn't available, an unsupported platform, or an EDR version that predates it, ethers keeps using its own, and nothing else changes.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.
Suppressed comments (2)
Previously missed (1) — in code that hasn't changed since the last review.
packages/hardhat-ethers/README.md:307
- This rationale is inaccurate: issue #8564 notes that ethers exposes signing-key hooks as well. Native signing can remain out of scope, but the documentation should not claim that no equivalent hook exists.
- Only Keccak-256 is replaced. Signing still runs in JavaScript, since ethers exposes no equivalent hook for it.
packages/hardhat-ethers/test/native-keccak256.ts:80
- The correctness gate from issue #8564 also calls for known-vector coverage of address checksumming and typed-data hashing. This only exercises an event signature, so regressions where those ethers paths do not use the registered implementation would go undetected. Add
getAddress/isAddressandTypedDataEncoder.hashassertions using canonical vectors.
it("should produce the well-known digest of an event signature", () => {
assert.equal(
ethers.id("Transfer(address,address,uint256)"),
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
);
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.
Suppressed comments (2)
packages/hardhat-ethers/README.md:301
- This fallback sentence is grammatically incomplete: “isn't available” cannot take “an unsupported platform” or “an EDR version” as alternatives. State those as reasons the native implementation may be unavailable.
When you connect to a network, this plugin replaces that implementation with EDR's native one through ethers' `keccak256.register` hook. The results are identical; only the speed differs. If the native implementation isn't available (e.g. due to an unsupported platform or an EDR version that predates it), ethers keeps using its own and nothing else changes.
packages/hardhat-ethers/README.md:306
- The final clause is joined with a comma despite being an independent sentence. Use a semicolon so the lock behavior is unambiguous.
- Registration overwrites any implementation you registered into that instance yourself, since ethers provides no way to detect one. Register yours after connecting, or call `ethers.keccak256.lock()` before connecting, the plugin then leaves it untouched.
| return; | ||
| } | ||
|
|
||
| keccak256.register(nativeKeccak256); |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…at into keccak-hardhat-edr
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.
Suppressed comments (2)
Previously missed (1) — in code that hasn't changed since the last review.
packages/hardhat-ethers/test/native-keccak256.ts:6
- This only exercises the same ESM
ethersinstance that the plugin imports. The linked issue requires proving that a separately resolved ethers copy is untouched, and the README specifically claims the CommonJS build remains on JS; add acreateRequire/separate-copy test that installs a sentinel there, registers the native ESM implementation, and verifies the sentinel is unchanged.
import * as ethers from "ethers";
packages/hardhat-ethers/src/internal/native-keccak256.ts:38
- The linked issue requires measured 32/64/128/1024-byte benchmarks before replacing ethers unconditionally, with a JS fallback for small inputs if N-API overhead loses. No benchmark result is included here, so this can regress the many short hashes that dominate the target workload. Please provide the measurements and gate small inputs if they show a crossover.
keccak256.register(nativeKeccak256);
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.
Suppressed comments (1)
packages/hardhat-ethers/src/internal/native-keccak256.ts:38
- This unconditionally routes every input through N-API, but issue #8564 explicitly requires benchmarking 32/64/128/1024-byte inputs and retaining the JS implementation for sizes where call overhead is slower. The PR contains neither those measurements nor a size threshold, so the optimization's required small-input performance gate is currently unverified. Please provide the measurements and add a size-based fallback if they show a regression.
keccak256.register(nativeKeccak256);
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Hardhat fix for issue: #8564.
Depends on EDR PR: NomicFoundation/edr#1671