@@ -21,6 +21,9 @@ library TxGen {
21
21
using Logic for Logic.VerifierInput[];
22
22
using Logic for Logic.VerifierInput;
23
23
24
+ uint256 public constant MAX_ACTIONS = 4 ;
25
+ uint256 public constant MAX_RESOURCES = 5 ;
26
+
24
27
struct ActionConfig {
25
28
uint256 complianceUnitCount;
26
29
}
@@ -35,6 +38,18 @@ library TxGen {
35
38
ResourceAndAppData[] created;
36
39
}
37
40
41
+ struct ActionParams {
42
+ Resource[2 ][MAX_RESOURCES] resources;
43
+ uint256 [MAX_RESOURCES] bijection;
44
+ uint256 targetResourcesLen;
45
+ uint256 [2 ][MAX_RESOURCES] valueCommitmentRandomness;
46
+ }
47
+
48
+ struct TransactionParams {
49
+ ActionParams[MAX_ACTIONS] actionParams;
50
+ uint256 targetActionsLen;
51
+ }
52
+
38
53
error ConsumedCreatedCountMismatch (uint256 nConsumed , uint256 nCreated );
39
54
error NonExistingTag (bytes32 tag );
40
55
error TransactionTagCountMismatch ();
@@ -44,7 +59,9 @@ library TxGen {
44
59
RiscZeroMockVerifier mockVerifier ,
45
60
bytes32 commitmentTreeRoot , // historical root
46
61
Resource memory consumed ,
47
- Resource memory created
62
+ uint256 consumedValueCommitmentRandomness ,
63
+ Resource memory created ,
64
+ uint256 createdValueCommitmentRandomness
48
65
) internal returns (Compliance.VerifierInput memory unit ) {
49
66
bytes32 nf = nullifier (consumed, 0 );
50
67
bytes32 cm = commitment (created);
@@ -56,7 +73,7 @@ library TxGen {
56
73
kind: kind (consumed),
57
74
quantity: consumed.quantity,
58
75
consumed: true ,
59
- valueCommitmentRandomness: 1
76
+ valueCommitmentRandomness: consumedValueCommitmentRandomness
60
77
})
61
78
);
62
79
// Construct the delta for creation based on kind and quantity
@@ -68,7 +85,7 @@ library TxGen {
68
85
kind: kind (created),
69
86
quantity: created.quantity,
70
87
consumed: false ,
71
- valueCommitmentRandomness: 1
88
+ valueCommitmentRandomness: createdValueCommitmentRandomness
72
89
})
73
90
)
74
91
);
@@ -139,7 +156,9 @@ library TxGen {
139
156
mockVerifier: mockVerifier,
140
157
commitmentTreeRoot: initialRoot (),
141
158
consumed: consumed[i].resource,
142
- created: created[i].resource
159
+ consumedValueCommitmentRandomness: 1 ,
160
+ created: created[i].resource,
161
+ createdValueCommitmentRandomness: 1
143
162
});
144
163
}
145
164
action = Action ({logicVerifierInputs: logicVerifierInputs, complianceVerifierInputs: complianceVerifierInputs});
@@ -287,6 +306,111 @@ library TxGen {
287
306
}).seal;
288
307
}
289
308
309
+ function generateAction (VmSafe vm , RiscZeroMockVerifier mockVerifier , ActionParams memory params )
310
+ internal
311
+ returns (Action memory action , uint256 totalValueCommitmentRandomness )
312
+ {
313
+ Resource[2 ][] memory truncatedResources =
314
+ truncateResources (params.resources, params.targetResourcesLen % MAX_RESOURCES);
315
+ action.logicVerifierInputs = new Logic.VerifierInput [](truncatedResources.length * 2 );
316
+ action.complianceVerifierInputs = new Compliance.VerifierInput [](truncatedResources.length );
317
+ // Created empty app data for all the resources
318
+ Logic.AppData memory appData = Logic.AppData ({
319
+ resourcePayload: new Logic.ExpirableBlob [](0 ),
320
+ discoveryPayload: new Logic.ExpirableBlob [](0 ),
321
+ externalPayload: new Logic.ExpirableBlob [](0 ),
322
+ applicationPayload: new Logic.ExpirableBlob [](0 )
323
+ });
324
+ // Match the created and consumed resources
325
+ uint256 [] memory bijection = generateBijection (params.bijection, truncatedResources.length );
326
+ for (uint256 i = 0 ; i < truncatedResources.length ; ++ i) {
327
+ truncatedResources[bijection[i]][1 ].quantity = truncatedResources[i][0 ].quantity;
328
+ truncatedResources[bijection[i]][1 ].logicRef = truncatedResources[i][0 ].logicRef;
329
+ truncatedResources[bijection[i]][1 ].labelRef = truncatedResources[i][0 ].labelRef;
330
+ }
331
+ // Compute action tree tags and action tree root
332
+ bytes32 [] memory actionTreeTags = new bytes32 [](2 * truncatedResources.length );
333
+ totalValueCommitmentRandomness = 0 ;
334
+ for (uint256 i = 0 ; i < truncatedResources.length ; ++ i) {
335
+ uint256 index = (i * 2 );
336
+
337
+ actionTreeTags[index] = nullifier (truncatedResources[i][0 ], 0 );
338
+ actionTreeTags[index + 1 ] = commitment (truncatedResources[i][1 ]);
339
+ // Adjust and accumulate the value randomness commitments
340
+ params.valueCommitmentRandomness[i][0 ] =
341
+ 1 + (params.valueCommitmentRandomness[i][0 ] % (DeltaGen.SECP256K1_ORDER - 1 ));
342
+ params.valueCommitmentRandomness[i][1 ] =
343
+ 1 + (params.valueCommitmentRandomness[i][1 ] % (DeltaGen.SECP256K1_ORDER - 1 ));
344
+ totalValueCommitmentRandomness =
345
+ addmod (totalValueCommitmentRandomness, params.valueCommitmentRandomness[i][0 ], DeltaGen.SECP256K1_ORDER);
346
+ totalValueCommitmentRandomness =
347
+ addmod (totalValueCommitmentRandomness, params.valueCommitmentRandomness[i][1 ], DeltaGen.SECP256K1_ORDER);
348
+ }
349
+ bytes32 actionTreeRoot = actionTreeTags.computeRoot ();
350
+ // Create logic and compliance verifier inputs
351
+ for (uint256 i = 0 ; i < truncatedResources.length ; i++ ) {
352
+ uint256 index = (i * 2 );
353
+
354
+ Resource memory consumedResource = truncatedResources[i][0 ];
355
+ Resource memory createdResource = truncatedResources[i][1 ];
356
+ // Created logic verifier input for a consumed resource
357
+ action.logicVerifierInputs[index] = logicVerifierInput ({
358
+ mockVerifier: mockVerifier,
359
+ actionTreeRoot: actionTreeRoot,
360
+ resource: consumedResource,
361
+ isConsumed: true ,
362
+ appData: appData
363
+ });
364
+ // Create logic verifier input for a created resource
365
+ action.logicVerifierInputs[index + 1 ] = logicVerifierInput ({
366
+ mockVerifier: mockVerifier,
367
+ actionTreeRoot: actionTreeRoot,
368
+ resource: createdResource,
369
+ isConsumed: false ,
370
+ appData: appData
371
+ });
372
+ // Create compliance verifier input for the resource pairs
373
+ action.complianceVerifierInputs[i] = complianceVerifierInput ({
374
+ vm: vm,
375
+ mockVerifier: mockVerifier,
376
+ commitmentTreeRoot: initialRoot (),
377
+ consumed: consumedResource,
378
+ consumedValueCommitmentRandomness: params.valueCommitmentRandomness[i][0 ],
379
+ created: createdResource,
380
+ createdValueCommitmentRandomness: params.valueCommitmentRandomness[i][1 ]
381
+ });
382
+ }
383
+ }
384
+
385
+ function transaction (VmSafe vm , RiscZeroMockVerifier mockVerifier , TransactionParams memory params )
386
+ internal
387
+ returns (Transaction memory txn )
388
+ {
389
+ // Generate actions
390
+ Action[] memory actions = new Action [](params.targetActionsLen % MAX_ACTIONS);
391
+ uint256 totalValueCommitmentRandomness = 0 ;
392
+ for (uint256 i = 0 ; i < actions.length ; i++ ) {
393
+ uint256 valueCommitmentRandomness;
394
+ (actions[i], valueCommitmentRandomness) = generateAction (vm, mockVerifier, params.actionParams[i]);
395
+ totalValueCommitmentRandomness =
396
+ addmod (totalValueCommitmentRandomness, valueCommitmentRandomness, DeltaGen.SECP256K1_ORDER);
397
+ }
398
+ // Generate delta proof
399
+ bytes memory proof = "" ;
400
+ bytes32 [] memory tags = TxGen.collectTags (actions);
401
+ if (tags.length != 0 ) {
402
+ proof = DeltaGen.generateProof (
403
+ vm,
404
+ DeltaGen.ProofInputs ({
405
+ valueCommitmentRandomness: totalValueCommitmentRandomness,
406
+ verifyingKey: Delta.computeVerifyingKey (tags)
407
+ })
408
+ );
409
+ }
410
+ // Generate transaction
411
+ txn = Transaction ({actions: actions, deltaProof: proof, aggregationProof: "" });
412
+ }
413
+
290
414
function logicVerifierInput (
291
415
RiscZeroMockVerifier mockVerifier ,
292
416
bytes32 actionTreeRoot ,
@@ -479,4 +603,43 @@ library TxGen {
479
603
480
604
root = actionTreeTags.computeRoot ();
481
605
}
606
+
607
+ function truncateResources (Resource[2 ][MAX_RESOURCES] memory resources , uint256 len )
608
+ internal
609
+ pure
610
+ returns (Resource[2 ][] memory truncatedResources )
611
+ {
612
+ truncatedResources = new Resource [2 ][](len);
613
+ for (uint256 i = 0 ; i < len; i++ ) {
614
+ truncatedResources[i][0 ] = resources[i][0 ];
615
+ truncatedResources[i][1 ] = resources[i][1 ];
616
+ }
617
+ }
618
+
619
+ function generateBijection (uint256 [MAX_RESOURCES] memory input , uint256 len )
620
+ internal
621
+ pure
622
+ returns (uint256 [] memory output )
623
+ {
624
+ output = new uint256 [](len);
625
+ uint256 [] memory duplicates = new uint256 [](len);
626
+ uint256 duplicateCount = 0 ;
627
+ for (uint256 i = 0 ; i < len; i++ ) {
628
+ output[i] = duplicates[i] = len;
629
+ input[i] %= len;
630
+ }
631
+ for (uint256 i = 0 ; i < len; i++ ) {
632
+ if (output[input[i]] == len) {
633
+ output[input[i]] = i;
634
+ } else {
635
+ duplicates[duplicateCount++ ] = i;
636
+ }
637
+ }
638
+ duplicateCount = 0 ;
639
+ for (uint256 i = 0 ; i < len; i++ ) {
640
+ if (output[i] == len) {
641
+ output[i] = duplicates[duplicateCount++ ];
642
+ }
643
+ }
644
+ }
482
645
}
0 commit comments