@@ -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