@@ -19,6 +19,8 @@ class InternalTransferGadget : public GadgetT
1919{
2020public:
2121
22+ const Constants& constants;
23+
2224 // User From state
2325 BalanceGadget balanceFBefore_From;
2426 BalanceGadget balanceTBefore_From;
@@ -36,7 +38,16 @@ class InternalTransferGadget : public GadgetT
3638 DualVariableGadget amount;
3739 DualVariableGadget feeTokenID;
3840 DualVariableGadget fee;
39- VariableT label;
41+ DualVariableGadget type;
42+
43+ // Signature
44+ Poseidon_gadget_T<9 , 1 , 6 , 53 , 8 , 1 > hash;
45+ SignatureVerifier signatureVerifier;
46+
47+ // Type
48+ NotGadget signatureInvalid;
49+ UnsafeAddGadget numConditionalTransfersAfter;
50+ RequireEqualGadget type_eq_signatureInvalid;
4051
4152 // User To account check
4253 RequireNotZeroGadget publicKeyX_notZero;
@@ -68,21 +79,20 @@ class InternalTransferGadget : public GadgetT
6879 // Update Operator
6980 UpdateBalanceGadget updateBalanceF_O;
7081
71- // Signature
72- Poseidon_gadget_T<10 , 1 , 6 , 53 , 9 , 1 > hash;
73- SignatureVerifier signatureVerifier;
74-
7582 InternalTransferGadget (
7683 ProtoboardT &pb,
7784 const jubjub::Params& params,
78- const Constants& constants ,
85+ const Constants& _constants ,
7986 const VariableT& accountsMerkleRoot,
8087 const VariableT& operatorBalancesRoot,
8188 const VariableT& blockExchangeID,
89+ const VariableT& numConditionalTransfersBefore,
8290 const std::string &prefix
8391 ) :
8492 GadgetT (pb, prefix),
8593
94+ constants (_constants),
95+
8696 // User From state
8797 balanceFBefore_From (pb, FMT(prefix, " balanceFBefore_From" )),
8898 balanceTBefore_From (pb, FMT(prefix, " balanceTBefore_From" )),
@@ -100,7 +110,16 @@ class InternalTransferGadget : public GadgetT
100110 amount (pb, NUM_BITS_AMOUNT, FMT(prefix, " .amount" )),
101111 feeTokenID (pb, NUM_BITS_TOKEN, FMT(prefix, " .feeTokenID" )),
102112 fee (pb, NUM_BITS_AMOUNT, FMT(prefix, " .fee" )),
103- label (make_variable(pb, FMT(prefix, " .label" ))),
113+ type (pb, NUM_BITS_TYPE, FMT(prefix, " .type" )),
114+
115+ // Signature
116+ hash (pb, var_array({blockExchangeID, accountID_From.packed , accountID_To.packed , tokenID.packed , amount.packed , feeTokenID.packed , fee.packed , accountBefore_From.nonce }), FMT(this ->annotation_prefix, " .hash" )),
117+ signatureVerifier (pb, params, constants, accountBefore_From.publicKey, hash.result(), FMT(prefix, " .signatureVerifier" ), false ),
118+
119+ // Type
120+ signatureInvalid (pb, signatureVerifier.result(), " .signatureInvalid" ),
121+ numConditionalTransfersAfter (pb, numConditionalTransfersBefore, signatureInvalid.result(), " .numConditionalTransfersAfter" ),
122+ type_eq_signatureInvalid (pb, type.packed, signatureInvalid.result(), " .type_eq_signatureInvalid" ),
104123
105124 // User To account check
106125 publicKeyX_notZero (pb, accountBefore_To.publicKey.x, FMT(prefix, " .publicKeyX_notZero" )),
@@ -117,8 +136,8 @@ class InternalTransferGadget : public GadgetT
117136 // Transfer from From to To
118137 transferPayment (pb, NUM_BITS_AMOUNT, balanceTBefore_From.balance, balanceTBefore_To.balance, fAmount .value(), FMT(prefix, " .transferPayment" )),
119138
120- // Increase the nonce of From by 1
121- nonce_From_after (pb, accountBefore_From.nonce, constants.one , NUM_BITS_NONCE, FMT(prefix, " .nonce_From_after" )),
139+ // Increase the nonce of From by 1 (unless it's a conditional transfer)
140+ nonce_From_after (pb, accountBefore_From.nonce, signatureVerifier.result() , NUM_BITS_NONCE, FMT(prefix, " .nonce_From_after" )),
122141
123142 // Update User From
124143 updateBalanceF_From (pb, accountBefore_From.balancesRoot, feeTokenID.bits,
@@ -148,11 +167,7 @@ class InternalTransferGadget : public GadgetT
148167 updateBalanceF_O(pb, operatorBalancesRoot, feeTokenID.bits,
149168 {balanceBefore_O.balance , balanceBefore_O.tradingHistory },
150169 {feePayment.Y , balanceBefore_O.tradingHistory },
151- FMT (prefix, " .updateBalanceF_O" )),
152-
153- // Signature
154- hash(pb, var_array({blockExchangeID, accountID_From.packed , accountID_To.packed , tokenID.packed , amount.packed , feeTokenID.packed , fee.packed , label, accountBefore_From.nonce }), FMT(this ->annotation_prefix, " .hash" )),
155- signatureVerifier(pb, params, accountBefore_From.publicKey, hash.result(), FMT(prefix, " .signatureVerifier" ))
170+ FMT (prefix, " .updateBalanceF_O" ))
156171 {
157172
158173 }
@@ -176,7 +191,16 @@ class InternalTransferGadget : public GadgetT
176191 amount.generate_r1cs_witness (pb, transfer.amount );
177192 feeTokenID.generate_r1cs_witness (pb, transfer.balanceUpdateF_From .tokenID );
178193 fee.generate_r1cs_witness (pb, transfer.fee );
179- pb.val (label) = transfer.label ;
194+ type.generate_r1cs_witness (pb, transfer.type );
195+
196+ // Signature
197+ hash.generate_r1cs_witness ();
198+ signatureVerifier.generate_r1cs_witness (transfer.signature );
199+
200+ // Type
201+ signatureInvalid.generate_r1cs_witness ();
202+ pb.val (numConditionalTransfersAfter.sum ) = transfer.numConditionalTransfersAfter ;
203+ type_eq_signatureInvalid.generate_r1cs_witness ();
180204
181205 // User To account check
182206 publicKeyX_notZero.generate_r1cs_witness ();
@@ -207,10 +231,6 @@ class InternalTransferGadget : public GadgetT
207231
208232 // Update Operator
209233 updateBalanceF_O.generate_r1cs_witness (transfer.balanceUpdateF_O .proof );
210-
211- // Signature
212- hash.generate_r1cs_witness ();
213- signatureVerifier.generate_r1cs_witness (transfer.signature );
214234 }
215235
216236 void generate_r1cs_constraints ()
@@ -222,7 +242,16 @@ class InternalTransferGadget : public GadgetT
222242 amount.generate_r1cs_constraints (true );
223243 feeTokenID.generate_r1cs_constraints (true );
224244 fee.generate_r1cs_constraints (true );
225- // label has no limit
245+ type.generate_r1cs_constraints (true );
246+
247+ // Signature
248+ hash.generate_r1cs_constraints ();
249+ signatureVerifier.generate_r1cs_constraints ();
250+
251+ // Type
252+ signatureInvalid.generate_r1cs_constraints ();
253+ numConditionalTransfersAfter.generate_r1cs_constraints ();
254+ type_eq_signatureInvalid.generate_r1cs_constraints ();
226255
227256 // User To account check
228257 publicKeyX_notZero.generate_r1cs_constraints ();
@@ -254,19 +283,16 @@ class InternalTransferGadget : public GadgetT
254283
255284 // Update Operator
256285 updateBalanceF_O.generate_r1cs_constraints ();
257-
258- // Signature
259- hash.generate_r1cs_constraints ();
260- signatureVerifier.generate_r1cs_constraints ();
261286 }
262287
263288 const std::vector<VariableArrayT> getPublicData () const
264289 {
265- return {accountID_From.bits ,
290+ return {type.bits ,
291+ accountID_From.bits ,
266292 accountID_To.bits ,
267- tokenID.bits ,
293+ VariableArrayT (2 , constants.zero ), tokenID.bits ,
294+ VariableArrayT (2 , constants.zero ), feeTokenID.bits ,
268295 fAmount .bits (),
269- feeTokenID.bits ,
270296 fFee .bits ()};
271297 }
272298
@@ -279,6 +305,11 @@ class InternalTransferGadget : public GadgetT
279305 {
280306 return updateBalanceF_O.result ();
281307 }
308+
309+ const VariableT& getNewNumConditionalTransfers () const
310+ {
311+ return numConditionalTransfersAfter.result ();
312+ }
282313};
283314
284315class InternalTransferCircuit : public Circuit
@@ -295,6 +326,7 @@ class InternalTransferCircuit : public Circuit
295326 DualVariableGadget exchangeID;
296327 DualVariableGadget merkleRootBefore;
297328 DualVariableGadget merkleRootAfter;
329+ std::unique_ptr<libsnark::dual_variable_gadget<FieldT>> numConditionalTransfers;
298330 DualVariableGadget operatorAccountID;
299331
300332 // Operator account check
@@ -308,10 +340,6 @@ class InternalTransferCircuit : public Circuit
308340 // Update Operator
309341 std::unique_ptr<UpdateAccountGadget> updateAccount_O;
310342
311- // Labels
312- std::vector<VariableT> labels;
313- std::unique_ptr<LabelHasher> labelHasher;
314-
315343 InternalTransferCircuit (ProtoboardT &pb, const std::string &prefix)
316344 : Circuit(pb, prefix),
317345
@@ -362,9 +390,9 @@ class InternalTransferCircuit : public Circuit
362390 transAccountsRoot,
363391 transOperatorBalancesRoot,
364392 exchangeID.packed ,
393+ (j == 0 ) ? constants.zero : transfers.back ().getNewNumConditionalTransfers (),
365394 std::string (" transfer_" ) + std::to_string (j));
366395 transfers.back ().generate_r1cs_constraints ();
367- labels.push_back (transfers.back ().label );
368396 }
369397
370398 // Update Operator
@@ -374,18 +402,19 @@ class InternalTransferCircuit : public Circuit
374402 FMT (annotation_prefix, " .updateAccount_O" )));
375403 updateAccount_O->generate_r1cs_constraints ();
376404
377- // Labels
378- labelHasher.reset (new LabelHasher (pb, constants, labels, FMT (annotation_prefix, " .labelHash" )));
379- labelHasher->generate_r1cs_constraints ();
405+ // Num conditional transfers
406+ numConditionalTransfers.reset (new libsnark::dual_variable_gadget<FieldT>(
407+ pb, transfers.back ().getNewNumConditionalTransfers (), 32 , " .numConditionalTransfers" )
408+ );
409+ numConditionalTransfers->generate_r1cs_constraints (true );
380410
381411 // Public data
382412 publicData.add (exchangeID.bits );
383413 publicData.add (merkleRootBefore.bits );
384414 publicData.add (merkleRootAfter.bits );
385- publicData.add (labelHasher-> result () ->bits );
415+ publicData.add (numConditionalTransfers ->bits );
386416 if (onchainDataAvailability)
387417 {
388- publicData.add (constants.padding_0000 );
389418 publicData.add (operatorAccountID.bits );
390419 for (const InternalTransferGadget& transfer : transfers)
391420 {
@@ -426,8 +455,8 @@ class InternalTransferCircuit : public Circuit
426455 // Update operator
427456 updateAccount_O->generate_r1cs_witness (block.accountUpdate_O .proof );
428457
429- // Labels
430- labelHasher-> generate_r1cs_witness ();
458+ // Num conditional transfers
459+ numConditionalTransfers-> generate_r1cs_witness_from_packed ();
431460
432461 // Public data
433462 publicData.generate_r1cs_witness ();
0 commit comments