UNPKG

minauth-merkle-membership-plugin

Version:

This package contains an implementation of a simple MinAuth plugin that extends the concept of password authentication into authenticating within sets that provide a level of anonymity. The proofs are built and verified with MINA's `o1js` library & proof

71 lines 3.88 kB
import * as z from 'zod'; import MembershipsProver from './prover.js'; import { pipe } from 'fp-ts/lib/function.js'; import * as A from 'fp-ts/lib/Array.js'; import * as E from 'fp-ts/lib/Either.js'; import { askConfig } from 'minauth/dist/plugin/proofgenerator.js'; import { wrapZodDec } from 'minauth/dist/plugin/encodedecoder.js'; import { fpInterfaceTag } from 'minauth/dist/plugin/interfacekind.js'; import * as RTE from 'fp-ts/lib/ReaderTaskEither.js'; import { safeFromString } from 'minauth/dist/utils/fp/either.js'; import { tapLogger } from 'minauth/dist/utils/fp/readertaskeither.js'; import { fieldEncDec } from 'minauth/dist/utils/fp/fieldEncDec.js'; // TODO/FIXME: Copy-paste from src/plugins/merkleMemberships/server/index.ts, should move to utils. const bigintEncDec = { __interface_tag: 'fp', decode: (i) => pipe(wrapZodDec('fp', z.string()).decode(i), E.chain(safeFromString(BigInt, (err) => `failed to decode bigint: ${err}`))), encode: (val) => val.toString() }; /** Prover input schema */ const rawPublicAndPrivateInputsSchema = z.object({ treeRoot: z.string(), leafIndex: z.string(), secret: z.string() }); /** Config schema */ const rawConfSchema = z.object({ pluginUrl: z.string(), allInputs: z.array(rawPublicAndPrivateInputsSchema) }); const confDec = { __interface_tag: fpInterfaceTag, decode: (inp) => pipe(E.Do, E.bind('confRaw', () => wrapZodDec(fpInterfaceTag, rawConfSchema).decode(inp)), E.bind('typedAllInputs', ({ confRaw: { allInputs } }) => A.traverse(E.Applicative)(({ treeRoot, leafIndex, secret }) => pipe(E.Do, E.bind('treeRoot', () => fieldEncDec.decode(treeRoot)), E.bind('leafIndex', () => bigintEncDec.decode(leafIndex)), E.bind('secret', () => fieldEncDec.decode(secret))))(allInputs)), E.map(({ confRaw: { pluginUrl }, typedAllInputs }) => ({ pluginUrl, allInputs: typedAllInputs }))) }; const fromTE = (mapError) => (f) => pipe(RTE.fromTaskEither(f), RTE.mapError(mapError)); /** * Generate a proof using the Merkle memberships prover. */ const generateProof = () => pipe(RTE.Do, tapLogger((logger) => logger.info('generating proof using merkle memberships prover')), RTE.bind('config', (askConfig)), RTE.bind('prover', ({ config: { pluginUrl } }) => fromTE((err) => ({ __tag: 'failedToInitializeProver', reason: err }))(MembershipsProver.initialize({ baseUrl: pluginUrl }))), tapLogger((logger) => logger.info('prover initialized')), RTE.let('publicInputArgs', ({ config: { allInputs } }) => A.map(({ treeRoot, leafIndex }) => ({ treeRoot, leafIndex }))(allInputs)), RTE.bind('publicInputs', ({ prover, publicInputArgs }) => fromTE((err) => ({ __tag: 'failedToFetchPublicInputs', reason: err, publicInputArgs }))(prover.fetchPublicInputs(publicInputArgs))), tapLogger((logger, { publicInputs }) => logger.debug('public inputs', publicInputs)), RTE.let('secretInputs', ({ config: { allInputs } }) => A.map(({ secret }) => secret)(allInputs)), tapLogger((logger) => logger.info('proving')), // build the proof RTE.bind('proof', ({ publicInputs, secretInputs, prover }) => fromTE((err) => ({ __tag: 'failedToProve', reason: err }))(prover.prove(publicInputs, secretInputs))), // NOTE: Public input arguments have a different meaning from the // server's point of view. In particular, the server must not know // which leaf was used. RTE.let('encodedPublicInputArgs', ({ publicInputArgs }) => A.map(({ treeRoot }) => treeRoot.toString())(publicInputArgs)), // return the proof RTE.map(({ encodedPublicInputArgs, proof }) => ({ plugin: 'MerkleMembershipsPlugin', input: { proof, merkleRoots: encodedPublicInputArgs } })), tapLogger((logger) => logger.info('all done'))); /** * Export the generator */ export const generator = { confDec, generateProof }; export default generator; //# sourceMappingURL=proofgenerator.js.map