diff --git a/bin/gnark/darwin-arm64-libprove.so b/bin/gnark/darwin-arm64-libprove.so index 16fd1dc..16a606a 100644 Binary files a/bin/gnark/darwin-arm64-libprove.so and b/bin/gnark/darwin-arm64-libprove.so differ diff --git a/bin/gnark/darwin-arm64-libverify.so b/bin/gnark/darwin-arm64-libverify.so index de56335..9ace6c9 100644 Binary files a/bin/gnark/darwin-arm64-libverify.so and b/bin/gnark/darwin-arm64-libverify.so differ diff --git a/js/src/config.ts b/js/src/config.ts index 2811e42..e50aab7 100644 --- a/js/src/config.ts +++ b/js/src/config.ts @@ -33,13 +33,13 @@ export const CONFIG: { [E in EncryptionAlgorithm]: AlgorithmConfig } = { }, 'aes-256-ctr': { index: 2, - chunkSize: 64, + chunkSize: 80, bitsPerWord: 8, keySizeBytes: 32, ivSizeBytes: 12, startCounter: 2, // num of blocks per chunk - blocksPerChunk: 4, + blocksPerChunk: 5, // AES circuit uses BE encoding isLittleEndian: false, uint8ArrayToBits, @@ -48,13 +48,13 @@ export const CONFIG: { [E in EncryptionAlgorithm]: AlgorithmConfig } = { }, 'aes-128-ctr': { index: 1, - chunkSize: 64, + chunkSize: 80, bitsPerWord: 8, keySizeBytes: 16, ivSizeBytes: 12, startCounter: 2, // num of blocks per chunk - blocksPerChunk: 4, + blocksPerChunk: 5, // AES circuit uses BE encoding isLittleEndian: false, uint8ArrayToBits, diff --git a/js/src/tests/oprf.test.ts b/js/src/tests/oprf.test.ts index b63df13..4a71893 100644 --- a/js/src/tests/oprf.test.ts +++ b/js/src/tests/oprf.test.ts @@ -1,12 +1,12 @@ +import { CONFIG } from '../config' import { makeLocalFileFetch } from '../file-fetch' import { makeGnarkOPRFOperator } from '../gnark/toprf' import { strToUint8Array } from '../gnark/utils' -import { OPRFResponseData, ZKTOPRFPublicSignals } from '../types' +import { EncryptionAlgorithm, OPRFOperator, OPRFResponseData, ZKEngine, ZKTOPRFPublicSignals } from '../types' import { generateProof, verifyProof } from '../zk' import { encryptData } from './utils' const fetcher = makeLocalFileFetch() -const operator = makeGnarkOPRFOperator({ fetcher, algorithm: 'chacha20' }) const threshold = 1 const POSITIONS = [ @@ -14,78 +14,98 @@ const POSITIONS = [ 10 ] -describe('TOPRF circuits Tests', () => { +type Config = { + make: (alg: EncryptionAlgorithm) => OPRFOperator + algorithms: EncryptionAlgorithm[] +} - it.each(POSITIONS)('should prove & verify TOPRF at pos=%s', async pos => { - const email = 'test@email.com' - const domainSeparator = 'reclaim' +const OPRF_ZK_ENGINES_MAP: { [E in ZKEngine]?: Config } = { + 'gnark': { + make: algorithm => makeGnarkOPRFOperator({ fetcher, algorithm }), + algorithms: ['chacha20', 'aes-128-ctr', 'aes-256-ctr'], + } +} - const keys = await operator.generateThresholdKeys(5, threshold) - const req = await operator - .generateOPRFRequestData(strToUint8Array(email), domainSeparator) +const OPRF_ENGINES = Object.keys(OPRF_ZK_ENGINES_MAP) as ZKEngine[] - const resps: OPRFResponseData[] = [] - for(let i = 0; i < threshold; i++) { - const evalResult = await operator.evaluateOPRF( - keys.shares[i].privateKey, - req.maskedData - ) +describe.each(OPRF_ENGINES)('%s TOPRF circuits Tests', engine => { - resps.push({ - publicKeyShare: keys.shares[i].publicKey, - evaluated: evalResult.evaluated, - c: evalResult.c, - r: evalResult.r, - }) - } - - const nullifier = await operator - .finaliseOPRF(keys.publicKey, req, resps) - const len = email.length - - const plaintext = new Uint8Array(Buffer.alloc(64)) - //replace part of plaintext with email - plaintext.set(new Uint8Array(Buffer.from(email)), pos) - - const key = new Uint8Array(Array.from(Array(32).keys())) - const iv = new Uint8Array(Array.from(Array(12).keys())) - - const ciphertext = encryptData('chacha20', plaintext, key, iv) - - const toprf: ZKTOPRFPublicSignals = { - pos: pos, //pos in plaintext - len: len, // length of data to "hash" - domainSeparator, - output: nullifier, - responses: resps - } - - const proof = await generateProof({ - algorithm: 'chacha20', - privateInput: { - key, - }, - publicInput: { - iv, - ciphertext, - offset: 0 - }, - operator, - mask: req.mask, - toprf, - }) + const { make, algorithms } = OPRF_ZK_ENGINES_MAP[engine]! + + describe.each(algorithms)('%s', algorithm => { + + const operator = make(algorithm) + + it.each(POSITIONS)('should prove & verify TOPRF at pos=%s', async pos => { + const email = 'test@email.com' + const domainSeparator = 'reclaim' + + const keys = await operator.generateThresholdKeys(5, threshold) + const req = await operator + .generateOPRFRequestData(strToUint8Array(email), domainSeparator) + + const resps: OPRFResponseData[] = [] + for(let i = 0; i < threshold; i++) { + const evalResult = await operator.evaluateOPRF( + keys.shares[i].privateKey, + req.maskedData + ) + + resps.push({ + publicKeyShare: keys.shares[i].publicKey, + evaluated: evalResult.evaluated, + c: evalResult.c, + r: evalResult.r, + }) + } - await expect( - verifyProof({ - proof, + const nullifier = await operator + .finaliseOPRF(keys.publicKey, req, resps) + const len = email.length + + const plaintext = new Uint8Array(Buffer.alloc(64)) + //replace part of plaintext with email + plaintext.set(new Uint8Array(Buffer.from(email)), pos) + + const { keySizeBytes } = CONFIG[algorithm] + const key = new Uint8Array(Array.from(Array(keySizeBytes).keys())) + const iv = new Uint8Array(Array.from(Array(12).keys())) + + const ciphertext = encryptData(algorithm, plaintext, key, iv) + + const toprf: ZKTOPRFPublicSignals = { + pos: pos, //pos in plaintext + len: len, // length of data to "hash" + domainSeparator, + output: nullifier, + responses: resps + } + + const proof = await generateProof({ + algorithm, + privateInput: { + key, + }, publicInput: { iv, ciphertext, offset: 0 }, + operator, + mask: req.mask, toprf, - operator }) - ).resolves.toBeUndefined() + + await expect( + verifyProof({ + proof, + publicInput: { iv, ciphertext, + offset: 0 + }, + toprf, + operator + }) + ).resolves.toBeUndefined() + }) }) }) \ No newline at end of file