2023-04-08 19:17:52 +00:00
// crypto types
import * as Types from 'types/sdk/crypto'
// External crypto
import circomlib from 'circomlib'
2023-04-11 19:36:32 +00:00
import { bigInt } from 'snarkjs'
import { Groth16 } from 'websnark/src/groth16'
2023-04-08 19:17:52 +00:00
import { buildGroth16 } from 'websnark'
2023-04-11 19:36:32 +00:00
import { MerkleTree } from 'fixed-merkle-tree'
import { genWitnessAndProve , toSolidityInput } from 'websnark/src/utils'
2023-04-08 19:17:52 +00:00
// Some utils to work with hex numbers
import { HexUtils , NumberUtils } from 'lib/utils'
// Parse some files
import { Files } from 'lib/data'
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SETUP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/ * *
* Several objects have to be set up , like the groth16 prover . All related types are
* ( will be ) contained within this namespace .
* /
export namespace Setup {
2023-04-11 19:36:32 +00:00
export async function getProvingKey ( ) : Promise < ArrayBufferLike > {
2023-04-08 19:17:52 +00:00
return ( await Files . loadRaw ( 'circuits/tornadoProvingKey.bin' ) ) . buffer
}
2023-04-11 19:36:32 +00:00
export async function getTornadoCircuit ( ) : Promise < Buffer > {
2023-04-08 19:17:52 +00:00
return await Files . loadRaw ( 'circuits/tornado.json' )
}
2023-04-11 19:36:32 +00:00
/ * *
* @note The following is a comment from tornado - cli : ` groth16 initialises a lot of Promises that will never be resolved, that's why we need to use process.exit to terminate the CLI ` . They literally didn ' t check the code to see that these are just worker threads and that ` groth16 ` has a ` terminate() ` function to remove them . 🤦
* /
export async function getGroth16 ( ) : Promise < Groth16 > {
2023-04-08 19:17:52 +00:00
const defaultParams = { wasmInitialMemory : 5000 }
2023-04-11 19:36:32 +00:00
return await buildGroth16 ( defaultParams )
2023-04-08 19:17:52 +00:00
}
}
export namespace Primitives {
export function calcPedersenHash (
pedersenHashData : Types.InputFor.PedersenHash
) : Types . OutputOf . PedersenHash {
return circomlib . babyJub . unpackPoint ( circomlib . pedersenHash . hash ( pedersenHashData . msg ) ) [ 0 ]
}
export function createNote ( msg : Buffer ) : string {
return HexUtils . bufferToHex ( msg , 62 )
}
2023-04-11 19:36:32 +00:00
export function parseNote ( hexNote : string ) : Types . ZKDepositData {
const buffer = Buffer . from ( hexNote , 'hex' )
return createDeposit ( {
// @ts-expect-error
nullifier : bigInt.leBuff2int ( buffer . subarray ( 0 , 31 ) ) ,
// @ts-expect-error
secret : bigInt.leBuff2int ( buffer . subarray ( 32 , 62 ) )
} )
}
export function createDeposit ( input? : Types.InputFor.CreateDeposit ) : Types . ZKDepositData {
if ( ! input ? . nullifier || ! input ? . secret )
input = {
2023-04-08 19:17:52 +00:00
nullifier : NumberUtils.randomBigInteger ( 31 ) ,
secret : NumberUtils.randomBigInteger ( 31 )
}
2023-04-11 19:36:32 +00:00
// @ts-expect-error
2023-04-08 19:17:52 +00:00
let preimage = Buffer . concat ( [ depositData . nullifier . leInt2Buff ( 31 ) , depositData . secret . leInt2Buff ( 31 ) ] )
let commitment = calcPedersenHash ( { msg : preimage } )
let commitmentHex = HexUtils . bigIntToHex ( commitment )
2023-04-11 19:36:32 +00:00
// @ts-expect-error
2023-04-08 19:17:52 +00:00
let nullifierHash = calcPedersenHash ( { msg : depositData.nullifier.leInt2Buff ( 31 ) } )
let nullifierHex = HexUtils . bigIntToHex ( nullifierHash )
return {
2023-04-11 19:36:32 +00:00
nullifier : input.nullifier ! ,
secret : input.secret ! ,
2023-04-08 19:17:52 +00:00
preimage : preimage ,
commitment : commitment ,
2023-04-11 19:36:32 +00:00
hexCommitment : commitmentHex ,
2023-04-08 19:17:52 +00:00
nullifierHash : nullifierHash ,
2023-04-11 19:36:32 +00:00
hexNullifierHash : nullifierHex
2023-04-08 19:17:52 +00:00
}
}
2023-04-11 19:36:32 +00:00
export function buildMerkleTree ( inputs : Types.InputFor.BuildMerkleTree ) : MerkleTree {
return new MerkleTree ( inputs . height , inputs . leaves )
}
export async function calcDepositProofs ( inputs : Array < Types.InputFor.ZKProof > ) : Promise < Array < any > > {
const proofs : string [ ] [ ] = [ ]
const args : any [ ] [ ] = [ ]
const groth16 = await Setup . getGroth16 ( )
const circuit = await Setup . getTornadoCircuit ( )
const provingKey = await Setup . getProvingKey ( )
for ( let i = 0 , len = inputs . length ; i < len ; i ++ ) {
const input = inputs [ i ]
// Compute Merkle Proof
const { pathElements , pathIndex } = input . public . tree . path ( input . public . leafIndex )
args . push ( [ ] )
proofs . push ( [ ] )
const proofData = await genWitnessAndProve (
groth16 ,
{
// Public inputs
root : input.public.root ,
// @ts-ignore
nullifierHash : bigInt ( input . public . hexNullifierHash ) ,
// @ts-ignore
fee : bigInt ( input . public . fee ) ,
// @ts-ignore
refund : bigInt ( input . public . refund ) ,
// @ts-ignore
relayer : bigInt ( input . public . relayerAddress ) ,
// @ts-ignore
recipient : bigInt ( input . public . recipientAddress ) ,
// Private inputs
nullifier : input.private.nullifier ,
secret : input.private.secret ,
pathElements : pathElements ,
pathIndices : pathIndex
} ,
circuit ,
provingKey
)
proofs [ i ] . push ( toSolidityInput ( proofData ) . proof )
args [ i ] . push ( [
input . public . root ,
input . public . hexNullifierHash ,
HexUtils . prepareAddress ( input . public . recipientAddress , 20 ) ,
// @ts-ignore
HexUtils . prepareAddress ( input . public . relayerAddress , 20 ) ,
HexUtils . numberToHex ( input . public . fee ) ,
HexUtils . numberToHex ( input . public . refund )
] )
}
// Done. 🤷♀️
groth16 . terminate ( )
return proofs . concat ( args )
}
2023-04-08 19:17:52 +00:00
}
// TODO: implement and decide whether to add in declarations an ambient namespace and merge it here
// export function buildMerkleTree(deposit: Crypto.TornadoDeposit): Crypto.MerkleTree {}
// export function calcMerkleProof(tree: Crypto.MerkleTree): Crypto.MerkleProof {}
// export function calcDepositProof(merkleProof: Crypto.InputFor.DepositProof): Crypto.OutputOf.DepositProof {}
// Namespace exports
export { Types }