Skip to content

Commit b38d64c

Browse files
authored
Testing + Cleanup (#14)
* WIP: Add testing * WIP: more tests * WIP: Removed unused gadgets + less manual constraints by using gadgets * WIP: Some improvements to order validity checks * WIP: add tests * WIP: testing... * WIP: testing... * Changed rounding error checking to rate checking * WIP: Split up tests in multiple source files * Cleanup withdrawal circuits * More circuit cleanup * More cleanup in circuits * Even more refactoring * Added Order and TradeHistoryTrimming tests * Refactoring * Store 0 filled amount after canceling with higher orderID
1 parent de34a37 commit b38d64c

27 files changed

+21478
-1676
lines changed

Circuits/DepositCircuit.h

Lines changed: 116 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include "../Utils/Constants.h"
55
#include "../Utils/Data.h"
66

7-
#include "../ThirdParty/BigInt.hpp"
7+
#include "../ThirdParty/BigIntHeader.hpp"
88
#include "ethsnarks.hpp"
99
#include "utils.hpp"
1010
#include "gadgets/sha256_many.hpp"
@@ -17,181 +17,169 @@ namespace Loopring
1717
class DepositGadget : public GadgetT
1818
{
1919
public:
20-
const Constants& constants;
2120

22-
VariableArrayT accountID;
23-
VariableArrayT tokenID;
21+
// User state
22+
BalanceGadget balanceBefore;
23+
AccountGadget accountBefore;
2424

25-
libsnark::dual_variable_gadget<FieldT> amount;
26-
libsnark::dual_variable_gadget<FieldT> publicKeyX;
27-
libsnark::dual_variable_gadget<FieldT> publicKeyY;
25+
// Inputs
26+
DualVariableGadget accountID;
27+
DualVariableGadget tokenID;
28+
DualVariableGadget amount;
29+
DualVariableGadget publicKeyX;
30+
DualVariableGadget publicKeyY;
2831

29-
BalanceState balanceBefore;
30-
AccountState accountBefore;
31-
VariableT uncappedBalanceAfter;
32-
MinGadget cappedBalanceAfter;
33-
BalanceState balanceAfter;
32+
// Calculate the new balance
33+
UnsafeAddGadget uncappedBalanceAfter;
34+
MinGadget balanceAfter;
35+
36+
// Update User
3437
UpdateBalanceGadget updateBalance;
35-
AccountState accountAfter;
3638
UpdateAccountGadget updateAccount;
3739

3840
DepositGadget(
3941
ProtoboardT& pb,
40-
const Constants& _constants,
42+
const Constants& constants,
4143
const VariableT& root,
4244
const std::string& prefix
4345
) :
4446
GadgetT(pb, prefix),
4547

46-
constants(_constants),
47-
48-
accountID(make_var_array(pb, NUM_BITS_ACCOUNT, FMT(prefix, ".accountID"))),
49-
tokenID(make_var_array(pb, NUM_BITS_TOKEN, FMT(prefix, ".tokenID"))),
48+
// User state
49+
balanceBefore(pb, FMT(prefix, ".balanceBefore")),
50+
accountBefore(pb, FMT(prefix, ".accountBefore")),
5051

52+
// Inputs
53+
accountID(pb, NUM_BITS_ACCOUNT, FMT(prefix, ".accountID")),
54+
tokenID(pb, NUM_BITS_TOKEN, FMT(prefix, ".tokenID")),
5155
amount(pb, NUM_BITS_AMOUNT, FMT(prefix, ".amount")),
5256
publicKeyX(pb, 256, FMT(prefix, ".publicKeyX")),
5357
publicKeyY(pb, 256, FMT(prefix, ".publicKeyY")),
5458

55-
// Balance
56-
balanceBefore({
57-
make_variable(pb, FMT(prefix, ".before.balance")),
58-
make_variable(pb, FMT(prefix, ".tradingHistoryRoot"))
59-
}),
60-
uncappedBalanceAfter(make_variable(pb, FMT(prefix, ".uncappedBalanceAfter"))),
61-
cappedBalanceAfter(pb, uncappedBalanceAfter, constants.maxAmount, NUM_BITS_AMOUNT + 1, FMT(prefix, ".cappedBalanceAfter")),
62-
balanceAfter({
63-
cappedBalanceAfter.result(),
64-
balanceBefore.tradingHistory
65-
}),
66-
// Account
67-
accountBefore({
68-
make_variable(pb, FMT(prefix, ".publicKeyX_before")),
69-
make_variable(pb, FMT(prefix, ".publicKeyY_before")),
70-
make_variable(pb, FMT(prefix, ".nonce")),
71-
make_variable(pb, FMT(prefix, ".balancesRoot_before"))
72-
}),
73-
// Update balance
74-
updateBalance(pb, accountBefore.balancesRoot, tokenID, balanceBefore, balanceAfter, FMT(prefix, ".updateBalance")),
75-
accountAfter({
76-
publicKeyX.packed,
77-
publicKeyY.packed,
78-
accountBefore.nonce,
79-
updateBalance.getNewRoot()
80-
}),
81-
// Update account
82-
updateAccount(pb, root, accountID, accountBefore, accountAfter, FMT(prefix, ".updateAccount"))
59+
// Calculate the new balance
60+
uncappedBalanceAfter(pb, balanceBefore.balance, amount.packed, FMT(prefix, ".uncappedBalanceAfter")),
61+
balanceAfter(pb, uncappedBalanceAfter.result(), constants.maxAmount, NUM_BITS_AMOUNT + 1, FMT(prefix, ".balanceAfter")),
62+
63+
// Update User
64+
updateBalance(pb, accountBefore.balancesRoot, tokenID.bits,
65+
{balanceBefore.balance, balanceBefore.tradingHistory},
66+
{balanceAfter.result(), balanceBefore.tradingHistory},
67+
FMT(prefix, ".updateBalance")),
68+
updateAccount(pb, root, accountID.bits,
69+
{accountBefore.publicKey.x, accountBefore.publicKey.y, accountBefore.nonce, accountBefore.balancesRoot},
70+
{publicKeyX.packed, publicKeyY.packed, accountBefore.nonce, updateBalance.result()},
71+
FMT(prefix, ".updateAccount"))
8372
{
8473

8574
}
8675

87-
const VariableT getNewAccountsRoot() const
88-
{
89-
return updateAccount.result();
90-
}
91-
92-
const std::vector<VariableArrayT> getOnchainData() const
93-
{
94-
return {constants.accountPadding, accountID,
95-
publicKeyX.bits, publicKeyY.bits,
96-
tokenID,
97-
amount.bits};
98-
}
99-
10076
void generate_r1cs_witness(const Deposit& deposit)
10177
{
102-
accountID.fill_with_bits_of_field_element(pb, deposit.accountUpdate.accountID);
103-
tokenID.fill_with_bits_of_field_element(pb, deposit.balanceUpdate.tokenID);
104-
105-
amount.bits.fill_with_bits_of_field_element(pb, deposit.amount);
106-
amount.generate_r1cs_witness_from_bits();
107-
publicKeyX.bits.fill_with_bits_of_field_element(pb, deposit.accountUpdate.after.publicKey.x);
108-
publicKeyX.generate_r1cs_witness_from_bits();
109-
publicKeyY.bits.fill_with_bits_of_field_element(pb, deposit.accountUpdate.after.publicKey.y);
110-
publicKeyY.generate_r1cs_witness_from_bits();
111-
112-
pb.val(balanceBefore.balance) = deposit.balanceUpdate.before.balance;
113-
pb.val(balanceBefore.tradingHistory) = deposit.balanceUpdate.before.tradingHistoryRoot;
114-
115-
pb.val(uncappedBalanceAfter) = deposit.balanceUpdate.before.balance + deposit.amount;
116-
cappedBalanceAfter.generate_r1cs_witness();
117-
118-
pb.val(accountBefore.publicKeyX) = deposit.accountUpdate.before.publicKey.x;
119-
pb.val(accountBefore.publicKeyY) = deposit.accountUpdate.before.publicKey.y;
120-
pb.val(accountBefore.nonce) = deposit.accountUpdate.before.nonce;
121-
pb.val(accountBefore.balancesRoot) = deposit.accountUpdate.before.balancesRoot;
122-
78+
// User state
79+
balanceBefore.generate_r1cs_witness(deposit.balanceUpdate.before);
80+
accountBefore.generate_r1cs_witness(deposit.accountUpdate.before);
81+
82+
// Inputs
83+
accountID.generate_r1cs_witness(pb, deposit.accountUpdate.accountID);
84+
tokenID.generate_r1cs_witness(pb, deposit.balanceUpdate.tokenID);
85+
amount.generate_r1cs_witness(pb, deposit.amount);
86+
publicKeyX.generate_r1cs_witness(pb, deposit.accountUpdate.after.publicKey.x);
87+
publicKeyY.generate_r1cs_witness(pb, deposit.accountUpdate.after.publicKey.y);
88+
89+
// Calculate the new balance
90+
uncappedBalanceAfter.generate_r1cs_witness();
91+
balanceAfter.generate_r1cs_witness();
92+
93+
// Update User
12394
updateBalance.generate_r1cs_witness(deposit.balanceUpdate.proof);
12495
updateAccount.generate_r1cs_witness(deposit.accountUpdate.proof);
12596
}
12697

12798
void generate_r1cs_constraints()
12899
{
100+
// Inputs
101+
accountID.generate_r1cs_constraints(true);
102+
tokenID.generate_r1cs_constraints(true);
129103
amount.generate_r1cs_constraints(true);
130104
publicKeyX.generate_r1cs_constraints(true);
131105
publicKeyY.generate_r1cs_constraints(true);
132106

133-
pb.add_r1cs_constraint(ConstraintT(balanceBefore.balance + amount.packed, 1, uncappedBalanceAfter), "balanceBefore + amount == uncappedBalanceAfter");
134-
cappedBalanceAfter.generate_r1cs_constraints();
107+
// Calculate the new balance
108+
uncappedBalanceAfter.generate_r1cs_constraints();
109+
balanceAfter.generate_r1cs_constraints();
135110

111+
// Update User
136112
updateBalance.generate_r1cs_constraints();
137113
updateAccount.generate_r1cs_constraints();
138114
}
115+
116+
const std::vector<VariableArrayT> getOnchainData(const Constants& constants) const
117+
{
118+
return {constants.padding_0000, accountID.bits,
119+
publicKeyX.bits, publicKeyY.bits,
120+
tokenID.bits,
121+
amount.bits};
122+
}
123+
124+
const VariableT getNewAccountsRoot() const
125+
{
126+
return updateAccount.result();
127+
}
139128
};
140129

141130
class DepositCircuit : public GadgetT
142131
{
143132
public:
144133

145-
unsigned int numAccounts;
146-
std::vector<DepositGadget> deposits;
147-
148134
PublicDataGadget publicData;
149-
150135
Constants constants;
151136

152-
libsnark::dual_variable_gadget<FieldT> exchangeID;
153-
libsnark::dual_variable_gadget<FieldT> merkleRootBefore;
154-
libsnark::dual_variable_gadget<FieldT> merkleRootAfter;
155-
156-
VariableArrayT depositBlockHashStart;
157-
libsnark::dual_variable_gadget<FieldT> startIndex;
158-
libsnark::dual_variable_gadget<FieldT> count;
137+
// Inputs
138+
DualVariableGadget exchangeID;
139+
DualVariableGadget merkleRootBefore;
140+
DualVariableGadget merkleRootAfter;
141+
DualVariableGadget depositBlockHashStart;
142+
DualVariableGadget startIndex;
143+
DualVariableGadget count;
159144

145+
// Deposits
146+
unsigned int numDeposits;
147+
std::vector<DepositGadget> deposits;
160148
std::vector<sha256_many> hashers;
161149

162150
DepositCircuit(ProtoboardT& pb, const std::string& prefix) :
163151
GadgetT(pb, prefix),
164152

165153
publicData(pb, FMT(prefix, ".publicData")),
166-
167154
constants(pb, FMT(prefix, ".constants")),
168155

169-
exchangeID(pb, 32, FMT(prefix, ".exchangeID")),
156+
// Inputs
157+
exchangeID(pb, NUM_BITS_EXCHANGE_ID, FMT(prefix, ".exchangeID")),
170158
merkleRootBefore(pb, 256, FMT(prefix, ".merkleRootBefore")),
171159
merkleRootAfter(pb, 256, FMT(prefix, ".merkleRootAfter")),
172-
173-
depositBlockHashStart(make_var_array(pb, 256, FMT(prefix, ".depositBlockHashStart"))),
160+
depositBlockHashStart(pb, 256, FMT(prefix, ".depositBlockHashStart")),
174161
startIndex(pb, 32, FMT(prefix, ".startIndex")),
175162
count(pb, 32, FMT(prefix, ".count"))
176163
{
177164

178165
}
179166

180-
void generate_r1cs_constraints(int numAccounts)
167+
void generate_r1cs_constraints(int numDeposits)
181168
{
182-
this->numAccounts = numAccounts;
169+
this->numDeposits = numDeposits;
183170

184171
constants.generate_r1cs_constraints();
185172

173+
// Inputs
186174
exchangeID.generate_r1cs_constraints(true);
187175
merkleRootBefore.generate_r1cs_constraints(true);
188176
merkleRootAfter.generate_r1cs_constraints(true);
177+
depositBlockHashStart.generate_r1cs_constraints(true);
178+
startIndex.generate_r1cs_constraints(true);
179+
count.generate_r1cs_constraints(true);
189180

190-
publicData.add(exchangeID.bits);
191-
publicData.add(merkleRootBefore.bits);
192-
publicData.add(merkleRootAfter.bits);
193-
publicData.add(reverse(depositBlockHashStart));
194-
for (size_t j = 0; j < numAccounts; j++)
181+
// Deposits
182+
for (size_t j = 0; j < numDeposits; j++)
195183
{
196184
VariableT depositAccountsRoot = (j == 0) ? merkleRootBefore.packed : deposits.back().getNewAccountsRoot();
197185
deposits.emplace_back(
@@ -202,73 +190,61 @@ class DepositCircuit : public GadgetT
202190
);
203191
deposits.back().generate_r1cs_constraints();
204192

205-
VariableArrayT depositBlockHash = (j == 0) ? depositBlockHashStart : hashers.back().result().bits;
206-
207193
// Hash data from deposit
208-
std::vector<VariableArrayT> depositData = deposits.back().getOnchainData();
194+
std::vector<VariableArrayT> depositData = deposits.back().getOnchainData(constants);
209195
std::vector<VariableArrayT> hashBits;
210-
hashBits.push_back(reverse(depositBlockHash));
196+
hashBits.push_back(reverse((j == 0) ? depositBlockHashStart.bits : hashers.back().result().bits));
211197
hashBits.insert(hashBits.end(), depositData.begin(), depositData.end());
212198
hashers.emplace_back(pb, flattenReverse(hashBits), std::string("hash_") + std::to_string(j));
213199
hashers.back().generate_r1cs_constraints();
214200
}
215201

216-
// Add the block hash
202+
// Public data
203+
publicData.add(exchangeID.bits);
204+
publicData.add(merkleRootBefore.bits);
205+
publicData.add(merkleRootAfter.bits);
206+
publicData.add(reverse(depositBlockHashStart.bits));
217207
publicData.add(reverse(hashers.back().result().bits));
218208
publicData.add(startIndex.bits);
219209
publicData.add(count.bits);
220-
221-
// Check the input hash
222210
publicData.generate_r1cs_constraints();
223211

224212
// Check the new merkle root
225213
forceEqual(pb, deposits.back().getNewAccountsRoot(), merkleRootAfter.packed, "newMerkleRoot");
226214
}
227215

228-
void printInfo()
229-
{
230-
std::cout << pb.num_constraints() << " constraints (" << (pb.num_constraints() / numAccounts) << "/deposit)" << std::endl;
231-
}
232-
233216
bool generateWitness(const DepositBlock& block)
234217
{
235218
constants.generate_r1cs_witness();
236219

237-
exchangeID.bits.fill_with_bits_of_field_element(pb, block.exchangeID);
238-
exchangeID.generate_r1cs_witness_from_bits();
239-
240-
merkleRootBefore.bits.fill_with_bits_of_field_element(pb, block.merkleRootBefore);
241-
merkleRootBefore.generate_r1cs_witness_from_bits();
242-
merkleRootAfter.bits.fill_with_bits_of_field_element(pb, block.merkleRootAfter);
243-
merkleRootAfter.generate_r1cs_witness_from_bits();
244-
245-
// Store the starting hash
246-
for (unsigned int i = 0; i < 256; i++)
247-
{
248-
pb.val(depositBlockHashStart[255 - i]) = block.startHash.test_bit(i);
249-
}
220+
// Inputs
221+
exchangeID.generate_r1cs_witness(pb, block.exchangeID);
222+
merkleRootBefore.generate_r1cs_witness(pb, block.merkleRootBefore);
223+
merkleRootAfter.generate_r1cs_witness(pb, block.merkleRootAfter);
224+
depositBlockHashStart.generate_r1cs_witness(pb, block.startHash);
225+
startIndex.generate_r1cs_witness(pb, block.startIndex);
226+
count.generate_r1cs_witness(pb, block.count);
250227
// printBits("start hash input: 0x", depositBlockHashStart.get_bits(pb), true);
251228

252-
startIndex.bits.fill_with_bits_of_field_element(pb, block.startIndex);
253-
startIndex.generate_r1cs_witness_from_bits();
254-
count.bits.fill_with_bits_of_field_element(pb, block.count);
255-
count.generate_r1cs_witness_from_bits();
256-
229+
// Deposits
230+
assert(deposits.size() == hashers.size());
257231
for(unsigned int i = 0; i < block.deposits.size(); i++)
258232
{
259233
deposits[i].generate_r1cs_witness(block.deposits[i]);
234+
hashers[i].generate_r1cs_witness();
260235
}
236+
// printBits("DepositBlockHash: 0x", hashers.back().result().bits.get_bits(pb));
261237

262-
for (auto& hasher : hashers)
263-
{
264-
hasher.generate_r1cs_witness();
265-
}
266-
printBits("DepositBlockHash: 0x", hashers.back().result().bits.get_bits(pb));
267-
238+
// Public data
268239
publicData.generate_r1cs_witness();
269240

270241
return true;
271242
}
243+
244+
void printInfo()
245+
{
246+
std::cout << pb.num_constraints() << " constraints (" << (pb.num_constraints() / numDeposits) << "/deposit)" << std::endl;
247+
}
272248
};
273249

274250
}

0 commit comments

Comments
 (0)