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
JavaScript
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