UNPKG

o1js-email-verify

Version:

Implemented using [o1js](https://github.com/o1-labs/o1js), this project is a reimplementation of [zk-email](https://github.com/zkemail/zk-email-verify), leveraging the Mina proving system [Kimchi](https://o1-labs.github.io/proof-systems/specs/kimchi.html#

128 lines (126 loc) 4.92 kB
import { Bytes, Field, ZkProgram } from 'o1js'; class Bytes1024 extends Bytes(1024) { } class Bytes1536 extends Bytes(1536) { } class Bytes32 extends Bytes(32) { } import { pkcs1v15Pad } from './utils.js'; const BHRegexProgram1024 = ZkProgram({ name: 'body-hash-regex', methods: { sha256: { privateInputs: [Field], async method(bodyHashIndex) { // Reveal the body hash from the email headers using regex // const { out, reveal } = bodyHashRegex(input.bytes); // out.assertEquals(1); // Select the body hash bytes subarray // const headerBodyHash = Bytes.from( // selectSubarray(reveal[0], bodyHashIndex, 44) // ); // let a = selectSubarray(input.toFields(), bodyHashIndex, 44); let rnd = Bytes(32).random(); const paddedHash = pkcs1v15Pad(rnd, Math.ceil(1024 / 8)); // PKCS#1 v1.5 encode the hash // Provable.assertEqual(rnd, rnd); }, }, }, }); console.log('Body Hash Regex (1024-byte) rnd rows:', (await BHRegexProgram1024.analyzeMethods()).sha256.summary()); /* bodyHashRegex - 1024: --> { 'Total rows': 85943, Generic: 75703, EndoMulScalar: 10240 } bodyHashRegex + subarray - 1024: --> { 'Total rows': 142884, Generic: 132644, EndoMulScalar: 10240 } bodyHashRegex - 1536: --> { 'Total rows': 129717, Generic: 114357, EndoMulScalar: 15360 } bodyHashRegex + subarray - 1536: --> { 'Total rows': 231202, Generic: 215842, EndoMulScalar: 15360 } */ import { assert, UInt8 } from 'o1js'; import { dynamicSHA256 } from 'dynamic-sha256'; function selectBytesSubarray(input, startIndex, subarrayLength) { let inputBytes = input.map((f) => UInt8.Unsafe.fromField(f)); const maxArrayLen = input.length; assert(subarrayLength <= maxArrayLen, 'Subarray length exceeds input array length!'); // Assert startIndex is not zero startIndex.assertNotEquals(0, 'Subarray start index must be greater than zero!'); const bitLength = Math.ceil(Math.log2(maxArrayLen)); const shiftBits = startIndex.toBits(bitLength); let tmp = Array.from({ length: bitLength }, () => Array.from({ length: maxArrayLen }, () => UInt8.from(0))); let a = UInt8.from(0); for (let j = 0; j < bitLength; j++) { for (let i = 0; i < maxArrayLen; i++) { let offset = (i + (1 << j)) % maxArrayLen; // Shift left by 2^j indices if bit is 1 if (j === 0) { tmp[j][i] = UInt8.Unsafe.fromField(shiftBits[j].toField()) .mul(inputBytes[offset].sub(inputBytes[i])) .add(inputBytes[i]); } else { tmp[j][i] = UInt8.Unsafe.fromField(shiftBits[j].toField()) .mul(tmp[j - 1][offset].sub(tmp[j - 1][i])) .add(tmp[j - 1][i]); } } } // console.log('shifted array length: ', tmp[bitLength - 1].length); // Return last row let subarray = []; for (let i = 0; i < subarrayLength; i++) { const selectedByte = tmp[bitLength - 1][i]; // In the context of zk-regex, matched data consists of non-null bytes, while unmatched data consists of null bytes // Assert that the subarray data doesn't contain a 0 (null) byte selectedByte.value.assertNotEquals(0, 'Selected subarray bytes should not contain null bytes!'); subarray.push(selectedByte); } // console.log('\noriginal array length: ', input.length); // console.log('subarray out length: ', subarray.length); return subarray; } // ------------------------------------- const SHA256Dynamic1024Program = ZkProgram({ name: 'sha256', publicOutput: Bytes32.provable, methods: { sha256: { privateInputs: [Bytes1024.provable, Field], async method(preimage, digestIndex) { return dynamicSHA256(preimage, digestIndex); }, }, }, }); const SHA256Dynamic1536Program = ZkProgram({ name: 'sha256', publicOutput: Bytes32.provable, methods: { sha256: { privateInputs: [Bytes1536.provable, Field], async method(preimage, digestIndex) { return dynamicSHA256(preimage, digestIndex); }, }, }, }); console.log('\nDynamic SHA256 (1024-byte) rows:', (await SHA256Dynamic1024Program.analyzeMethods()).sha256.summary()); console.log('Dynamic SHA256 (1536-byte) rows:', (await SHA256Dynamic1536Program.analyzeMethods()).sha256.summary()); /* Dynamic SHA256 (1024-byte) rows: { 'Total rows': 92675, Generic: 31203, EndoMulScalar: 27704, Xor16: 22512, Zero: 11256 } Dynamic SHA256 (1536-byte) rows: { 'Total rows': 138883, Generic: 46691, EndoMulScalar: 41528, Xor16: 33776, Zero: 16888 } */ //# sourceMappingURL=trash.js.map