Skip to content

Commit 55cd1f0

Browse files
committed
Move transaction generation code into TxGen.
1 parent 7337da2 commit 55cd1f0

File tree

2 files changed

+184
-200
lines changed

2 files changed

+184
-200
lines changed

contracts/test/ProtocolAdapterMock.t.sol

Lines changed: 2 additions & 200 deletions
Original file line numberDiff line numberDiff line change
@@ -219,206 +219,8 @@ contract ProtocolAdapterMockVerifierTest is Test {
219219
_mockPa.execute(txn);
220220
}
221221

222-
uint256 public constant MAX_ACTIONS = 4;
223-
uint256 public constant MAX_RESOURCES = 4;
224-
225-
struct ActionParams {
226-
Resource[2][MAX_RESOURCES] resources;
227-
uint256[MAX_RESOURCES] bijection;
228-
uint256 targetResourcesLen;
229-
uint256[2][MAX_RESOURCES] valueCommitmentRandomness;
230-
}
231-
232-
function commitment(Resource memory resource) internal pure returns (bytes32 hash) {
233-
hash = sha256(abi.encode(resource));
234-
}
235-
236-
function nullifier(Resource memory resource, bytes32 nullifierKey) internal pure returns (bytes32 hash) {
237-
hash = sha256(abi.encode(resource, nullifierKey));
238-
}
239-
240-
function kind(Resource memory resource) internal pure returns (uint256 hash) {
241-
hash = uint256(sha256(abi.encode(resource.logicRef, resource.labelRef)));
242-
}
243-
244-
function initialRoot() internal pure returns (bytes32 root) {
245-
root = SHA256.EMPTY_HASH;
246-
}
247-
248-
function truncateResources(Resource[2][MAX_RESOURCES] memory resources, uint256 len) public pure returns (Resource[2][] memory truncatedResources) {
249-
truncatedResources = new Resource[2][](len);
250-
for (uint256 i = 0; i < len; i++) {
251-
truncatedResources[i][0] = resources[i][0];
252-
truncatedResources[i][1] = resources[i][1];
253-
}
254-
}
255-
256-
function generateBijection(uint256[MAX_RESOURCES] memory input, uint256 len) public pure returns (uint256[] memory output) {
257-
output = new uint256[](len);
258-
uint256[] memory duplicates = new uint256[](len);
259-
uint256 duplicateCount = 0;
260-
for (uint i = 0; i < len; i++) {
261-
output[i] = duplicates[i] = len;
262-
input[i] %= len;
263-
}
264-
for (uint i = 0; i < len; i++) {
265-
if (output[input[i]] == len) {
266-
output[input[i]] = i;
267-
} else {
268-
duplicates[duplicateCount++] = i;
269-
}
270-
}
271-
duplicateCount = 0;
272-
for (uint i = 0; i < len; i++) {
273-
if (output[i] == len) {
274-
output[i] = duplicates[duplicateCount++];
275-
}
276-
}
277-
}
278-
279-
function generateAction(ActionParams memory params) public returns (Action memory action, uint256 totalValueCommitmentRandomness) {
280-
Resource[2][] memory truncatedResources = truncateResources(params.resources, params.targetResourcesLen % MAX_RESOURCES);
281-
action.logicVerifierInputs = new Logic.VerifierInput[](truncatedResources.length * 2);
282-
action.complianceVerifierInputs = new Compliance.VerifierInput[](truncatedResources.length);
283-
// Created empty app data for all the resources
284-
Logic.AppData memory appData = Logic.AppData({
285-
resourcePayload: new Logic.ExpirableBlob[](0),
286-
discoveryPayload: new Logic.ExpirableBlob[](0),
287-
externalPayload: new Logic.ExpirableBlob[](0),
288-
applicationPayload: new Logic.ExpirableBlob[](0)
289-
});
290-
// Match the created and consumed resources
291-
uint256[] memory bijection = generateBijection(params.bijection, truncatedResources.length);
292-
for (uint256 i = 0; i < truncatedResources.length; ++i) {
293-
truncatedResources[bijection[i]][1].quantity = truncatedResources[i][0].quantity;
294-
truncatedResources[bijection[i]][1].logicRef = truncatedResources[i][0].logicRef;
295-
truncatedResources[bijection[i]][1].labelRef = truncatedResources[i][0].labelRef;
296-
}
297-
// Compute action tree tags and action tree root
298-
bytes32[] memory actionTreeTags = new bytes32[](2 * truncatedResources.length);
299-
totalValueCommitmentRandomness = 0;
300-
for (uint256 i = 0; i < truncatedResources.length; ++i) {
301-
uint256 index = (i * 2);
302-
303-
actionTreeTags[index] = nullifier(truncatedResources[i][0], 0);
304-
actionTreeTags[index + 1] = commitment(truncatedResources[i][1]);
305-
// Adjust and accumulate the value randomness commitments
306-
params.valueCommitmentRandomness[i][0] = bound(params.valueCommitmentRandomness[i][0], 1, SECP256K1_ORDER-1);
307-
params.valueCommitmentRandomness[i][1] = bound(params.valueCommitmentRandomness[i][1], 1, SECP256K1_ORDER-1);
308-
totalValueCommitmentRandomness = addmod(totalValueCommitmentRandomness, params.valueCommitmentRandomness[i][0], SECP256K1_ORDER);
309-
totalValueCommitmentRandomness = addmod(totalValueCommitmentRandomness, params.valueCommitmentRandomness[i][1], SECP256K1_ORDER);
310-
}
311-
bytes32 actionTreeRoot = actionTreeTags.computeRoot();
312-
// Create logic and compliance verifier inputs
313-
for (uint256 i = 0; i < truncatedResources.length; i++) {
314-
Resource memory consumedResource = truncatedResources[i][0];
315-
Resource memory createdResource = truncatedResources[i][1];
316-
bytes32 nf = nullifier(consumedResource, 0);
317-
bytes32 cm = commitment(createdResource);
318-
319-
// Created logic verifier input for a consumed resource
320-
action.logicVerifierInputs[2*i] = Logic.VerifierInput({
321-
tag: nf,
322-
verifyingKey: consumedResource.logicRef,
323-
proof: "",
324-
appData: appData
325-
});
326-
action.logicVerifierInputs[2*i].proof = _mockVerifier.mockProve({
327-
imageId: consumedResource.logicRef,
328-
journalDigest: sha256(action.logicVerifierInputs[2*i].toJournal(actionTreeRoot, true))
329-
}).seal;
330-
// Create logic verifier input for a created resource
331-
action.logicVerifierInputs[2*i + 1] = Logic.VerifierInput({
332-
tag: cm,
333-
verifyingKey: createdResource.logicRef,
334-
proof: "",
335-
appData: appData
336-
});
337-
action.logicVerifierInputs[2*i + 1].proof = _mockVerifier.mockProve({
338-
imageId: createdResource.logicRef,
339-
journalDigest: sha256(action.logicVerifierInputs[2*i + 1].toJournal(actionTreeRoot, false))
340-
}).seal;
341-
// Create the delta for the consumed resource
342-
Delta.CurvePoint memory unitDelta = DeltaGen.generateInstance(
343-
vm,
344-
DeltaGen.InstanceInputs({
345-
kind: kind(consumedResource),
346-
quantity: consumedResource.quantity,
347-
consumed: true,
348-
valueCommitmentRandomness: params.valueCommitmentRandomness[i][0]
349-
})
350-
);
351-
352-
// Add the delta for the created resource
353-
unitDelta = Delta.add(
354-
unitDelta,
355-
DeltaGen.generateInstance(
356-
vm,
357-
DeltaGen.InstanceInputs({
358-
kind: kind(createdResource),
359-
quantity: createdResource.quantity,
360-
consumed: false,
361-
valueCommitmentRandomness: params.valueCommitmentRandomness[i][1]
362-
})
363-
)
364-
);
365-
// Create the compliance verifier input
366-
Compliance.Instance memory instance = Compliance.Instance({
367-
unitDeltaX: bytes32(unitDelta.x),
368-
unitDeltaY: bytes32(unitDelta.y),
369-
consumed: Compliance.ConsumedRefs({
370-
nullifier: nf,
371-
logicRef: consumedResource.logicRef,
372-
commitmentTreeRoot: initialRoot()
373-
}),
374-
created: Compliance.CreatedRefs({
375-
commitment: cm,
376-
logicRef: createdResource.logicRef
377-
})
378-
});
379-
action.complianceVerifierInputs[i] = Compliance.VerifierInput({
380-
instance: instance,
381-
proof: _mockVerifier.mockProve({imageId: Compliance._VERIFYING_KEY, journalDigest: sha256(instance.toJournal())}).seal
382-
});
383-
}
384-
}
385-
386-
struct TransactionParams {
387-
ActionParams[MAX_ACTIONS] actionParams;
388-
uint256 targetActionsLen;
389-
}
390-
391-
function generateTransaction(TransactionParams memory params) public returns (Transaction memory txn) {
392-
// Generate actions
393-
Action[] memory actions = new Action[](params.targetActionsLen % MAX_ACTIONS);
394-
uint256 totalValueCommitmentRandomness = 0;
395-
for (uint256 i = 0; i < actions.length; i++) {
396-
uint256 valueCommitmentRandomness;
397-
(actions[i], valueCommitmentRandomness) = generateAction(params.actionParams[i]);
398-
totalValueCommitmentRandomness = addmod(totalValueCommitmentRandomness, valueCommitmentRandomness, SECP256K1_ORDER);
399-
}
400-
// Generate delta proof
401-
bytes memory proof = "";
402-
bytes32[] memory tags = TxGen.collectTags(actions);
403-
if (tags.length != 0) {
404-
proof = DeltaGen.generateProof(
405-
vm,
406-
DeltaGen.ProofInputs({
407-
valueCommitmentRandomness: totalValueCommitmentRandomness,
408-
verifyingKey: Delta.computeVerifyingKey(tags)
409-
})
410-
);
411-
}
412-
// Generate transaction
413-
txn = Transaction({
414-
actions: actions,
415-
deltaProof: proof,
416-
aggregationProof: ""
417-
});
418-
}
419-
420-
function test_random_transactions_execute(TransactionParams memory params) public {
421-
_mockPa.execute(generateTransaction(params));
222+
function test_random_transactions_execute(TxGen.TransactionParams memory params) public {
223+
_mockPa.execute(vm.generateTransaction(_mockVerifier, params));
422224
}
423225

424226
function test_execute_reverts_on_pre_existing_nullifier() public {

contracts/test/libs/TxGen.sol

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,4 +391,186 @@ library TxGen {
391391
function initialRoot() internal pure returns (bytes32 root) {
392392
root = SHA256.EMPTY_HASH;
393393
}
394+
395+
uint256 public constant MAX_ACTIONS = 4;
396+
uint256 public constant MAX_RESOURCES = 5;
397+
398+
struct ActionParams {
399+
Resource[2][MAX_RESOURCES] resources;
400+
uint256[MAX_RESOURCES] bijection;
401+
uint256 targetResourcesLen;
402+
uint256[2][MAX_RESOURCES] valueCommitmentRandomness;
403+
}
404+
405+
function truncateResources(Resource[2][MAX_RESOURCES] memory resources, uint256 len) public pure returns (Resource[2][] memory truncatedResources) {
406+
truncatedResources = new Resource[2][](len);
407+
for (uint256 i = 0; i < len; i++) {
408+
truncatedResources[i][0] = resources[i][0];
409+
truncatedResources[i][1] = resources[i][1];
410+
}
411+
}
412+
413+
function generateBijection(uint256[MAX_RESOURCES] memory input, uint256 len) public pure returns (uint256[] memory output) {
414+
output = new uint256[](len);
415+
uint256[] memory duplicates = new uint256[](len);
416+
uint256 duplicateCount = 0;
417+
for (uint i = 0; i < len; i++) {
418+
output[i] = duplicates[i] = len;
419+
input[i] %= len;
420+
}
421+
for (uint i = 0; i < len; i++) {
422+
if (output[input[i]] == len) {
423+
output[input[i]] = i;
424+
} else {
425+
duplicates[duplicateCount++] = i;
426+
}
427+
}
428+
duplicateCount = 0;
429+
for (uint i = 0; i < len; i++) {
430+
if (output[i] == len) {
431+
output[i] = duplicates[duplicateCount++];
432+
}
433+
}
434+
}
435+
436+
function generateAction(VmSafe vm, RiscZeroMockVerifier mockVerifier, ActionParams memory params) public returns (Action memory action, uint256 totalValueCommitmentRandomness) {
437+
Resource[2][] memory truncatedResources = truncateResources(params.resources, params.targetResourcesLen % MAX_RESOURCES);
438+
action.logicVerifierInputs = new Logic.VerifierInput[](truncatedResources.length * 2);
439+
action.complianceVerifierInputs = new Compliance.VerifierInput[](truncatedResources.length);
440+
// Created empty app data for all the resources
441+
Logic.AppData memory appData = Logic.AppData({
442+
resourcePayload: new Logic.ExpirableBlob[](0),
443+
discoveryPayload: new Logic.ExpirableBlob[](0),
444+
externalPayload: new Logic.ExpirableBlob[](0),
445+
applicationPayload: new Logic.ExpirableBlob[](0)
446+
});
447+
// Match the created and consumed resources
448+
uint256[] memory bijection = generateBijection(params.bijection, truncatedResources.length);
449+
for (uint256 i = 0; i < truncatedResources.length; ++i) {
450+
truncatedResources[bijection[i]][1].quantity = truncatedResources[i][0].quantity;
451+
truncatedResources[bijection[i]][1].logicRef = truncatedResources[i][0].logicRef;
452+
truncatedResources[bijection[i]][1].labelRef = truncatedResources[i][0].labelRef;
453+
}
454+
// Compute action tree tags and action tree root
455+
bytes32[] memory actionTreeTags = new bytes32[](2 * truncatedResources.length);
456+
totalValueCommitmentRandomness = 0;
457+
for (uint256 i = 0; i < truncatedResources.length; ++i) {
458+
uint256 index = (i * 2);
459+
460+
actionTreeTags[index] = nullifier(truncatedResources[i][0], 0);
461+
actionTreeTags[index + 1] = commitment(truncatedResources[i][1]);
462+
// Adjust and accumulate the value randomness commitments
463+
params.valueCommitmentRandomness[i][0] = 1 + (params.valueCommitmentRandomness[i][0] % (DeltaGen.SECP256K1_ORDER-1));
464+
params.valueCommitmentRandomness[i][1] = 1 + (params.valueCommitmentRandomness[i][1] % (DeltaGen.SECP256K1_ORDER-1));
465+
totalValueCommitmentRandomness = addmod(totalValueCommitmentRandomness, params.valueCommitmentRandomness[i][0], DeltaGen.SECP256K1_ORDER);
466+
totalValueCommitmentRandomness = addmod(totalValueCommitmentRandomness, params.valueCommitmentRandomness[i][1], DeltaGen.SECP256K1_ORDER);
467+
}
468+
bytes32 actionTreeRoot = actionTreeTags.computeRoot();
469+
// Create logic and compliance verifier inputs
470+
for (uint256 i = 0; i < truncatedResources.length; i++) {
471+
Resource memory consumedResource = truncatedResources[i][0];
472+
Resource memory createdResource = truncatedResources[i][1];
473+
bytes32 nf = nullifier(consumedResource, 0);
474+
bytes32 cm = commitment(createdResource);
475+
476+
// Created logic verifier input for a consumed resource
477+
action.logicVerifierInputs[2*i] = Logic.VerifierInput({
478+
tag: nf,
479+
verifyingKey: consumedResource.logicRef,
480+
proof: "",
481+
appData: appData
482+
});
483+
action.logicVerifierInputs[2*i].proof = mockVerifier.mockProve({
484+
imageId: consumedResource.logicRef,
485+
journalDigest: sha256(action.logicVerifierInputs[2*i].toJournal(actionTreeRoot, true))
486+
}).seal;
487+
// Create logic verifier input for a created resource
488+
action.logicVerifierInputs[2*i + 1] = Logic.VerifierInput({
489+
tag: cm,
490+
verifyingKey: createdResource.logicRef,
491+
proof: "",
492+
appData: appData
493+
});
494+
action.logicVerifierInputs[2*i + 1].proof = mockVerifier.mockProve({
495+
imageId: createdResource.logicRef,
496+
journalDigest: sha256(action.logicVerifierInputs[2*i + 1].toJournal(actionTreeRoot, false))
497+
}).seal;
498+
// Create the delta for the consumed resource
499+
Delta.CurvePoint memory unitDelta = DeltaGen.generateInstance(
500+
vm,
501+
DeltaGen.InstanceInputs({
502+
kind: kind(consumedResource),
503+
quantity: consumedResource.quantity,
504+
consumed: true,
505+
valueCommitmentRandomness: params.valueCommitmentRandomness[i][0]
506+
})
507+
);
508+
509+
// Add the delta for the created resource
510+
unitDelta = Delta.add(
511+
unitDelta,
512+
DeltaGen.generateInstance(
513+
vm,
514+
DeltaGen.InstanceInputs({
515+
kind: kind(createdResource),
516+
quantity: createdResource.quantity,
517+
consumed: false,
518+
valueCommitmentRandomness: params.valueCommitmentRandomness[i][1]
519+
})
520+
)
521+
);
522+
// Create the compliance verifier input
523+
Compliance.Instance memory instance = Compliance.Instance({
524+
unitDeltaX: bytes32(unitDelta.x),
525+
unitDeltaY: bytes32(unitDelta.y),
526+
consumed: Compliance.ConsumedRefs({
527+
nullifier: nf,
528+
logicRef: consumedResource.logicRef,
529+
commitmentTreeRoot: initialRoot()
530+
}),
531+
created: Compliance.CreatedRefs({
532+
commitment: cm,
533+
logicRef: createdResource.logicRef
534+
})
535+
});
536+
action.complianceVerifierInputs[i] = Compliance.VerifierInput({
537+
instance: instance,
538+
proof: mockVerifier.mockProve({imageId: Compliance._VERIFYING_KEY, journalDigest: sha256(instance.toJournal())}).seal
539+
});
540+
}
541+
}
542+
543+
struct TransactionParams {
544+
ActionParams[MAX_ACTIONS] actionParams;
545+
uint256 targetActionsLen;
546+
}
547+
548+
function generateTransaction(VmSafe vm, RiscZeroMockVerifier mockVerifier, TransactionParams memory params) public returns (Transaction memory txn) {
549+
// Generate actions
550+
Action[] memory actions = new Action[](params.targetActionsLen % MAX_ACTIONS);
551+
uint256 totalValueCommitmentRandomness = 0;
552+
for (uint256 i = 0; i < actions.length; i++) {
553+
uint256 valueCommitmentRandomness;
554+
(actions[i], valueCommitmentRandomness) = generateAction(vm, mockVerifier, params.actionParams[i]);
555+
totalValueCommitmentRandomness = addmod(totalValueCommitmentRandomness, valueCommitmentRandomness, DeltaGen.SECP256K1_ORDER);
556+
}
557+
// Generate delta proof
558+
bytes memory proof = "";
559+
bytes32[] memory tags = TxGen.collectTags(actions);
560+
if (tags.length != 0) {
561+
proof = DeltaGen.generateProof(
562+
vm,
563+
DeltaGen.ProofInputs({
564+
valueCommitmentRandomness: totalValueCommitmentRandomness,
565+
verifyingKey: Delta.computeVerifyingKey(tags)
566+
})
567+
);
568+
}
569+
// Generate transaction
570+
txn = Transaction({
571+
actions: actions,
572+
deltaProof: proof,
573+
aggregationProof: ""
574+
});
575+
}
394576
}

0 commit comments

Comments
 (0)