From 65638910381f4506c50c72ee00b156530310f7bd Mon Sep 17 00:00:00 2001 From: Michael Heuer Date: Wed, 30 Apr 2025 16:53:53 +0200 Subject: [PATCH 1/6] WIP --- src/ProtocolAdapter.sol | 174 ++++++++++++------------------ src/Types.sol | 9 +- src/libs/ArrayLookup.sol | 17 +++ src/libs/ComputableComponents.sol | 4 + src/proving/Compliance.sol | 8 +- src/proving/Logic.sol | 33 +++--- test/mocks/MockTypes.sol | 50 ++++++--- 7 files changed, 145 insertions(+), 150 deletions(-) diff --git a/src/ProtocolAdapter.sol b/src/ProtocolAdapter.sol index 121e887..86fbdba 100644 --- a/src/ProtocolAdapter.sol +++ b/src/ProtocolAdapter.sol @@ -10,20 +10,19 @@ import {MockDelta} from "../test/mocks/MockDelta.sol"; // TODO remove import {IForwarder} from "./interfaces/IForwarder.sol"; import {IProtocolAdapter} from "./interfaces/IProtocolAdapter.sol"; -import {AppData} from "./libs/AppData.sol"; import {ArrayLookup} from "./libs/ArrayLookup.sol"; import {ComputableComponents} from "./libs/ComputableComponents.sol"; import {Reference} from "./libs/Reference.sol"; import {ComplianceUnit} from "./proving/Compliance.sol"; import {Delta} from "./proving/Delta.sol"; -import {LogicInstance, LogicProofs, TagLogicProofPair, LogicRefProofPair} from "./proving/Logic.sol"; +import {LogicInstance, LogicProofs, LogicProof, TagLogicProofPair} from "./proving/Logic.sol"; import {BlobStorage, DeletionCriterion, ExpirableBlob} from "./state/BlobStorage.sol"; import {CommitmentAccumulator} from "./state/CommitmentAccumulator.sol"; import {NullifierSet} from "./state/NullifierSet.sol"; -import {Action, ForwarderCalldata, Resource, TagAppDataPair, Transaction} from "./Types.sol"; +import {Action, ForwarderCalldata, Resource, Transaction} from "./Types.sol"; contract ProtocolAdapter is IProtocolAdapter, @@ -35,7 +34,6 @@ contract ProtocolAdapter is using ArrayLookup for bytes32[]; using ComputableComponents for Resource; using Reference for bytes; - using AppData for TagAppDataPair[]; using LogicProofs for TagLogicProofPair[]; using EnumerableSet for EnumerableSet.Bytes32Set; @@ -76,33 +74,30 @@ contract ProtocolAdapter is emit TransactionExecuted({id: ++_txCount, transaction: transaction}); - uint256 n = transaction.actions.length; - uint256 m; - uint256 j; bytes32 newRoot = 0; - for (uint256 i = 0; i < n; ++i) { + for (uint256 i = 0; i < transaction.actions.length; ++i) { Action calldata action = transaction.actions[i]; - m = action.tagAppDataPairs.length; - for (j = 0; j < m; ++j) { - _storeBlob(action.tagAppDataPairs[j].appData); - } - - m = action.nullifiers.length; - for (j = 0; j < m; ++j) { - // Nullifier non-existence was already checked in `_verify(transaction);` at the top. - _addNullifierUnchecked(action.nullifiers[j]); - } + uint256 nResources = action.logicProofs.length; + for (uint256 j = 0; j < nResources; ++j) { + TagLogicProofPair calldata pair = action.logicProofs[j]; - m = action.commitments.length; + if (pair.logicProof.isConsumed) { + // Nullifier non-existence was already checked in `_verify(transaction);` at the top. + _addNullifierUnchecked(pair.tag); + } else { + // Commitment non-existence was already checked in `_verify(transaction);` at the top. + newRoot = _addCommitmentUnchecked(pair.tag); + } - for (j = 0; j < m; ++j) { - // Commitment non-existence was already checked in `_verify(transaction);` at the top. - newRoot = _addCommitmentUnchecked(action.commitments[j]); + uint256 nBlobs = pair.logicProof.appData.length; + for (uint256 k = 0; k < nBlobs; ++j) { + _storeBlob(pair.logicProof.appData[k]); + } } - m = action.resourceCalldataPairs.length; - for (j = 0; j < m; ++j) { + uint256 nForwarderCalls = action.resourceCalldataPairs.length; + for (uint256 j = 0; j < nForwarderCalls; ++j) { _executeForwarderCall(action.resourceCalldataPairs[j].call); } } @@ -129,51 +124,27 @@ contract ProtocolAdapter is // slither-disable-next-line calls-loop function _verify(Transaction calldata transaction) internal view { // Can also be named DeltaHash (which is what Yulia does). - uint256[2] memory transactionDelta = Delta.zero(); - // Helper variable - uint256 resourceCount = 0; + uint256[2] memory transactionDelta = Delta.zero(); + bytes32[] storage tags; uint256 nActions = transaction.actions.length; - for (uint256 i; i < nActions; ++i) { - resourceCount += transaction.actions[i].commitments.length; - resourceCount += transaction.actions[i].nullifiers.length; - } - bytes32[] memory tags = new bytes32[](resourceCount); - - // Reset resource count for later use. - resourceCount = 0; - - uint256 len; for (uint256 i; i < nActions; ++i) { Action calldata action = transaction.actions[i]; _verifyForwarderCalls(action); // Compliance Proofs - len = action.complianceUnits.length; - for (uint256 j; j < len; ++j) { + uint256 nCUs = action.complianceUnits.length; + for (uint256 j = 0; j < nCUs; ++j) { ComplianceUnit calldata unit = action.complianceUnits[j]; // Check consumed resources - // TODO This check can be removed after Xuyang's and Artem's specs change proposal gets merged. - if (!transaction.roots.contains(unit.instance.consumed.rootRef)) { - revert InvalidRootRef(unit.instance.consumed.rootRef); - } _checkRootPreExistence(unit.instance.consumed.rootRef); - - // TODO This check can be removed after Xuyang's and Artem's specs change proposal gets merged. - if (!action.nullifiers.contains(unit.instance.consumed.nullifierRef)) { - revert InvalidNullifierRef(unit.instance.consumed.nullifierRef); - } - _checkNullifierNonExistence(unit.instance.consumed.nullifierRef); + _checkNullifierNonExistence(unit.instance.consumed.nullifier); // Check created resources - // TODO This check can be removed after Xuyang's and Artem's specs change proposal gets merged. - if (!action.commitments.contains(unit.instance.created.commitmentRef)) { - revert InvalidCommitmentRef(unit.instance.created.commitmentRef); - } - _checkCommitmentNonExistence(unit.instance.created.commitmentRef); + _checkCommitmentNonExistence(unit.instance.created.commitment); _TRUSTED_RISC_ZERO_VERIFIER.verify({ seal: unit.proof, @@ -185,72 +156,67 @@ contract ProtocolAdapter is transactionDelta = Delta.add({p1: transactionDelta, p2: unit.instance.unitDelta}); } - // Logic Proofs - LogicInstance memory instance = LogicInstance({ - tag: bytes32(0), - isConsumed: true, - consumed: action.nullifiers, - created: action.commitments, - tagSpecificAppData: ExpirableBlob({deletionCriterion: DeletionCriterion.Immediately, blob: bytes("")}) - }); - LogicRefProofPair memory logicRefProofPair; - - // Check consumed resources - len = action.nullifiers.length; - for (uint256 j; j < len; ++j) { - bytes32 tag = action.nullifiers[j]; - - tags[j] = tag; - ++resourceCount; - - instance.tag = tag; - instance.tagSpecificAppData = action.tagAppDataPairs.lookupCalldata(tag); - - { - logicRefProofPair = action.logicProofs.lookup(tag); - - _TRUSTED_RISC_ZERO_VERIFIER.verify({ - seal: logicRefProofPair.proof, - imageId: _LOGIC_CIRCUIT_ID, - journalDigest: sha256(abi.encode( /*verifying key*/ logicRefProofPair.logicRef, instance)) - }); + uint256 nResources = action.logicProofs.length; + + bytes32[] storage allNullifiers; + bytes32[] storage allCommitments; + for (uint256 j = 0; j < nResources; ++j) { + TagLogicProofPair calldata pair = action.logicProofs[j]; + + tags.push(pair.tag); + if (pair.logicProof.isConsumed) { + allNullifiers.push(pair.tag); + } else { + allCommitments.push(pair.tag); } } - // Check created resources - instance.isConsumed = false; - - len = action.commitments.length; - for (uint256 j; j < len; ++j) { - bytes32 tag = action.commitments[j]; - tags[action.nullifiers.length + j] = tag; - ++resourceCount; + for (uint256 j = 0; j < nResources; ++j) { + bytes32 tag = action.logicProofs[j].tag; + LogicProof calldata proof = action.logicProofs[j].logicProof; - instance.tag = tag; - instance.tagSpecificAppData = action.tagAppDataPairs.lookup(tag); + LogicInstance memory instance; - { - logicRefProofPair = action.logicProofs.lookup(tag); - _TRUSTED_RISC_ZERO_VERIFIER.verify({ - seal: logicRefProofPair.proof, - imageId: _LOGIC_CIRCUIT_ID, - journalDigest: sha256(abi.encode( /*verifying key*/ logicRefProofPair.logicRef, instance)) + if (proof.isConsumed) { + instance = LogicInstance({ + tag: tag, + isConsumed: true, + consumed: allNullifiers.removeElement(tag), + created: allCommitments, + appData: proof.appData + }); + } else { + instance = LogicInstance({ + tag: tag, + isConsumed: false, + consumed: allNullifiers, + created: allCommitments.removeElement(tag), + appData: proof.appData }); } + + _TRUSTED_RISC_ZERO_VERIFIER.verify({ + seal: proof.proof, + imageId: _LOGIC_CIRCUIT_ID, + journalDigest: sha256(abi.encode(proof.logicVerifyingKeyOuter, instance)) + }); } } // Delta Proof // TODO: THIS IS A TEMPORARY MOCK PROOF AND MUST BE REMOVED. // NOTE: The `transactionHash(tags)` and `transactionDelta` are not used here. - _transactionHash(tags); + ComputableComponents.transactionHash(tags); + // TODO do we even needs this? + // bytes32 deltaVerifyingKey; // TransactionHash is part of the transaction MockDelta.verify({deltaProof: transaction.deltaProof}); + /* Delta.verify({ - transactionHash: _transactionHash(tags), + transactionHash: transaction.deltaVerifyingKey, transactionDelta: transactionDelta, deltaProof: transaction.deltaProof - }); + }); */ } @@ -284,8 +250,4 @@ contract ProtocolAdapter is } } } - - function _transactionHash(bytes32[] memory tags) internal pure returns (bytes32 txHash) { - txHash = sha256(abi.encode(tags)); - } } diff --git a/src/Types.sol b/src/Types.sol index 761c844..23639fb 100644 --- a/src/Types.sol +++ b/src/Types.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; -import {TagAppDataPair} from "./libs/AppData.sol"; import {ComplianceUnit} from "./proving/Compliance.sol"; + import {TagLogicProofPair} from "./proving/Logic.sol"; struct Resource { @@ -17,17 +17,16 @@ struct Resource { } struct Transaction { - bytes32[] roots; + // bytes32[] roots; Action[] actions; bytes deltaProof; + bytes32 deltaVerifyingKey; // TransactionHash + uint256[2] expectedBalance; } struct Action { - bytes32[] commitments; - bytes32[] nullifiers; TagLogicProofPair[] logicProofs; ComplianceUnit[] complianceUnits; - TagAppDataPair[] tagAppDataPairs; ResourceForwarderCalldataPair[] resourceCalldataPairs; } diff --git a/src/libs/ArrayLookup.sol b/src/libs/ArrayLookup.sol index 06d1ecd..4358d43 100644 --- a/src/libs/ArrayLookup.sol +++ b/src/libs/ArrayLookup.sol @@ -1,7 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; +// TODO! Rename library ArrayLookup { + error ElementNotFound(bytes32 tag); + function contains(bytes32[] memory set, bytes32 tag) internal pure returns (bool success) { uint256 len = set.length; for (uint256 i = 0; i < len; ++i) { @@ -11,4 +14,18 @@ library ArrayLookup { } return success = false; } + + // TODO! write test to make sure that this works + function removeElement(bytes32[] storage array, bytes32 elem) internal returns (bytes32[] storage modified) { + modified = array; + for (uint256 i = 0; i < array.length; i++) { + if (modified[i] == elem) { + // Swap with last and pop for gas-efficient removal + modified[i] = array[array.length - 1]; + modified.pop(); + break; + } + } + revert ElementNotFound(elem); + } } diff --git a/src/libs/ComputableComponents.sol b/src/libs/ComputableComponents.sol index 02be158..f613a91 100644 --- a/src/libs/ComputableComponents.sol +++ b/src/libs/ComputableComponents.sol @@ -31,4 +31,8 @@ library ComputableComponents { function kindCalldata(Resource calldata resource) internal pure returns (bytes32 k) { k = sha256(abi.encode(resource.logicRef, resource.labelRef)); } + + function transactionHash(bytes32[] memory tags) internal pure returns (bytes32 txHash) { + txHash = sha256(abi.encode(tags)); + } } diff --git a/src/proving/Compliance.sol b/src/proving/Compliance.sol index eec7d60..df049d6 100644 --- a/src/proving/Compliance.sol +++ b/src/proving/Compliance.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.27; struct ComplianceUnit { - bytes proof; - ComplianceInstance instance; bytes32 verifyingKey; + ComplianceInstance instance; + bytes proof; } struct ComplianceInstance { @@ -14,12 +14,12 @@ struct ComplianceInstance { } struct ConsumedRefs { - bytes32 nullifierRef; + bytes32 nullifier; bytes32 rootRef; bytes32 logicRef; } struct CreatedRefs { - bytes32 commitmentRef; + bytes32 commitment; bytes32 logicRef; } diff --git a/src/proving/Logic.sol b/src/proving/Logic.sol index 1147202..c6ca8bd 100644 --- a/src/proving/Logic.sol +++ b/src/proving/Logic.sol @@ -8,46 +8,41 @@ struct LogicInstance { bool isConsumed; bytes32[] consumed; bytes32[] created; - ExpirableBlob tagSpecificAppData; + ExpirableBlob[] appData; // ExpirableBlob tagSpecificAppData; // TODO! } -struct TagLogicProofPair { - bytes32 tag; - LogicRefProofPair pair; +// TODO! PICK BETTER NAME +struct LogicProof { + bool isConsumed; + bytes32 logicVerifyingKeyOuter; // TODO rename logic ref + ExpirableBlob[] appData; + bytes proof; } -struct LogicRefProofPair { - bytes32 logicRef; - bytes proof; +struct TagLogicProofPair { + bytes32 tag; + LogicProof logicProof; } library LogicProofs { error LogicProofTagNotFound(bytes32 tag); error LogicProofIndexOutBounds(uint256 index, uint256 max); - function lookup(TagLogicProofPair[] calldata map, bytes32 tag) - internal - pure - returns (LogicRefProofPair memory elem) - { + function lookup(TagLogicProofPair[] calldata map, bytes32 tag) internal pure returns (LogicProof memory elem) { uint256 len = map.length; for (uint256 i = 0; i < len; ++i) { if (map[i].tag == tag) { - return elem = (map[i].pair); + return elem = (map[i].logicProof); } } revert LogicProofTagNotFound(tag); } - function at(TagLogicProofPair[] calldata map, uint256 index) - internal - pure - returns (LogicRefProofPair memory elem) - { + function at(TagLogicProofPair[] calldata map, uint256 index) internal pure returns (LogicProof memory elem) { uint256 lastIndex = map.length - 1; if (index > lastIndex) { revert LogicProofIndexOutBounds({index: index, max: lastIndex}); } - elem = map[index].pair; + elem = map[index].logicProof; } } diff --git a/test/mocks/MockTypes.sol b/test/mocks/MockTypes.sol index b09f34d..5cd6ff7 100644 --- a/test/mocks/MockTypes.sol +++ b/test/mocks/MockTypes.sol @@ -5,12 +5,13 @@ import {Receipt as RiscZeroReceipt} from "@risc0-ethereum/IRiscZeroVerifier.sol" import {RiscZeroMockVerifier} from "@risc0-ethereum/test/RiscZeroMockVerifier.sol"; import {AppData, TagAppDataPair} from "../../src/libs/AppData.sol"; +import {ArrayLookup} from "../../src/libs/ArrayLookup.sol"; import {ComputableComponents} from "../../src/libs/ComputableComponents.sol"; import {Universal} from "../../src/libs/Identities.sol"; import {ComplianceUnit, ComplianceInstance, ConsumedRefs, CreatedRefs} from "../../src/proving/Compliance.sol"; import {Delta} from "../../src/proving/Delta.sol"; -import {LogicInstance, TagLogicProofPair, LogicRefProofPair} from "../../src/proving/Logic.sol"; +import {LogicInstance, LogicProof, TagLogicProofPair} from "../../src/proving/Logic.sol"; import {ExpirableBlob, DeletionCriterion} from "../../src/state/BlobStorage.sol"; import {Action, ResourceForwarderCalldataPair, Resource, Transaction} from "../../src/Types.sol"; @@ -19,6 +20,7 @@ import {MockDelta} from "../mocks/MockDelta.sol"; import {MockRiscZeroProof} from "../mocks/MockRiscZeroProof.sol"; library MockTypes { + using ArrayLookup for bytes32[]; using ComputableComponents for Resource; using AppData for TagAppDataPair[]; using Delta for uint256[2]; @@ -86,19 +88,25 @@ library MockTypes { ResourceForwarderCalldataPair[] memory emptyCalls; - actions[a] = Action({ - commitments: cms, - nullifiers: nfs, - logicProofs: rlProofs, - complianceUnits: complianceUnits, - tagAppDataPairs: appData, - resourceCalldataPairs: emptyCalls - }); + actions[a] = + Action({logicProofs: rlProofs, complianceUnits: complianceUnits, resourceCalldataPairs: emptyCalls}); } bytes memory deltaProof = MockDelta.PROOF; - transaction = Transaction({roots: roots, actions: actions, deltaProof: deltaProof}); + bytes32[] storage tags; + for (uint256 i = 0; i < actions.length; ++i) { + for (uint256 j = 0; j < actions[i].logicProofs.length; ++j) { + tags.push(actions[i].logicProofs[j].tag); + } + } + + transaction = Transaction({ + actions: actions, + deltaProof: deltaProof, + deltaVerifyingKey: ComputableComponents.transactionHash(tags), + expectedBalance: Delta.zero() + }); } // solhint-disable-next-line function-max-lines @@ -106,7 +114,7 @@ library MockTypes { RiscZeroMockVerifier mockVerifier, bytes32[] memory nullifiers, bytes32[] memory commitments, - TagAppDataPair[] memory appData + TagAppDataPair[] memory appData // TODO! ) internal view returns (TagLogicProofPair[] memory logicProofs) { logicProofs = new TagLogicProofPair[](nullifiers.length + commitments.length); @@ -117,9 +125,9 @@ library MockTypes { LogicInstance memory instance = LogicInstance({ tag: tag, isConsumed: true, - consumed: nullifiers, + consumed: nullifiers.removeElement(tag), created: commitments, - tagSpecificAppData: appData.lookup(tag) + appData: [] // TODO! }); bytes32 verifyingKey = _ALWAYS_VALID_LOGIC_REF; @@ -131,7 +139,12 @@ library MockTypes { logicProofs[i] = TagLogicProofPair({ tag: tag, - pair: LogicRefProofPair({logicRef: _ALWAYS_VALID_LOGIC_REF, proof: receipt.seal}) + logicProof: LogicProof({ + isConsumed: true, + logicVerifyingKeyOuter: _ALWAYS_VALID_LOGIC_REF, + appData: [], // TODO! + proof: receipt.seal + }) }); } @@ -143,7 +156,7 @@ library MockTypes { tag: tag, isConsumed: false, consumed: nullifiers, - created: commitments, + created: commitments.removeElement(tag), tagSpecificAppData: appData.lookup(tag) }); @@ -156,7 +169,12 @@ library MockTypes { logicProofs[nullifiers.length + i] = TagLogicProofPair({ tag: tag, - pair: LogicRefProofPair({logicRef: _ALWAYS_VALID_LOGIC_REF, proof: receipt.seal}) + logicProof: LogicProof({ + isConsumed: true, + logicVerifyingKeyOuter: _ALWAYS_VALID_LOGIC_REF, + appData: [], // TODO! + proof: receipt.seal + }) }); } } From 923eea355b8c5bab751cf1109410cbd166c54bb1 Mon Sep 17 00:00:00 2001 From: Michael Heuer Date: Tue, 6 May 2025 16:46:49 +0200 Subject: [PATCH 2/6] WIP --- src/ProtocolAdapter.sol | 86 +++++++++++++++---------------- src/Types.sol | 2 +- src/libs/ArrayLookup.sol | 35 ++++++++++++- src/libs/ComputableComponents.sol | 48 ++++++++++++++++- test/mocks/MockTypes.sol | 86 +++++++++++++++++-------------- 5 files changed, 170 insertions(+), 87 deletions(-) diff --git a/src/ProtocolAdapter.sol b/src/ProtocolAdapter.sol index 86fbdba..a0ee946 100644 --- a/src/ProtocolAdapter.sol +++ b/src/ProtocolAdapter.sol @@ -78,9 +78,9 @@ contract ProtocolAdapter is for (uint256 i = 0; i < transaction.actions.length; ++i) { Action calldata action = transaction.actions[i]; - uint256 nResources = action.logicProofs.length; + uint256 nResources = action.tagLogicProofPairs.length; for (uint256 j = 0; j < nResources; ++j) { - TagLogicProofPair calldata pair = action.logicProofs[j]; + TagLogicProofPair calldata pair = action.tagLogicProofPairs[j]; if (pair.logicProof.isConsumed) { // Nullifier non-existence was already checked in `_verify(transaction);` at the top. @@ -123,10 +123,12 @@ contract ProtocolAdapter is // solhint-disable-next-line function-max-lines // slither-disable-next-line calls-loop function _verify(Transaction calldata transaction) internal view { - // Can also be named DeltaHash (which is what Yulia does). + uint256[2] memory transactionDelta = Delta.zero(); // TODO: Renamed to DeltaHash? - uint256[2] memory transactionDelta = Delta.zero(); - bytes32[] storage tags; + uint256 resCount = counts(transaction); + + bytes32[] memory tags = new bytes32[](resCount); + uint256 resCounter; uint256 nActions = transaction.actions.length; for (uint256 i; i < nActions; ++i) { @@ -156,44 +158,26 @@ contract ProtocolAdapter is transactionDelta = Delta.add({p1: transactionDelta, p2: unit.instance.unitDelta}); } - uint256 nResources = action.logicProofs.length; + // Resource Logic Proofs - bytes32[] storage allNullifiers; - bytes32[] storage allCommitments; - for (uint256 j = 0; j < nResources; ++j) { - TagLogicProofPair calldata pair = action.logicProofs[j]; + uint256 nResources = action.tagLogicProofPairs.length; - tags.push(pair.tag); - if (pair.logicProof.isConsumed) { - allNullifiers.push(pair.tag); - } else { - allCommitments.push(pair.tag); - } - } + (bytes32[][] memory consumed, bytes32[][] memory created) = + ComputableComponents.prepareLists(action.tagLogicProofPairs); for (uint256 j = 0; j < nResources; ++j) { - bytes32 tag = action.logicProofs[j].tag; - LogicProof calldata proof = action.logicProofs[j].logicProof; - - LogicInstance memory instance; - - if (proof.isConsumed) { - instance = LogicInstance({ - tag: tag, - isConsumed: true, - consumed: allNullifiers.removeElement(tag), - created: allCommitments, - appData: proof.appData - }); - } else { - instance = LogicInstance({ - tag: tag, - isConsumed: false, - consumed: allNullifiers, - created: allCommitments.removeElement(tag), - appData: proof.appData - }); - } + bytes32 tag = action.tagLogicProofPairs[j].tag; + tags[resCounter++] = tag; + + LogicProof calldata proof = action.tagLogicProofPairs[j].logicProof; + + LogicInstance memory instance = LogicInstance({ + tag: tag, + isConsumed: proof.isConsumed, + consumed: consumed[j], + created: created[j], + appData: proof.appData + }); _TRUSTED_RISC_ZERO_VERIFIER.verify({ seal: proof.proof, @@ -222,10 +206,10 @@ contract ProtocolAdapter is // slither-disable-next-line calls-loop function _verifyForwarderCalls(Action calldata action) internal view { - uint256 len = action.resourceCalldataPairs.length; - for (uint256 j; j < len; ++j) { - Resource calldata carrier = action.resourceCalldataPairs[j].carrier; - ForwarderCalldata calldata call = action.resourceCalldataPairs[j].call; + uint256 nForwarderCalls = action.resourceCalldataPairs.length; + for (uint256 i = 0; i < nForwarderCalls; ++i) { + Resource calldata carrier = action.resourceCalldataPairs[i].carrier; + ForwarderCalldata calldata call = action.resourceCalldataPairs[i].call; // Kind integrity check { @@ -242,7 +226,9 @@ contract ProtocolAdapter is { bytes32 expectedAppDataHash = keccak256(abi.encode(call.untrustedForwarder, call.input, call.output)); - bytes32 actualAppDataHash = keccak256(action.tagAppDataPairs.lookup(carrier.commitment()).blob); + // Lookup the first appData entry. + bytes32 actualAppDataHash = + keccak256(abi.encode(action.tagLogicProofPairs.lookup(carrier.commitment()).appData[0])); if (actualAppDataHash != expectedAppDataHash) { revert CalldataCarrierAppDataMismatch({actual: actualAppDataHash, expected: expectedAppDataHash}); @@ -250,4 +236,16 @@ contract ProtocolAdapter is } } } + + function counts(Transaction calldata transaction) internal pure returns (uint256 resCount) { + uint256 nActions = transaction.actions.length; + + for (uint256 i = 0; i < nActions; ++i) { + Action calldata action = transaction.actions[i]; + uint256 nResources = action.tagLogicProofPairs.length; + for (uint256 j = 0; j < nResources; ++j) { + ++resCount; + } + } + } } diff --git a/src/Types.sol b/src/Types.sol index 23639fb..2af81c9 100644 --- a/src/Types.sol +++ b/src/Types.sol @@ -25,7 +25,7 @@ struct Transaction { } struct Action { - TagLogicProofPair[] logicProofs; + TagLogicProofPair[] tagLogicProofPairs; ComplianceUnit[] complianceUnits; ResourceForwarderCalldataPair[] resourceCalldataPairs; } diff --git a/src/libs/ArrayLookup.sol b/src/libs/ArrayLookup.sol index 4358d43..20c7610 100644 --- a/src/libs/ArrayLookup.sol +++ b/src/libs/ArrayLookup.sol @@ -16,7 +16,10 @@ library ArrayLookup { } // TODO! write test to make sure that this works - function removeElement(bytes32[] storage array, bytes32 elem) internal returns (bytes32[] storage modified) { + function removeElementStorage(bytes32[] storage array, bytes32 elem) + internal + returns (bytes32[] storage modified) + { modified = array; for (uint256 i = 0; i < array.length; i++) { if (modified[i] == elem) { @@ -28,4 +31,34 @@ library ArrayLookup { } revert ElementNotFound(elem); } + + function removeElement(bytes32[] memory arr, bytes32 elem) internal pure returns (bytes32[] memory) { + uint256 indexToRemove = 0; + bool found = false; + + // Find index of the elem + for (uint256 i = 0; i < arr.length; i++) { + if (arr[i] == elem) { + indexToRemove = i; + found = true; + break; + } + } + + if (!found) revert ElementNotFound(elem); + + // Create new array with one less element + bytes32[] memory result = new bytes32[](arr.length - 1); + uint256 j = 0; + + // Copy all elements except the one to remove + for (uint256 i = 0; i < arr.length; i++) { + if (i != indexToRemove) { + result[j] = arr[i]; + j++; + } + } + + return result; + } } diff --git a/src/libs/ComputableComponents.sol b/src/libs/ComputableComponents.sol index f613a91..d40b61c 100644 --- a/src/libs/ComputableComponents.sol +++ b/src/libs/ComputableComponents.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; -import {Resource} from "../Types.sol"; +import {Resource, Action, Transaction} from "../Types.sol"; +import {TagLogicProofPair} from "../proving/Logic.sol"; library ComputableComponents { function commitment(Resource memory resource) internal pure returns (bytes32 cm) { @@ -35,4 +36,49 @@ library ComputableComponents { function transactionHash(bytes32[] memory tags) internal pure returns (bytes32 txHash) { txHash = sha256(abi.encode(tags)); } + + // TODO! MOVE ELSEWHERE + function prepareLists(TagLogicProofPair[] calldata pairs) + internal + pure + returns (bytes32[][] memory consumed, bytes32[][] memory created) + { + uint256 nResources = pairs.length; + + consumed = new bytes32[][](nResources); + created = new bytes32[][](nResources); + + // Count nullifiers and commitments + uint256 nfsCount = 0; + uint256 cmsCount = 0; + for (uint256 i = 0; i < nResources; ++i) { + pairs[i].logicProof.isConsumed ? ++nfsCount : ++cmsCount; + } + + // Populate lists + for (uint256 i = 0; i < nResources; ++i) { + // Initialize list lengths. + if (pairs[i].logicProof.isConsumed) { + consumed[i] = new bytes32[](nfsCount - 1); + created[i] = new bytes32[](cmsCount); + } else { + consumed[i] = new bytes32[](nfsCount); + created[i] = new bytes32[](cmsCount - 1); + } + + uint256 nfsCounter = 0; + uint256 cmsCounter = 0; + + // Store tags + for (uint256 j = 0; j < nResources; ++j) { + if (i != j) { + if (pairs[j].logicProof.isConsumed) { + consumed[i][++nfsCounter] = pairs[j].tag; + } else { + created[i][++cmsCounter] = pairs[j].tag; + } + } + } + } + } } diff --git a/test/mocks/MockTypes.sol b/test/mocks/MockTypes.sol index 5cd6ff7..a3ef4fe 100644 --- a/test/mocks/MockTypes.sol +++ b/test/mocks/MockTypes.sol @@ -88,16 +88,19 @@ library MockTypes { ResourceForwarderCalldataPair[] memory emptyCalls; - actions[a] = - Action({logicProofs: rlProofs, complianceUnits: complianceUnits, resourceCalldataPairs: emptyCalls}); + actions[a] = Action({ + tagLogicProofPairs: rlProofs, + complianceUnits: complianceUnits, + resourceCalldataPairs: emptyCalls + }); } bytes memory deltaProof = MockDelta.PROOF; bytes32[] storage tags; for (uint256 i = 0; i < actions.length; ++i) { - for (uint256 j = 0; j < actions[i].logicProofs.length; ++j) { - tags.push(actions[i].logicProofs[j].tag); + for (uint256 j = 0; j < actions[i].tagLogicProofPairs.length; ++j) { + tags.push(actions[i].tagLogicProofPairs[j].tag); } } @@ -110,24 +113,40 @@ library MockTypes { } // solhint-disable-next-line function-max-lines - function _mockLogicProofs( - RiscZeroMockVerifier mockVerifier, - bytes32[] memory nullifiers, - bytes32[] memory commitments, - TagAppDataPair[] memory appData // TODO! - ) internal view returns (TagLogicProofPair[] memory logicProofs) { - logicProofs = new TagLogicProofPair[](nullifiers.length + commitments.length); + function _mockLogicProofs(RiscZeroMockVerifier mockVerifier, TagAppDataPair[] memory tagAppDataPairs) + internal + view + returns (TagLogicProofPair[] memory logicProofs) + { + (bytes32[][] memory consumed, bytes32[][] memory created) = ComputableComponents.prepareLists(tagAppDataPairs); + + uint256 nResources = tagAppDataPairs.length; + + for (uint256 j = 0; j < nResources; ++j) { + bytes32 tag = tagAppDataPairs[j].tag; + tags[resCounter++] = tag; + + LogicProof calldata proof = action.tagLogicProofPairs[j].logicProof; + + LogicInstance memory instance = LogicInstance({ + tag: tag, + isConsumed: proof.isConsumed, + consumed: consumed[j], + created: created[j], + appData: proof.appData + }); + } - uint256 len = nullifiers.length; + uint256 len = consumedTagAppDataPair.length; for (uint256 i = 0; i < len; ++i) { - bytes32 tag = nullifiers[i]; + bytes32 tag = consumedTagAppDataPair[i].tag; LogicInstance memory instance = LogicInstance({ tag: tag, isConsumed: true, consumed: nullifiers.removeElement(tag), created: commitments, - appData: [] // TODO! + appData: appDataEntries[i] }); bytes32 verifyingKey = _ALWAYS_VALID_LOGIC_REF; @@ -142,7 +161,7 @@ library MockTypes { logicProof: LogicProof({ isConsumed: true, logicVerifyingKeyOuter: _ALWAYS_VALID_LOGIC_REF, - appData: [], // TODO! + appData: appDataEntries[i], proof: receipt.seal }) }); @@ -157,7 +176,7 @@ library MockTypes { isConsumed: false, consumed: nullifiers, created: commitments.removeElement(tag), - tagSpecificAppData: appData.lookup(tag) + appData: appDataEntries[nullifiers.length + i] }); bytes32 verifyingKey = _ALWAYS_VALID_LOGIC_REF; @@ -172,7 +191,7 @@ library MockTypes { logicProof: LogicProof({ isConsumed: true, logicVerifyingKeyOuter: _ALWAYS_VALID_LOGIC_REF, - appData: [], // TODO! + appData: appDataEntries[nullifiers.length + i], proof: receipt.seal }) }); @@ -194,8 +213,8 @@ library MockTypes { for (uint256 i = 0; i < nUnits; ++i) { ComplianceInstance memory instance = ComplianceInstance({ - consumed: ConsumedRefs({nullifierRef: nullifiers[i], rootRef: root, logicRef: _ALWAYS_VALID_LOGIC_REF}), - created: CreatedRefs({commitmentRef: commitments[i], logicRef: _ALWAYS_VALID_LOGIC_REF}), + consumed: ConsumedRefs({nullifier: nullifiers[i], rootRef: root, logicRef: _ALWAYS_VALID_LOGIC_REF}), + created: CreatedRefs({commitment: commitments[i], logicRef: _ALWAYS_VALID_LOGIC_REF}), unitDelta: Delta.zero() // TODO }); @@ -242,27 +261,14 @@ library MockTypes { } } - function mockAppData(bytes32[] memory nullifiers, bytes32[] memory commitments) - internal - pure - returns (TagAppDataPair[] memory appData) - { - appData = new TagAppDataPair[](nullifiers.length + commitments.length); - { - uint256 len = nullifiers.length; - for (uint256 i = 0; i < len; ++i) { - appData[i] = TagAppDataPair({ - tag: nullifiers[i], - appData: ExpirableBlob({deletionCriterion: DeletionCriterion.Immediately, blob: _MOCK_BLOB}) - }); - } - len = commitments.length; - for (uint256 i = 0; i < len; ++i) { - appData[nullifiers.length + i] = TagAppDataPair({ - tag: commitments[i], - appData: ExpirableBlob({deletionCriterion: DeletionCriterion.Immediately, blob: _MOCK_BLOB}) - }); - } + function mockAppData(bytes32[] memory tags) internal pure returns (TagAppDataPair[] memory appData) { + appData = new TagAppDataPair[](tags.length); + + for (uint256 i = 0; i < tags.length; ++i) { + appData[i] = TagAppDataPair({ + tag: tags[i], + appData: ExpirableBlob({deletionCriterion: DeletionCriterion.Immediately, blob: _MOCK_BLOB}) + }); } } From 88e8a7f1b659930981c08afb9ebaa444783ebde9 Mon Sep 17 00:00:00 2001 From: Michael Heuer Date: Tue, 6 May 2025 17:58:26 +0200 Subject: [PATCH 3/6] feat: add events and interfaces and refactor type --- .solhint.json | 1 + .solhint.other.json | 1 + bun.lock | 6 +-- package.json | 2 +- src/ERC20Forwarder.sol | 1 - src/ProtocolAdapter.sol | 20 ++++++-- src/Types.sol | 58 +++++++++++++++++++++-- src/interfaces/ICommitmentAccumulator.sol | 6 +++ src/interfaces/INullifierSet.sol | 9 ++++ src/libs/AppData.sol | 7 +-- src/proving/Compliance.sol | 25 ---------- src/proving/Logic.sol | 20 +------- src/state/BlobStorage.sol | 19 ++++---- src/state/NullifierSet.sol | 6 +-- test/Deployment.t.sol | 2 +- test/mocks/MockTypes.sol | 17 +++++-- 16 files changed, 120 insertions(+), 80 deletions(-) create mode 100644 src/interfaces/INullifierSet.sol delete mode 100644 src/proving/Compliance.sol diff --git a/.solhint.json b/.solhint.json index e5ab429..4b00016 100644 --- a/.solhint.json +++ b/.solhint.json @@ -34,6 +34,7 @@ "imports-on-top": "warn", "imports-order": "warn", + "import-path-check": "off", "ordering": "warn", "visibility-modifier-order": "error", "constructor-syntax": "error", diff --git a/.solhint.other.json b/.solhint.other.json index a8f1eb8..5a19429 100644 --- a/.solhint.other.json +++ b/.solhint.other.json @@ -27,6 +27,7 @@ "imports-on-top": "warn", "imports-order": "warn", + "import-path-check": "off", "ordering": "warn", "visibility-modifier-order": "error", "constructor-syntax": "error", diff --git a/bun.lock b/bun.lock index 92f1eae..d557376 100644 --- a/bun.lock +++ b/bun.lock @@ -3,7 +3,7 @@ "workspaces": { "": { "dependencies": { - "solhint": "^5.0.5", + "solhint": "^5.1.0", }, }, }, @@ -20,7 +20,7 @@ "@sindresorhus/is": ["@sindresorhus/is@5.6.0", "", {}, "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g=="], - "@solidity-parser/parser": ["@solidity-parser/parser@0.19.0", "", {}, "sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA=="], + "@solidity-parser/parser": ["@solidity-parser/parser@0.20.1", "", {}, "sha512-58I2sRpzaQUN+jJmWbHfbWf9AKfzqCI8JAdFB0vbyY+u8tBRcuTt9LxzasvR0LGQpcRv97eyV7l61FQ3Ib7zVw=="], "@szmarczak/http-timer": ["@szmarczak/http-timer@5.0.1", "", { "dependencies": { "defer-to-connect": "^2.0.1" } }, "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw=="], @@ -184,7 +184,7 @@ "slice-ansi": ["slice-ansi@4.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", "is-fullwidth-code-point": "^3.0.0" } }, "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ=="], - "solhint": ["solhint@5.0.5", "", { "dependencies": { "@solidity-parser/parser": "^0.19.0", "ajv": "^6.12.6", "antlr4": "^4.13.1-patch-1", "ast-parents": "^0.0.1", "chalk": "^4.1.2", "commander": "^10.0.0", "cosmiconfig": "^8.0.0", "fast-diff": "^1.2.0", "glob": "^8.0.3", "ignore": "^5.2.4", "js-yaml": "^4.1.0", "latest-version": "^7.0.0", "lodash": "^4.17.21", "pluralize": "^8.0.0", "semver": "^7.5.2", "strip-ansi": "^6.0.1", "table": "^6.8.1", "text-table": "^0.2.0" }, "optionalDependencies": { "prettier": "^2.8.3" }, "bin": { "solhint": "solhint.js" } }, "sha512-WrnG6T+/UduuzSWsSOAbfq1ywLUDwNea3Gd5hg6PS+pLUm8lz2ECNr0beX609clBxmDeZ3676AiA9nPDljmbJQ=="], + "solhint": ["solhint@5.1.0", "", { "dependencies": { "@solidity-parser/parser": "^0.20.0", "ajv": "^6.12.6", "antlr4": "^4.13.1-patch-1", "ast-parents": "^0.0.1", "chalk": "^4.1.2", "commander": "^10.0.0", "cosmiconfig": "^8.0.0", "fast-diff": "^1.2.0", "glob": "^8.0.3", "ignore": "^5.2.4", "js-yaml": "^4.1.0", "latest-version": "^7.0.0", "lodash": "^4.17.21", "pluralize": "^8.0.0", "semver": "^7.5.2", "strip-ansi": "^6.0.1", "table": "^6.8.1", "text-table": "^0.2.0" }, "optionalDependencies": { "prettier": "^2.8.3" }, "bin": { "solhint": "solhint.js" } }, "sha512-KWg4gnOnznxHXzH0fUvnhnxnk+1R50GiPChcPeQgA7SKQTSF1LLIEh8R1qbkCEn/fFzz4CfJs+Gh7Rl9uhHy+g=="], "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], diff --git a/package.json b/package.json index 6ec1725..e7c0c1f 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { "dependencies": { - "solhint": "^5.0.5" + "solhint": "^5.1.0" } } \ No newline at end of file diff --git a/src/ERC20Forwarder.sol b/src/ERC20Forwarder.sol index 0829efa..a4eb637 100644 --- a/src/ERC20Forwarder.sol +++ b/src/ERC20Forwarder.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.27; import {Ownable} from "@openzeppelin-contracts/access/Ownable.sol"; import {Address} from "@openzeppelin-contracts/utils/Address.sol"; -//import { IERC20 } from "openzeppelin-contracts/token/ERC20/IERC20.sol"; import {ForwarderBase} from "./ForwarderBase.sol"; diff --git a/src/ProtocolAdapter.sol b/src/ProtocolAdapter.sol index 121e887..51d00fa 100644 --- a/src/ProtocolAdapter.sol +++ b/src/ProtocolAdapter.sol @@ -15,15 +15,25 @@ import {ArrayLookup} from "./libs/ArrayLookup.sol"; import {ComputableComponents} from "./libs/ComputableComponents.sol"; import {Reference} from "./libs/Reference.sol"; -import {ComplianceUnit} from "./proving/Compliance.sol"; import {Delta} from "./proving/Delta.sol"; -import {LogicInstance, LogicProofs, TagLogicProofPair, LogicRefProofPair} from "./proving/Logic.sol"; - -import {BlobStorage, DeletionCriterion, ExpirableBlob} from "./state/BlobStorage.sol"; +import {LogicProofs} from "./proving/Logic.sol"; +import {BlobStorage} from "./state/BlobStorage.sol"; import {CommitmentAccumulator} from "./state/CommitmentAccumulator.sol"; import {NullifierSet} from "./state/NullifierSet.sol"; -import {Action, ForwarderCalldata, Resource, TagAppDataPair, Transaction} from "./Types.sol"; +import { + Action, + ForwarderCalldata, + Resource, + TagAppDataPair, + Transaction, + LogicInstance, + TagLogicProofPair, + LogicRefProofPair, + ComplianceUnit, + DeletionCriterion, + ExpirableBlob +} from "./Types.sol"; contract ProtocolAdapter is IProtocolAdapter, diff --git a/src/Types.sol b/src/Types.sol index 761c844..72d2f18 100644 --- a/src/Types.sol +++ b/src/Types.sol @@ -1,9 +1,15 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; -import {TagAppDataPair} from "./libs/AppData.sol"; -import {ComplianceUnit} from "./proving/Compliance.sol"; -import {TagLogicProofPair} from "./proving/Logic.sol"; +enum DeletionCriterion { + Immediately, + Never +} + +struct ExpirableBlob { + DeletionCriterion deletionCriterion; + bytes blob; +} struct Resource { bytes32 logicRef; @@ -31,6 +37,47 @@ struct Action { ResourceForwarderCalldataPair[] resourceCalldataPairs; } +struct LogicInstance { + bytes32 tag; + bool isConsumed; + bytes32[] consumed; + bytes32[] created; + ExpirableBlob tagSpecificAppData; +} + +struct TagLogicProofPair { + bytes32 tag; + LogicRefProofPair pair; +} + +struct LogicRefProofPair { + bytes32 logicRef; + bytes proof; +} + +struct ComplianceUnit { + bytes proof; + ComplianceInstance instance; + bytes32 verifyingKey; +} + +struct ComplianceInstance { + ConsumedRefs consumed; + CreatedRefs created; + uint256[2] unitDelta; +} + +struct ConsumedRefs { + bytes32 nullifierRef; + bytes32 rootRef; + bytes32 logicRef; +} + +struct CreatedRefs { + bytes32 commitmentRef; + bytes32 logicRef; +} + struct ResourceForwarderCalldataPair { Resource carrier; ForwarderCalldata call; @@ -46,3 +93,8 @@ struct ForwarderCalldata { bytes input; bytes output; } + +struct TagAppDataPair { + bytes32 tag; + ExpirableBlob appData; +} diff --git a/src/interfaces/ICommitmentAccumulator.sol b/src/interfaces/ICommitmentAccumulator.sol index 0aa780d..194e41b 100644 --- a/src/interfaces/ICommitmentAccumulator.sol +++ b/src/interfaces/ICommitmentAccumulator.sol @@ -2,7 +2,13 @@ pragma solidity ^0.8.27; interface ICommitmentAccumulator { + /// @notice Emitted if a commitment is added to the commitment accumulator. + /// @param commitment The commitment being stored. + /// @param index The index of the commitment in the Merkle tree. event CommitmentAdded(bytes32 indexed commitment, uint256 indexed index); + + /// @notice Emitted if a root is stored in the root storage. + /// @param root The root. event RootAdded(bytes32 indexed root); /// @notice Returns the latest commitment tree state root. diff --git a/src/interfaces/INullifierSet.sol b/src/interfaces/INullifierSet.sol new file mode 100644 index 0000000..9339766 --- /dev/null +++ b/src/interfaces/INullifierSet.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +interface INullifierSet { + /// @notice Emitted if a nullifier is added to the nullifier set. + /// @param nullifier The nullifier being stored. + /// @param index The index of the nullifier in the enumerable set. + event NullifierAdded(bytes32 indexed nullifier, uint256 indexed index); +} diff --git a/src/libs/AppData.sol b/src/libs/AppData.sol index 0caafd7..f4ae50d 100644 --- a/src/libs/AppData.sol +++ b/src/libs/AppData.sol @@ -1,12 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; -import {ExpirableBlob} from "../state/BlobStorage.sol"; - -struct TagAppDataPair { - bytes32 tag; - ExpirableBlob appData; -} +import {TagAppDataPair, ExpirableBlob} from "../Types.sol"; library AppData { error AppDataTagNotFound(bytes32 tag); diff --git a/src/proving/Compliance.sol b/src/proving/Compliance.sol deleted file mode 100644 index eec7d60..0000000 --- a/src/proving/Compliance.sol +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.27; - -struct ComplianceUnit { - bytes proof; - ComplianceInstance instance; - bytes32 verifyingKey; -} - -struct ComplianceInstance { - ConsumedRefs consumed; - CreatedRefs created; - uint256[2] unitDelta; -} - -struct ConsumedRefs { - bytes32 nullifierRef; - bytes32 rootRef; - bytes32 logicRef; -} - -struct CreatedRefs { - bytes32 commitmentRef; - bytes32 logicRef; -} diff --git a/src/proving/Logic.sol b/src/proving/Logic.sol index 1147202..d72143d 100644 --- a/src/proving/Logic.sol +++ b/src/proving/Logic.sol @@ -1,25 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; -import {ExpirableBlob} from "../state/BlobStorage.sol"; - -struct LogicInstance { - bytes32 tag; - bool isConsumed; - bytes32[] consumed; - bytes32[] created; - ExpirableBlob tagSpecificAppData; -} - -struct TagLogicProofPair { - bytes32 tag; - LogicRefProofPair pair; -} - -struct LogicRefProofPair { - bytes32 logicRef; - bytes proof; -} +import {TagLogicProofPair, LogicRefProofPair} from "../Types.sol"; library LogicProofs { error LogicProofTagNotFound(bytes32 tag); diff --git a/src/state/BlobStorage.sol b/src/state/BlobStorage.sol index cc22a3b..3e93223 100644 --- a/src/state/BlobStorage.sol +++ b/src/state/BlobStorage.sol @@ -3,15 +3,7 @@ pragma solidity ^0.8.27; import {IBlobStorage} from "../interfaces/IBlobStorage.sol"; -enum DeletionCriterion { - Immediately, - Never -} - -struct ExpirableBlob { - DeletionCriterion deletionCriterion; - bytes blob; -} +import {ExpirableBlob, DeletionCriterion} from "../Types.sol"; contract BlobStorage is IBlobStorage { bytes internal constant _EMPTY_BLOB = bytes(""); @@ -19,6 +11,11 @@ contract BlobStorage is IBlobStorage { mapping(bytes32 blobHash => bytes blob) internal _blobs; + /// @notice Emitted if a blob is stored. + /// @param blobHash The hash of the blob being stored. + /// @param deletionCriterion The deletion criterion of the blob. + event BlobStored(bytes32 indexed blobHash, DeletionCriterion indexed deletionCriterion); + error BlobEmpty(); error BlobNotFound(bytes32 blobHash); error BlobHashMismatch(bytes32 expected, bytes32 actual); @@ -44,6 +41,8 @@ contract BlobStorage is IBlobStorage { // Blob doesn't need to be stored if (deletionCriterion == DeletionCriterion.Immediately) { + // TODO Should an event be emitted? + // Return zero return blobHash; } @@ -53,6 +52,8 @@ contract BlobStorage is IBlobStorage { } // Store blob forever else if (deletionCriterion == DeletionCriterion.Never) { + emit BlobStored({blobHash: blobHash, deletionCriterion: DeletionCriterion.Never}); + _blobs[blobHash] = blob; return blobHash; } diff --git a/src/state/NullifierSet.sol b/src/state/NullifierSet.sol index b7e26de..fbe19e1 100644 --- a/src/state/NullifierSet.sol +++ b/src/state/NullifierSet.sol @@ -3,13 +3,13 @@ pragma solidity ^0.8.27; import {EnumerableSet} from "@openzeppelin-contracts/utils/structs/EnumerableSet.sol"; -contract NullifierSet { +import {INullifierSet} from "../interfaces/INullifierSet.sol"; + +contract NullifierSet is INullifierSet { using EnumerableSet for EnumerableSet.Bytes32Set; EnumerableSet.Bytes32Set internal _nullifierSet; - event NullifierAdded(bytes32 indexed nullifier, uint256 indexed index); - error PreExistingNullifier(bytes32 nullifier); // slither-disable-next-line dead-code diff --git a/test/Deployment.t.sol b/test/Deployment.t.sol index c91d4b5..5d255b9 100644 --- a/test/Deployment.t.sol +++ b/test/Deployment.t.sol @@ -17,6 +17,6 @@ contract ProtocolAdapterTest is Test { } function test_run_deploys_deterministically() public view { - assertEq(address(_pa), 0xB8F3A136883b06b98505d53d158f3556BF49204A); + assertEq(address(_pa), 0x83a5347727703729F6ffca6046CC44B99b56bF81); } } diff --git a/test/mocks/MockTypes.sol b/test/mocks/MockTypes.sol index b09f34d..4387f1f 100644 --- a/test/mocks/MockTypes.sol +++ b/test/mocks/MockTypes.sol @@ -7,13 +7,22 @@ import {RiscZeroMockVerifier} from "@risc0-ethereum/test/RiscZeroMockVerifier.so import {AppData, TagAppDataPair} from "../../src/libs/AppData.sol"; import {ComputableComponents} from "../../src/libs/ComputableComponents.sol"; import {Universal} from "../../src/libs/Identities.sol"; - -import {ComplianceUnit, ComplianceInstance, ConsumedRefs, CreatedRefs} from "../../src/proving/Compliance.sol"; import {Delta} from "../../src/proving/Delta.sol"; -import {LogicInstance, TagLogicProofPair, LogicRefProofPair} from "../../src/proving/Logic.sol"; import {ExpirableBlob, DeletionCriterion} from "../../src/state/BlobStorage.sol"; -import {Action, ResourceForwarderCalldataPair, Resource, Transaction} from "../../src/Types.sol"; +import { + Action, + ResourceForwarderCalldataPair, + Resource, + Transaction, + LogicInstance, + TagLogicProofPair, + LogicRefProofPair, + ComplianceUnit, + ComplianceInstance, + ConsumedRefs, + CreatedRefs +} from "../../src/Types.sol"; import {MockDelta} from "../mocks/MockDelta.sol"; import {MockRiscZeroProof} from "../mocks/MockRiscZeroProof.sol"; From 4aef040f9774ab20d2f97f67297a138d80b30ae0 Mon Sep 17 00:00:00 2001 From: Michael Heuer Date: Wed, 7 May 2025 19:20:47 +0200 Subject: [PATCH 4/6] feat: updated PA to match SRM --- script/Deploy.s.sol | 10 +- script/constructor-args.txt | 4 +- src/ERC20Forwarder.sol | 7 - src/ProtocolAdapter.sol | 209 ++++++++++++----------- src/Types.sol | 38 ++--- src/interfaces/IProtocolAdapter.sol | 2 + src/libs/AppData.sol | 41 ----- src/libs/ArrayLookup.sol | 52 +----- src/libs/ComputableComponents.sol | 52 +----- src/{state => libs}/MerkleTree.sol | 31 +++- src/libs/Reference.sol | 16 -- src/libs/SHA256.sol | 4 + src/proving/Logic.sol | 4 +- src/state/CommitmentAccumulator.sol | 2 +- test/Deployment.t.sol | 2 +- test/ProtocolAdapter.t.sol | 19 ++- test/mocks/CommitmentAccumulatorMock.sol | 2 +- test/mocks/ExampleLogicProof.sol | 10 ++ test/mocks/MockDelta.sol | 2 +- test/mocks/MockRiscZeroProof.sol | 3 +- test/mocks/MockRiscZeroProof.t.sol | 12 +- test/mocks/MockTree.sol | 4 +- test/mocks/MockTypes.sol | 27 ++- test/state/CommitmentAccumulator.t.sol | 2 +- test/state/MerkleTree.t.sol | 2 +- 25 files changed, 225 insertions(+), 332 deletions(-) delete mode 100644 src/libs/AppData.sol rename src/{state => libs}/MerkleTree.sol (89%) delete mode 100644 src/libs/Reference.sol create mode 100644 test/mocks/ExampleLogicProof.sol diff --git a/script/Deploy.s.sol b/script/Deploy.s.sol index 81b60a7..75f19ef 100644 --- a/script/Deploy.s.sol +++ b/script/Deploy.s.sol @@ -12,18 +12,18 @@ contract Deploy is BaseScript { IRiscZeroVerifier trustedSepoliaVerifier = IRiscZeroVerifier(vm.parseAddress(vm.readLine(path))); - bytes32 logicCircuitID = vm.parseBytes32(vm.readLine(path)); - bytes32 complianceCircuitID = vm.parseBytes32(vm.readLine(path)); - uint8 treeDepth = uint8(vm.parseUint(vm.readLine(path))); + uint8 commitmentTreeDepth = uint8(vm.parseUint(vm.readLine(path))); + + uint8 actionTreeDepth = uint8(vm.parseUint(vm.readLine(path))); protocolAdapter = address( new ProtocolAdapter{salt: sha256("ProtocolAdapter")}({ riscZeroVerifier: trustedSepoliaVerifier, - logicCircuitID: logicCircuitID, complianceCircuitID: complianceCircuitID, - treeDepth: treeDepth + commitmentTreeDepth: commitmentTreeDepth, + actionTreeDepth: actionTreeDepth }) ); } diff --git a/script/constructor-args.txt b/script/constructor-args.txt index 2c8ca23..3eb4281 100644 --- a/script/constructor-args.txt +++ b/script/constructor-args.txt @@ -1,4 +1,4 @@ 0x925d8331ddc0a1F0d96E68CF073DFE1d92b69187 0x0000000000000000000000000000000000000000000000000000000000000000 -0x0000000000000000000000000000000000000000000000000000000000000000 -32 \ No newline at end of file +32 +4 \ No newline at end of file diff --git a/src/ERC20Forwarder.sol b/src/ERC20Forwarder.sol index f1fd934..342e2bf 100644 --- a/src/ERC20Forwarder.sol +++ b/src/ERC20Forwarder.sol @@ -19,14 +19,7 @@ contract ERC20Forwarder is ForwarderBase { _ERC20_CONTRACT = erc20; } - // TODO make generic proxy, allow native ETH transfers function _forwardCall(bytes calldata input) internal override returns (bytes memory output) { output = _ERC20_CONTRACT.functionCall(input); } - - // Native ETH transfer - // TODO! The msg.sender must call directly, but the protocol adapter is the caller. This won't work. - //receive() external payable { - // emit NativeTokenDeposited(msg.sender, msg.value); - //} } diff --git a/src/ProtocolAdapter.sol b/src/ProtocolAdapter.sol index 27528f0..1fd2eba 100644 --- a/src/ProtocolAdapter.sol +++ b/src/ProtocolAdapter.sol @@ -2,36 +2,29 @@ pragma solidity ^0.8.27; import {ReentrancyGuardTransient} from "@openzeppelin-contracts/utils/ReentrancyGuardTransient.sol"; -import {EnumerableSet} from "@openzeppelin-contracts/utils/structs/EnumerableSet.sol"; import {IRiscZeroVerifier as TrustedRiscZeroVerifier} from "@risc0-ethereum/IRiscZeroVerifier.sol"; -import {MockDelta} from "../test/mocks/MockDelta.sol"; // TODO remove - import {IForwarder} from "./interfaces/IForwarder.sol"; import {IProtocolAdapter} from "./interfaces/IProtocolAdapter.sol"; -import {ArrayLookup} from "./libs/ArrayLookup.sol"; import {ComputableComponents} from "./libs/ComputableComponents.sol"; -import {Reference} from "./libs/Reference.sol"; +import {MerkleTree} from "./libs/MerkleTree.sol"; import {Delta} from "./proving/Delta.sol"; import {LogicProofs} from "./proving/Logic.sol"; import {BlobStorage} from "./state/BlobStorage.sol"; import {CommitmentAccumulator} from "./state/CommitmentAccumulator.sol"; + import {NullifierSet} from "./state/NullifierSet.sol"; import { Action, ForwarderCalldata, Resource, - TagAppDataPair, Transaction, - LogicInstance, TagLogicProofPair, - LogicRefProofPair, - ComplianceUnit, - DeletionCriterion, - ExpirableBlob + LogicProof, + ComplianceUnit } from "./Types.sol"; contract ProtocolAdapter is @@ -41,39 +34,36 @@ contract ProtocolAdapter is NullifierSet, BlobStorage { - using ArrayLookup for bytes32[]; using ComputableComponents for Resource; - using Reference for bytes; using LogicProofs for TagLogicProofPair[]; - using EnumerableSet for EnumerableSet.Bytes32Set; TrustedRiscZeroVerifier internal immutable _TRUSTED_RISC_ZERO_VERIFIER; bytes32 internal immutable _COMPLIANCE_CIRCUIT_ID; - bytes32 internal immutable _LOGIC_CIRCUIT_ID; + uint8 internal immutable _ACTION_TREE_DEPTH; uint256 private _txCount; - event TransactionExecuted(uint256 indexed id, Transaction transaction); - error InvalidRootRef(bytes32 root); error InvalidNullifierRef(bytes32 nullifier); error InvalidCommitmentRef(bytes32 commitment); error ForwarderCallOutputMismatch(bytes expected, bytes actual); + error RootMismatch(bytes32 expected, bytes32 actual); + error LogicRefMismatch(bytes32 expected, bytes32 actual); + error CalldataCarrierKindMismatch(bytes32 expected, bytes32 actual); error CalldataCarrierAppDataMismatch(bytes32 expected, bytes32 actual); error CalldataCarrierLabelMismatch(bytes32 expected, bytes32 actual); error CalldataCarrierCommitmentNotFound(bytes32 commitment); - error TransactionUnbalanced(uint256 expected, uint256 actual); constructor( TrustedRiscZeroVerifier riscZeroVerifier, - bytes32 logicCircuitID, bytes32 complianceCircuitID, - uint8 treeDepth - ) CommitmentAccumulator(treeDepth) { + uint8 commitmentTreeDepth, + uint8 actionTreeDepth + ) CommitmentAccumulator(commitmentTreeDepth) { _TRUSTED_RISC_ZERO_VERIFIER = riscZeroVerifier; - _LOGIC_CIRCUIT_ID = logicCircuitID; + _ACTION_TREE_DEPTH = actionTreeDepth; _COMPLIANCE_CIRCUIT_ID = complianceCircuitID; } @@ -85,14 +75,16 @@ contract ProtocolAdapter is emit TransactionExecuted({id: ++_txCount, transaction: transaction}); bytes32 newRoot = 0; - for (uint256 i = 0; i < transaction.actions.length; ++i) { + + uint256 nActions = transaction.actions.length; + for (uint256 i = 0; i < nActions; ++i) { Action calldata action = transaction.actions[i]; uint256 nResources = action.tagLogicProofPairs.length; for (uint256 j = 0; j < nResources; ++j) { TagLogicProofPair calldata pair = action.tagLogicProofPairs[j]; - if (pair.logicProof.isConsumed) { + if (pair.logicProof.instance.isConsumed) { // Nullifier non-existence was already checked in `_verify(transaction);` at the top. _addNullifierUnchecked(pair.tag); } else { @@ -100,9 +92,9 @@ contract ProtocolAdapter is newRoot = _addCommitmentUnchecked(pair.tag); } - uint256 nBlobs = pair.logicProof.appData.length; + uint256 nBlobs = pair.logicProof.instance.appData.length; for (uint256 k = 0; k < nBlobs; ++j) { - _storeBlob(pair.logicProof.appData[k]); + _storeBlob(pair.logicProof.instance.appData[k]); } } @@ -120,7 +112,6 @@ contract ProtocolAdapter is _verify(transaction); } - // TODO Consider DoS attacks https://detectors.auditbase.com/avoid-external-calls-in-unbounded-loops-solidity // slither-disable-next-line calls-loop function _executeForwarderCall(ForwarderCalldata calldata call) internal { bytes memory output = IForwarder(call.untrustedForwarder).forwardCall(call.input); @@ -133,85 +124,113 @@ contract ProtocolAdapter is // solhint-disable-next-line function-max-lines // slither-disable-next-line calls-loop function _verify(Transaction calldata transaction) internal view { - uint256[2] memory transactionDelta = Delta.zero(); // TODO: Renamed to DeltaHash? + uint256[2] memory transactionDelta = Delta.zero(); + + uint256 nActions = transaction.actions.length; - uint256 resCount = counts(transaction); + uint256 resCounter = 0; + for (uint256 i = 0; i < nActions; ++i) { + resCounter += transaction.actions[i].tagLogicProofPairs.length; + } - bytes32[] memory tags = new bytes32[](resCount); - uint256 resCounter; + // Allocate the array. + bytes32[] memory tags = new bytes32[](resCounter); + + // Reset the resource counter. + resCounter = 0; - uint256 nActions = transaction.actions.length; for (uint256 i; i < nActions; ++i) { Action calldata action = transaction.actions[i]; _verifyForwarderCalls(action); // Compliance Proofs - uint256 nCUs = action.complianceUnits.length; - for (uint256 j = 0; j < nCUs; ++j) { - ComplianceUnit calldata unit = action.complianceUnits[j]; - - // Check consumed resources - _checkRootPreExistence(unit.instance.consumed.rootRef); - _checkNullifierNonExistence(unit.instance.consumed.nullifier); - - // Check created resources - _checkCommitmentNonExistence(unit.instance.created.commitment); - - _TRUSTED_RISC_ZERO_VERIFIER.verify({ - seal: unit.proof, - imageId: _COMPLIANCE_CIRCUIT_ID, - journalDigest: sha256(abi.encode(unit.verifyingKey, unit.instance)) - }); - - // Prepare delta proof - transactionDelta = Delta.add({p1: transactionDelta, p2: unit.instance.unitDelta}); + { + uint256 nCUs = action.complianceUnits.length; + for (uint256 j = 0; j < nCUs; ++j) { + ComplianceUnit calldata unit = action.complianceUnits[j]; + + // Check consumed resources + _checkRootPreExistence(unit.instance.consumed.root); + _checkNullifierNonExistence(unit.instance.consumed.nullifier); + + // Check created resources + _checkCommitmentNonExistence(unit.instance.created.commitment); + + _TRUSTED_RISC_ZERO_VERIFIER.verify({ + seal: unit.proof, + imageId: _COMPLIANCE_CIRCUIT_ID, + journalDigest: sha256(abi.encode(unit.verifyingKey, unit.instance)) + }); + + // Check the logic ref consistency + { + bytes32 nf = unit.instance.consumed.nullifier; + LogicProof calldata logicProof = action.tagLogicProofPairs.lookup(nf); + + if (unit.instance.consumed.logicRef != logicProof.logicRef) { + revert LogicRefMismatch({ + expected: logicProof.logicRef, + actual: unit.instance.consumed.logicRef + }); + } + // solhint-disable-next-line gas-increment-by-one + tags[resCounter++] = nf; + } + { + bytes32 cm = unit.instance.created.commitment; + LogicProof calldata logicProof = action.tagLogicProofPairs.lookup(cm); + + if (unit.instance.created.logicRef != logicProof.logicRef) { + revert LogicRefMismatch({ + expected: logicProof.logicRef, + actual: unit.instance.created.logicRef + }); + } + // solhint-disable-next-line gas-increment-by-one + tags[resCounter++] = cm; + } + + // Prepare delta proof + transactionDelta = Delta.add({p1: transactionDelta, p2: unit.instance.unitDelta}); + } } - // Resource Logic Proofs + // Logic Proofs + { + uint256 nResources = action.tagLogicProofPairs.length; - uint256 nResources = action.tagLogicProofPairs.length; + bytes32[] memory actionTags = new bytes32[](nResources); + for (uint256 j = 0; j < nResources; ++j) { + actionTags[j] = action.tagLogicProofPairs[j].tag; + } + bytes32 computedActionTreeRoot = MerkleTree.computeRoot(actionTags, _ACTION_TREE_DEPTH); - (bytes32[][] memory consumed, bytes32[][] memory created) = - ComputableComponents.prepareLists(action.tagLogicProofPairs); + for (uint256 j = 0; j < nResources; ++j) { + LogicProof calldata proof = action.tagLogicProofPairs[j].logicProof; - for (uint256 j = 0; j < nResources; ++j) { - bytes32 tag = action.tagLogicProofPairs[j].tag; - tags[resCounter++] = tag; - - LogicProof calldata proof = action.tagLogicProofPairs[j].logicProof; - - LogicInstance memory instance = LogicInstance({ - tag: tag, - isConsumed: proof.isConsumed, - consumed: consumed[j], - created: created[j], - appData: proof.appData - }); - - _TRUSTED_RISC_ZERO_VERIFIER.verify({ - seal: proof.proof, - imageId: _LOGIC_CIRCUIT_ID, - journalDigest: sha256(abi.encode(proof.logicVerifyingKeyOuter, instance)) - }); + // Check root consistency + if (proof.instance.root != computedActionTreeRoot) { + revert RootMismatch({expected: computedActionTreeRoot, actual: proof.instance.root}); + } + + _TRUSTED_RISC_ZERO_VERIFIER.verify({ + seal: proof.proof, + imageId: proof.logicRef, + journalDigest: sha256(abi.encode(proof.instance)) + }); + } } } // Delta Proof - // TODO: THIS IS A TEMPORARY MOCK PROOF AND MUST BE REMOVED. - // NOTE: The `transactionHash(tags)` and `transactionDelta` are not used here. - ComputableComponents.transactionHash(tags); - // TODO do we even needs this? - // bytes32 deltaVerifyingKey; // TransactionHash is part of the transaction - MockDelta.verify({deltaProof: transaction.deltaProof}); - - /* - Delta.verify({ - transactionHash: transaction.deltaVerifyingKey, - transactionDelta: transactionDelta, - deltaProof: transaction.deltaProof - }); - */ + { + Delta.verify({ + transactionHash: sha256(abi.encode(tags)), + transactionDelta: transactionDelta, + deltaProof: transaction.deltaProof.delta + }); + } } // slither-disable-next-line calls-loop @@ -238,7 +257,7 @@ contract ProtocolAdapter is // Lookup the first appData entry. bytes32 actualAppDataHash = - keccak256(abi.encode(action.tagLogicProofPairs.lookup(carrier.commitment()).appData[0])); + keccak256(abi.encode(action.tagLogicProofPairs.lookup(carrier.commitment()).instance.appData[0])); if (actualAppDataHash != expectedAppDataHash) { revert CalldataCarrierAppDataMismatch({actual: actualAppDataHash, expected: expectedAppDataHash}); @@ -246,16 +265,4 @@ contract ProtocolAdapter is } } } - - function counts(Transaction calldata transaction) internal pure returns (uint256 resCount) { - uint256 nActions = transaction.actions.length; - - for (uint256 i = 0; i < nActions; ++i) { - Action calldata action = transaction.actions[i]; - uint256 nResources = action.tagLogicProofPairs.length; - for (uint256 j = 0; j < nResources; ++j) { - ++resCount; - } - } - } } diff --git a/src/Types.sol b/src/Types.sol index fcc09e1..47dd50c 100644 --- a/src/Types.sol +++ b/src/Types.sol @@ -25,9 +25,7 @@ struct Resource { struct Transaction { // bytes32[] roots; Action[] actions; - bytes deltaProof; - bytes32 deltaVerifyingKey; // TransactionHash - uint256[2] expectedBalance; + DeltaProof deltaProof; } struct Action { @@ -36,22 +34,27 @@ struct Action { ResourceForwarderCalldataPair[] resourceCalldataPairs; } +struct DeltaProof { + bytes delta; // Type: DeltaHash + bytes32 deltaVerifyingKey; // NOTE by Xuyang: This is currently not used in SRM. +} + struct LogicInstance { bytes32 tag; bool isConsumed; - bytes32[] consumed; - bytes32[] created; - ExpirableBlob tagSpecificAppData; + bytes32 root; + ExpirableBlob[] appData; } -struct TagLogicProofPair { - bytes32 tag; - LogicRefProofPair pair; +struct LogicProof { + bytes proof; + LogicInstance instance; + bytes32 logicRef; // logicVerifyingKeyOuter; } -struct LogicRefProofPair { - bytes32 logicRef; - bytes proof; +struct TagLogicProofPair { + bytes32 tag; + LogicProof logicProof; } struct ComplianceUnit { @@ -67,13 +70,13 @@ struct ComplianceInstance { } struct ConsumedRefs { - bytes32 nullifierRef; - bytes32 rootRef; + bytes32 nullifier; + bytes32 root; bytes32 logicRef; } struct CreatedRefs { - bytes32 commitmentRef; + bytes32 commitment; bytes32 logicRef; } @@ -92,8 +95,3 @@ struct ForwarderCalldata { bytes input; bytes output; } - -struct TagAppDataPair { - bytes32 tag; - ExpirableBlob appData; -} diff --git a/src/interfaces/IProtocolAdapter.sol b/src/interfaces/IProtocolAdapter.sol index 9ac7f7e..1095308 100644 --- a/src/interfaces/IProtocolAdapter.sol +++ b/src/interfaces/IProtocolAdapter.sol @@ -4,6 +4,8 @@ pragma solidity ^0.8.27; import {Transaction} from "../Types.sol"; interface IProtocolAdapter { + event TransactionExecuted(uint256 indexed id, Transaction transaction); + /// @notice Executes a transaction by adding the commitments and nullifiers to the commitment tree and nullifier /// set, respectively. /// @param transaction The transaction to execute. diff --git a/src/libs/AppData.sol b/src/libs/AppData.sol deleted file mode 100644 index f4ae50d..0000000 --- a/src/libs/AppData.sol +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.27; - -import {TagAppDataPair, ExpirableBlob} from "../Types.sol"; - -library AppData { - error AppDataTagNotFound(bytes32 tag); - error AppDataIndexOutBounds(uint256 index, uint256 max); - - function lookupCalldata(TagAppDataPair[] calldata map, bytes32 tag) - internal - pure - returns (ExpirableBlob memory appData) - { - uint256 len = map.length; - for (uint256 i = 0; i < len; ++i) { - if (map[i].tag == tag) { - return appData = map[i].appData; - } - } - revert AppDataTagNotFound(tag); - } - - function lookup(TagAppDataPair[] memory map, bytes32 tag) internal pure returns (ExpirableBlob memory appData) { - uint256 len = map.length; - for (uint256 i = 0; i < len; ++i) { - if (map[i].tag == tag) { - return appData = map[i].appData; - } - } - revert AppDataTagNotFound(tag); - } - - function at(TagAppDataPair[] calldata map, uint256 index) internal pure returns (ExpirableBlob memory appData) { - uint256 lastIndex = map.length - 1; - if (index > lastIndex) { - revert AppDataIndexOutBounds({index: index, max: lastIndex}); - } - appData = map[index].appData; - } -} diff --git a/src/libs/ArrayLookup.sol b/src/libs/ArrayLookup.sol index 20c7610..0e61b27 100644 --- a/src/libs/ArrayLookup.sol +++ b/src/libs/ArrayLookup.sol @@ -1,64 +1,16 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; -// TODO! Rename library ArrayLookup { error ElementNotFound(bytes32 tag); - function contains(bytes32[] memory set, bytes32 tag) internal pure returns (bool success) { + function contains(bytes32[] memory set, bytes32 elem) internal pure returns (bool success) { uint256 len = set.length; for (uint256 i = 0; i < len; ++i) { - if (set[i] == tag) { + if (set[i] == elem) { return success = true; } } return success = false; } - - // TODO! write test to make sure that this works - function removeElementStorage(bytes32[] storage array, bytes32 elem) - internal - returns (bytes32[] storage modified) - { - modified = array; - for (uint256 i = 0; i < array.length; i++) { - if (modified[i] == elem) { - // Swap with last and pop for gas-efficient removal - modified[i] = array[array.length - 1]; - modified.pop(); - break; - } - } - revert ElementNotFound(elem); - } - - function removeElement(bytes32[] memory arr, bytes32 elem) internal pure returns (bytes32[] memory) { - uint256 indexToRemove = 0; - bool found = false; - - // Find index of the elem - for (uint256 i = 0; i < arr.length; i++) { - if (arr[i] == elem) { - indexToRemove = i; - found = true; - break; - } - } - - if (!found) revert ElementNotFound(elem); - - // Create new array with one less element - bytes32[] memory result = new bytes32[](arr.length - 1); - uint256 j = 0; - - // Copy all elements except the one to remove - for (uint256 i = 0; i < arr.length; i++) { - if (i != indexToRemove) { - result[j] = arr[i]; - j++; - } - } - - return result; - } } diff --git a/src/libs/ComputableComponents.sol b/src/libs/ComputableComponents.sol index d40b61c..02be158 100644 --- a/src/libs/ComputableComponents.sol +++ b/src/libs/ComputableComponents.sol @@ -1,8 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; -import {Resource, Action, Transaction} from "../Types.sol"; -import {TagLogicProofPair} from "../proving/Logic.sol"; +import {Resource} from "../Types.sol"; library ComputableComponents { function commitment(Resource memory resource) internal pure returns (bytes32 cm) { @@ -32,53 +31,4 @@ library ComputableComponents { function kindCalldata(Resource calldata resource) internal pure returns (bytes32 k) { k = sha256(abi.encode(resource.logicRef, resource.labelRef)); } - - function transactionHash(bytes32[] memory tags) internal pure returns (bytes32 txHash) { - txHash = sha256(abi.encode(tags)); - } - - // TODO! MOVE ELSEWHERE - function prepareLists(TagLogicProofPair[] calldata pairs) - internal - pure - returns (bytes32[][] memory consumed, bytes32[][] memory created) - { - uint256 nResources = pairs.length; - - consumed = new bytes32[][](nResources); - created = new bytes32[][](nResources); - - // Count nullifiers and commitments - uint256 nfsCount = 0; - uint256 cmsCount = 0; - for (uint256 i = 0; i < nResources; ++i) { - pairs[i].logicProof.isConsumed ? ++nfsCount : ++cmsCount; - } - - // Populate lists - for (uint256 i = 0; i < nResources; ++i) { - // Initialize list lengths. - if (pairs[i].logicProof.isConsumed) { - consumed[i] = new bytes32[](nfsCount - 1); - created[i] = new bytes32[](cmsCount); - } else { - consumed[i] = new bytes32[](nfsCount); - created[i] = new bytes32[](cmsCount - 1); - } - - uint256 nfsCounter = 0; - uint256 cmsCounter = 0; - - // Store tags - for (uint256 j = 0; j < nResources; ++j) { - if (i != j) { - if (pairs[j].logicProof.isConsumed) { - consumed[i][++nfsCounter] = pairs[j].tag; - } else { - created[i][++cmsCounter] = pairs[j].tag; - } - } - } - } - } } diff --git a/src/state/MerkleTree.sol b/src/libs/MerkleTree.sol similarity index 89% rename from src/state/MerkleTree.sol rename to src/libs/MerkleTree.sol index ecdfb39..5fb254d 100644 --- a/src/state/MerkleTree.sol +++ b/src/libs/MerkleTree.sol @@ -17,10 +17,6 @@ library MerkleTree { bytes32[] _zeros; } - /// @notice The hash representing the empty leaf that is not expected to be part of the tree. - /// @dev Obtained from `sha256("EMPTY_LEAF")`. - bytes32 internal constant _EMPTY_LEAF_HASH = 0x283d1bb3a401a7e0302d0ffb9102c8fc1f4730c2715a2bfd46a9d9209d5965e0; - error TreeCapacityExceeded(); error NonExistentLeafIndex(uint256 index); @@ -32,7 +28,7 @@ library MerkleTree { function setup(Tree storage self, uint8 treeDepth) internal returns (bytes32 initialRoot) { Arrays.unsafeSetLength(self._zeros, treeDepth); - bytes32 currentZero = _EMPTY_LEAF_HASH; + bytes32 currentZero = SHA256.EMPTY_HASH; for (uint256 i = 0; i < treeDepth; ++i) { Arrays.unsafeAccess(self._zeros, i).value = currentZero; @@ -189,4 +185,29 @@ library MerkleTree { function isLeftSibling(uint256 directionBits, uint256 d) internal pure returns (bool isLeft) { isLeft = (directionBits >> d) & 1 == 0; } + + function computeRoot(bytes32[] memory leafs, uint256 treeDepth) internal pure returns (bytes32 root) { + uint256 totalLeafs = 1 << treeDepth; // 2^treeDepth + + // Create array of full leaf set with padding if necessary + bytes32[] memory nodes = new bytes32[](totalLeafs); + for (uint256 i = 0; i < totalLeafs; ++i) { + if (i < leafs.length) { + nodes[i] = leafs[i]; + } else { + nodes[i] = SHA256.EMPTY_HASH; + } + } + + // Build the tree upward + uint256 currentSize = totalLeafs; + while (currentSize > 1) { + for (uint256 i = 0; i < currentSize / 2; ++i) { + nodes[i] = sha256(abi.encodePacked(nodes[2 * i], nodes[2 * i + 1])); + } + currentSize /= 2; + } + + root = nodes[0]; // root + } } diff --git a/src/libs/Reference.sol b/src/libs/Reference.sol deleted file mode 100644 index 52d4689..0000000 --- a/src/libs/Reference.sol +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.27; - -library Reference { - function toRef(address addr) internal pure returns (bytes32 ref) { - ref = sha256(abi.encode(addr)); - } - - function toRef(bytes calldata data) internal pure returns (bytes32 ref) { - ref = sha256(data); - } - - function toRefCalldata(bytes memory data) internal pure returns (bytes32 ref) { - ref = sha256(data); - } -} diff --git a/src/libs/SHA256.sol b/src/libs/SHA256.sol index 88ab818..5ee1a58 100644 --- a/src/libs/SHA256.sol +++ b/src/libs/SHA256.sol @@ -2,6 +2,10 @@ pragma solidity ^0.8.27; library SHA256 { + /// @notice The hash representing the empty leaf that is not expected to be part of the tree. + /// @dev Obtained from `sha256("EMPTY")`. + bytes32 public constant EMPTY_HASH = 0xcc1d2f838445db7aec431df9ee8a871f40e7aa5e064fc056633ef8c60fab7b06; + function hash(bytes32 a) internal pure returns (bytes32 ha) { ha = sha256(abi.encode(a)); } diff --git a/src/proving/Logic.sol b/src/proving/Logic.sol index 28cc89d..e98ff41 100644 --- a/src/proving/Logic.sol +++ b/src/proving/Logic.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; -import {TagLogicProofPair, LogicRefProofPair} from "../Types.sol"; +import {TagLogicProofPair, LogicProof} from "../Types.sol"; library LogicProofs { error LogicProofTagNotFound(bytes32 tag); error LogicProofIndexOutBounds(uint256 index, uint256 max); - function lookup(TagLogicProofPair[] calldata map, bytes32 tag) internal pure returns (LogicProof memory elem) { + function lookup(TagLogicProofPair[] calldata map, bytes32 tag) internal pure returns (LogicProof calldata elem) { uint256 len = map.length; for (uint256 i = 0; i < len; ++i) { if (map[i].tag == tag) { diff --git a/src/state/CommitmentAccumulator.sol b/src/state/CommitmentAccumulator.sol index 34f2e19..509ea6c 100644 --- a/src/state/CommitmentAccumulator.sol +++ b/src/state/CommitmentAccumulator.sol @@ -5,7 +5,7 @@ import {Arrays} from "@openzeppelin-contracts/utils/Arrays.sol"; import {EnumerableSet} from "@openzeppelin-contracts/utils/structs/EnumerableSet.sol"; import {ICommitmentAccumulator} from "../interfaces/ICommitmentAccumulator.sol"; -import {MerkleTree} from "./MerkleTree.sol"; +import {MerkleTree} from "../libs/MerkleTree.sol"; contract CommitmentAccumulator is ICommitmentAccumulator { using MerkleTree for MerkleTree.Tree; diff --git a/test/Deployment.t.sol b/test/Deployment.t.sol index 5d255b9..2ea260c 100644 --- a/test/Deployment.t.sol +++ b/test/Deployment.t.sol @@ -17,6 +17,6 @@ contract ProtocolAdapterTest is Test { } function test_run_deploys_deterministically() public view { - assertEq(address(_pa), 0x83a5347727703729F6ffca6046CC44B99b56bF81); + assertEq(address(_pa), 0x33C502854bF03C04ff8333BA07aB6830021226b3); } } diff --git a/test/ProtocolAdapter.t.sol b/test/ProtocolAdapter.t.sol index c1d308a..0c6ebad 100644 --- a/test/ProtocolAdapter.t.sol +++ b/test/ProtocolAdapter.t.sol @@ -5,13 +5,17 @@ import {RiscZeroMockVerifier} from "@risc0-ethereum/test/RiscZeroMockVerifier.so import {Test} from "forge-std/Test.sol"; import {ProtocolAdapter} from "../src/ProtocolAdapter.sol"; -import {Resource, Transaction} from "../src/Types.sol"; +// import {Resource, Transaction} from "../src/Types.sol"; import {MockRiscZeroProof} from "./mocks/MockRiscZeroProof.sol"; -import {MockTypes} from "./mocks/MockTypes.sol"; + +//import {MockTypes} from "./mocks/MockTypes.sol"; contract ProtocolAdapterTest is Test { - uint8 internal constant _TREE_DEPTH = 2 ^ 32; + uint8 internal constant _COMMITMENT_TREE_DEPTH = 32; + + uint8 internal constant _ACTION_TREE_DEPTH = 4; + // IRiscZeroVerifier internal constant _SEPOLIA_VERIFIER = // IRiscZeroVerifier(address(0x925d8331ddc0a1F0d96E68CF073DFE1d92b69187)); @@ -23,12 +27,13 @@ contract ProtocolAdapterTest is Test { _pa = new ProtocolAdapter({ riscZeroVerifier: _mockVerifier, - logicCircuitID: MockRiscZeroProof.IMAGE_ID_1, - complianceCircuitID: MockRiscZeroProof.IMAGE_ID_2, - treeDepth: _TREE_DEPTH + complianceCircuitID: MockRiscZeroProof.IMAGE_ID, + commitmentTreeDepth: _COMMITMENT_TREE_DEPTH, + actionTreeDepth: _ACTION_TREE_DEPTH }); } + /* function test_benchmark() public { uint16[3] memory n = [uint16(5), uint16(50), uint16(500)]; @@ -90,5 +95,5 @@ contract ProtocolAdapterTest is Test { }); _pa.verify(txn); - } + }*/ } diff --git a/test/mocks/CommitmentAccumulatorMock.sol b/test/mocks/CommitmentAccumulatorMock.sol index ef0a8d2..33d0e31 100644 --- a/test/mocks/CommitmentAccumulatorMock.sol +++ b/test/mocks/CommitmentAccumulatorMock.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.27; import {EnumerableSet} from "@openzeppelin-contracts/utils/structs/EnumerableSet.sol"; +import {MerkleTree} from "../../src/libs/MerkleTree.sol"; import {CommitmentAccumulator} from "../../src/state/CommitmentAccumulator.sol"; -import {MerkleTree} from "../../src/state/MerkleTree.sol"; contract CommitmentAccumulatorMock is CommitmentAccumulator { using EnumerableSet for EnumerableSet.Bytes32Set; diff --git a/test/mocks/ExampleLogicProof.sol b/test/mocks/ExampleLogicProof.sol new file mode 100644 index 0000000..cbcc9ef --- /dev/null +++ b/test/mocks/ExampleLogicProof.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +library ExampleLogicProof { + bytes internal constant SEAL = hex"70D0"; + + bytes32 internal constant LOGIC_CIRCUIT_ID = hex"70D0"; + + bytes32 internal constant JOURNAL_DIGEST = sha256(hex"70D0"); +} diff --git a/test/mocks/MockDelta.sol b/test/mocks/MockDelta.sol index 738804f..a2f66d7 100644 --- a/test/mocks/MockDelta.sol +++ b/test/mocks/MockDelta.sol @@ -6,9 +6,9 @@ import {Delta} from "../../src/proving/Delta.sol"; library MockDelta { using Delta for uint256[2]; + /// @notice A message containing the empty `bytes32` array. /// @dev Obtained from `abi.encode(new bytes32[](0))`. - bytes internal constant MESSAGE = hex"0000000000000000000000000000000000000000000000000000000000000020" hex"0000000000000000000000000000000000000000000000000000000000000000"; diff --git a/test/mocks/MockRiscZeroProof.sol b/test/mocks/MockRiscZeroProof.sol index 46f76ba..bff8eae 100644 --- a/test/mocks/MockRiscZeroProof.sol +++ b/test/mocks/MockRiscZeroProof.sol @@ -4,8 +4,7 @@ pragma solidity ^0.8.27; library MockRiscZeroProof { bytes4 internal constant VERIFIER_SELECTOR = 0x12345678; - bytes32 internal constant IMAGE_ID_1 = bytes32(uint256(1)); - bytes32 internal constant IMAGE_ID_2 = bytes32(uint256(2)); + bytes32 internal constant IMAGE_ID = bytes32(uint256(1)); /// @notice Generated from `sha256("MOCK_JOURNAL_DIGEST");`. bytes32 internal constant JOURNAL_DIGEST = 0x26968006c64cf2912711161619df51842dc3d1b2dd9e58765cf6385c16beee1f; diff --git a/test/mocks/MockRiscZeroProof.t.sol b/test/mocks/MockRiscZeroProof.t.sol index 55a05fa..98ae687 100644 --- a/test/mocks/MockRiscZeroProof.t.sol +++ b/test/mocks/MockRiscZeroProof.t.sol @@ -19,7 +19,7 @@ contract MockRiscZeroProofTest is Test { _MOCK_VERIFIER = new RiscZeroMockVerifier(MockRiscZeroProof.VERIFIER_SELECTOR); _proof = _MOCK_VERIFIER.mockProve({ - imageId: MockRiscZeroProof.IMAGE_ID_1, + imageId: MockRiscZeroProof.IMAGE_ID, journalDigest: MockRiscZeroProof.JOURNAL_DIGEST }); } @@ -29,7 +29,7 @@ contract MockRiscZeroProofTest is Test { vm.expectRevert(VerificationFailed.selector); _MOCK_VERIFIER.verify({ seal: _proof.seal, - imageId: MockRiscZeroProof.IMAGE_ID_2, + imageId: bytes32(uint256(123)), journalDigest: MockRiscZeroProof.JOURNAL_DIGEST }); } @@ -40,7 +40,7 @@ contract MockRiscZeroProofTest is Test { vm.expectRevert(VerificationFailed.selector, address(_MOCK_VERIFIER)); _MOCK_VERIFIER.verify({ seal: wrongSeal, - imageId: MockRiscZeroProof.IMAGE_ID_1, + imageId: MockRiscZeroProof.IMAGE_ID, journalDigest: MockRiscZeroProof.JOURNAL_DIGEST }); } @@ -54,7 +54,7 @@ contract MockRiscZeroProofTest is Test { ); _MOCK_VERIFIER.verify({ seal: abi.encode(wrongSelector), - imageId: MockRiscZeroProof.IMAGE_ID_1, + imageId: MockRiscZeroProof.IMAGE_ID, journalDigest: MockRiscZeroProof.JOURNAL_DIGEST }); } @@ -63,14 +63,14 @@ contract MockRiscZeroProofTest is Test { bytes32 wrongDigest = bytes32(0); vm.expectRevert(VerificationFailed.selector, address(_MOCK_VERIFIER)); - _MOCK_VERIFIER.verify({seal: _proof.seal, imageId: MockRiscZeroProof.IMAGE_ID_1, journalDigest: wrongDigest}); + _MOCK_VERIFIER.verify({seal: _proof.seal, imageId: MockRiscZeroProof.IMAGE_ID, journalDigest: wrongDigest}); } /// @notice It should verify correct _proofs. function test_correctProof() public view { _MOCK_VERIFIER.verify({ seal: _proof.seal, - imageId: MockRiscZeroProof.IMAGE_ID_1, + imageId: MockRiscZeroProof.IMAGE_ID, journalDigest: MockRiscZeroProof.JOURNAL_DIGEST }); } diff --git a/test/mocks/MockTree.sol b/test/mocks/MockTree.sol index ede2ad7..60d175f 100644 --- a/test/mocks/MockTree.sol +++ b/test/mocks/MockTree.sol @@ -3,8 +3,6 @@ pragma solidity ^0.8.27; import {SHA256} from "../../src/libs/SHA256.sol"; -import {MerkleTree} from "../../src/state/MerkleTree.sol"; - contract MockTree { uint8 internal constant _TREE_DEPTH = 2; uint256 internal constant _N_LEAFS = 2 ** _TREE_DEPTH; @@ -33,7 +31,7 @@ contract MockTree { } for (uint256 j = i; j < _N_ROOTS - 1; ++j) { - _leaves[i][j] = MerkleTree._EMPTY_LEAF_HASH; + _leaves[i][j] = SHA256.EMPTY_HASH; } _nodes[i][0] = SHA256.hash(_leaves[i][0], _leaves[i][1]); diff --git a/test/mocks/MockTypes.sol b/test/mocks/MockTypes.sol index 7881f71..b308504 100644 --- a/test/mocks/MockTypes.sol +++ b/test/mocks/MockTypes.sol @@ -1,10 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; +/* import {Receipt as RiscZeroReceipt} from "@risc0-ethereum/IRiscZeroVerifier.sol"; import {RiscZeroMockVerifier} from "@risc0-ethereum/test/RiscZeroMockVerifier.sol"; -import {AppData, TagAppDataPair} from "../../src/libs/AppData.sol"; +//import {AppData, TagAppDataPair} from "../../src/libs/AppData.sol"; import {ArrayLookup} from "../../src/libs/ArrayLookup.sol"; import {ComputableComponents} from "../../src/libs/ComputableComponents.sol"; import {Universal} from "../../src/libs/Identities.sol"; @@ -18,7 +19,7 @@ import { Transaction, LogicInstance, TagLogicProofPair, - LogicRefProofPair, + LogicProof, ComplianceUnit, ComplianceInstance, ConsumedRefs, @@ -31,7 +32,7 @@ import {MockRiscZeroProof} from "../mocks/MockRiscZeroProof.sol"; library MockTypes { using ArrayLookup for bytes32[]; using ComputableComponents for Resource; - using AppData for TagAppDataPair[]; + // using AppData for TagAppDataPair[]; using Delta for uint256[2]; bytes32 internal constant _ALWAYS_VALID_LOGIC_REF = bytes32(0); @@ -88,9 +89,10 @@ library MockTypes { } } - TagAppDataPair[] memory appData = mockAppData({nullifiers: nfs, commitments: cms}); + //TagAppDataPair[] memory appData = mockAppData({nullifiers: nfs, commitments: cms}); + TagLogicProofPair[] memory rlProofs = - _mockLogicProofs({mockVerifier: mockVerifier, nullifiers: nfs, commitments: cms, appData: appData}); + _mockLogicProofs({mockVerifier: mockVerifier, nullifiers: nfs, commitments: cms}); ComplianceUnit[] memory complianceUnits = mockComplianceUnits({mockVerifier: mockVerifier, root: roots[0], commitments: cms, nullifiers: nfs}); @@ -122,7 +124,12 @@ library MockTypes { } // solhint-disable-next-line function-max-lines - function _mockLogicProofs(RiscZeroMockVerifier mockVerifier, TagAppDataPair[] memory tagAppDataPairs) + function _mockLogicProofs( + RiscZeroMockVerifier mockVerifier, + bytes32[] memory nullifiers, + bytes32[] memory commitments + ) + //, TagAppDataPair[] memory tagAppDataPairs internal view returns (TagLogicProofPair[] memory logicProofs) @@ -131,11 +138,14 @@ library MockTypes { uint256 nResources = tagAppDataPairs.length; + ExpirableBlob[] memory appData = new ExpirableBlob[](1); + appData[0] = ExpirableBlob({deletionCriterion: DeletionCriterion.Immediately, blob: _MOCK_BLOB}); + for (uint256 j = 0; j < nResources; ++j) { bytes32 tag = tagAppDataPairs[j].tag; - tags[resCounter++] = tag; + // tags[resCounter++] = tag; - LogicProof calldata proof = action.tagLogicProofPairs[j].logicProof; + LogicProof calldata proof = tagLogicProofPairs[j].logicProof; LogicInstance memory instance = LogicInstance({ tag: tag, @@ -340,3 +350,4 @@ library MockTypes { } } } +*/ diff --git a/test/state/CommitmentAccumulator.t.sol b/test/state/CommitmentAccumulator.t.sol index 59416c5..a5fd929 100644 --- a/test/state/CommitmentAccumulator.t.sol +++ b/test/state/CommitmentAccumulator.t.sol @@ -3,9 +3,9 @@ pragma solidity ^0.8.27; import {Test} from "forge-std/Test.sol"; +import {MerkleTree} from "../../src/libs/MerkleTree.sol"; import {SHA256} from "../../src/libs/SHA256.sol"; import {CommitmentAccumulator} from "../../src/state/CommitmentAccumulator.sol"; -import {MerkleTree} from "../../src/state/MerkleTree.sol"; import {CommitmentAccumulatorMock} from "../mocks/CommitmentAccumulatorMock.sol"; import {MockTree} from "../mocks/MockTree.sol"; diff --git a/test/state/MerkleTree.t.sol b/test/state/MerkleTree.t.sol index 6dbe0fe..6670392 100644 --- a/test/state/MerkleTree.t.sol +++ b/test/state/MerkleTree.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.27; import {Test} from "forge-std/Test.sol"; -import {MerkleTree} from "../../src/state/MerkleTree.sol"; +import {MerkleTree} from "../../src/libs/MerkleTree.sol"; import {MockTree} from "../mocks/MockTree.sol"; contract MerkleTreeTest is Test, MockTree { From 7500d764faf4a7e0dcd5352e6d691ffb204b03fd Mon Sep 17 00:00:00 2001 From: Michael Heuer Date: Wed, 7 May 2025 19:27:54 +0200 Subject: [PATCH 5/6] refactor: simplify DeltaProof --- src/ProtocolAdapter.sol | 2 +- src/Types.sol | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ProtocolAdapter.sol b/src/ProtocolAdapter.sol index 1fd2eba..7940529 100644 --- a/src/ProtocolAdapter.sol +++ b/src/ProtocolAdapter.sol @@ -228,7 +228,7 @@ contract ProtocolAdapter is Delta.verify({ transactionHash: sha256(abi.encode(tags)), transactionDelta: transactionDelta, - deltaProof: transaction.deltaProof.delta + deltaProof: transaction.deltaProof }); } } diff --git a/src/Types.sol b/src/Types.sol index 47dd50c..334f5b8 100644 --- a/src/Types.sol +++ b/src/Types.sol @@ -23,9 +23,9 @@ struct Resource { } struct Transaction { - // bytes32[] roots; Action[] actions; - DeltaProof deltaProof; + // DeltaProof deltaProof + bytes deltaProof; } struct Action { @@ -34,10 +34,10 @@ struct Action { ResourceForwarderCalldataPair[] resourceCalldataPairs; } -struct DeltaProof { - bytes delta; // Type: DeltaHash - bytes32 deltaVerifyingKey; // NOTE by Xuyang: This is currently not used in SRM. -} +//struct DeltaProof { +// bytes delta; // Type: DeltaHash +// bytes32 deltaVerifyingKey; // NOTE by Xuyang: This is currently not //used in SRM. +//} struct LogicInstance { bytes32 tag; From 0bb802d307c709317292f6f1f684418d33a50128 Mon Sep 17 00:00:00 2001 From: Michael Heuer Date: Wed, 7 May 2025 19:28:16 +0200 Subject: [PATCH 6/6] fix: deterministic deployment test --- test/Deployment.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Deployment.t.sol b/test/Deployment.t.sol index 2ea260c..3234de2 100644 --- a/test/Deployment.t.sol +++ b/test/Deployment.t.sol @@ -17,6 +17,6 @@ contract ProtocolAdapterTest is Test { } function test_run_deploys_deterministically() public view { - assertEq(address(_pa), 0x33C502854bF03C04ff8333BA07aB6830021226b3); + assertEq(address(_pa), 0xAFCbB5614652Da927D480A9e82bA832C22836D1C); } }