-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathelasticGroup.sol
180 lines (155 loc) · 5.13 KB
/
elasticGroup.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// SPDX-License-Identifier: MIT OR Apache-2.0
pragma solidity >= 0.8.0;
import {PoseidonT3} from "@zk-kit/incremental-merkle-tree.sol/Hashes.sol";
import "@zk-kit/incremental-merkle-tree.sol/IncrementalBinaryTree.sol";
enum JOIN_STRATEGY {
SEQUENTIAL,
RANDOM
}
struct EG {
uint gurantee;
uint maxTreeNum;
mapping(uint => IncrementalTreeData) merkleTree;
JOIN_STRATEGY strategy;
uint treeNum;
uint zeroValue;
mapping(uint => uint) member2tree;
}
interface IVerifier {
function verifyProof(
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[1] memory input
) external view;
}
contract elasticGroup {
using IncrementalBinaryTree for IncrementalTreeData;
event GroupCreated(uint indexed groupId, uint gurantee, uint maxTreeNum);
mapping(uint => EG) eg;
uint public GROUP_ID;
mapping(uint => IVerifier) internal verifiers;
struct Verifier {
address contractAddress;
uint merkleTreeDepth;
}
constructor(Verifier[] memory _verifiers) {
for (uint8 i = 0; i < _verifiers.length; ) {
verifiers[_verifiers[i].merkleTreeDepth] = IVerifier(_verifiers[i].contractAddress);
unchecked {
++i;
}
}
}
function createTree(
uint groupId
) internal virtual {
require(eg[groupId].treeNum < eg[groupId].maxTreeNum, "Group Full!!");
eg[groupId].merkleTree[eg[GROUP_ID].treeNum + 1].init(
eg[groupId].gurantee,
eg[groupId].zeroValue
);
eg[groupId].treeNum++;
}
function createGroup(
uint gurantee,
uint maxTreeNum,
uint zeroValue,
JOIN_STRATEGY strategy
) public returns(uint) {
GROUP_ID ++;
eg[GROUP_ID].gurantee = gurantee;
eg[GROUP_ID].maxTreeNum = maxTreeNum;
eg[GROUP_ID].zeroValue = zeroValue;
eg[GROUP_ID].treeNum = 0;
eg[GROUP_ID].strategy = strategy;
createTree(GROUP_ID);
emit GroupCreated(GROUP_ID, gurantee, maxTreeNum);
return GROUP_ID;
}
function insert(
uint groupId,
uint identity
) public {
require(eg[groupId].strategy == JOIN_STRATEGY.SEQUENTIAL, "only support seqential join now!!!");
if (eg[groupId].merkleTree[eg[groupId].treeNum].numberOfLeaves == 2 ** eg[groupId].gurantee) {
// current tree full, create new tree
createTree(groupId);
}
uint treeId = eg[groupId].treeNum;
eg[groupId].merkleTree[treeId].insert(identity);
eg[groupId].member2tree[identity] = treeId;
}
// TODO : IBT verify is private function, so using remove for check contains
// check identity in the tree. (if last tree, gurantee double proof?)
function contains(
uint groupId,
uint identity,
uint[] calldata proofSiblings,
uint8[] calldata proofPathIndices
) public {
uint treeId = eg[groupId].member2tree[identity];
require(treeId != 0, "not in group!!");
//eg[groupId].merkleTree[treeId].verify(identity, proofSiblings, proofPathIndices);
}
// prove membership by combile merkle trees, provide elastic gurantee
function verifyProof(
uint groupId,
uint[] calldata treeIds,
uint[8] calldata proof
) external view returns (bool) {
uint merkleTreeDepth;
uint merkleTreeRoot;
if (treeIds.length == 1) {
merkleTreeDepth = eg[groupId].gurantee;
merkleTreeRoot = eg[groupId].merkleTree[treeIds[0]].root;
} else if (treeIds.length == 2) {
merkleTreeDepth = eg[groupId].gurantee + 1;
merkleTreeRoot = PoseidonT3.poseidon([
eg[groupId].merkleTree[treeIds[0]].root,
eg[groupId].merkleTree[treeIds[1]].root
]);
} else {
// TODO : merge more trees to provide higher gurantee.
}
IVerifier verifier = verifiers[merkleTreeDepth];
verifier.verifyProof(
[proof[0], proof[1]],
[[proof[2], proof[3]], [proof[4], proof[5]]],
[proof[6], proof[7]],
[merkleTreeRoot]
);
return true;
}
function remove(
uint groupId,
uint identity,
uint[] calldata proofSiblings,
uint8[] calldata proofPathIndices
) public {
uint treeId = eg[groupId].member2tree[identity];
require(treeId != 0, "not in group!!");
eg[groupId].merkleTree[treeId].remove(identity, proofSiblings, proofPathIndices);
delete eg[groupId].member2tree[identity];
}
function enlarge(
uint groupId,
uint size
) public {
eg[groupId].maxTreeNum = size - eg[groupId].gurantee;
}
function downsize(
uint groupId,
uint maxTreeNum
) public {
require(eg[groupId].treeNum < maxTreeNum);
eg[groupId].maxTreeNum = maxTreeNum;
}
function migrate(
IncrementalTreeData storage merkleTree,
uint groupId
) internal {
// merkle tree --> group
// add items in lookup table for each member
}
}