-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Mock the confidential datastore for Foundry (#40)
* Scaffold the solution+ * Use mock confidential store * Remove view funcç * Clean PR * Fix example * Add signatures in a better way·
- Loading branch information
Showing
10 changed files
with
304 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.8; | ||
|
||
import "../suavelib/Suave.sol"; | ||
import "forge-std/Test.sol"; | ||
|
||
// ConfidentialStore is an implementation of the confidential store in Solidity. | ||
contract ConfidentialStore is Test { | ||
mapping(bytes32 => Suave.DataRecord[]) private dataRecordsByConditionAndNamespace; | ||
mapping(Suave.DataId => mapping(string => bytes)) private dataRecordsContent; | ||
mapping(Suave.DataId => Suave.DataRecord) private dataRecords; | ||
|
||
uint64 private numRecords; | ||
|
||
type DataId is bytes16; | ||
|
||
constructor() { | ||
vm.record(); | ||
} | ||
|
||
function newDataRecord( | ||
uint64 decryptionCondition, | ||
address[] memory allowedPeekers, | ||
address[] memory allowedStores, | ||
string memory dataType | ||
) public returns (Suave.DataRecord memory) { | ||
numRecords++; | ||
|
||
// Use a counter of the records to create a unique key | ||
Suave.DataId id = Suave.DataId.wrap(bytes16(keccak256(abi.encodePacked(numRecords)))); | ||
numRecords++; | ||
|
||
Suave.DataRecord memory newRecord; | ||
newRecord.id = id; | ||
newRecord.decryptionCondition = decryptionCondition; | ||
newRecord.allowedPeekers = allowedPeekers; | ||
newRecord.allowedStores = allowedStores; | ||
newRecord.version = dataType; | ||
|
||
// Store the data record metadata | ||
dataRecords[id] = newRecord; | ||
|
||
// Use a composite index to store the records for the 'fetchDataRecords' function | ||
bytes32 key = keccak256(abi.encodePacked(decryptionCondition, dataType)); | ||
dataRecordsByConditionAndNamespace[key].push(newRecord); | ||
|
||
return newRecord; | ||
} | ||
|
||
function fetchDataRecords(uint64 cond, string memory namespace) public view returns (Suave.DataRecord[] memory) { | ||
bytes32 key = keccak256(abi.encodePacked(cond, namespace)); | ||
return dataRecordsByConditionAndNamespace[key]; | ||
} | ||
|
||
function confidentialStore(Suave.DataId dataId, string memory key, bytes memory value) public { | ||
address[] memory allowedStores = dataRecords[dataId].allowedStores; | ||
for (uint256 i = 0; i < allowedStores.length; i++) { | ||
if (allowedStores[i] == msg.sender || allowedStores[i] == Suave.ANYALLOWED) { | ||
dataRecordsContent[dataId][key] = value; | ||
return; | ||
} | ||
} | ||
|
||
revert("Not allowed to store"); | ||
} | ||
|
||
function confidentialRetrieve(Suave.DataId dataId, string memory key) public view returns (bytes memory) { | ||
address[] memory allowedPeekers = dataRecords[dataId].allowedPeekers; | ||
for (uint256 i = 0; i < allowedPeekers.length; i++) { | ||
if (allowedPeekers[i] == msg.sender || allowedPeekers[i] == Suave.ANYALLOWED) { | ||
return dataRecordsContent[dataId][key]; | ||
} | ||
} | ||
|
||
revert("Not allowed to retrieve"); | ||
} | ||
|
||
function reset() public { | ||
(, bytes32[] memory writes) = vm.accesses(address(this)); | ||
for (uint256 i = 0; i < writes.length; i++) { | ||
vm.store(address(this), writes[i], 0); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.8; | ||
|
||
import "./ConfidentialStore.sol"; | ||
import "../suavelib/Suave.sol"; | ||
|
||
contract ConfidentialStoreConnector { | ||
fallback() external { | ||
address confidentialStoreAddr = 0x0101010101010101010101010101010101010101; | ||
|
||
address addr = address(this); | ||
bytes4 sig; | ||
|
||
if (addr == Suave.CONFIDENTIAL_STORE) { | ||
sig = ConfidentialStore.confidentialStore.selector; | ||
} else if (addr == Suave.CONFIDENTIAL_RETRIEVE) { | ||
sig = ConfidentialStore.confidentialRetrieve.selector; | ||
} else if (addr == Suave.FETCH_DATA_RECORDS) { | ||
sig = ConfidentialStore.fetchDataRecords.selector; | ||
} else if (addr == Suave.NEW_DATA_RECORD) { | ||
sig = ConfidentialStore.newDataRecord.selector; | ||
} else { | ||
revert("function signature not found in the confidential store"); | ||
} | ||
|
||
bytes memory input = msg.data; | ||
|
||
// call 'confidentialStore' with the selector and the input data. | ||
(bool success, bytes memory output) = confidentialStoreAddr.call(abi.encodePacked(sig, input)); | ||
if (!success) { | ||
revert("Call to confidentialStore failed"); | ||
} | ||
|
||
if (addr == Suave.CONFIDENTIAL_RETRIEVE) { | ||
// special case we have to unroll the value from the abi | ||
// since it comes encoded as tuple() but we return the value normally | ||
// this was a special case that was not fixed yet in suave-geth. | ||
output = abi.decode(output, (bytes)); | ||
} | ||
|
||
assembly { | ||
let location := output | ||
let length := mload(output) | ||
return(add(location, 0x20), length) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.