UNPKG

micro-zk-proofs

Version:

Create & verify zero-knowledge SNARK proofs in parallel, using noble cryptography

103 lines 3.71 kB
/** * MiMC: Efficient Encryption and Cryptographic * Hashing with Minimal Multiplicative Complexity. * {@link https://eprint.iacr.org/2016/492.pdf} * {@link https://crypto.ethereum.org/bounties/mimc-hash-challenge} * @module */ import { bn254 } from '@noble/curves/bn254.js'; import { keccak_256 } from '@noble/hashes/sha3.js'; import { utf8ToBytes } from '@noble/hashes/utils.js'; const Fr = bn254.fields.Fr; const SEED = 'mimcsponge'; const NROUNDS = 220; /** * Derives the MiMC sponge IV from the seed. * @param seed - Seed string used for derivation. * @returns Field element used as the initial vector. * @example * Derive the default MiMC IV, or pass your own seed for compatibility tests. * ```ts * const iv = getIV('mimcsponge'); * ``` */ export function getIV(seed = SEED) { return Fr.create(Fr.fromBytes(keccak_256(utf8ToBytes(`${seed}_iv`)), true)); } /** * Derives the MiMC round constants from the seed. * @param seed - Seed string used for derivation. * @param nRounds - Number of MiMC rounds to generate; must include the two zero endpoints. * @returns Round constant list. * @throws If `nRounds` is not an integer at least 2. {@link Error} * @example * Rebuild a short constant table for test vectors or compatibility checks. * ```ts * const constants = getConstants('mimcsponge', 4); * ``` */ export function getConstants(seed = SEED, nRounds = NROUNDS) { // Circomlib-compatible tables reserve first and last constants as zero endpoints. if (!Number.isSafeInteger(nRounds) || nRounds < 2) throw new Error(`expected nRounds >= 2, got ${nRounds}`); const cts = [BigInt(0)]; let c = keccak_256(utf8ToBytes(seed)); for (let i = 0; i < nRounds - 2; i++) cts.push(Fr.create(Fr.fromBytes((c = keccak_256(c)), true))); cts.push(BigInt(0)); return cts; } const CONSTANTS = /* @__PURE__ */ getConstants(SEED, NROUNDS); /** * Runs one MiMC sponge hash round sequence. * @param L - Left input lane. * @param R - Right input lane. * @param k - Key value. * @returns Updated left and right lanes. * @example * Run one MiMC round sequence on two field elements with an optional key. * ```ts * const round = hash(1n, 2n, 0n); * round.xL; * ``` */ export function hash(L, R, k) { for (let i = 0; i < NROUNDS; i++) { const t = i == 0 ? Fr.addN(L, k) : Fr.addN(Fr.addN(L, k), CONSTANTS[i]); const tmp = Fr.addN(R, Fr.pow(t, BigInt(5))); if (i < NROUNDS - 1) { R = L; L = tmp; } else R = tmp; } return { xL: Fr.create(L), xR: Fr.create(R) }; } /** * Hashes one or more field elements with the MiMC sponge. * @param lst - Input field elements. * @param key - Optional key value. * @param numOutputs - Number of outputs to squeeze; must be at least one. * @returns One field element or an array of field elements. * @throws If `numOutputs` is not an integer at least 1. {@link Error} * @example * Hash one or more field elements and optionally squeeze multiple outputs. * ```ts * const out = multiHash([1n, 2n], 0n, 2); * ``` */ export function multiHash(lst, key = Fr.ZERO, numOutputs = 1) { if (!Number.isSafeInteger(numOutputs) || numOutputs < 1) throw new Error(`expected numOutputs >= 1, got ${numOutputs}`); let R = Fr.ZERO; let C = Fr.ZERO; for (let i = 0; i < lst.length; i++) ({ xL: R, xR: C } = hash(Fr.addN(R, BigInt(lst[i])), C, key)); const out = [R]; for (let i = 1; i < numOutputs; i++, out.push(R)) ({ xL: R, xR: C } = hash(R, C, key)); const res = out.map((x) => Fr.create(x)); return numOutputs === 1 ? res[0] : res; } //# sourceMappingURL=mimcsponge.js.map