-
Notifications
You must be signed in to change notification settings - Fork 2
/
ConfidentialControl.sol
95 lines (75 loc) · 3.18 KB
/
ConfidentialControl.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// SPDX-License-Identifier: MIT
// Author: Miha Lotric (halo3mic)
pragma solidity ^0.8.8;
import { SuaveContract, Suave } from "./SuaveContract.sol";
abstract contract ConfidentialControl is SuaveContract {
struct UnlockArgs {
bytes32 key;
bytes32 nextHash;
}
modifier unlock(UnlockArgs calldata unlockPair) {
crequire(isValidKey(unlockPair.key), "Invalid key");
_;
presentHash = unlockPair.nextHash;
nonce++;
}
string internal constant S_NAMESPACE = "blockad:v0:secret";
Suave.BidId internal secretBidId;
bytes32 internal presentHash;
uint internal nonce;
/**********************************************************************
* ⛓️ ON-CHAIN METHODS *
***********************************************************************/
function ccCallback(bytes32 nextHash, Suave.BidId sBidId) external {
crequire(!isInitialized(), "Already initialized");
presentHash = nextHash;
secretBidId = sBidId;
}
function isInitialized() public view returns (bool) {
return presentHash != 0;
}
/**********************************************************************
* 🔒 CONFIDENTIAL METHODS *
***********************************************************************/
function confidentialConstructor() public view virtual onlyConfidential returns (bytes memory) {
crequire(!isInitialized(), "Already initialized");
bytes memory secret = Suave.confidentialInputs();
Suave.BidId sBidId = storeSecret(secret);
bytes32 nextHash = makeHash(abi.decode(secret, (bytes32)), nonce);
return abi.encodeWithSelector(this.ccCallback.selector, nextHash, sBidId);
}
/**********************************************************************
* 🛠️ INTERNAL METHODS *
***********************************************************************/
function storeSecret(bytes memory secret) internal view returns (Suave.BidId) {
address[] memory peekers = new address[](3);
peekers[0] = address(this);
peekers[1] = Suave.FETCH_BIDS;
peekers[2] = Suave.CONFIDENTIAL_RETRIEVE;
Suave.Bid memory secretBid = Suave.newBid(0, peekers, peekers, S_NAMESPACE);
Suave.confidentialStore(secretBid.id, S_NAMESPACE, secret);
return secretBid.id;
}
function isValidKey(bytes32 key) internal view returns (bool) {
return keccak256(abi.encode(key)) == presentHash;
}
function getUnlockPair() internal view returns (UnlockArgs memory) {
return UnlockArgs(getKey(nonce), getHash(nonce + 1));
}
function getHash(uint _nonce) internal view returns (bytes32) {
return keccak256(abi.encode(getKey(_nonce)));
}
function getKey(uint _nonce) internal view returns (bytes32) {
return makeKey(getSecret(), _nonce);
}
function makeHash(bytes32 secret, uint _nonce) internal pure returns (bytes32) {
return keccak256(abi.encode(makeKey(secret, _nonce)));
}
function makeKey(bytes32 secret, uint _nonce) internal pure returns (bytes32) {
return keccak256(abi.encode(secret, _nonce));
}
function getSecret() internal view returns (bytes32) {
bytes memory secretB = Suave.confidentialRetrieve(secretBidId, S_NAMESPACE);
return abi.decode(secretB, (bytes32));
}
}