Repository navigation
fix(mock-contracts): give each input of a mocks batch its own ctHash - #482
Merged
alexshchur merged 1 commit intoNov 2, 2026
Merged
Conversation
zkVerifyCalcCtHashesPacked calculated every item of a batch with the current salt, and the salt only advances when insertPackedCtHashes stores the items afterwards. Equal values encrypted in one encryptInputs call on Hardhat therefore got the same ctHash. Calculate item i with salt + i, the salt it is inserted at. Item 0 and single item batches keep their hashes, and a batch now gets the same hashes the Foundry CofheClient produces by calculating and inserting one item at a time.
🦋 Changeset detectedLatest commit: 273eb6e The changes in this PR will be included in the next version bump. This PR includes changesets to release 9 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 |
alexshchur
approved these changes
Nov 2, 2026
alexshchur
left a comment
Contributor
There was a problem hiding this comment.
Thanks @erkancamli, nice catch. On the Hardhat mocks, equal values of the same type in one batch shared a handle. Now each gets its own, same as Foundry already did. Merging.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On Hardhat,
encryptInputsreturns the same ctHash for equal values encrypted in one batch:So two separate inputs become one handle in the mocks. A contract that keys anything on the handle (a mapping, a per handle
FHE.allow, a check that an input is not used twice) sees one value where it was given two. Each encryption against CoFHE is a fresh ciphertext, and the Foundry mocks already give every input its own hash.Cause
The SDK mocks path calculates all ctHashes of a batch with one view call to
MockZkVerifier.zkVerifyCalcCtHashesPacked, then stores them withinsertPackedCtHashes. The hash commits to the value, the account andsalt, butsaltonly advances ininsertCtHash, so every item of the batch is calculated with the same salt. Equal values (with the same utype) then hash to the same ctHash.The Foundry
CofheClientdoes not have this problem because it callszkVerifyCalcCtHashandinsertCtHashone item at a time.Fix
zkVerifyCalcCtHashesPackednow calculates itemiwithsalt + i, the salt that item is inserted at. Item 0 and single item batches keep the hashes they had. A batch now gets exactly the hashes the Foundry client produces for the same inputs (checked on Hardhat by comparingzkVerifyCalcCtHashesPackedagainstzkVerifyCalcCtHashplusinsertCtHashper item). The ABI is unchanged, and thechainIdargument is passed through as before, so no new compiler warning.Tests
test/hardhat-plugin-test/test/encrypt-inputs.test.ts: encrypts[uint32(9n), uint32(9n)], expects two different hashes, then verifies the batch on chain and decrypts the stored value to9n. It fails on master (expected '0x464e…' to not equal '0x464e…') and passes with the fix.test/hardhat-plugin-testsuite: 102 passing and 1 failing (the new case) on master, 103 passing with the fix.Changeset
.changeset/mock-zk-verifier-batch-hashes.md, patch for@cofhe/mock-contracts.Note
Low Risk
Changes are limited to mock verifier hashing for local Hardhat tests; production contracts and ABIs are unchanged.
Overview
Fixes Hardhat mock behavior where
encryptInputsbatches with duplicate plaintexts (e.g. twouint32(9n)) returned identical ctHashes, so contracts treating handles as distinct inputs saw a single ciphertext.MockZkVerifiernow folds an explicit salt into_calcPlaceholderKey, andzkVerifyCalcCtHashesPackedderives itemiwithsalt + iso precomputed hashes match the salt advanced byinsertPackedCtHashes/insertCtHash. Single-input andzkVerifypaths still use the current salt, so batch-of-one behavior stays the same and packed results align with per-item Foundry-style verification.Adds a Hardhat plugin test that asserts two equal batch inputs get different hashes, then batch-verify and decrypt still succeed. Includes a patch changeset for
@cofhe/mock-contracts.Reviewed by Cursor Bugbot for commit 273eb6e. Bugbot is set up for automated code reviews on this repo. Configure here.