-
Notifications
You must be signed in to change notification settings - Fork 40
Enhance the SmtLib to support configurable hashing algorithm #402
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
3f1dc34
a60ef3e
e8ed999
94a535f
27784d6
a5721e9
a6193c6
78c998a
2357773
d9de57e
2a94371
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| // SPDX-License-Identifier: GPL-3.0 | ||
| pragma solidity 0.8.27; | ||
|
|
||
| /** | ||
| * @dev IHasher. Interface for generating hashes. Specifically used for Merkle Tree hashing. | ||
| */ | ||
| interface IHasher { | ||
| /** | ||
| * @dev hash2. hashes two uint256 parameters and returns the resulting hash as uint256. | ||
| * @param params The parameters array of size 2 to be hashed. | ||
| * @return The resulting hash as uint256. | ||
| */ | ||
| function hash2(uint256[2] memory params) external pure returns (uint256); | ||
|
|
||
| /** | ||
| * @dev hash3. hashes three uint256 parameters and returns the resulting hash as uint256. | ||
| * @param params The parameters array of size 3 to be hashed. | ||
| * @return The resulting hash as uint256. | ||
| */ | ||
| function hash3(uint256[3] memory params) external pure returns (uint256); | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,6 +3,7 @@ pragma solidity 0.8.27; | |||||||||||||||||||||
|
|
||||||||||||||||||||||
| import {PoseidonUnit2L, PoseidonUnit3L} from "./Poseidon.sol"; | ||||||||||||||||||||||
| import {ArrayUtils} from "./ArrayUtils.sol"; | ||||||||||||||||||||||
| import {IHasher} from "../interfaces/IHasher.sol"; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /// @title A sparse merkle tree implementation, which keeps tree history. | ||||||||||||||||||||||
| // Note that this SMT implementation can manage duplicated roots in the history, | ||||||||||||||||||||||
|
|
@@ -54,6 +55,8 @@ library SmtLib { | |||||||||||||||||||||
| // storage of upgradable contracts that use this struct as a state variable | ||||||||||||||||||||||
| // (see https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable#storage-gaps) | ||||||||||||||||||||||
| uint256[45] __gap; | ||||||||||||||||||||||
| bool isCustomHasherSet; | ||||||||||||||||||||||
| IHasher hasher; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /** | ||||||||||||||||||||||
|
|
@@ -136,6 +139,15 @@ library SmtLib { | |||||||||||||||||||||
| _; | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| /** | ||||||||||||||||||||||
| * @dev Sets custom hashers for the SMT. MUST be called before any other SMT operations. | ||||||||||||||||||||||
| * @param customerHasher IHasher implementation to be used for hashing. | ||||||||||||||||||||||
| */ | ||||||||||||||||||||||
| function setHasher(Data storage self, IHasher customerHasher) external { | ||||||||||||||||||||||
|
||||||||||||||||||||||
| function setHasher(Data storage self, IHasher customerHasher) external { | |
| function setHasher(Data storage self, IHasher customerHasher) external { | |
| require(address(customerHasher) != address(0), "Invalid hasher"); | |
| require(self.rootEntries.length == 1, "Hasher must be set before SMT usage"); |
Copilot
AI
Dec 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parameter name has a typo: "customerHasher" should be "customHasher". This naming inconsistency could cause confusion when reviewing or using the API.
| * @param customerHasher IHasher implementation to be used for hashing. | |
| */ | |
| function setHasher(Data storage self, IHasher customerHasher) external { | |
| self.isCustomHasherSet = true; | |
| self.hasher = customerHasher; | |
| * @param customHasher IHasher implementation to be used for hashing. | |
| */ | |
| function setHasher(Data storage self, IHasher customHasher) external { | |
| self.isCustomHasherSet = true; | |
| self.hasher = customHasher; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| // SPDX-License-Identifier: GPL-3.0 | ||
| pragma solidity 0.8.27; | ||
|
|
||
| import {IHasher} from "../../interfaces/IHasher.sol"; | ||
|
|
||
| /// @title A IHasher implementation using Keccak256. | ||
| contract Keccak256Hasher is IHasher { | ||
| function hash2(uint256[2] memory params) external pure override returns (uint256) { | ||
| bytes memory encoded = abi.encode(params); | ||
| return uint256(keccak256(encoded)); | ||
| } | ||
|
|
||
| function hash3(uint256[3] memory params) external pure override returns (uint256) { | ||
| bytes memory encoded = abi.encode(params); | ||
| return uint256(keccak256(encoded)); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| // SPDX-License-Identifier: GPL-3.0 | ||
| pragma solidity 0.8.27; | ||
|
|
||
| import {SmtLib} from "../lib/SmtLib.sol"; | ||
| import {SmtLibTestWrapper} from "./SmtLibTestWrapper.sol"; | ||
| import {Keccak256Hasher} from "../lib/hash/KeccakHasher.sol"; | ||
|
|
||
| contract SmtLibKeccakTestWrapper is SmtLibTestWrapper { | ||
| using SmtLib for SmtLib.Data; | ||
|
|
||
| constructor(uint256 maxDepth) SmtLibTestWrapper(maxDepth) { | ||
| smtData.setHasher(new Keccak256Hasher()); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The storage gap has been reduced from 45 to what should be 43 slots, but the comment still says
uint256[45] __gap. After addingisCustomHasherSet(bool, typically 1 slot when packed) andhasher(address reference, 1 slot), the gap should be reduced to maintain the same total storage footprint. The gap array size declaration needs to be updated touint256[43]to account for the two new fields, ensuring storage layout compatibility for upgradeable contracts.