micro-zk-proofs
Version:
Create & verify zero-knowledge SNARK proofs in parallel, using noble cryptography
51 lines (44 loc) • 1.66 kB
text/typescript
/**
* MiMC: Efficient Encryption and Cryptographic
* Hashing with Minimal Multiplicative Complexity.
* https://eprint.iacr.org/2016/492.pdf
* https://crypto.ethereum.org/bounties/mimc-hash-challenge
* @module
*/
import { bn254 } from '@noble/curves/bn254';
import { keccak_256 } from '@noble/hashes/sha3';
const Fr = bn254.fields.Fr;
const SEED = 'mimcsponge';
const NROUNDS = 220;
export function getIV(seed: string = SEED): bigint {
return Fr.create(Fr.fromBytes(keccak_256(`${seed}_iv`)));
}
export function getConstants(seed: string = SEED, nRounds: number = NROUNDS): bigint[] {
const cts = [BigInt(0)];
let c = keccak_256(seed);
for (let i = 0; i < nRounds - 2; i++) cts.push(Fr.create(Fr.fromBytes((c = keccak_256(c)))));
cts.push(BigInt(0));
return cts;
}
const CONSTANTS = getConstants(SEED, NROUNDS);
export function hash(L: bigint, R: bigint, k: bigint): { xL: bigint; xR: bigint } {
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) };
}
export function multiHash(lst: bigint[], key: bigint = Fr.ZERO, numOutputs = 1): bigint | bigint[] {
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;
}