sequenceDiagram
actor ExternalCaller
participant IthacaAccount
participant MerkleProofLib
ExternalCaller->>IthacaAccount: unwrapAndValidateSignature(digest, wrappedSig)
alt signature_length == 65
IthacaAccount-->>ExternalCaller: isValid = (ECDSA.recoverCalldata == this), keyHash = 0
else wrapped_signature
IthacaAccount->>IthacaAccount: parse keyHash, prehashFlag, merkleFlag from wrappedSig
alt prehashFlag != 0
IthacaAccount->>IthacaAccount: digest = EfficientHashLib.sha2(digest)
end
alt merkleFlag != 0
IthacaAccount->>IthacaAccount: _verifyMerkleSig(digest, merkleSigPayload)
IthacaAccount->>MerkleProofLib: verifyCalldata(proof, root, digest)
alt MerkleProofLib returns true
IthacaAccount->>IthacaAccount: unwrapAndValidateSignature(root, rootSig)
IthacaAccount-->>ExternalCaller: isValid, keyHash (from rootSig validation)
else MerkleProofLib returns false
IthacaAccount-->>ExternalCaller: isValid = false, keyHash = 0
end
else merkleFlag == 0
IthacaAccount->>IthacaAccount: getKey(keyHash) and validate
IthacaAccount-->>ExternalCaller: isValid, keyHash
end
end
Reviewer's Guide
Adds Merkle tree–based signature support to IthacaAccount (including a merkle flag in wrapped signatures), updates tests and benchmarks to the new signature encoding, and introduces fuzz tests for Merkle signatures, along with minor EIP-712 domain and version updates plus some IDE config files.
Sequence diagram for merkle-based wrapped signature verification
sequenceDiagram actor ExternalCaller participant IthacaAccount participant MerkleProofLib ExternalCaller->>IthacaAccount: unwrapAndValidateSignature(digest, wrappedSig) alt signature_length == 65 IthacaAccount-->>ExternalCaller: isValid = (ECDSA.recoverCalldata == this), keyHash = 0 else wrapped_signature IthacaAccount->>IthacaAccount: parse keyHash, prehashFlag, merkleFlag from wrappedSig alt prehashFlag != 0 IthacaAccount->>IthacaAccount: digest = EfficientHashLib.sha2(digest) end alt merkleFlag != 0 IthacaAccount->>IthacaAccount: _verifyMerkleSig(digest, merkleSigPayload) IthacaAccount->>MerkleProofLib: verifyCalldata(proof, root, digest) alt MerkleProofLib returns true IthacaAccount->>IthacaAccount: unwrapAndValidateSignature(root, rootSig) IthacaAccount-->>ExternalCaller: isValid, keyHash (from rootSig validation) else MerkleProofLib returns false IthacaAccount-->>ExternalCaller: isValid = false, keyHash = 0 end else merkleFlag == 0 IthacaAccount->>IthacaAccount: getKey(keyHash) and validate IthacaAccount-->>ExternalCaller: isValid, keyHash end endClass diagram for updated IthacaAccount merkle-aware signature validation
classDiagram class IthacaAccount { +unwrapAndValidateSignature(bytes32 digest, bytes signature) bool isValid, bytes32 keyHash -_verifyMerkleSig(bytes32 digest, bytes signature) bool isValid, bytes32 keyHash +eip712DomainDetails() string name, string version } class MerkleProofLib { +verifyCalldata(bytes32[] proof, bytes32 root, bytes32 leaf) bool } class LibBytes { +loadCalldata(bytes data, uint256 index) bytes32 +truncatedCalldata(bytes data, uint256 newLength) bytes } class EfficientHashLib { +sha2(bytes32 digest) bytes32 } class ECDSA { +recoverCalldata(bytes32 digest, bytes signature) address } IthacaAccount ..> MerkleProofLib : uses IthacaAccount ..> LibBytes : uses IthacaAccount ..> EfficientHashLib : uses IthacaAccount ..> ECDSA : usesFile-Level Changes
src/IthacaAccount.soltest/Base.t.soltest/Account.t.soltest/Orchestrator.t.soltest/SimulateExecute.t.soltest/Benchmark.t.sol.idea/.gitignore.idea/account.iml.idea/caches/deviceStreaming.xml.idea/codeStyles/Project.xml.idea/codeStyles/codeStyleConfig.xml.idea/copilot.data.migration.ask2agent.xml.idea/markdown.xml.idea/modules.xml.idea/vcs.xmlPossibly linked issues
Tips and commands
Interacting with Sourcery
@sourcery-ai reviewon the pull request.issue from a review comment by replying to it. You can also reply to a
review comment with
@sourcery-ai issueto create an issue from it.@sourcery-aianywhere in the pullrequest title to generate a title at any time. You can also comment
@sourcery-ai titleon the pull request to (re-)generate the title at any time.@sourcery-ai summaryanywhere inthe pull request body to generate a PR summary at any time exactly where you
want it. You can also comment
@sourcery-ai summaryon the pull request to(re-)generate the summary at any time.
@sourcery-ai guideon the pullrequest to (re-)generate the reviewer's guide at any time.
@sourcery-ai resolveon thepull request to resolve all Sourcery comments. Useful if you've already
addressed all the comments and don't want to see them anymore.
@sourcery-ai dismisson the pullrequest to dismiss all existing Sourcery reviews. Especially useful if you
want to start fresh with a new review - don't forget to comment
@sourcery-ai reviewto trigger a new review!Customizing Your Experience
Access your dashboard to:
summary, the reviewer's guide, and others.
Getting Help
Originally posted by @sourcery-ai[bot] in #86 (comment)