From 0a2d518edad22efe4fb7506503eb6b663ce3cef0 Mon Sep 17 00:00:00 2001 From: ognjenkurtic Date: Sun, 23 Jun 2024 22:02:55 +0200 Subject: [PATCH 1/8] Remove unnecessary params from prepareInputs call in circuitService interface --- .../transactions/agents/transactions.agent.ts | 2 +- .../circuit/circuitService.interface.ts | 3 ++- .../circuit/snarkjs/snarkjs.service.spec.ts | 15 ++++-------- .../circuit/snarkjs/snarkjs.service.ts | 23 ++++++------------- 4 files changed, 14 insertions(+), 29 deletions(-) diff --git a/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts b/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts index f70efccc9..5f6ccc72f 100644 --- a/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts +++ b/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts @@ -195,7 +195,7 @@ export class TransactionAgent { } = this.constructCircuitPathsFromWorkstepName(workstep.name); txResult.witness = await this.circuitService.createWitness( - { tx, merkelizedPayload }, + tx, snakeCaseWorkstepName, circuitPath, circuitProvingKeyPath, diff --git a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitService.interface.ts b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitService.interface.ts index 6eb3b4446..93c85bfce 100644 --- a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitService.interface.ts +++ b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitService.interface.ts @@ -1,8 +1,9 @@ import { Witness } from '../../models/witness'; +import { Transaction } from '../../../transactions/models/transaction'; export interface ICircuitService { createWitness( - inputs: object, + tx: Transaction, circuitName: string, pathToCircuit: string, pathToProvingKey: string, diff --git a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.spec.ts b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.spec.ts index d0fe6a374..4711c893f 100644 --- a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.spec.ts +++ b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.spec.ts @@ -18,17 +18,12 @@ import { } from '../../../../identity/bpiSubjects/models/publicKey'; jest.setTimeout(20000); +//NOTE: Skiping out the workstep1 as it requires compiled artifacts to run. describe.skip('SnarkjsService', () => { const snarkjs = new SnarkjsCircuitService(); - let inputs: any; + let tx: Transaction; let witness: Witness; - //REMOVE THIS TEST: Empty test - it('this is empty test', () => { - expect('test').toBe('test'); - }); - - //NOTE: Commenting out the workstep1 as it requires compiled artifacts to run. RUN THIS. beforeAll(async () => { const eddsa = await circomlib.buildEddsa(); const babyJub = await circomlib.buildBabyjub(); @@ -112,7 +107,7 @@ describe.skip('SnarkjsService', () => { const packedSignature = eddsa.packSignature(eddsaSignature); const signature = Buffer.from(packedSignature).toString('hex'); - const tx: Transaction = new Transaction( + tx = new Transaction( '123', 12, '123', @@ -123,8 +118,6 @@ describe.skip('SnarkjsService', () => { signature, TransactionStatus.Initialized, ); - - inputs = { tx }; }); it('creates witness for workstep1', async () => { @@ -141,7 +134,7 @@ describe.skip('SnarkjsService', () => { './zeroKnowledgeArtifacts/circuits/workstep1/witness.txt'; witness = await snarkjs.createWitness( - inputs, + tx, circuitName, pathToCircuit, pathToProvingKey, diff --git a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.ts b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.ts index 549c6f3be..3337c6b1e 100644 --- a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.ts +++ b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.ts @@ -21,10 +21,7 @@ export class SnarkjsCircuitService implements ICircuitService { } public async createWitness( - inputs: { - tx: Transaction; - merkelizedPayload: MerkleTree; - }, + tx: Transaction, circuitName: string, pathToCircuit: string, pathToProvingKey: string, @@ -34,7 +31,7 @@ export class SnarkjsCircuitService implements ICircuitService { ): Promise { this.witness = new Witness(); - const preparedInputs = await this.prepareInputs(inputs, circuitName); + const preparedInputs = await this.prepareInputs(tx, circuitName); const { proof, publicInputs } = await this.executeCircuit( preparedInputs, @@ -102,25 +99,19 @@ export class SnarkjsCircuitService implements ICircuitService { } private async prepareInputs( - inputs: { - tx: Transaction; - merkelizedPayload: MerkleTree; - }, + tx: Transaction, circuitName: string, ): Promise { - return await this[circuitName](inputs); + return await this[circuitName](tx); } // TODO: Mil5 - How to parametrize this for different use-cases? - private async workstep1(inputs: { - tx: Transaction; - merkelizedPayload: MerkleTree; - }): Promise { + private async workstep1(tx: Transaction): Promise { //1. Ecdsa signature - const { message, A, R8, S } = await computeEddsaSigPublicInputs(inputs.tx); + const { message, A, R8, S } = await computeEddsaSigPublicInputs(tx); //2. Items - const payload = JSON.parse(inputs.tx.payload); + const payload = JSON.parse(tx.payload); const itemPrices: number[] = []; const itemAmount: number[] = []; From 95bcae33ca45ed99c01987f2b83f840d2700bc4b Mon Sep 17 00:00:00 2001 From: ognjenkurtic Date: Sun, 23 Jun 2024 22:20:12 +0200 Subject: [PATCH 2/8] MOve prepareInputs to transaction agent level as preparation for refactor --- .../transactions/agents/transactions.agent.ts | 57 +++++++++++++++++-- .../circuit/circuitService.interface.ts | 4 +- .../circuit/snarkjs/snarkjs.service.spec.ts | 3 +- .../circuit/snarkjs/snarkjs.service.ts | 54 +----------------- 4 files changed, 58 insertions(+), 60 deletions(-) diff --git a/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts b/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts index 5f6ccc72f..269fd04a6 100644 --- a/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts +++ b/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts @@ -9,19 +9,20 @@ import { TransactionStatus } from '../models/transactionStatus.enum'; import { AuthAgent } from '../../auth/agent/auth.agent'; import { BpiSubjectAccount } from '../../identity/bpiSubjectAccounts/models/bpiSubjectAccount'; +import { PublicKeyType } from '../../identity/bpiSubjects/models/publicKey'; import { MerkleTreeService } from '../../merkleTree/services/merkleTree.service'; import { WorkflowStorageAgent } from '../../workgroup/workflows/agents/workflowsStorage.agent'; import { WorkstepStorageAgent } from '../../workgroup/worksteps/agents/workstepsStorage.agent'; import { Workstep } from '../../workgroup/worksteps/models/workstep'; import { ICircuitService } from '../../zeroKnowledgeProof/services/circuit/circuitService.interface'; +import { computeEddsaSigPublicInputs } from '../../zeroKnowledgeProof/services/circuit/snarkjs/utils/computePublicInputs'; import { DELETE_WRONG_STATUS_ERR_MESSAGE, NOT_FOUND_ERR_MESSAGE, UPDATE_WRONG_STATUS_ERR_MESSAGE, } from '../api/err.messages'; -import { TransactionStorageAgent } from './transactionStorage.agent'; import { TransactionResult } from '../models/transactionResult'; -import { PublicKeyType } from '../../identity/bpiSubjects/models/publicKey'; +import { TransactionStorageAgent } from './transactionStorage.agent'; @Injectable() export class TransactionAgent { @@ -194,9 +195,10 @@ export class TransactionAgent { circuitWitnessFilePath, } = this.constructCircuitPathsFromWorkstepName(workstep.name); + const circuitInputs = await this.prepareInputs(tx, snakeCaseWorkstepName); + txResult.witness = await this.circuitService.createWitness( - tx, - snakeCaseWorkstepName, + circuitInputs, circuitPath, circuitProvingKeyPath, circuitVerificatioKeyPath, @@ -299,4 +301,51 @@ export class TransactionAgent { return name; } + + private async prepareInputs( + tx: Transaction, + circuitName: string, + ): Promise { + return await this[circuitName](tx); + } + + // TODO: Mil5 - How to parametrize this for different use-cases? + private async workstep1(tx: Transaction): Promise { + //1. Ecdsa signature + const { message, A, R8, S } = await computeEddsaSigPublicInputs(tx); + + //2. Items + const payload = JSON.parse(tx.payload); + + const itemPrices: number[] = []; + const itemAmount: number[] = []; + + payload.items.forEach((item: object) => { + itemPrices.push(item['price']); + itemAmount.push(item['amount']); + }); + + const preparedInputs = { + invoiceStatus: this.calculateStringCharCodeSum(payload.status), + invoiceAmount: payload.amount, + itemPrices, + itemAmount, + message, + A, + R8, + S, + }; + + return preparedInputs; + } + + private calculateStringCharCodeSum(status: string): number { + let sum = 0; + + for (let i = 0; i < status.length; i++) { + sum += status.charCodeAt(i); + } + + return sum; + } } diff --git a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitService.interface.ts b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitService.interface.ts index 93c85bfce..b202280f4 100644 --- a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitService.interface.ts +++ b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitService.interface.ts @@ -3,13 +3,13 @@ import { Transaction } from '../../../transactions/models/transaction'; export interface ICircuitService { createWitness( - tx: Transaction, - circuitName: string, + circuitInputs: object, pathToCircuit: string, pathToProvingKey: string, pathToVerificationKey: string, pathToWitnessCalculator?: string, pathToWitnessFile?: string, ): Promise; + verifyProofUsingWitness(witness: Witness): Promise; } diff --git a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.spec.ts b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.spec.ts index 4711c893f..21d41aad6 100644 --- a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.spec.ts +++ b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.spec.ts @@ -134,8 +134,7 @@ describe.skip('SnarkjsService', () => { './zeroKnowledgeArtifacts/circuits/workstep1/witness.txt'; witness = await snarkjs.createWitness( - tx, - circuitName, + 'TODO: circuitInputs' as unknown as object, pathToCircuit, pathToProvingKey, pathToVerificationKey, diff --git a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.ts b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.ts index 3337c6b1e..dcad8c063 100644 --- a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.ts +++ b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.ts @@ -21,8 +21,7 @@ export class SnarkjsCircuitService implements ICircuitService { } public async createWitness( - tx: Transaction, - circuitName: string, + circuitInputs: object, pathToCircuit: string, pathToProvingKey: string, pathToVerificationKey: string, @@ -31,10 +30,8 @@ export class SnarkjsCircuitService implements ICircuitService { ): Promise { this.witness = new Witness(); - const preparedInputs = await this.prepareInputs(tx, circuitName); - const { proof, publicInputs } = await this.executeCircuit( - preparedInputs, + circuitInputs, pathToCircuit, pathToProvingKey, pathToWitnessCalculator, @@ -98,43 +95,6 @@ export class SnarkjsCircuitService implements ICircuitService { return { proof: newProof, publicInputs }; } - private async prepareInputs( - tx: Transaction, - circuitName: string, - ): Promise { - return await this[circuitName](tx); - } - - // TODO: Mil5 - How to parametrize this for different use-cases? - private async workstep1(tx: Transaction): Promise { - //1. Ecdsa signature - const { message, A, R8, S } = await computeEddsaSigPublicInputs(tx); - - //2. Items - const payload = JSON.parse(tx.payload); - - const itemPrices: number[] = []; - const itemAmount: number[] = []; - - payload.items.forEach((item: object) => { - itemPrices.push(item['price']); - itemAmount.push(item['amount']); - }); - - const preparedInputs = { - invoiceStatus: this.calculateStringCharCodeSum(payload.status), - invoiceAmount: payload.amount, - itemPrices, - itemAmount, - message, - A, - R8, - S, - }; - - return preparedInputs; - } - private async workstep2(inputs: { tx: Transaction; merkelizedPayload: MerkleTree; @@ -174,14 +134,4 @@ export class SnarkjsCircuitService implements ICircuitService { return preparedInputs; } - - private calculateStringCharCodeSum(status: string): number { - let sum = 0; - - for (let i = 0; i < status.length; i++) { - sum += status.charCodeAt(i); - } - - return sum; - } } From 549e7c6e5e2e569b294d0e04f75777355ef4b865 Mon Sep 17 00:00:00 2001 From: ognjenkurtic Date: Tue, 25 Jun 2024 16:23:25 +0200 Subject: [PATCH 3/8] Refactor circuit input preparation to split public and payload inputs --- .../transactions/agents/transactions.agent.ts | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts b/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts index 269fd04a6..fc7dd2f19 100644 --- a/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts +++ b/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts @@ -195,7 +195,8 @@ export class TransactionAgent { circuitWitnessFilePath, } = this.constructCircuitPathsFromWorkstepName(workstep.name); - const circuitInputs = await this.prepareInputs(tx, snakeCaseWorkstepName); + const payloadAsCircuitInputs = await this.preparePayloadAsCircuitInputs(tx, snakeCaseWorkstepName); + const circuitInputs = Object.assign(payloadAsCircuitInputs, await computeEddsaSigPublicInputs(tx)); txResult.witness = await this.circuitService.createWitness( circuitInputs, @@ -302,7 +303,7 @@ export class TransactionAgent { return name; } - private async prepareInputs( + private async preparePayloadAsCircuitInputs( tx: Transaction, circuitName: string, ): Promise { @@ -311,10 +312,7 @@ export class TransactionAgent { // TODO: Mil5 - How to parametrize this for different use-cases? private async workstep1(tx: Transaction): Promise { - //1. Ecdsa signature - const { message, A, R8, S } = await computeEddsaSigPublicInputs(tx); - - //2. Items + //2. TODO: Use circuit inputs parser const payload = JSON.parse(tx.payload); const itemPrices: number[] = []; @@ -329,11 +327,7 @@ export class TransactionAgent { invoiceStatus: this.calculateStringCharCodeSum(payload.status), invoiceAmount: payload.amount, itemPrices, - itemAmount, - message, - A, - R8, - S, + itemAmount }; return preparedInputs; From 9ff966812e01cd7abc87e82ac81375824f62eec7 Mon Sep 17 00:00:00 2001 From: ognjenkurtic Date: Tue, 25 Jun 2024 16:36:52 +0200 Subject: [PATCH 4/8] Use circuitInputsParserService in tx agent to prep inputs WIP --- .../transactions/agents/transactions.agent.ts | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts b/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts index fc7dd2f19..ae00aa9aa 100644 --- a/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts +++ b/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts @@ -2,7 +2,7 @@ import { BadRequestException, Inject, Injectable, - NotFoundException, + NotFoundException } from '@nestjs/common'; import { Transaction } from '../models/transaction'; import { TransactionStatus } from '../models/transactionStatus.enum'; @@ -14,12 +14,13 @@ import { MerkleTreeService } from '../../merkleTree/services/merkleTree.service' import { WorkflowStorageAgent } from '../../workgroup/workflows/agents/workflowsStorage.agent'; import { WorkstepStorageAgent } from '../../workgroup/worksteps/agents/workstepsStorage.agent'; import { Workstep } from '../../workgroup/worksteps/models/workstep'; +import { CircuitInputsParserService } from '../../zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service'; import { ICircuitService } from '../../zeroKnowledgeProof/services/circuit/circuitService.interface'; import { computeEddsaSigPublicInputs } from '../../zeroKnowledgeProof/services/circuit/snarkjs/utils/computePublicInputs'; import { DELETE_WRONG_STATUS_ERR_MESSAGE, NOT_FOUND_ERR_MESSAGE, - UPDATE_WRONG_STATUS_ERR_MESSAGE, + UPDATE_WRONG_STATUS_ERR_MESSAGE } from '../api/err.messages'; import { TransactionResult } from '../models/transactionResult'; import { TransactionStorageAgent } from './transactionStorage.agent'; @@ -34,6 +35,7 @@ export class TransactionAgent { private merkleTreeService: MerkleTreeService, @Inject('ICircuitService') private readonly circuitService: ICircuitService, + private circuitInputsParserService: CircuitInputsParserService ) {} public throwIfCreateTransactionInputInvalid() { @@ -186,8 +188,10 @@ export class TransactionAgent { ); txResult.merkelizedPayload = merkelizedPayload; + const payloadAsCircuitInputs = await this.preparePayloadAsCircuitInputs(tx.payload, workstep.circuitInputsTranslationSchema); + const circuitInputs = Object.assign(payloadAsCircuitInputs, await computeEddsaSigPublicInputs(tx)); + const { - snakeCaseWorkstepName, circuitProvingKeyPath, circuitVerificatioKeyPath, circuitPath, @@ -195,9 +199,6 @@ export class TransactionAgent { circuitWitnessFilePath, } = this.constructCircuitPathsFromWorkstepName(workstep.name); - const payloadAsCircuitInputs = await this.preparePayloadAsCircuitInputs(tx, snakeCaseWorkstepName); - const circuitInputs = Object.assign(payloadAsCircuitInputs, await computeEddsaSigPublicInputs(tx)); - txResult.witness = await this.circuitService.createWitness( circuitInputs, circuitPath, @@ -228,7 +229,6 @@ export class TransactionAgent { // Format is: /_. // Will be ditched completely as part of milestone 5. private constructCircuitPathsFromWorkstepName(name: string): { - snakeCaseWorkstepName: string; circuitProvingKeyPath: string; circuitVerificatioKeyPath: string; circuitPath: string; @@ -273,7 +273,6 @@ export class TransactionAgent { snakeCaseWorkstepName + '/witness.txt'; return { - snakeCaseWorkstepName, circuitProvingKeyPath, circuitVerificatioKeyPath, circuitPath, @@ -304,10 +303,22 @@ export class TransactionAgent { } private async preparePayloadAsCircuitInputs( - tx: Transaction, - circuitName: string, + txPayload: string, + workstepTranslationSchema: string, ): Promise { - return await this[circuitName](tx); + const mapping:CircuitInputsMapping = JSON.parse(workstepTranslationSchema); + + if (!mapping) { + throw new Error(`Broken mapping`); + } + + const parsedInputs = this.circuitInputsParserService.applyMappingToJSONPayload(txPayload, mapping); + if (!parsedInputs) { + throw new Error(`Failed to parse inputs`); + } + + return parsedInputs; + // return await this[circuitName](tx); } // TODO: Mil5 - How to parametrize this for different use-cases? From 8caaa4b9e608c607544d1f2b95cde6a462f0b71d Mon Sep 17 00:00:00 2001 From: ognjenkurtic Date: Thu, 27 Jun 2024 22:14:24 +0200 Subject: [PATCH 5/8] Introduce parsing of arrays of objects to cirucit input parser --- .../agents/transactions.agent.spec.ts | 44 ++++++------- .../transactions/agents/transactions.agent.ts | 26 +++++--- .../api/transactions.controller.spec.ts | 16 +++-- .../circuitInputParser.service.spec.ts | 62 +++++++++++++++++++ .../circuitInputParser.service.ts | 19 +++++- .../circuitInputsMapping.ts | 2 + 6 files changed, 133 insertions(+), 36 deletions(-) diff --git a/examples/bri-3/src/bri/transactions/agents/transactions.agent.spec.ts b/examples/bri-3/src/bri/transactions/agents/transactions.agent.spec.ts index 8565f199f..48f2b7870 100644 --- a/examples/bri-3/src/bri/transactions/agents/transactions.agent.spec.ts +++ b/examples/bri-3/src/bri/transactions/agents/transactions.agent.spec.ts @@ -1,35 +1,36 @@ -import { AuthAgent } from '../../auth/agent/auth.agent'; -import { BpiSubjectAccount as BpiSubjectAccountPrismaModel } from '../../identity/bpiSubjectAccounts/models/bpiSubjectAccount'; -import { WorkflowStorageAgent } from '../../workgroup/workflows/agents/workflowsStorage.agent'; -import { WorkstepStorageAgent } from '../../workgroup/worksteps/agents/workstepsStorage.agent'; -import { Transaction } from '../models/transaction'; -import { TransactionStatus } from '../models/transactionStatus.enum'; -import { TransactionStorageAgent } from './transactionStorage.agent'; -import { TransactionAgent } from './transactions.agent'; -import { MerkleTreeService } from '../../merkleTree/services/merkleTree.service'; +import { classes } from '@automapper/classes'; +import { AutomapperModule } from '@automapper/nestjs'; +import { NotFoundException } from '@nestjs/common'; +import { Test, TestingModule } from '@nestjs/testing'; import { + BpiAccount, BpiSubject, BpiSubjectAccount, + PrismaClient, + PublicKeyType, Workflow, Workgroup, Workstep, - BpiAccount, - PrismaClient, - PublicKeyType, } from '../../../../__mocks__/@prisma/client'; -import { Test, TestingModule } from '@nestjs/testing'; -import { SnarkjsCircuitService } from '../../zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service'; +import { AuthModule } from '../../../bri/auth/auth.module'; +import { LoggingModule } from '../../../shared/logging/logging.module'; import { PrismaMapper } from '../../../shared/prisma/prisma.mapper'; import { PrismaService } from '../../../shared/prisma/prisma.service'; +import { AuthAgent } from '../../auth/agent/auth.agent'; +import { BpiSubjectAccount as BpiSubjectAccountPrismaModel } from '../../identity/bpiSubjectAccounts/models/bpiSubjectAccount'; import { BpiSubjectStorageAgent } from '../../identity/bpiSubjects/agents/bpiSubjectsStorage.agent'; -import { LoggingModule } from '../../../shared/logging/logging.module'; -import { NotFoundException } from '@nestjs/common'; -import { NOT_FOUND_ERR_MESSAGE as WORKSTEP_NOT_FOUND_ERR_MESSAGE } from '../../workgroup/worksteps/api/err.messages'; +import { MerkleTreeService } from '../../merkleTree/services/merkleTree.service'; +import { WorkflowStorageAgent } from '../../workgroup/workflows/agents/workflowsStorage.agent'; import { NOT_FOUND_ERR_MESSAGE as WORKFLOW_NOT_FOUND_ERR_MESSAGE } from '../../workgroup/workflows/api/err.messages'; -import { AuthModule } from '../../../bri/auth/auth.module'; -import { AutomapperModule } from '@automapper/nestjs'; -import { classes } from '@automapper/classes'; -import { uuid } from 'uuidv4'; +import { WorkstepStorageAgent } from '../../workgroup/worksteps/agents/workstepsStorage.agent'; +import { NOT_FOUND_ERR_MESSAGE as WORKSTEP_NOT_FOUND_ERR_MESSAGE } from '../../workgroup/worksteps/api/err.messages'; +import { CircuitInputsParserService } from '../../zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service'; +import { SnarkjsCircuitService } from '../../zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service'; +import { ZeroKnowledgeProofModule } from '../../zeroKnowledgeProof/zeroKnowledgeProof.module'; +import { Transaction } from '../models/transaction'; +import { TransactionStatus } from '../models/transactionStatus.enum'; +import { TransactionAgent } from './transactions.agent'; +import { TransactionStorageAgent } from './transactionStorage.agent'; let agent: TransactionAgent; let authAgent: AuthAgent; @@ -66,6 +67,7 @@ beforeEach(async () => { provide: 'ICircuitService', useClass: SnarkjsCircuitService, }, + CircuitInputsParserService, ], }) .overrideProvider(PrismaService) diff --git a/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts b/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts index ae00aa9aa..ddefbbbe9 100644 --- a/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts +++ b/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts @@ -2,7 +2,7 @@ import { BadRequestException, Inject, Injectable, - NotFoundException + NotFoundException, } from '@nestjs/common'; import { Transaction } from '../models/transaction'; import { TransactionStatus } from '../models/transactionStatus.enum'; @@ -20,7 +20,7 @@ import { computeEddsaSigPublicInputs } from '../../zeroKnowledgeProof/services/c import { DELETE_WRONG_STATUS_ERR_MESSAGE, NOT_FOUND_ERR_MESSAGE, - UPDATE_WRONG_STATUS_ERR_MESSAGE + UPDATE_WRONG_STATUS_ERR_MESSAGE, } from '../api/err.messages'; import { TransactionResult } from '../models/transactionResult'; import { TransactionStorageAgent } from './transactionStorage.agent'; @@ -35,7 +35,7 @@ export class TransactionAgent { private merkleTreeService: MerkleTreeService, @Inject('ICircuitService') private readonly circuitService: ICircuitService, - private circuitInputsParserService: CircuitInputsParserService + private circuitInputsParserService: CircuitInputsParserService, ) {} public throwIfCreateTransactionInputInvalid() { @@ -188,8 +188,14 @@ export class TransactionAgent { ); txResult.merkelizedPayload = merkelizedPayload; - const payloadAsCircuitInputs = await this.preparePayloadAsCircuitInputs(tx.payload, workstep.circuitInputsTranslationSchema); - const circuitInputs = Object.assign(payloadAsCircuitInputs, await computeEddsaSigPublicInputs(tx)); + const payloadAsCircuitInputs = await this.preparePayloadAsCircuitInputs( + tx.payload, + workstep.circuitInputsTranslationSchema, + ); + const circuitInputs = Object.assign( + payloadAsCircuitInputs, + await computeEddsaSigPublicInputs(tx), + ); const { circuitProvingKeyPath, @@ -306,13 +312,17 @@ export class TransactionAgent { txPayload: string, workstepTranslationSchema: string, ): Promise { - const mapping:CircuitInputsMapping = JSON.parse(workstepTranslationSchema); + const mapping: CircuitInputsMapping = JSON.parse(workstepTranslationSchema); if (!mapping) { throw new Error(`Broken mapping`); } - const parsedInputs = this.circuitInputsParserService.applyMappingToJSONPayload(txPayload, mapping); + const parsedInputs = + this.circuitInputsParserService.applyMappingToJSONPayload( + txPayload, + mapping, + ); if (!parsedInputs) { throw new Error(`Failed to parse inputs`); } @@ -338,7 +348,7 @@ export class TransactionAgent { invoiceStatus: this.calculateStringCharCodeSum(payload.status), invoiceAmount: payload.amount, itemPrices, - itemAmount + itemAmount, }; return preparedInputs; diff --git a/examples/bri-3/src/bri/transactions/api/transactions.controller.spec.ts b/examples/bri-3/src/bri/transactions/api/transactions.controller.spec.ts index 01da6b495..8c48782bc 100644 --- a/examples/bri-3/src/bri/transactions/api/transactions.controller.spec.ts +++ b/examples/bri-3/src/bri/transactions/api/transactions.controller.spec.ts @@ -6,17 +6,24 @@ import { Test, TestingModule } from '@nestjs/testing'; import { DeepMockProxy, mockDeep } from 'jest-mock-extended'; import { validate as uuidValidate, version as uuidVersion } from 'uuid'; import { uuid } from 'uuidv4'; +import { LoggingModule } from '../../../shared/logging/logging.module'; import { AuthAgent } from '../../auth/agent/auth.agent'; import { BpiSubjectAccountAgent } from '../../identity/bpiSubjectAccounts/agents/bpiSubjectAccounts.agent'; import { BpiSubjectAccountStorageAgent } from '../../identity/bpiSubjectAccounts/agents/bpiSubjectAccountsStorage.agent'; import { BpiSubjectAccount } from '../../identity/bpiSubjectAccounts/models/bpiSubjectAccount'; import { BpiSubjectStorageAgent } from '../../identity/bpiSubjects/agents/bpiSubjectsStorage.agent'; import { BpiSubject } from '../../identity/bpiSubjects/models/bpiSubject'; +import { + PublicKey, + PublicKeyType, +} from '../../identity/bpiSubjects/models/publicKey'; +import { MerkleTreeService } from '../../merkleTree/services/merkleTree.service'; import { WorkflowStorageAgent } from '../../workgroup/workflows/agents/workflowsStorage.agent'; import { WorkstepStorageAgent } from '../../workgroup/worksteps/agents/workstepsStorage.agent'; +import { CircuitInputsParserService } from '../../zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service'; import { SnarkjsCircuitService } from '../../zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service'; -import { TransactionStorageAgent } from '../agents/transactionStorage.agent'; import { TransactionAgent } from '../agents/transactions.agent'; +import { TransactionStorageAgent } from '../agents/transactionStorage.agent'; import { CreateTransactionCommandHandler } from '../capabilities/createTransaction/createTransactionCommand.handler'; import { DeleteTransactionCommandHandler } from '../capabilities/deleteTransaction/deleteTransactionCommand.handler'; import { GetTransactionByIdQueryHandler } from '../capabilities/getTransactionById/getTransactionByIdQuery.handler'; @@ -28,11 +35,6 @@ import { CreateTransactionDto } from './dtos/request/createTransaction.dto'; import { UpdateTransactionDto } from './dtos/request/updateTransaction.dto'; import { NOT_FOUND_ERR_MESSAGE } from './err.messages'; import { TransactionController } from './transactions.controller'; -import { MerkleTreeService } from '../../merkleTree/services/merkleTree.service'; -import { - PublicKey, - PublicKeyType, -} from '../../identity/bpiSubjects/models/publicKey'; describe('TransactionController', () => { let controller: TransactionController; @@ -84,6 +86,7 @@ describe('TransactionController', () => { AutomapperModule.forRoot({ strategyInitializer: classes(), }), + LoggingModule, ], controllers: [TransactionController], providers: [ @@ -105,6 +108,7 @@ describe('TransactionController', () => { provide: 'ICircuitService', useClass: SnarkjsCircuitService, }, + CircuitInputsParserService, ], }) .overrideProvider(TransactionStorageAgent) diff --git a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service.spec.ts b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service.spec.ts index de452a9af..0490323c6 100644 --- a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service.spec.ts +++ b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service.spec.ts @@ -388,4 +388,66 @@ describe('CircuitInputsParserService', () => { // Assert expect(circuitInputs).toStrictEqual({ dascircuitinput: [387, 388, 389] }); }); + + it('Should generate a single circuit input param based on a object string property of an object array at root level', () => { + // Arrange + const payload = `{ + "supplierInvoiceIDs": [ + { "id": "INV123", "price" : 222 }, + { "id": "INV124", "price" : 223 }, + { "id": "INV125", "price" : 224 } + ] + }`; + + const schema = { + mapping: [ + { + circuitInput: 'dascircuitinput', + description: 'desc', + payloadJsonPath: 'supplierInvoiceIDs', + dataType: 'array', + arrayType: 'object', + arrayItemFieldName: 'id', + arrayItemFieldType: 'string', + } as CircuitInputMapping, + ], + } as CircuitInputsMapping; + + // Act + const circuitInputs = cips.applyMappingToJSONPayload(payload, schema); + + // Assert + expect(circuitInputs).toStrictEqual({ dascircuitinput: [387, 388, 389] }); + }); + + it('Should generate a single circuit input param based on a object integer property of an object array at root level', () => { + // Arrange + const payload = `{ + "supplierInvoiceIDs": [ + { "id": "1", "price" : 222 }, + { "id": "2", "price" : 223 }, + { "id": "3", "price" : 224 } + ] + }`; + + const schema = { + mapping: [ + { + circuitInput: 'dascircuitinput', + description: 'desc', + payloadJsonPath: 'supplierInvoiceIDs', + dataType: 'array', + arrayType: 'object', + arrayItemFieldName: 'price', + arrayItemFieldType: 'integer', + } as CircuitInputMapping, + ], + } as CircuitInputsMapping; + + // Act + const circuitInputs = cips.applyMappingToJSONPayload(payload, schema); + + // Assert + expect(circuitInputs).toStrictEqual({ dascircuitinput: [222, 223, 224] }); + }); }); diff --git a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service.ts b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service.ts index 63da30b5f..f226d4da0 100644 --- a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service.ts +++ b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service.ts @@ -94,7 +94,24 @@ export class CircuitInputsParserService { } if (mapping.arrayType === 'object') { - // TODO + if (mapping.arrayItemFieldName && mapping.arrayItemFieldType) { + result[mapping.circuitInput] = value + ? value.map((item) => { + const fieldValue = item[mapping.arrayItemFieldName!]; + if (mapping.arrayItemFieldType === 'integer') { + return parseInt(fieldValue, 10); + } else if (mapping.arrayItemFieldType === 'string') { + return this.calculateStringCharCodeSum(fieldValue); + } + return fieldValue; + }) + : mapping.defaultValue; + } else { + this.logger.logError( + `Missing arrayItemFieldName or arrayItemFieldType for object array mapping ${mapping.circuitInput}`, + ); + return null; + } } break; default: diff --git a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputsMapping.ts b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputsMapping.ts index ec0e1a510..1d9a50e35 100644 --- a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputsMapping.ts +++ b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputsMapping.ts @@ -9,4 +9,6 @@ type CircuitInputMapping = { dataType: string; defaultValue?: any; arrayType?: string; + arrayItemFieldName?: string; + arrayItemFieldType?: string; }; From 829ae4d51b1237fbc98a4b1d2eb084bfbb3eb3f9 Mon Sep 17 00:00:00 2001 From: ognjenkurtic Date: Thu, 27 Jun 2024 22:35:12 +0200 Subject: [PATCH 6/8] Extend the e2e test to use a mapping to translate tx payload into circuit inputs --- .../transactions/agents/transactions.agent.ts | 53 +++++++++---------- .../circuit/snarkjs/snarkjs.service.ts | 43 --------------- examples/bri-3/test/sriUseCase.e2e-spec.ts | 36 ++++++++++++- 3 files changed, 59 insertions(+), 73 deletions(-) diff --git a/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts b/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts index ddefbbbe9..4f221ff9d 100644 --- a/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts +++ b/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts @@ -328,39 +328,36 @@ export class TransactionAgent { } return parsedInputs; - // return await this[circuitName](tx); } +} +// TODO: Example input preparation for other workstep circuits from the example use-case, to be used +// to properly setup dynamic mappings and to delete afterwards +// private async workstep2(inputs: { +// tx: Transaction; +// merkelizedPayload: MerkleTree; +// }): Promise { +// //1. Eddsa signature - // TODO: Mil5 - How to parametrize this for different use-cases? - private async workstep1(tx: Transaction): Promise { - //2. TODO: Use circuit inputs parser - const payload = JSON.parse(tx.payload); +// const payload = JSON.parse(inputs.tx.payload); - const itemPrices: number[] = []; - const itemAmount: number[] = []; +// const preparedInputs = { +// invoiceStatus: payload.status, +// }; - payload.items.forEach((item: object) => { - itemPrices.push(item['price']); - itemAmount.push(item['amount']); - }); +// return preparedInputs; +// } - const preparedInputs = { - invoiceStatus: this.calculateStringCharCodeSum(payload.status), - invoiceAmount: payload.amount, - itemPrices, - itemAmount, - }; +// private async workstep3(inputs: { +// tx: Transaction; +// merkelizedPayload: MerkleTree; +// }): Promise { +// //1. Eddsa signature - return preparedInputs; - } +// const payload = JSON.parse(inputs.tx.payload); - private calculateStringCharCodeSum(status: string): number { - let sum = 0; +// const preparedInputs = { +// invoiceStatus: payload.status, +// }; - for (let i = 0; i < status.length; i++) { - sum += status.charCodeAt(i); - } - - return sum; - } -} +// return preparedInputs; +// } diff --git a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.ts b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.ts index dcad8c063..951acfd31 100644 --- a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.ts +++ b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/snarkjs/snarkjs.service.ts @@ -2,10 +2,7 @@ import { Injectable, BadRequestException } from '@nestjs/common'; import { Witness } from '../../../models/witness'; import { Proof } from '../../../models/proof'; import { ICircuitService } from '../circuitService.interface'; -import { computeEddsaSigPublicInputs } from './utils/computePublicInputs'; import * as snarkjs from 'snarkjs'; -import { Transaction } from '../../../../transactions/models/transaction'; -import MerkleTree from 'merkletreejs'; import * as fs from 'fs'; @Injectable() @@ -94,44 +91,4 @@ export class SnarkjsCircuitService implements ICircuitService { return { proof: newProof, publicInputs }; } - - private async workstep2(inputs: { - tx: Transaction; - merkelizedPayload: MerkleTree; - }): Promise { - //1. Eddsa signature - const { message, A, R8, S } = await computeEddsaSigPublicInputs(inputs.tx); - - const payload = JSON.parse(inputs.tx.payload); - - const preparedInputs = { - invoiceStatus: payload.status, - message, - A, - R8, - S, - }; - - return preparedInputs; - } - - private async workstep3(inputs: { - tx: Transaction; - merkelizedPayload: MerkleTree; - }): Promise { - //1. Eddsa signature - const { message, A, R8, S } = await computeEddsaSigPublicInputs(inputs.tx); - - const payload = JSON.parse(inputs.tx.payload); - - const preparedInputs = { - invoiceStatus: payload.status, - message, - A, - R8, - S, - }; - - return preparedInputs; - } } diff --git a/examples/bri-3/test/sriUseCase.e2e-spec.ts b/examples/bri-3/test/sriUseCase.e2e-spec.ts index a97e01505..c7cb13c84 100644 --- a/examples/bri-3/test/sriUseCase.e2e-spec.ts +++ b/examples/bri-3/test/sriUseCase.e2e-spec.ts @@ -141,8 +141,40 @@ describe('SRI use-case end-to-end test', () => { }); it('Add a circuit input translation schema to a workstep', async () => { - const schema = - '{"mapping": [{"circuitInput": "input1", "description": "desc1", "payloadJsonPath": "path1", "dataType": "string"}]}'; + const schema = `{ + "mapping": [ + { + "circuitInput": "invoiceStatus", + "description": "Invoice status", + "payloadJsonPath": "status", + "dataType": "string" + }, + { + "circuitInput": "invoiceAmount", + "description": "Total gross amount of the invoice", + "payloadJsonPath": "amount", + "dataType": "integer" + }, + { + "circuitInput": "itemPrices", + "description": "Invoice item prices", + "payloadJsonPath": "items", + "dataType": "array", + "arrayType": "object", + "arrayItemFieldName": "price", + "arrayItemFieldType": "integer" + }, + { + "circuitInput": "itemAmount", + "description": "Invoice item amounts", + "payloadJsonPath": "items", + "dataType": "array", + "arrayType": "object", + "arrayItemFieldName": "amount", + "arrayItemFieldType": "integer" + } + ] + }`; await addCircuitInputsSchema(createdWorkstepId, schema); }); From 04e4653394766296f651c0dde0ebe60771bc72c6 Mon Sep 17 00:00:00 2001 From: ognjenkurtic Date: Fri, 28 Jun 2024 22:33:24 +0200 Subject: [PATCH 7/8] Refactor trasaction agent executeTransaction method for better readability --- .../transactions/agents/transactions.agent.ts | 62 +++++++++++-------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts b/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts index 4f221ff9d..7bc3d78ee 100644 --- a/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts +++ b/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts @@ -7,6 +7,8 @@ import { import { Transaction } from '../models/transaction'; import { TransactionStatus } from '../models/transactionStatus.enum'; +import MerkleTree from 'merkletreejs'; +import { Witness } from 'src/bri/zeroKnowledgeProof/models/witness'; import { AuthAgent } from '../../auth/agent/auth.agent'; import { BpiSubjectAccount } from '../../identity/bpiSubjectAccounts/models/bpiSubjectAccount'; import { PublicKeyType } from '../../identity/bpiSubjects/models/publicKey'; @@ -182,20 +184,10 @@ export class TransactionAgent { ): Promise { const txResult = new TransactionResult(); - const merkelizedPayload = this.merkleTreeService.merkelizePayload( + txResult.merkelizedPayload = this.merkleTreeService.merkelizePayload( JSON.parse(tx.payload), `${process.env.MERKLE_TREE_HASH_ALGH}`, ); - txResult.merkelizedPayload = merkelizedPayload; - - const payloadAsCircuitInputs = await this.preparePayloadAsCircuitInputs( - tx.payload, - workstep.circuitInputsTranslationSchema, - ); - const circuitInputs = Object.assign( - payloadAsCircuitInputs, - await computeEddsaSigPublicInputs(tx), - ); const { circuitProvingKeyPath, @@ -206,7 +198,7 @@ export class TransactionAgent { } = this.constructCircuitPathsFromWorkstepName(workstep.name); txResult.witness = await this.circuitService.createWitness( - circuitInputs, + await this.prepareCircuitInputs(tx, workstep.circuitInputsTranslationSchema), circuitPath, circuitProvingKeyPath, circuitVerificatioKeyPath, @@ -214,17 +206,9 @@ export class TransactionAgent { circuitWitnessFilePath, ); - const hashFn = this.merkleTreeService.createHashFunction( - `${process.env.MERKLE_TREE_HASH_ALGH}`, - ); - - const merkelizedInvoiceRoot = merkelizedPayload.getRoot().toString('hex'); - const witnessHash = hashFn(JSON.stringify(txResult.witness)).toString( - 'hex', - ); - - txResult.hash = hashFn(`${merkelizedInvoiceRoot}${witnessHash}`).toString( - 'hex', + txResult.hash = this.constructTxHash( + txResult.merkelizedPayload, + txResult.witness, ); return txResult; @@ -287,10 +271,7 @@ export class TransactionAgent { }; } - // TODO: #744 ChatGPT generated only for the purposes of temporary convention - // to connect worksteps with circuits on the file system. private convertStringToSnakeCase(name: string): string { - // Remove any leading or trailing spaces name = name.trim(); // Replace spaces, hyphens, and underscores with a single underscore @@ -308,6 +289,21 @@ export class TransactionAgent { return name; } + private async prepareCircuitInputs( + tx: Transaction, + circuitInputsTranslationSchema: string, + ): Promise { + const payloadAsCircuitInputs = await this.preparePayloadAsCircuitInputs( + tx.payload, + circuitInputsTranslationSchema, + ); + + return Object.assign( + payloadAsCircuitInputs, + await computeEddsaSigPublicInputs(tx), + ); + } + private async preparePayloadAsCircuitInputs( txPayload: string, workstepTranslationSchema: string, @@ -329,6 +325,20 @@ export class TransactionAgent { return parsedInputs; } + + private constructTxHash( + merkelizedPayload: MerkleTree, + witness: Witness, + ): string { + const hashFn = this.merkleTreeService.createHashFunction( + `${process.env.MERKLE_TREE_HASH_ALGH}`, + ); + + const merkelizedInvoiceRoot = merkelizedPayload.getRoot().toString('hex'); + const witnessHash = hashFn(JSON.stringify(witness)).toString('hex'); + + return hashFn(`${merkelizedInvoiceRoot}${witnessHash}`).toString('hex'); + } } // TODO: Example input preparation for other workstep circuits from the example use-case, to be used // to properly setup dynamic mappings and to delete afterwards From 8c5465d94d4beab10a0f911718e80c9a226e8c58 Mon Sep 17 00:00:00 2001 From: ognjenkurtic Date: Fri, 28 Jun 2024 22:53:19 +0200 Subject: [PATCH 8/8] Fix formatting --- .../bri-3/src/bri/transactions/agents/transactions.agent.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts b/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts index 7bc3d78ee..e5bd34a54 100644 --- a/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts +++ b/examples/bri-3/src/bri/transactions/agents/transactions.agent.ts @@ -198,7 +198,10 @@ export class TransactionAgent { } = this.constructCircuitPathsFromWorkstepName(workstep.name); txResult.witness = await this.circuitService.createWitness( - await this.prepareCircuitInputs(tx, workstep.circuitInputsTranslationSchema), + await this.prepareCircuitInputs( + tx, + workstep.circuitInputsTranslationSchema, + ), circuitPath, circuitProvingKeyPath, circuitVerificatioKeyPath,