@@ -21,6 +21,9 @@ library TxGen {
2121 using Logic for Logic.VerifierInput[];
2222 using Logic for Logic.VerifierInput;
2323
24+ uint256 public constant MAX_ACTIONS = 4 ;
25+ uint256 public constant MAX_RESOURCES = 5 ;
26+
2427 struct ActionConfig {
2528 uint256 complianceUnitCount;
2629 }
@@ -35,6 +38,18 @@ library TxGen {
3538 ResourceAndAppData[] created;
3639 }
3740
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+
3853 error ConsumedCreatedCountMismatch (uint256 nConsumed , uint256 nCreated );
3954 error NonExistingTag (bytes32 tag );
4055 error TransactionTagCountMismatch ();
@@ -44,7 +59,9 @@ library TxGen {
4459 RiscZeroMockVerifier mockVerifier ,
4560 bytes32 commitmentTreeRoot , // historical root
4661 Resource memory consumed ,
47- Resource memory created
62+ uint256 consumedValueCommitmentRandomness ,
63+ Resource memory created ,
64+ uint256 createdValueCommitmentRandomness
4865 ) internal returns (Compliance.VerifierInput memory unit ) {
4966 bytes32 nf = nullifier (consumed, 0 );
5067 bytes32 cm = commitment (created);
@@ -56,7 +73,7 @@ library TxGen {
5673 kind: kind (consumed),
5774 quantity: consumed.quantity,
5875 consumed: true ,
59- valueCommitmentRandomness: 1
76+ valueCommitmentRandomness: consumedValueCommitmentRandomness
6077 })
6178 );
6279 // Construct the delta for creation based on kind and quantity
@@ -68,7 +85,7 @@ library TxGen {
6885 kind: kind (created),
6986 quantity: created.quantity,
7087 consumed: false ,
71- valueCommitmentRandomness: 1
88+ valueCommitmentRandomness: createdValueCommitmentRandomness
7289 })
7390 )
7491 );
@@ -139,7 +156,9 @@ library TxGen {
139156 mockVerifier: mockVerifier,
140157 commitmentTreeRoot: initialRoot (),
141158 consumed: consumed[i].resource,
142- created: created[i].resource
159+ consumedValueCommitmentRandomness: 1 ,
160+ created: created[i].resource,
161+ createdValueCommitmentRandomness: 1
143162 });
144163 }
145164 action = Action ({logicVerifierInputs: logicVerifierInputs, complianceVerifierInputs: complianceVerifierInputs});
@@ -287,6 +306,111 @@ library TxGen {
287306 }).seal;
288307 }
289308
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+
290414 function logicVerifierInput (
291415 RiscZeroMockVerifier mockVerifier ,
292416 bytes32 actionTreeRoot ,
@@ -479,4 +603,43 @@ library TxGen {
479603
480604 root = actionTreeTags.computeRoot ();
481605 }
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+ }
482645}
0 commit comments