11import type { CompiledCircuit } from "@noir-lang/noir_js" ;
22import { ethers } from "ethers" ;
3- import { range } from "lodash" ;
3+ import { omit , range } from "lodash" ;
44import fs from "node:fs" ;
55import path from "node:path" ;
66import { assert } from "ts-essentials" ;
77import { z } from "zod" ;
8+ import { promiseWithResolvers } from "../utils.js" ;
89import { inWorkingDir , makeRunCommand } from "./utils.js" ;
910
11+ export type OrderId = string & { __brand : "OrderId" } ;
12+ export type PartyIndex = 0 | 1 | 2 ;
13+ export type Side = "seller" | "buyer" ;
14+
15+ type Order = {
16+ side : Side ;
17+ id : OrderId ;
18+ inputShared : string ;
19+ result : ReturnType < typeof promiseWithResolvers < string > > ;
20+ } ;
21+
1022export class MpcProverService {
23+ // TODO: split this service into per party service to manage storage easier
24+ #storage: Record < PartyIndex , Map < OrderId , Order > > = {
25+ 0 : new Map ( ) ,
26+ 1 : new Map ( ) ,
27+ 2 : new Map ( ) ,
28+ } ;
29+ async requestProveAsParty ( params : {
30+ orderId : OrderId ;
31+ side : Side ;
32+ partyIndex : PartyIndex ;
33+ inputShared : string ;
34+ circuit : CompiledCircuit ;
35+ // TODO: infer number of public inputs
36+ numPublicInputs : number ;
37+ } ) {
38+ // TODO(security): authorization
39+ if ( this . #storage[ params . partyIndex ] . has ( params . orderId ) ) {
40+ throw new Error ( `order already exists ${ params . orderId } ` ) ;
41+ }
42+ const order : Order = {
43+ id : params . orderId ,
44+ inputShared : params . inputShared ,
45+ side : params . side ,
46+ result : promiseWithResolvers ( ) ,
47+ } ;
48+ this . #storage[ params . partyIndex ] . set ( params . orderId , order ) ;
49+
50+ this . #tryExecuteOrder( params . orderId , {
51+ partyIndex : params . partyIndex ,
52+ circuit : params . circuit ,
53+ numPublicInputs : params . numPublicInputs ,
54+ } ) ;
55+
56+ return await order . result . promise ;
57+ }
58+
59+ async #tryExecuteOrder(
60+ orderId : OrderId ,
61+
62+ params : {
63+ partyIndex : PartyIndex ;
64+ circuit : CompiledCircuit ;
65+ numPublicInputs : number ;
66+ } ,
67+ ) {
68+ const order = this . #storage[ params . partyIndex ] . get ( orderId ) ;
69+ if ( ! order ) {
70+ throw new Error (
71+ `order not found in party storage ${ params . partyIndex } : ${ orderId } ` ,
72+ ) ;
73+ }
74+
75+ const otherOrders = Array . from (
76+ this . #storage[ params . partyIndex ] . values ( ) ,
77+ ) . filter ( ( o ) => o . id !== order . id && o . side !== order . side ) ;
78+ if ( otherOrders . length === 0 ) {
79+ return ;
80+ }
81+ const otherOrder = otherOrders [ 0 ] ! ;
82+ const inputsShared =
83+ order . side === "seller"
84+ ? ( [ order . inputShared , otherOrder . inputShared ] as const )
85+ : ( [ otherOrder . inputShared , order . inputShared ] as const ) ;
86+ console . log (
87+ "executing orders" ,
88+ params . partyIndex ,
89+ omit ( order , "inputShared" ) ,
90+ omit ( otherOrder , "inputShared" ) ,
91+ ) ;
92+ try {
93+ const { proof } = await this . proveAsParty ( {
94+ partyIndex : params . partyIndex ,
95+ circuit : params . circuit ,
96+ input0Shared : inputsShared [ 0 ] ,
97+ input1Shared : inputsShared [ 1 ] ,
98+ numPublicInputs : params . numPublicInputs ,
99+ } ) ;
100+ console . log ( "got proof" , orderId , params . partyIndex , proof . length ) ;
101+ const proofHex = ethers . hexlify ( proof ) ;
102+ order . result . resolve ( proofHex ) ;
103+ otherOrder . result . resolve ( proofHex ) ;
104+ } catch ( error ) {
105+ order . result . reject ( error ) ;
106+ otherOrder . result . reject ( error ) ;
107+ }
108+ }
109+
11110 async proveAsParty ( params : {
12111 partyIndex : number ;
13112 circuit : CompiledCircuit ;
@@ -16,6 +115,7 @@ export class MpcProverService {
16115 // TODO: infer number of public inputs
17116 numPublicInputs : number ;
18117 } ) {
118+ console . log ( "proving as party" , params . partyIndex ) ;
19119 return await inWorkingDir ( async ( workingDir ) => {
20120 for ( const [ traderIndex , inputShared ] of [
21121 params . input0Shared ,
0 commit comments