From 0c110bdb779e5af5d80aa9ef4c802512f8547202 Mon Sep 17 00:00:00 2001 From: Michael Elliot Date: Tue, 27 Aug 2024 22:18:47 +0800 Subject: [PATCH 01/60] improve passport compatibility - increase max padded econtent length to 640 - allow dynamic length signed_attr input - update econtent/signed_attr vars to correctly match referenced data - allow dynamic econtent hash position in signed_attr --- ...ifier_sha256WithRSAEncryption_65537.circom | 100 ++++++++---------- ...ister_sha256WithRSAEncryption_65537.circom | 32 +++--- .../sha256WithRSAEncryption_65537.ts | 30 +++--- circuits/test/register_sha256.test.ts | 12 +-- common/src/constants/constants.ts | 17 ++- common/src/utils/generateInputs.ts | 70 ++++++------ common/src/utils/mockPassportData.ts | 18 ++-- common/src/utils/types.ts | 4 +- common/src/utils/utils.ts | 26 ++--- 9 files changed, 157 insertions(+), 152 deletions(-) diff --git a/circuits/circuits/passport_verifier_sha256WithRSAEncryption_65537.circom b/circuits/circuits/passport_verifier_sha256WithRSAEncryption_65537.circom index 8f35e41e..0e6a9bce 100644 --- a/circuits/circuits/passport_verifier_sha256WithRSAEncryption_65537.circom +++ b/circuits/circuits/passport_verifier_sha256WithRSAEncryption_65537.circom @@ -6,91 +6,79 @@ include "@zk-email/circuits/lib/sha.circom"; include "@zk-email/circuits/utils/array.circom"; include "./utils/Sha256BytesStatic.circom"; -template PassportVerifier_sha256WithRSAEncryption_65537(n, k, max_datahashes_bytes) { - var hashLen = 32; - var eContentBytesLength = 72 + hashLen; // 104 - - signal input mrz[93]; // formatted mrz (5 + 88) chars - signal input dg1_hash_offset; - signal input dataHashes[max_datahashes_bytes]; - signal input datahashes_padded_length; - signal input eContentBytes[eContentBytesLength]; - +template PassportVerifier_sha256WithRSAEncryption_65537(n, k, MAX_ECONTENT_LEN, MAX_SIGNED_ATTR_LEN) { + var HASH_LEN = 32; + var HASH_LEN_BITS = 256; + + signal input dg1[93]; + signal input eContent[MAX_ECONTENT_LEN]; + signal input eContentPaddedLength; + signal input eContentDG1HashOffset; + signal input signedAttr[MAX_SIGNED_ATTR_LEN]; + signal input signedAttrPaddedLength; + signal input signedAttreContentHashOffset; // pubkey that signed the passport signal input pubkey[k]; - // signature of the passport signal input signature[k]; - // compute sha256 of formatted mrz - signal mrzSha[256] <== Sha256BytesStatic(93)(mrz); - - // mrzSha_bytes: list of 32 Bits2Num - component mrzSha_bytes[hashLen]; - - // cast the 256 bits from mrzSha into a list of 32 bytes - for (var i = 0; i < hashLen; i++) { - mrzSha_bytes[i] = Bits2Num(8); - + // compute hash of DG1 + signal dg1Sha[HASH_LEN_BITS] <== Sha256BytesStatic(93)(dg1); + component dg1Sha_bytes[HASH_LEN]; + for (var i = 0; i < HASH_LEN; i++) { + dg1Sha_bytes[i] = Bits2Num(8); for (var j = 0; j < 8; j++) { - mrzSha_bytes[i].in[7 - j] <== mrzSha[i * 8 + j]; + dg1Sha_bytes[i].in[7 - j] <== dg1Sha[i * 8 + j]; } } - // assert mrz_hash equals the one extracted from dataHashes input (bytes dg1_hash_offset to dg1_hash_offset + hashLen) - signal dg1Hash[hashLen] <== SelectSubArray(max_datahashes_bytes, hashLen)(dataHashes, dg1_hash_offset, hashLen); - for(var i = 0; i < hashLen; i++) { - dg1Hash[i] === mrzSha_bytes[i].out; + // assert DG1 hash matches the one in eContent input + signal dg1Hash[HASH_LEN] <== SelectSubArray(MAX_ECONTENT_LEN, HASH_LEN)(eContent, eContentDG1HashOffset, HASH_LEN); + for(var i = 0; i < HASH_LEN; i++) { + dg1Hash[i] === dg1Sha_bytes[i].out; } - // hash dataHashes dynamically - signal dataHashesSha[256] <== Sha256Bytes(max_datahashes_bytes)(dataHashes, datahashes_padded_length); - - // get output of dataHashes sha256 into bytes to check against eContent - component dataHashesSha_bytes[hashLen]; - for (var i = 0; i < hashLen; i++) { - dataHashesSha_bytes[i] = Bits2Num(8); + // compute hash of eContent + signal eContentSha[HASH_LEN_BITS] <== Sha256Bytes(MAX_ECONTENT_LEN)(eContent, eContentPaddedLength); + component eContentSha_bytes[HASH_LEN]; + for (var i = 0; i < HASH_LEN; i++) { + eContentSha_bytes[i] = Bits2Num(8); for (var j = 0; j < 8; j++) { - dataHashesSha_bytes[i].in[7 - j] <== dataHashesSha[i * 8 + j]; + eContentSha_bytes[i].in[7 - j] <== eContentSha[i * 8 + j]; } } - // assert dataHashesSha is in eContentBytes in range bytes 72 to 104 - for(var i = 0; i < hashLen; i++) { - eContentBytes[eContentBytesLength - hashLen + i] === dataHashesSha_bytes[i].out; + // assert eContent hash matches the one in signedAttr + signal eContentHashInSignedAttr[HASH_LEN] <== SelectSubArray(MAX_SIGNED_ATTR_LEN, HASH_LEN)(signedAttr, signedAttreContentHashOffset, HASH_LEN); + for(var i = 0; i < HASH_LEN; i++) { + eContentHashInSignedAttr[i] === eContentSha_bytes[i].out; } - // hash eContentBytes - signal eContentSha[256] <== Sha256BytesStatic(104)(eContentBytes); - - // get output of eContentBytes sha256 into k chunks of n bits each + // compute hash of signedAttr + signal signedAttrSha[256] <== Sha256Bytes(MAX_SIGNED_ATTR_LEN)(signedAttr, signedAttrPaddedLength); + // get output of signedAttr sha256 into k chunks of n bits each var msg_len = (256 + n) \ n; - - //eContentHash: list of length 256/n +1 of components of n bits - component eContentHash[msg_len]; + // signedAttrHash: list of length 256/n+1 of components of n bits + component signedAttrHash[msg_len]; for (var i = 0; i < msg_len; i++) { - eContentHash[i] = Bits2Num(n); + // instantiate each component of the list of Bits2Num of size n + signedAttrHash[i] = Bits2Num(n); } - for (var i = 0; i < 256; i++) { - eContentHash[i \ n].in[i % n] <== eContentSha[255 - i]; + signedAttrHash[i \ n].in[i % n] <== signedAttrSha[255 - i]; } - for (var i = 256; i < n * msg_len; i++) { - eContentHash[i \ n].in[i % n] <== 0; + signedAttrHash[i \ n].in[i % n] <== 0; } - - // verify eContentHash signature - component rsa = RSAVerifier65537(n, k); + // verify RSA signature + component rsa = RSAVerifier65537(n, k); for (var i = 0; i < msg_len; i++) { - rsa.message[i] <== eContentHash[i].out; + rsa.message[i] <== signedAttrHash[i].out; } - for (var i = msg_len; i < k; i++) { rsa.message[i] <== 0; } - rsa.modulus <== pubkey; rsa.signature <== signature; -} \ No newline at end of file +} diff --git a/circuits/circuits/register_sha256WithRSAEncryption_65537.circom b/circuits/circuits/register_sha256WithRSAEncryption_65537.circom index 590c9a05..da4a56d2 100644 --- a/circuits/circuits/register_sha256WithRSAEncryption_65537.circom +++ b/circuits/circuits/register_sha256WithRSAEncryption_65537.circom @@ -7,14 +7,16 @@ include "./utils/chunk_data.circom"; include "./utils/compute_pubkey_leaf.circom"; include "binary-merkle-root.circom"; -template Register_sha256WithRSAEncryption_65537(n, k, max_datahashes_bytes, nLevels, signatureAlgorithm) { +template Register_sha256WithRSAEncryption_65537(n, k, max_padded_econtent_len, max_padded_signed_attr_len, nLevels, signatureAlgorithm) { signal input secret; - signal input mrz[93]; + signal input dg1[93]; signal input dg1_hash_offset; - signal input econtent[max_datahashes_bytes]; - signal input datahashes_padded_length; - signal input signed_attributes[104]; + signal input econtent[max_padded_econtent_len]; + signal input econtent_padded_length; + signal input signed_attr[max_padded_signed_attr_len]; + signal input signed_attr_padded_length; + signal input signed_attr_econtent_hash_offset; signal input signature[k]; signal input pubkey[k]; @@ -30,12 +32,14 @@ template Register_sha256WithRSAEncryption_65537(n, k, max_datahashes_bytes, nLev merkle_root === computed_merkle_root; // Verify passport validity - component PV = PassportVerifier_sha256WithRSAEncryption_65537(n, k, max_datahashes_bytes); - PV.mrz <== mrz; - PV.dg1_hash_offset <== dg1_hash_offset; - PV.dataHashes <== econtent; - PV.datahashes_padded_length <== datahashes_padded_length; - PV.eContentBytes <== signed_attributes; + component PV = PassportVerifier_sha256WithRSAEncryption_65537(n, k, max_padded_econtent_len, max_padded_signed_attr_len); + PV.dg1 <== dg1; + PV.eContent <== econtent; + PV.eContentPaddedLength <== econtent_padded_length; + PV.eContentDG1HashOffset <== dg1_hash_offset; + PV.signedAttr <== signed_attr; + PV.signedAttrPaddedLength <== signed_attr_padded_length; + PV.signedAttreContentHashOffset <== signed_attr_econtent_hash_offset; PV.pubkey <== pubkey; PV.signature <== signature; @@ -45,17 +49,17 @@ template Register_sha256WithRSAEncryption_65537(n, k, max_datahashes_bytes, nLev poseidon_hasher.inputs[1] <== attestation_id; poseidon_hasher.inputs[2] <== leaf; - signal mrz_packed[3] <== PackBytes(93)(mrz); + signal mrz_packed[3] <== PackBytes(93)(dg1); for (var i = 0; i < 3; i++) { poseidon_hasher.inputs[i + 3] <== mrz_packed[i]; } signal output commitment <== poseidon_hasher.out; - // Generate the nullifier + // Generate the nullifier var chunk_size = 11; // Since ceil(32 / 3) in integer division is 11 signal chunked_signature[chunk_size] <== ChunkData(n, k, chunk_size)(signature); signal output nullifier <== Poseidon(chunk_size)(chunked_signature); } // We hardcode 1 here for sha256WithRSAEncryption_65537 -component main { public [ merkle_root, attestation_id ] } = Register_sha256WithRSAEncryption_65537(64, 32, 320, 16, 1); +component main { public [ merkle_root, attestation_id ] } = Register_sha256WithRSAEncryption_65537(64, 32, 640, 512, 16, 1); diff --git a/circuits/scripts/genMockPassportData/sha256WithRSAEncryption_65537.ts b/circuits/scripts/genMockPassportData/sha256WithRSAEncryption_65537.ts index a6733237..26755217 100644 --- a/circuits/scripts/genMockPassportData/sha256WithRSAEncryption_65537.ts +++ b/circuits/scripts/genMockPassportData/sha256WithRSAEncryption_65537.ts @@ -1,6 +1,6 @@ import assert from "assert"; import { PassportData } from "../../../common/src/utils/types"; -import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, hexToDecimal, arraysAreEqual, findSubarrayIndex } from "../../../common/src/utils/utils"; +import { hash, assembleSignedAttr, formatAndConcatenateDataHashes, formatMrz, hexToDecimal, arraysAreEqual, findSubarrayIndex } from "../../../common/src/utils/utils"; import * as forge from 'node-forge'; import { writeFileSync } from "fs"; @@ -35,21 +35,21 @@ const signatureAlgorithm = 'sha256WithRSAEncryption' const hashLen = 32 export function genMockPassportData_sha256WithRSAEncryption_65537(): PassportData { - const mrzHash = hash(signatureAlgorithm, formatMrz(sampleMRZ)); - const concatenatedDataHashes = formatAndConcatenateDataHashes( - [[1, mrzHash], ...sampleDataHashes], + const dg1Hash = hash(signatureAlgorithm, formatMrz(sampleMRZ)); + const eContent = formatAndConcatenateDataHashes( + [[1, dg1Hash], ...sampleDataHashes], hashLen, 31 ); - const eContent = assembleEContent(hash(signatureAlgorithm, concatenatedDataHashes)); + const signedAttr = assembleSignedAttr(hash(signatureAlgorithm, eContent)); const rsa = forge.pki.rsa; const privKey = rsa.generateKeyPair({ bits: 2048 }).privateKey; const modulus = privKey.n.toString(16); const md = forge.md.sha256.create(); - md.update(forge.util.binary.raw.encode(new Uint8Array(eContent))); + md.update(forge.util.binary.raw.encode(new Uint8Array(signedAttr))); const signature = privKey.sign(md) const signatureBytes = Array.from(signature, (c: string) => c.charCodeAt(0)); @@ -61,28 +61,28 @@ export function genMockPassportData_sha256WithRSAEncryption_65537(): PassportDat modulus: hexToDecimal(modulus), exponent: '65537', }, - dataGroupHashes: concatenatedDataHashes, eContent: eContent, + signedAttr: signedAttr, encryptedDigest: signatureBytes, photoBase64: "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjElEQVR42mL8//8/AyUYiBQYmIw3..." } } function verify(passportData: PassportData): boolean { - const { mrz, signatureAlgorithm, pubKey, dataGroupHashes, eContent, encryptedDigest } = passportData; + const { mrz, signatureAlgorithm, pubKey, eContent, signedAttr, encryptedDigest } = passportData; const formattedMrz = formatMrz(mrz); const mrzHash = hash(signatureAlgorithm, formattedMrz); - const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash) + const dg1HashOffset = findSubarrayIndex(eContent, mrzHash) console.log('dg1HashOffset', dg1HashOffset); - assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes'); + assert(dg1HashOffset !== -1, 'MRZ hash index not found in eContent'); - const concatHash = hash(signatureAlgorithm, dataGroupHashes) + const concatHash = hash(signatureAlgorithm, eContent) assert( arraysAreEqual( concatHash, - eContent.slice(eContent.length - hashLen) + signedAttr.slice(signedAttr.length - hashLen) ), - 'concatHash is not at the right place in eContent' + 'concatHash is not at the right place in signedAttr' ); const modulus = new forge.jsbn.BigInteger(pubKey.modulus, 10); @@ -90,7 +90,7 @@ function verify(passportData: PassportData): boolean { const rsaPublicKey = forge.pki.rsa.setPublicKey(modulus, exponent); const md = forge.md.sha256.create(); - md.update(forge.util.binary.raw.encode(new Uint8Array(eContent))); + md.update(forge.util.binary.raw.encode(new Uint8Array(signedAttr))); const signature = Buffer.from(encryptedDigest).toString( 'binary', @@ -103,4 +103,4 @@ const mockPassportData = genMockPassportData_sha256WithRSAEncryption_65537(); console.log("Passport Data:", JSON.stringify(mockPassportData, null, 2)); console.log("Signature valid:", verify(mockPassportData)); -writeFileSync(__dirname + '/passportData.json', JSON.stringify(mockPassportData, null, 2)); \ No newline at end of file +writeFileSync(__dirname + '/passportData.json', JSON.stringify(mockPassportData, null, 2)); diff --git a/circuits/test/register_sha256.test.ts b/circuits/test/register_sha256.test.ts index fe97b02f..8bcea2bb 100644 --- a/circuits/test/register_sha256.test.ts +++ b/circuits/test/register_sha256.test.ts @@ -54,7 +54,7 @@ describe("Circuits - sha256WithRSAEncryption_65537 Register flow", function () { const commitment_circom = (await circuit.getOutput(w, ["commitment"])).commitment; - const mrz_bytes = packBytes(inputs.mrz); + const dg1_bytes = packBytes(inputs.dg1); const commitment_bytes = poseidon6([ inputs.secret[0], attestation_id, @@ -63,9 +63,9 @@ describe("Circuits - sha256WithRSAEncryption_65537 Register flow", function () { modulus: passportData.pubKey.modulus, exponent: passportData.pubKey.exponent }), - mrz_bytes[0], - mrz_bytes[1], - mrz_bytes[2] + dg1_bytes[0], + dg1_bytes[1], + dg1_bytes[2] ]); const commitment_js = commitment_bytes.toString(); console.log('commitment_js', commitment_js) @@ -77,7 +77,7 @@ describe("Circuits - sha256WithRSAEncryption_65537 Register flow", function () { try { const invalidInputs = { ...inputs, - mrz: Array(93).fill(0).map(byte => BigInt(byte).toString()) + dg1: Array(93).fill(0).map(byte => BigInt(byte).toString()) } await circuit.calculateWitness(invalidInputs); expect.fail("Expected an error but none was thrown."); @@ -125,4 +125,4 @@ describe("Circuits - sha256WithRSAEncryption_65537 Register flow", function () { } }); -}); \ No newline at end of file +}); diff --git a/common/src/constants/constants.ts b/common/src/constants/constants.ts index bbbfee75..eeed7311 100644 --- a/common/src/constants/constants.ts +++ b/common/src/constants/constants.ts @@ -37,7 +37,20 @@ export const attributeToPosition = { older_than: [88, 89] }; -export const MAX_DATAHASHES_LEN = 320; // max formatted and concatenated datagroup hashes length in bytes +// MAX_PADDED_ECONTENT_LEN in bytes +// Bits (*8) must be multiple of 64, such that b * 8 % 512 == 0 +// Valid values: 64, 128, 192, 256, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960, 1024, ... +// In bits: 512,1024,1536,2048,2560,3072,3584,4096,4608,5120,5632,6144,6656,7168,7680,8192, ... +// +// The maximum possible byte length of the encapsulated content (eContent) section in an ePassport, +// assuming all 16 possible data groups are present, using SHA-256 for each data group hash, and +// including ASN.1 header and encoding overhead +// Max possible eContent Length = Length of ASN.1 encoding header + ((Length of ASN.1 encoding + Length of SHA-256 hash) * Max possible data groups) +// Max possible eContent Length = 19 + ((4 + 32 ) * 16) +// Max possible eContent Length = 595 +export const MAX_PADDED_ECONTENT_LEN = 640; + +export const MAX_PADDED_SIGNED_ATTR_LEN = 512; export const countryCodes = { "AFG": "Afghanistan", @@ -1471,4 +1484,4 @@ export const SBT_ABI = [ "stateMutability": "view", "type": "function" } -] \ No newline at end of file +] diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index 9c01a436..7f5924b1 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -1,4 +1,4 @@ -import { MAX_DATAHASHES_LEN, SignatureAlgorithm, PUBKEY_TREE_DEPTH, DEVELOPMENT_MODE } from "../constants/constants"; +import { MAX_PADDED_ECONTENT_LEN, MAX_PADDED_SIGNED_ATTR_LEN, SignatureAlgorithm, PUBKEY_TREE_DEPTH, DEVELOPMENT_MODE } from "../constants/constants"; import { assert, shaPad } from "./shaPad"; import { PassportData } from "./types"; import { @@ -23,7 +23,7 @@ export function generateCircuitInputsRegister( passportData: PassportData, mocks: PassportData[] = mockPassportDatas ) { - const { mrz, signatureAlgorithm, pubKey, dataGroupHashes, eContent, encryptedDigest } = passportData; + const { mrz, signatureAlgorithm, pubKey, eContent, signedAttr, encryptedDigest } = passportData; const tree = new IMT(poseidon2, PUBKEY_TREE_DEPTH, 0, 2); tree.setNodes(JSON.parse(JSON.stringify(serializedTree))); //deep copy @@ -43,24 +43,17 @@ export function generateCircuitInputsRegister( throw new Error(`${signatureAlgorithm} has not been implemented.`); } - const hashLen = getHashLen(signatureAlgorithm); - const formattedMrz = formatMrz(mrz); - const mrzHash = hash(signatureAlgorithm, formattedMrz); + const dg1 = formatMrz(mrz); + const dg1Hash = hash(signatureAlgorithm, dg1); - const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash) + const dg1HashOffset = findSubarrayIndex(eContent, dg1Hash) console.log('dg1HashOffset', dg1HashOffset); + assert(dg1HashOffset !== -1, `DG1 hash ${dg1Hash} not found in eContent`); - assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes'); - - const concatHash = hash(signatureAlgorithm, dataGroupHashes); - - assert( - arraysAreEqual( - concatHash, - eContent.slice(eContent.length - hashLen) - ), - 'concatHash is not at the right place in eContent' - ); + const eContentHash = hash(signatureAlgorithm, eContent); + const eContentHashOffset = findSubarrayIndex(signedAttr, eContentHash) + console.log('eContentHashOffset', eContentHashOffset); + assert(eContentHashOffset !== -1, `eContent hash ${eContentHash} not found in signedAttr`); const leaf = getLeaf({ signatureAlgorithm: signatureAlgorithm, @@ -76,24 +69,31 @@ export function generateCircuitInputsRegister( const proof = tree.createProof(index); // console.log("verifyProof", tree.verifyProof(proof)); - if (dataGroupHashes.length > MAX_DATAHASHES_LEN) { - console.error(`Data hashes too long (${dataGroupHashes.length} bytes). Max length is ${MAX_DATAHASHES_LEN} bytes.`); - throw new Error(`This length of datagroups (${dataGroupHashes.length} bytes) is currently unsupported. Please contact us so we add support!`); + if (eContent.length > MAX_PADDED_ECONTENT_LEN) { + console.error(`Data hashes too long (${eContent.length} bytes). Max length is ${MAX_PADDED_ECONTENT_LEN} bytes.`); + throw new Error(`This length of datagroups (${eContent.length} bytes) is currently unsupported. Please contact us so we add support!`); } - const [messagePadded, messagePaddedLen] = shaPad( + const [eContentPadded, eContentLen] = shaPad( signatureAlgorithm, - new Uint8Array(dataGroupHashes), - MAX_DATAHASHES_LEN + new Uint8Array(eContent), + MAX_PADDED_ECONTENT_LEN + ); + const [signedAttrPadded, signedAttrPaddedLen] = shaPad( + signatureAlgorithm, + new Uint8Array(signedAttr), + MAX_PADDED_SIGNED_ATTR_LEN ); return { secret: [secret], - mrz: formattedMrz.map(byte => String(byte)), - // dg1_hash_offset: [dg1HashOffset.toString()], // uncomment when adding new circuits - econtent: Array.from(messagePadded).map((x) => x.toString()), - datahashes_padded_length: [messagePaddedLen.toString()], - signed_attributes: eContent.map(toUnsignedByte).map(byte => String(byte)), + dg1: dg1.map(byte => String(byte)), + dg1_hash_offset: [dg1HashOffset.toString()], // uncomment when adding new circuits + econtent: Array.from(eContentPadded).map((x) => x.toString()), + econtent_padded_length: [eContentLen.toString()], + signed_attr: Array.from(signedAttrPadded).map((x) => x.toString()), + signed_attr_padded_length: [signedAttrPaddedLen.toString()], + signed_attr_econtent_hash_offset: [eContentHashOffset.toString()], signature: splitToWords( BigInt(bytesToBigDecimal(encryptedDigest)), BigInt(64), @@ -127,15 +127,15 @@ export function generateCircuitInputsDisclose( exponent: passportData.pubKey.exponent, }); - const formattedMrz = formatMrz(passportData.mrz); - const mrz_bytes = packBytes(formattedMrz); + const dg1 = formatMrz(passportData.mrz); + const dg1_bytes = packBytes(dg1); const commitment = poseidon6([ secret, attestation_id, pubkey_leaf, - mrz_bytes[0], - mrz_bytes[1], - mrz_bytes[2] + dg1_bytes[0], + dg1_bytes[1], + dg1_bytes[2] ]); console.log('commitment', commitment.toString()); @@ -148,7 +148,7 @@ export function generateCircuitInputsDisclose( secret: [secret], attestation_id: [attestation_id], pubkey_leaf: [pubkey_leaf.toString()], - mrz: formattedMrz.map(byte => String(byte)), + dg1: dg1.map(byte => String(byte)), merkle_root: [merkletree.root.toString()], merkletree_size: [BigInt(depthForThisOne).toString()], path: merkleProofIndices.map(index => BigInt(index).toString()), @@ -175,4 +175,4 @@ export function findIndexInTree(tree: LeanIMT, commitment: bigint): number { console.log(`Index of commitment in the registry: ${index}`); } return index; -} \ No newline at end of file +} diff --git a/common/src/utils/mockPassportData.ts b/common/src/utils/mockPassportData.ts index de7da57f..612aeca3 100644 --- a/common/src/utils/mockPassportData.ts +++ b/common/src/utils/mockPassportData.ts @@ -7,7 +7,7 @@ export const mockPassportData_sha256WithRSAEncryption_65537 = { "25765736223988998667840500778189949868451613342077606460859210922511052625759496119999327689569971597023682649195203990693368929496225818878431536656524613749134155885566243710074017849156387160630116071644605393154527561104329314133650925802529202493002281004186898817134780029845600308376449076243160628443612875871696451909631444284612538876146775788454905886375392424559872753930863026490112290338742311706592933371007008127621682785088607674884944461624900996663751897866140822800320086882377049066596330978938181261694513943840546157351331784368336520946815362357363027160374987439808774582633894814729403608773", exponent: '65537', }, - dataGroupHashes: [ + eContent: [ 48, -126, 1, 37, 2, 1, 0, 48, 11, 6, 9, 96, -122, 72, 1, 101, 3, 4, 2, 1, 48, -126, 1, 17, 48, 37, 2, 1, 1, 4, 32, -80, -33, 31, -123, 108, 84, -98, 102, 70, 11, -91, -81, -60, 12, -55, -126, 25, -125, 46, 125, -100, -62, 28, @@ -27,7 +27,7 @@ export const mockPassportData_sha256WithRSAEncryption_65537 = { -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38, ], - eContent: [ + signedAttr: [ 49, 102, 48, 21, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 3, 49, 8, 6, 6, 103, -127, 8, 1, 1, 1, 48, 28, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 5, 49, 15, 23, 13, 49, 57, 49, 50, 49, 54, 49, 55, 50, 50, 51, 56, 90, 48, 47, @@ -64,7 +64,7 @@ export const mockPassportData_sha1WithRSAEncryption_65537 = { "modulus": "20477031263147244346544354323301139601767744651331737943714766460516664058082391743915964756920726372697500098227541056656534509790848219914065063450254512903386658696088730805744727685744405394693971334276618576488964256042813600534930503696024422088264315736568950128068378868800582180148051833784527554546754791204156184140725514551605098415493542414077617305222270389904871499963025793941382419026429864346013405680126698407208744643562350140521858134083837345319748263151665682715101379642817725445684162202972421222752622195419953301171758360850976312384329379594810200565973441549610793320035551786822491809767", "exponent": "65537" }, - "dataGroupHashes": [ + "eContent": [ 48, -126, 1, 37, 2, 1, 0, 48, 11, 6, 9, 96, -122, 72, 1, 101, 3, 4, 2, 1, 48, -126, 1, 17, 48, 37, 2, 1, 1, 4, 32, -96, 114, -93, 25, 75, 70, 94, 85, 95, 40, -11, -101, 88, -85, -108, -10, -44, 104, -62, -117, 48, 37, 2, 1, 2, @@ -74,7 +74,7 @@ export const mockPassportData_sha1WithRSAEncryption_65537 = { 2, 1, 14, 4, 32, 76, 123, -40, 13, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59 ], - "eContent": [ + "signedAttr": [ 49, 102, 48, 21, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 3, 49, 8, 6, 6, 103, -127, 8, 1, 1, 1, 48, 28, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 5, 49, 15, 23, 13, 49, 57, 49, 50, 49, 54, 49, 55, 50, 50, 51, 56, 90, 48, 47, @@ -109,7 +109,7 @@ export const mockPassportData_sha256WithRSASSAPSS_65537 = { "modulus": "27981978959425503209292172727411418014990488071831976226616367950429509197421162582363593871537790010637936055771010989334091016580571842937938354969046967519746517641154578603398020951481965428574606776389054131169105002076650294369622499723554669350745204676674747140249001021406402432647568831293745606703965825595133008436759474663968651546630831308202454181181120020140624552468338395531631589140331577857081313096404575404894488069125604202487567850880274432629308635934045271542662361749283762712193704727156223863656866893752036283212382351869615567264550513950129097969243499462760447180472872921300872481279", "exponent": "65537" }, - "dataGroupHashes": [ + "eContent": [ -108, 40, 38, -36, -86, 78, 46, -48, -116, 81, 75, -76, -57, 37, -42, -101, -94, 90, -113, -91, -37, 116, -73, 75, -114, -42, -31, 76, -22, 2, -80, -33, 31, -123, 108, 84, -98, 102, 70, 11, -91, -81, -60, 12, -55, -126, 25, -125, @@ -127,7 +127,7 @@ export const mockPassportData_sha256WithRSASSAPSS_65537 = { 13, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38 ], - "eContent": [ + "signedAttr": [ 49, 102, 48, 21, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 3, 49, 8, 6, 6, 103, -127, 8, 1, 1, 1, 48, 28, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 5, 49, 15, 23, 13, 49, 57, 49, 50, 49, 54, 49, 55, 50, 50, 51, 56, 90, 48, 47, @@ -164,7 +164,7 @@ export const mockPassportData_SHA384withECDSA = { "pubKey": { "publicKeyQ": "(1719bfd10ce41b5015348e588fcf43fa1970c019593444097bf52e96f6793ae3ae351a43619faff892e0e53947365e4a,131ad96fb34330662ad88ec50227be0cbff1586cb50f258de2a1312869b17743e04fb7afa1ee0d7d8b2f5cfada6c36f2,1,fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc)" }, - "dataGroupHashes": [ + "eContent": [ 31, -31, 126, 52, -48, 58, 7, 73, -30, -28, -67, -32, 70, 102, -20, -16, -27, 38, -93, 33, 74, -16, -45, 10, -7, -124, -102, -8, -124, -42, 7, 67, -36, -106, 120, -70, 115, 70, -106, -117, -119, 124, 6, -12, -6, -19, -27, @@ -186,7 +186,7 @@ export const mockPassportData_SHA384withECDSA = { -18, 38, 76, 123, -40, 13, 51, -29, 72, -11, 59, -63, -18, -90, 103, 49, 23, -92, -85, -68, -62, -59, -100, -69, -7, 28, -58, 95, 69, 15, -74, 56, 54, 38 ], - "eContent": [ + "signedAttr": [ 49, 102, 48, 21, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 3, 49, 8, 6, 6, 103, -127, 8, 1, 1, 1, 48, 28, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 5, 49, 15, 23, 13, 49, 57, 49, 50, 49, 54, 49, 55, 50, 50, 51, 56, 90, 48, 47, @@ -212,4 +212,4 @@ export const mockPassportDatas = [ mockPassportData_sha1WithRSAEncryption_65537, mockPassportData_sha256WithRSASSAPSS_65537, // mockPassportData_SHA384withECDSA // temp cause formatting of ecdsa key is not done well now -] \ No newline at end of file +] diff --git a/common/src/utils/types.ts b/common/src/utils/types.ts index f4174b7f..f4525c80 100644 --- a/common/src/utils/types.ts +++ b/common/src/utils/types.ts @@ -3,8 +3,8 @@ export type PassportData = { signatureAlgorithm: string; dsc?: string; pubKey: {modulus?: string, exponent?: string, curveName?: string, publicKeyQ?: string}; - dataGroupHashes: number[]; eContent: number[]; + signedAttr: number[]; encryptedDigest: number[]; photoBase64: string; }; @@ -16,4 +16,4 @@ export type Proof = { c: [string, string] }; pub_signals: string[]; -} \ No newline at end of file +} diff --git a/common/src/utils/utils.ts b/common/src/utils/utils.ts index 75c46ee6..31e358ab 100644 --- a/common/src/utils/utils.ts +++ b/common/src/utils/utils.ts @@ -69,7 +69,7 @@ export function formatAndConcatenateDataHashes( // 96, -122, 72, 1, 101, 3, 4, 2, 1, // // NULL tag + SEQUENCE + length (117 bytes) // 5, 0, 48, 117, - + // SHA384withECDSA (index of mrzhash is 33) // // SEQUENCE + long form indicator + length (313 bytes) // 48, -126, 1, 57, @@ -101,37 +101,37 @@ export function formatAndConcatenateDataHashes( return concat; } -export function assembleEContent( +export function assembleSignedAttr( messageDigest: number[], ) { - const constructedEContent = []; + const constructedSignedAttr = []; // Detailed description is in private file r&d.ts for now // First, the tag and length, assumed to be always the same - constructedEContent.push(...[49, 102]); + constructedSignedAttr.push(...[49, 102]); // 1.2.840.113549.1.9.3 is RFC_3369_CONTENT_TYPE_OID - constructedEContent.push( + constructedSignedAttr.push( ...[48, 21, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 3], ); // 2.23.136.1.1.1 is ldsSecurityObject - constructedEContent.push(...[49, 8, 6, 6, 103, -127, 8, 1, 1, 1]); + constructedSignedAttr.push(...[49, 8, 6, 6, 103, -127, 8, 1, 1, 1]); // 1.2.840.113549.1.9.5 is signing-time - constructedEContent.push( + constructedSignedAttr.push( ...[48, 28, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 5], ); // mock time of signature - constructedEContent.push(...[49, 15, 23, 13, 49, 57, 49, 50, 49, 54, 49, 55, 50, 50, 51, 56, 90]); + constructedSignedAttr.push(...[49, 15, 23, 13, 49, 57, 49, 50, 49, 54, 49, 55, 50, 50, 51, 56, 90]); // 1.2.840.113549.1.9.4 is RFC_3369_MESSAGE_DIGEST_OID - constructedEContent.push( + constructedSignedAttr.push( ...[48, 47, 6, 9, 42, -122, 72, -122, -9, 13, 1, 9, 4], ); // TAG and length of the message digest - constructedEContent.push(...[49, 34, 4, 32]); + constructedSignedAttr.push(...[49, 34, 4, 32]); - constructedEContent.push(...messageDigest); - return constructedEContent; + constructedSignedAttr.push(...messageDigest); + return constructedSignedAttr; } export function toUnsigned(byte: number) { @@ -321,4 +321,4 @@ export function findSubarrayIndex(arr: any[], subarray: any[]): number { return arr.findIndex((_, index) => subarray.every((element, i) => element === arr[index + i]) ); -} \ No newline at end of file +} From a121a78e63d11cc929b4357aa76b027fc94e2f11 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Sat, 14 Sep 2024 19:44:48 +0200 Subject: [PATCH 02/60] add signatureAlgorithm.circom --- .../circuits/utils/signatureAlgorithm.circom | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 circuits/circuits/utils/signatureAlgorithm.circom diff --git a/circuits/circuits/utils/signatureAlgorithm.circom b/circuits/circuits/utils/signatureAlgorithm.circom new file mode 100644 index 00000000..dc523b98 --- /dev/null +++ b/circuits/circuits/utils/signatureAlgorithm.circom @@ -0,0 +1,52 @@ +function getHashLength(signatureAlgorithm) { + if (signatureAlgorithm == 1 ) { + return 256; + } + if (signatureAlgorithm == 3) { + return 160; + } + if (signatureAlgorithm == 4) { + return 256; + } + if (signatureAlgorithm == 7) { + return 160; + } + if (signatureAlgorithm == 8) { + return 256; + } + if (signatureAlgorithm == 9) { + return 384; + } + return 0; +} + +function getKeyLength(signatureAlgorithm) { + if (signatureAlgorithm == 1 ) { + return 2048; + } + if (signatureAlgorithm == 3) { + return 2048; + } + if (signatureAlgorithm == 4) { + return 2048; + } + if (signatureAlgorithm == 7) { + return 256; + } + if (signatureAlgorithm == 8) { + return 256; + } + if (signatureAlgorithm == 9) { + return 384; + } + return 0; +} + +function getExponentBits(signatureAlgorithm) { + if (signatureAlgorithm == 1 ) { + return 16; + } + if (signatureAlgorithm == 3) { + return 1; + } +} \ No newline at end of file From 6e80cc6f8c0e8d3e9fb4f3f339778eb7ff7996b8 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Mon, 16 Sep 2024 12:52:59 +0200 Subject: [PATCH 03/60] delete old LeafHasher templates --- circuits/circuits/utils/leafHasher.circom | 25 ------------------ .../circuits/utils/leafHasher.circom.save | 26 ------------------- 2 files changed, 51 deletions(-) delete mode 100644 circuits/circuits/utils/leafHasher.circom delete mode 100644 circuits/circuits/utils/leafHasher.circom.save diff --git a/circuits/circuits/utils/leafHasher.circom b/circuits/circuits/utils/leafHasher.circom deleted file mode 100644 index 74076b46..00000000 --- a/circuits/circuits/utils/leafHasher.circom +++ /dev/null @@ -1,25 +0,0 @@ -pragma circom 2.1.6; -include "@zk-email/circuits/lib/fp.circom"; -include "circomlib/circuits/poseidon.circom"; -include "../utils/splitSignalsToWords.circom"; - -template LeafHasher(n, k) { - signal input in[k]; - signal output out; - var wordsSize = div_ceil(n * k, 64); - component splitSignalsToWords = SplitSignalsToWords(n, k, wordsSize, 64); - splitSignalsToWords.in <== in; - - component hash[4]; - for (var i = 0; i < 4 ; i ++){ - hash[i] = Poseidon(16); - } - for (var i = 0; i < 64 ; i ++){ - hash[ i % 4 ].inputs[ i \ 4 ] <== splitSignalsToWords.out[i]; - } - component finalHash = Poseidon(4); - for (var i = 0 ; i < 4 ; i++){ - finalHash.inputs[i] <== hash[i].out; - } - out <== finalHash.out; -} diff --git a/circuits/circuits/utils/leafHasher.circom.save b/circuits/circuits/utils/leafHasher.circom.save deleted file mode 100644 index 508a0657..00000000 --- a/circuits/circuits/utils/leafHasher.circom.save +++ /dev/null @@ -1,26 +0,0 @@ -pragma circom 2.1.6; - -include "circomlib/circuits/poseidon.circom"; - -template LeafHasher (k) { - signal input in[k]; - signal output out; - component hash[4]; - for (var i = 0; i < 4 ; i ++){ - hash[i] = Poseidon(16); - } - for (var i = 0; i < 64 ; i ++){ - if (i < k ){ - hash[ i % 4 ].inputs[ i \ 4 ] <== in[i]; - } - else{ - hash[ i % 4 ].inputs[ i \ 4 ] <== 0; - } - } - component finalHash = Poseidon(4); - for (var i = 0 ; i < 4 ; i++){ - finalHash.inputs[i] <== hash[i].out; - } - log(finalHash.out); - out <== finalHash.out; -} From ce48d1d96aca782b0a64228b627dbc43b0f39e10 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Mon, 16 Sep 2024 13:03:09 +0200 Subject: [PATCH 04/60] refactor openpassport register circuits templates, correction of variable names eContent and signAttr --- .../instances/register_ecdsa_sha256.circom | 5 + .../register_rsa_65537_sha256.circom | 5 + .../register/openpassport_register.circom | 43 ++++ .../register/register_ecdsa_sha1.circom | 65 ----- .../register/register_ecdsa_sha256.circom | 64 ----- .../register/register_rsa_65537_sha1.circom | 54 ---- .../register/register_rsa_65537_sha256.circom | 54 ---- .../register_rsapss_65537_sha256.circom | 54 ---- .../circuits/utils/computeCommitment.circom | 11 +- .../circuits/utils/leafHasherLight.circom | 1 + .../utils/passport/formatECDSAInputs.circom | 6 + .../{ => passport}/signatureAlgorithm.circom | 28 ++ circuits/tests/register.test.ts | 239 +++++++++--------- common/src/constants/constants.ts | 4 + common/src/utils/genMockPassportData.ts | 4 +- common/src/utils/generateInputs.ts | 92 ++++++- common/src/utils/types.ts | 2 +- 17 files changed, 311 insertions(+), 420 deletions(-) create mode 100644 circuits/circuits/register/instances/register_ecdsa_sha256.circom create mode 100644 circuits/circuits/register/instances/register_rsa_65537_sha256.circom create mode 100644 circuits/circuits/register/openpassport_register.circom delete mode 100644 circuits/circuits/register/register_ecdsa_sha1.circom delete mode 100644 circuits/circuits/register/register_ecdsa_sha256.circom delete mode 100644 circuits/circuits/register/register_rsa_65537_sha1.circom delete mode 100644 circuits/circuits/register/register_rsa_65537_sha256.circom delete mode 100644 circuits/circuits/register/register_rsapss_65537_sha256.circom create mode 100644 circuits/circuits/utils/passport/formatECDSAInputs.circom rename circuits/circuits/utils/{ => passport}/signatureAlgorithm.circom (67%) diff --git a/circuits/circuits/register/instances/register_ecdsa_sha256.circom b/circuits/circuits/register/instances/register_ecdsa_sha256.circom new file mode 100644 index 00000000..456304c6 --- /dev/null +++ b/circuits/circuits/register/instances/register_ecdsa_sha256.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.6; + +include "../openpassport_register.circom"; + +component main = OPENPASSPORT_REGISTER(8, 43, 6, 640, 512); \ No newline at end of file diff --git a/circuits/circuits/register/instances/register_rsa_65537_sha256.circom b/circuits/circuits/register/instances/register_rsa_65537_sha256.circom new file mode 100644 index 00000000..bf7123c8 --- /dev/null +++ b/circuits/circuits/register/instances/register_rsa_65537_sha256.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.6; + +include "../openpassport_register.circom"; + +component main = OPENPASSPORT_REGISTER(1, 64, 32, 640, 512); \ No newline at end of file diff --git a/circuits/circuits/register/openpassport_register.circom b/circuits/circuits/register/openpassport_register.circom new file mode 100644 index 00000000..7fb7430f --- /dev/null +++ b/circuits/circuits/register/openpassport_register.circom @@ -0,0 +1,43 @@ +pragma circom 2.1.6; + +// include "circomlib/circuits/poseidon.circom"; +// include "@zk-email/circuits/utils/bytes.circom"; +// include "./passport_verifier_sha256WithRSAEncryption_65537.circom"; +// include "./utils/chunk_data.circom"; +// include "./utils/compute_pubkey_leaf.circom"; +include "../utils/leafHasherLight.circom"; +include "../utils/computeCommitment.circom"; +include "../utils/passport/signatureAlgorithm.circom"; + +template OPENPASSPORT_REGISTER(signatureAlgorithm, n, k, max_padded_econtent_len, max_padded_signed_attr_len) { + var kLengthFactor = getKLengthFactor(signatureAlgorithm); + var kScaled = k * kLengthFactor; + + signal input secret; + signal input dsc_secret; + signal input dg1[93]; + signal input dg1_hash_offset; + signal input econtent[max_padded_econtent_len]; + signal input econtent_padded_length; + signal input signed_attr[max_padded_signed_attr_len]; + signal input signed_attr_padded_length; + signal input signed_attr_econtent_hash_offset; + signal input signature[kScaled]; + + signal input pubkey[kScaled]; + + signal input attestation_id; + + // leaf + signal leaf <== LeafHasherLightWithSigAlg(kScaled)(pubkey, signatureAlgorithm); + + // commitment + signal output commitment <== ComputeCommitment()(secret, attestation_id, leaf, dg1); + + // blinded dsc commitment + signal output blinded_dsc_commitment <== Poseidon(2)([dsc_secret, leaf]); + + // nullifier + signal output nullifier <== LeafHasherLight(kScaled)(signature); + +} \ No newline at end of file diff --git a/circuits/circuits/register/register_ecdsa_sha1.circom b/circuits/circuits/register/register_ecdsa_sha1.circom deleted file mode 100644 index b3c57ac2..00000000 --- a/circuits/circuits/register/register_ecdsa_sha1.circom +++ /dev/null @@ -1,65 +0,0 @@ -pragma circom 2.1.5; - -include "circomlib/circuits/poseidon.circom"; -include "../verifier/passport_verifier_ecdsa_sha1.circom"; -include "../utils/computeCommitment.circom"; -include "../utils/leafHasherLight.circom"; - -template REGISTER_ECDSA_SHA1(n, k, max_datahashes_bytes, nLevels, signatureAlgorithm) { - signal input secret; - - signal input mrz[93]; - signal input dg1_hash_offset; - signal input dataHashes[max_datahashes_bytes]; - signal input datahashes_padded_length; - signal input eContent[92]; - - signal input signature_r[k]; // ECDSA signature component r - signal input signature_s[k]; // ECDSA signature component s - signal input dsc_modulus_x[k]; // Public Key x-coordinate - signal input dsc_modulus_y[k]; // Public Key y-coordinate - - signal input dsc_secret; - signal input attestation_id; - - // hash the dsc pubkey to generate the leaf - component leafHasher = LeafHasherLightWithSigAlgECDSA(k); - leafHasher.sigAlg <== signatureAlgorithm; - leafHasher.x <== dsc_modulus_x; - leafHasher.y <== dsc_modulus_y; - signal leaf <== leafHasher.out; - - - component dsc_commitment_hasher = Poseidon(2); - component nullifier_hasher = Poseidon(2); - - dsc_commitment_hasher.inputs[0] <== dsc_secret; - dsc_commitment_hasher.inputs[1] <== leaf; - - signal output blinded_dsc_commitment <== dsc_commitment_hasher.out; - - // Poseidon(signature_r[0], signature_r[1], ..., signature_r[5]) - signal signature_r_hash <== Poseidon(k)(signature_r); - signal signature_s_hash <== Poseidon(k)(signature_s); - - nullifier_hasher.inputs[0] <== signature_r_hash; - nullifier_hasher.inputs[1] <== signature_s_hash; - signal output nullifier <== nullifier_hasher.out; - - // Verify passport validity - component PV = PASSPORT_VERIFIER_ECDSA_SHA1(n, k, max_datahashes_bytes); - PV.mrz <== mrz; - PV.dg1_hash_offset <== dg1_hash_offset; - PV.dataHashes <== dataHashes; - PV.datahashes_padded_length <== datahashes_padded_length; - PV.eContentBytes <== eContent; - PV.dsc_modulus <== [dsc_modulus_x, dsc_modulus_y]; - PV.signature_r <== signature_r; - PV.signature_s <== signature_s; - - // Generate the commitment - signal output commitment <== ComputeCommitment()(secret, attestation_id, leaf_hasher.out, mrz); -} - -// We hardcode 7 here for ecdsa_with_SHA1 -component main { public [ attestation_id ] } = REGISTER_ECDSA_SHA1(43, 6, 320, 16, 7); diff --git a/circuits/circuits/register/register_ecdsa_sha256.circom b/circuits/circuits/register/register_ecdsa_sha256.circom deleted file mode 100644 index 74ebf4d9..00000000 --- a/circuits/circuits/register/register_ecdsa_sha256.circom +++ /dev/null @@ -1,64 +0,0 @@ -pragma circom 2.1.5; - -include "circomlib/circuits/poseidon.circom"; -include "../verifier/passport_verifier_ecdsa_sha256.circom"; -include "../utils/computeCommitment.circom"; -include "../utils/leafHasherLight.circom"; - -template REGISTER_ECDSA_SHA256(n, k, max_datahashes_bytes, nLevels, signatureAlgorithm) { - signal input secret; - - signal input mrz[93]; - signal input dg1_hash_offset; - signal input dataHashes[max_datahashes_bytes]; - signal input datahashes_padded_length; - signal input eContent[104]; - - signal input signature_r[k]; // ECDSA signature component r - signal input signature_s[k]; // ECDSA signature component s - signal input dsc_modulus_x[k]; // Public Key x-coordinate - signal input dsc_modulus_y[k]; // Public Key y-coordinate - - signal input dsc_secret; - signal input attestation_id; - - // hash the dsc pubkey to generate the leaf - component leafHasher = LeafHasherLightWithSigAlgECDSA(k); - leafHasher.sigAlg <== signatureAlgorithm; - leafHasher.x <== dsc_modulus_x; - leafHasher.y <== dsc_modulus_y; - signal leaf <== leafHasher.out; - - component dsc_commitment_hasher = Poseidon(2); - component nullifier_hasher = Poseidon(2); - - dsc_commitment_hasher.inputs[0] <== dsc_secret; - dsc_commitment_hasher.inputs[1] <== leaf; - - signal output blinded_dsc_commitment <== dsc_commitment_hasher.out; - - // Poseidon(signature_r[0], signature_r[1], ..., signature_r[5]) - signal signature_r_hash <== Poseidon(k)(signature_r); - signal signature_s_hash <== Poseidon(k)(signature_s); - - nullifier_hasher.inputs[0] <== signature_r_hash; - nullifier_hasher.inputs[1] <== signature_s_hash; - signal output nullifier <== nullifier_hasher.out; - - // Verify passport validity - component PV = PASSPORT_VERIFIER_ECDSA_SHA256(n, k, max_datahashes_bytes); - PV.mrz <== mrz; - PV.dg1_hash_offset <== dg1_hash_offset; - PV.dataHashes <== dataHashes; - PV.datahashes_padded_length <== datahashes_padded_length; - PV.eContentBytes <== eContent; - PV.dsc_modulus <== [dsc_modulus_x, dsc_modulus_y]; - PV.signature_r <== signature_r; - PV.signature_s <== signature_s; - - // Generate the commitment - signal output commitment <== ComputeCommitment()(secret, attestation_id, leaf, mrz); -} - -// We hardcode 8 here for ecdsa_with_SHA256 -component main { public [ attestation_id ] } = REGISTER_ECDSA_SHA256(43, 6, 320, 16, 8); diff --git a/circuits/circuits/register/register_rsa_65537_sha1.circom b/circuits/circuits/register/register_rsa_65537_sha1.circom deleted file mode 100644 index c6cd3437..00000000 --- a/circuits/circuits/register/register_rsa_65537_sha1.circom +++ /dev/null @@ -1,54 +0,0 @@ -pragma circom 2.1.5; - -include "circomlib/circuits/poseidon.circom"; -include "../verifier/passport_verifier_rsa_65537_sha1.circom"; -include "../utils/splitSignalsToWords.circom"; -include "../utils/leafHasherLight.circom"; -include "../utils/computeCommitment.circom"; - -template REGISTER_RSA_65537_SHA1(n, k, max_datahashes_bytes, nLevels, signatureAlgorithm) { - signal input secret; - - signal input mrz[93]; - signal input dg1_hash_offset; - signal input dataHashes[max_datahashes_bytes]; - signal input datahashes_padded_length; - signal input eContent[92]; - signal input signature[k]; - signal input dsc_modulus[k]; - signal input dsc_secret; - signal input attestation_id; - - signal split_signature[9] <== SplitSignalsToWords(n, k, 230, 9)(signature); - signal output nullifier <== Poseidon(9)(split_signature); - - signal split_modulus[9] <== SplitSignalsToWords(n, k, 230, 9)(dsc_modulus); - component dsc_commitment_hasher = Poseidon(10); - dsc_commitment_hasher.inputs[0] <== dsc_secret; - for (var i = 0; i < 9; i++) { - dsc_commitment_hasher.inputs[i + 1] <== split_modulus[i]; - } - signal output blinded_dsc_commitment <== dsc_commitment_hasher.out; - - // Verify passport validity - component PV = PASSPORT_VERIFIER_RSA_65537_SHA1(n, k, max_datahashes_bytes); - PV.mrz <== mrz; - PV.dg1_hash_offset <== dg1_hash_offset; - PV.dataHashes <== dataHashes; - PV.datahashes_padded_length <== datahashes_padded_length; - PV.eContentBytes <== eContent; - PV.dsc_modulus <== dsc_modulus; - PV.signature <== signature; - - // Generate the leaf - component leafHasher = LeafHasherLightWithSigAlg(k); - leafHasher.sigAlg <== signatureAlgorithm; - leafHasher.in <== dsc_modulus; - signal leaf <== leafHasher.out; - - // Generate the commitment - signal output commitment <== ComputeCommitment()(secret, attestation_id, leaf, mrz); -} - -// We hardcode 3 here for sha1WithRSAEncryption_65537 -component main { public [ attestation_id ] } = REGISTER_RSA_65537_SHA1(64, 32, 320, 16, 3); diff --git a/circuits/circuits/register/register_rsa_65537_sha256.circom b/circuits/circuits/register/register_rsa_65537_sha256.circom deleted file mode 100644 index 23c0fd45..00000000 --- a/circuits/circuits/register/register_rsa_65537_sha256.circom +++ /dev/null @@ -1,54 +0,0 @@ -pragma circom 2.1.5; - -include "circomlib/circuits/poseidon.circom"; -include "../verifier/passport_verifier_rsa_65537_sha256.circom"; -include "../utils/splitSignalsToWords.circom"; -include "../utils/leafHasherLight.circom"; -include "../utils/computeCommitment.circom"; - -template REGISTER_RSA_65537_SHA256(n, k, max_datahashes_bytes, nLevels, signatureAlgorithm) { - signal input secret; - - signal input mrz[93]; - signal input dg1_hash_offset; - signal input dataHashes[max_datahashes_bytes]; - signal input datahashes_padded_length; - signal input eContent[104]; - signal input signature[k]; - signal input dsc_modulus[k]; - signal input dsc_secret; - signal input attestation_id; - - signal split_signature[9] <== SplitSignalsToWords(n, k, 230, 9)(signature); - signal output nullifier <== Poseidon(9)(split_signature); - - signal split_modulus[9] <== SplitSignalsToWords(n, k, 230, 9)(dsc_modulus); - component dsc_commitment_hasher = Poseidon(10); - dsc_commitment_hasher.inputs[0] <== dsc_secret; - for (var i = 0; i < 9; i++) { - dsc_commitment_hasher.inputs[i + 1] <== split_modulus[i]; - } - signal output blinded_dsc_commitment <== dsc_commitment_hasher.out; - - // Verify passport validity - component PV = PASSPORT_VERIFIER_RSA_65537_SHA256(n, k, max_datahashes_bytes); - PV.mrz <== mrz; - PV.dg1_hash_offset <== dg1_hash_offset; - PV.dataHashes <== dataHashes; - PV.datahashes_padded_length <== datahashes_padded_length; - PV.eContentBytes <== eContent; - PV.dsc_modulus <== dsc_modulus; - PV.signature <== signature; - - // Generate the leaf - component leafHasher = LeafHasherLightWithSigAlg(k); - leafHasher.sigAlg <== signatureAlgorithm; - leafHasher.in <== dsc_modulus; - signal leaf <== leafHasher.out; - - // Generate the commitment - signal output commitment <== ComputeCommitment()(secret, attestation_id, leaf, mrz); -} - -// We hardcode 1 here for sha256WithRSAEncryption_65537 -component main { public [ attestation_id ] } = REGISTER_RSA_65537_SHA256(64, 32, 320, 16, 1); diff --git a/circuits/circuits/register/register_rsapss_65537_sha256.circom b/circuits/circuits/register/register_rsapss_65537_sha256.circom deleted file mode 100644 index e3400da1..00000000 --- a/circuits/circuits/register/register_rsapss_65537_sha256.circom +++ /dev/null @@ -1,54 +0,0 @@ -pragma circom 2.1.5; - -include "circomlib/circuits/poseidon.circom"; -include "../verifier/passport_verifier_rsapss_65537_sha256.circom"; -include "../utils/splitSignalsToWords.circom"; -include "../utils/leafHasherLight.circom"; -include "../utils/computeCommitment.circom"; - -template REGISTER_RSAPSS_65537_SHA256(n, k, max_datahashes_bytes, nLevels, signatureAlgorithm) { - signal input secret; - - signal input mrz[93]; - signal input dg1_hash_offset; - signal input dataHashes[max_datahashes_bytes]; - signal input datahashes_padded_length; - signal input eContent[104]; - signal input signature[k]; - signal input dsc_modulus[k]; - signal input dsc_secret; - signal input attestation_id; - - signal split_signature[9] <== SplitSignalsToWords(n, k, 230, 9)(signature); - signal output nullifier <== Poseidon(9)(split_signature); - - signal split_modulus[9] <== SplitSignalsToWords(n, k, 230, 9)(dsc_modulus); - component dsc_commitment_hasher = Poseidon(10); - dsc_commitment_hasher.inputs[0] <== dsc_secret; - for (var i = 0; i < 9; i++) { - dsc_commitment_hasher.inputs[i + 1] <== split_modulus[i]; - } - signal output blinded_dsc_commitment <== dsc_commitment_hasher.out; - - // Verify passport validity - component PV = PASSPORT_VERIFIER_RSAPSS_65537_SHA256(n, k, max_datahashes_bytes); - PV.mrz <== mrz; - PV.dg1_hash_offset <== dg1_hash_offset; - PV.dataHashes <== dataHashes; - PV.datahashes_padded_length <== datahashes_padded_length; - PV.eContentBytes <== eContent; - PV.dsc_modulus <== dsc_modulus; - PV.signature <== signature; - - // Generate the leaf - component leafHasher = LeafHasherLightWithSigAlg(k); - leafHasher.sigAlg <== signatureAlgorithm; - leafHasher.in <== dsc_modulus; - signal leaf <== leafHasher.out; - - // Generate the commitment - signal output commitment <== ComputeCommitment()(secret, attestation_id, leaf, mrz); -} - -// We hardcode 4 here for sha256WithRSASSAPSS_65537 -component main { public [ attestation_id ] } = REGISTER_RSAPSS_65537_SHA256(64, 32, 320, 16, 4); diff --git a/circuits/circuits/utils/computeCommitment.circom b/circuits/circuits/utils/computeCommitment.circom index e14fbe52..c4454a78 100644 --- a/circuits/circuits/utils/computeCommitment.circom +++ b/circuits/circuits/utils/computeCommitment.circom @@ -1,12 +1,12 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "circomlib/circuits/poseidon.circom"; - +include "@zk-email/circuits/utils/bytes.circom"; template ComputeCommitment() { signal input secret; signal input attestation_id; signal input leaf; - signal input mrz[93]; + signal input dg1[93]; signal output out; component poseidon_hasher = Poseidon(6); @@ -14,9 +14,10 @@ template ComputeCommitment() { poseidon_hasher.inputs[1] <== attestation_id; poseidon_hasher.inputs[2] <== leaf; - signal mrz_packed[3] <== PackBytes(93)(mrz); + signal dg1_packed[3] <== PackBytes(93)(dg1); for (var i = 0; i < 3; i++) { - poseidon_hasher.inputs[i + 3] <== mrz_packed[i]; + poseidon_hasher.inputs[i + 3] <== dg1_packed[i]; } out <== poseidon_hasher.out; + // out <== leaf; } diff --git a/circuits/circuits/utils/leafHasherLight.circom b/circuits/circuits/utils/leafHasherLight.circom index 10555de1..1a5204e1 100644 --- a/circuits/circuits/utils/leafHasherLight.circom +++ b/circuits/circuits/utils/leafHasherLight.circom @@ -5,6 +5,7 @@ include "circomlib/circuits/poseidon.circom"; template LeafHasherLight(k) { signal input in[k]; var rounds = div_ceil(k, 16); + assert(rounds < 17); component hash[rounds]; for (var i = 0; i < rounds ; i ++){ diff --git a/circuits/circuits/utils/passport/formatECDSAInputs.circom b/circuits/circuits/utils/passport/formatECDSAInputs.circom new file mode 100644 index 00000000..03ca51bb --- /dev/null +++ b/circuits/circuits/utils/passport/formatECDSAInputs.circom @@ -0,0 +1,6 @@ +pragma circom 2.1.6; + + +template FormatECDSAInputs(signatureAlgorithm, k) { + +} diff --git a/circuits/circuits/utils/signatureAlgorithm.circom b/circuits/circuits/utils/passport/signatureAlgorithm.circom similarity index 67% rename from circuits/circuits/utils/signatureAlgorithm.circom rename to circuits/circuits/utils/passport/signatureAlgorithm.circom index dc523b98..0f32e116 100644 --- a/circuits/circuits/utils/signatureAlgorithm.circom +++ b/circuits/circuits/utils/passport/signatureAlgorithm.circom @@ -1,3 +1,5 @@ +pragma circom 2.1.6; + function getHashLength(signatureAlgorithm) { if (signatureAlgorithm == 1 ) { return 256; @@ -42,6 +44,30 @@ function getKeyLength(signatureAlgorithm) { return 0; } +//returns 1 for rsa, 2 for ecdsa +function getKLengthFactor(signatureAlgorithm) { + if (signatureAlgorithm == 1) { + return 1; + } + if (signatureAlgorithm == 3) { + return 1; + } + if (signatureAlgorithm == 4) { + return 1; + } + if (signatureAlgorithm == 7) { + return 2; + } + if (signatureAlgorithm == 8) { + return 2; + } + if (signatureAlgorithm == 9) { + return 2; + } + return 0; + +} + function getExponentBits(signatureAlgorithm) { if (signatureAlgorithm == 1 ) { return 16; @@ -49,4 +75,6 @@ function getExponentBits(signatureAlgorithm) { if (signatureAlgorithm == 3) { return 1; } + + return 0; } \ No newline at end of file diff --git a/circuits/tests/register.test.ts b/circuits/tests/register.test.ts index 704185b3..ac3224da 100644 --- a/circuits/tests/register.test.ts +++ b/circuits/tests/register.test.ts @@ -6,11 +6,11 @@ import { poseidon6 } from 'poseidon-lite'; import { generateCircuitInputsRegister } from '../../common/src/utils/generateInputs'; import { hexToDecimal, packBytes } from '../../common/src/utils/utils'; import { - n_dsc, - k_dsc, - n_dsc_ecdsa, - k_dsc_ecdsa, - PASSPORT_ATTESTATION_ID, + n_dsc, + k_dsc, + n_dsc_ecdsa, + k_dsc_ecdsa, + PASSPORT_ATTESTATION_ID, } from '../../common/src/constants/constants'; import { genMockPassportData } from '../../common/src/utils/genMockPassportData'; import { getCircuitName, parseDSC } from '../../common/src/utils/certificates/handleCertificate'; @@ -18,134 +18,133 @@ import { getLeaf } from '../../common/src/utils/pubkeyTree'; import { SignatureAlgorithm } from '../../common/src/utils/types'; const sigAlgs = [ - { sigAlg: 'rsa', hashFunction: 'sha1' }, - { sigAlg: 'rsa', hashFunction: 'sha256' }, - { sigAlg: 'rsapss', hashFunction: 'sha256' }, - { sigAlg: 'ecdsa', hashFunction: 'sha256' }, - { sigAlg: 'ecdsa', hashFunction: 'sha1' }, + { sigAlg: 'rsa', hashFunction: 'sha256' }, + { sigAlg: 'ecdsa', hashFunction: 'sha256' }, ]; sigAlgs.forEach(({ sigAlg, hashFunction }) => { - describe(`Register - ${hashFunction.toUpperCase()} ${sigAlg.toUpperCase()}`, function () { - this.timeout(0); - let circuit: any; + describe(`Register - ${hashFunction.toUpperCase()} ${sigAlg.toUpperCase()}`, function () { + this.timeout(0); + let circuit: any; - const passportData = genMockPassportData( - `${sigAlg}_${hashFunction}` as SignatureAlgorithm, - 'FRA', - '000101', - '300101' - ); - const secret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); - const dscSecret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); + const passportData = genMockPassportData( + `${sigAlg}_${hashFunction}` as SignatureAlgorithm, + 'FRA', + '000101', + '300101' + ); + const secret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); + const dscSecret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); - const inputs = generateCircuitInputsRegister( - secret, - dscSecret, - PASSPORT_ATTESTATION_ID, - passportData, - sigAlg === 'ecdsa' ? n_dsc_ecdsa : n_dsc, - sigAlg === 'ecdsa' ? k_dsc_ecdsa : k_dsc - ); + const inputs = generateCircuitInputsRegister( + secret, + dscSecret, + PASSPORT_ATTESTATION_ID, + passportData, + sigAlg === 'ecdsa' ? n_dsc_ecdsa : n_dsc, + sigAlg === 'ecdsa' ? k_dsc_ecdsa : k_dsc + ); - before(async () => { - circuit = await wasm_tester( - path.join( - __dirname, - `../circuits/register/${getCircuitName('register', sigAlg, hashFunction)}.circom` - ), - { - include: [ - 'node_modules', - './node_modules/@zk-kit/binary-merkle-root.circom/src', - './node_modules/circomlib/circuits', - ], - } - ); - }); + before(async () => { + circuit = await wasm_tester( + path.join( + __dirname, + `../circuits/register/instances/${getCircuitName('register', sigAlg, hashFunction)}.circom` + ), + { + include: [ + 'node_modules', + './node_modules/@zk-kit/binary-merkle-root.circom/src', + './node_modules/circomlib/circuits', + ], + } + ); + }); - it('should compile and load the circuit', async function () { - expect(circuit).to.not.be.undefined; - }); + it('should compile and load the circuit', async function () { + expect(circuit).to.not.be.undefined; + }); - it('should calculate the witness with correct inputs', async function () { - console.log('inputs', inputs); - const w = await circuit.calculateWitness(inputs); - await circuit.checkConstraints(w); + it('should calculate the witness with correct inputs', async function () { + console.log('inputs', inputs); + const w = await circuit.calculateWitness(inputs); + await circuit.checkConstraints(w); - const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; - console.log('\x1b[34m%s\x1b[0m', 'nullifier', nullifier); - const commitment_circom = (await circuit.getOutput(w, ['commitment'])).commitment; - console.log('\x1b[34m%s\x1b[0m', 'commitment', commitment_circom); - const blinded_dsc_commitment = (await circuit.getOutput(w, ['blinded_dsc_commitment'])) - .blinded_dsc_commitment; - console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment', blinded_dsc_commitment); + const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; + console.log('\x1b[34m%s\x1b[0m', 'nullifier', nullifier); - const n = sigAlg === 'ecdsa' ? n_dsc_ecdsa : n_dsc; - const k = sigAlg === 'ecdsa' ? k_dsc_ecdsa : k_dsc; - const mrz_bytes = packBytes(inputs.mrz); - const leaf = getLeaf(passportData.dsc, n, k).toString(); + // const commitment_circom = (await circuit.getOutput(w, ['commitment'])).commitment; + // console.log('\x1b[34m%s\x1b[0m', 'commitment', commitment_circom); - const commitment_bytes = poseidon6([ - inputs.secret[0], - PASSPORT_ATTESTATION_ID, - leaf, - mrz_bytes[0], - mrz_bytes[1], - mrz_bytes[2], - ]); - const commitment_js = commitment_bytes.toString(); - console.log('commitment_js', commitment_js); - console.log('commitment_circom', commitment_circom); - expect(commitment_circom).to.be.equal(commitment_js); - }); + const blinded_dsc_commitment = (await circuit.getOutput(w, ['blinded_dsc_commitment'])) + .blinded_dsc_commitment; + console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment', blinded_dsc_commitment); - it('should fail to calculate witness with invalid mrz', async function () { - try { - const invalidInputs = { - ...inputs, - mrz: Array(93) - .fill(0) - .map((byte) => BigInt(byte).toString()), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); + // const n = sigAlg === 'ecdsa' ? n_dsc_ecdsa : n_dsc; + // const k = sigAlg === 'ecdsa' ? k_dsc_ecdsa : k_dsc; + // const mrz_bytes = packBytes(inputs.mrz); + // const leaf = getLeaf(passportData.dsc, n, k).toString(); - it('should fail to calculate witness with invalid dataHashes', async function () { - try { - const invalidInputs = { - ...inputs, - dataHashes: inputs.dataHashes.map((byte: string) => - String((parseInt(byte, 10) + 1) % 256) - ), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); + // const commitment_bytes = poseidon6([ + // inputs.secret[0], + // PASSPORT_ATTESTATION_ID, + // leaf, + // mrz_bytes[0], + // mrz_bytes[1], + // mrz_bytes[2], + // ]); + // const commitment_js = commitment_bytes.toString(); + // console.log('commitment_js', commitment_js); + // console.log('commitment_circom', commitment_circom); + // expect(commitment_circom).to.be.equal(commitment_js); + }); + + // it('should fail to calculate witness with invalid mrz', async function () { + // try { + // const invalidInputs = { + // ...inputs, + // mrz: Array(93) + // .fill(0) + // .map((byte) => BigInt(byte).toString()), + // }; + // await circuit.calculateWitness(invalidInputs); + // expect.fail('Expected an error but none was thrown.'); + // } catch (error) { + // expect(error.message).to.include('Assert Failed'); + // } + // }); + + // it('should fail to calculate witness with invalid dataHashes', async function () { + // try { + // const invalidInputs = { + // ...inputs, + // dataHashes: inputs.dataHashes.map((byte: string) => + // String((parseInt(byte, 10) + 1) % 256) + // ), + // }; + // await circuit.calculateWitness(invalidInputs); + // expect.fail('Expected an error but none was thrown.'); + // } catch (error) { + // expect(error.message).to.include('Assert Failed'); + // } + // }); - it('should fail to calculate witness with invalid signature', async function () { - try { - const invalidInputs = { - ...inputs, - signature: inputs.signature - ? inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)) - : undefined, - signature_s: inputs.signature_s - ? inputs.signature_s.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)) - : undefined, - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } + // it('should fail to calculate witness with invalid signature', async function () { + // try { + // const invalidInputs = { + // ...inputs, + // signature: inputs.signature + // ? inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)) + // : undefined, + // signature_s: inputs.signature_s + // ? inputs.signature_s.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)) + // : undefined, + // }; + // await circuit.calculateWitness(invalidInputs); + // expect.fail('Expected an error but none was thrown.'); + // } catch (error) { + // expect(error.message).to.include('Assert Failed'); + // } + // }); }); - }); }); diff --git a/common/src/constants/constants.ts b/common/src/constants/constants.ts index 54984b25..530e7b17 100644 --- a/common/src/constants/constants.ts +++ b/common/src/constants/constants.ts @@ -20,6 +20,10 @@ export const RPC_URL = "https://opt-mainnet.g.alchemy.com/v2/Mjj_SdklUaCdR6EPfVK export const DEVELOPMENT_MODE = true export const DEFAULT_MAJORITY = "18" +export const MAX_PADDED_ECONTENT_LEN = 640; + +export const MAX_PADDED_SIGNED_ATTR_LEN = 512; + export enum SignatureAlgorithmIndex { rsa_65537_sha256_2048 = 1, rsa_65537_sha1_2048 = 3, diff --git a/common/src/utils/genMockPassportData.ts b/common/src/utils/genMockPassportData.ts index 9e92491e..6836f713 100644 --- a/common/src/utils/genMockPassportData.ts +++ b/common/src/utils/genMockPassportData.ts @@ -96,8 +96,8 @@ export function genMockPassportData( return { dsc: dsc, mrz: mrz, - dataGroupHashes: concatenatedDataHashes, - eContent: eContent, + eContent: concatenatedDataHashes, + signedAttr: eContent, encryptedDigest: signatureBytes, photoBase64: 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABjElEQVR42mL8//8/AyUYiBQYmIy3...', mockUser: true, diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index b1160de1..781e1e16 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -1,4 +1,4 @@ -import { MAX_DATAHASHES_LEN, PUBKEY_TREE_DEPTH, DEVELOPMENT_MODE, DEFAULT_USER_ID_TYPE, n_dsc, k_dsc } from '../constants/constants'; +import { MAX_DATAHASHES_LEN, PUBKEY_TREE_DEPTH, DEVELOPMENT_MODE, DEFAULT_USER_ID_TYPE, MAX_PADDED_ECONTENT_LEN, MAX_PADDED_SIGNED_ATTR_LEN } from '../constants/constants'; import { assert, shaPad } from './shaPad'; import { PassportData } from './types'; import { @@ -27,7 +27,97 @@ import { getCSCAModulusMerkleTree } from "./csca"; import { SMT } from "@ashpect/smt" import { parseCertificate } from './certificates/handleCertificate'; + export function generateCircuitInputsRegister( + secret: string, + dscSecret: string, + attestation_id: string, + passportData: PassportData, + n_dsc: number, + k_dsc: number +) { + const { mrz, eContent, signedAttr, encryptedDigest, dsc } = passportData; + const { signatureAlgorithm, hashFunction, hashLen, x, y, modulus } = parseCertificate(passportData.dsc); + + + + + let pubKey: any; + let signature: any; + + if (signatureAlgorithm === 'ecdsa') { + const { r, s } = extractRSFromSignature(encryptedDigest); + + const signature_r = splitToWords(BigInt(hexToDecimal(r)), n_dsc, k_dsc) + const signature_s = splitToWords(BigInt(hexToDecimal(s)), n_dsc, k_dsc) + + signature = [...signature_r, ...signature_s] + const dsc_modulus_x = splitToWords(BigInt(hexToDecimal(x)), n_dsc, k_dsc) + const dsc_modulus_y = splitToWords(BigInt(hexToDecimal(y)), n_dsc, k_dsc) + pubKey = [...dsc_modulus_x, ...dsc_modulus_y] + } else { + + signature = splitToWords( + BigInt(bytesToBigDecimal(encryptedDigest)), + n_dsc, + k_dsc + ) + + pubKey = splitToWords( + BigInt(hexToDecimal(modulus)), + n_dsc, + k_dsc + ) + } + + + const dg1 = formatMrz(mrz); + const dg1Hash = hash(signatureAlgorithm, dg1); + + const dg1HashOffset = findSubarrayIndex(eContent, dg1Hash) + console.log('dg1HashOffset', dg1HashOffset); + assert(dg1HashOffset !== -1, `DG1 hash ${dg1Hash} not found in eContent`); + + const eContentHash = hash(signatureAlgorithm, eContent); + const eContentHashOffset = findSubarrayIndex(signedAttr, eContentHash) + console.log('eContentHashOffset', eContentHashOffset); + assert(eContentHashOffset !== -1, `eContent hash ${eContentHash} not found in signedAttr`); + + + if (eContent.length > MAX_PADDED_ECONTENT_LEN) { + console.error(`Data hashes too long (${eContent.length} bytes). Max length is ${MAX_PADDED_ECONTENT_LEN} bytes.`); + throw new Error(`This length of datagroups (${eContent.length} bytes) is currently unsupported. Please contact us so we add support!`); + } + + const [eContentPadded, eContentLen] = shaPad( + signatureAlgorithm, + new Uint8Array(eContent), + MAX_PADDED_ECONTENT_LEN + ); + const [signedAttrPadded, signedAttrPaddedLen] = shaPad( + signatureAlgorithm, + new Uint8Array(signedAttr), + MAX_PADDED_SIGNED_ATTR_LEN + ); + + return { + secret: [secret], + dsc_secret: [dscSecret], + dg1: dg1.map(byte => String(byte)), + dg1_hash_offset: [dg1HashOffset.toString()], // uncomment when adding new circuits + econtent: Array.from(eContentPadded).map((x) => x.toString()), + econtent_padded_length: [eContentLen.toString()], + signed_attr: Array.from(signedAttrPadded).map((x) => x.toString()), + signed_attr_padded_length: [signedAttrPaddedLen.toString()], + signed_attr_econtent_hash_offset: [eContentHashOffset.toString()], + signature: signature, + pubkey: pubKey, + attestation_id: [attestation_id], + }; +} + + +export function generateCircuitInputsRegisterOld( secret: string, dscSecret: string, attestation_id: string, diff --git a/common/src/utils/types.ts b/common/src/utils/types.ts index 51968d8f..8f2f6a95 100644 --- a/common/src/utils/types.ts +++ b/common/src/utils/types.ts @@ -1,8 +1,8 @@ export type PassportData = { mrz: string; dsc: string; - dataGroupHashes: number[]; eContent: number[]; + signedAttr: number[]; encryptedDigest: number[]; photoBase64: string; mockUser?: boolean; From 1cd37294e48bdd0f54c9efd1b95d23205232dd74 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Mon, 16 Sep 2024 16:48:01 +0200 Subject: [PATCH 05/60] move utils test from circuits/tests/utils to circuits/tests/other_circuits --- .../Mgf1_sha256.test.ts | 0 .../is_older_than.test.ts | 0 .../is_valid.test.ts | 0 .../tests/other_circuits/leaf_hasher.test.ts | 97 +++++++++++++++++++ .../rsa_verifier.test.ts | 0 .../rsapss_verifier.test.ts | 0 circuits/tests/utils/leaf_hasher.test.ts | 74 -------------- .../utlis/generateMockInputsInCircuits.ts | 58 +++++++++++ 8 files changed, 155 insertions(+), 74 deletions(-) rename circuits/tests/{utils => other_circuits}/Mgf1_sha256.test.ts (100%) rename circuits/tests/{utils => other_circuits}/is_older_than.test.ts (100%) rename circuits/tests/{utils => other_circuits}/is_valid.test.ts (100%) create mode 100644 circuits/tests/other_circuits/leaf_hasher.test.ts rename circuits/tests/{utils => other_circuits}/rsa_verifier.test.ts (100%) rename circuits/tests/{utils => other_circuits}/rsapss_verifier.test.ts (100%) delete mode 100644 circuits/tests/utils/leaf_hasher.test.ts create mode 100644 circuits/tests/utlis/generateMockInputsInCircuits.ts diff --git a/circuits/tests/utils/Mgf1_sha256.test.ts b/circuits/tests/other_circuits/Mgf1_sha256.test.ts similarity index 100% rename from circuits/tests/utils/Mgf1_sha256.test.ts rename to circuits/tests/other_circuits/Mgf1_sha256.test.ts diff --git a/circuits/tests/utils/is_older_than.test.ts b/circuits/tests/other_circuits/is_older_than.test.ts similarity index 100% rename from circuits/tests/utils/is_older_than.test.ts rename to circuits/tests/other_circuits/is_older_than.test.ts diff --git a/circuits/tests/utils/is_valid.test.ts b/circuits/tests/other_circuits/is_valid.test.ts similarity index 100% rename from circuits/tests/utils/is_valid.test.ts rename to circuits/tests/other_circuits/is_valid.test.ts diff --git a/circuits/tests/other_circuits/leaf_hasher.test.ts b/circuits/tests/other_circuits/leaf_hasher.test.ts new file mode 100644 index 00000000..9802dd69 --- /dev/null +++ b/circuits/tests/other_circuits/leaf_hasher.test.ts @@ -0,0 +1,97 @@ +import { expect } from 'chai'; +import { X509Certificate } from 'crypto'; +import path from 'path'; +import { wasm as wasm_tester } from 'circom_tester'; +import forge from 'node-forge'; + +import { + mock_dsc_sha256_rsa_2048, + mock_csca_sha256_rsa_2048, + mock_dsc_sha1_rsa_2048, + mock_csca_sha1_rsa_2048, + mock_dsc_sha256_ecdsa, +} from '../../../common/src/constants/mockCertificates'; +import { hexToDecimal, splitToWords } from '../../../common/src/utils/utils'; +import { getLeaf, customHasher } from '../../../common/src/utils/pubkeyTree'; +import { k_dsc, k_dsc_ecdsa, n_dsc, n_dsc_ecdsa, SignatureAlgorithmIndex } from '../../../common/src/constants/constants'; +import { + parseCertificate, + parseDSC, +} from '../../../common/src/utils/certificates/handleCertificate'; +import { genMockPassportData } from '../../../common/src/utils/genMockPassportData'; +import { generateCircuitInputsInCircuits } from '../utlis/generateMockInputsInCircuits'; + +function loadCertificates(dscCertContent: string, cscaCertContent: string) { + const dscCert = new X509Certificate(dscCertContent); + const cscaCert = new X509Certificate(cscaCertContent); + const dscCert_forge = forge.pki.certificateFromPem(dscCertContent); + const cscaCert_forge = forge.pki.certificateFromPem(cscaCertContent); + + return { dscCert, cscaCert, dscCert_forge, cscaCert_forge }; +} + +describe('LeafHasher Light', function () { + this.timeout(0); + let circuit; + + this.beforeAll(async () => { + const circuitPath = path.resolve( + __dirname, + '../../circuits/tests/utils/leafHasher_tester.circom' + ); + circuit = await wasm_tester(circuitPath, { + include: [ + 'node_modules', + './node_modules/@zk-kit/binary-merkle-root.circom/src', + './node_modules/circomlib/circuits', + ], + }); + }); + + + describe('CustomHasher - getLeaf ECDSA', async () => { + const cert = mock_dsc_sha256_ecdsa; + const { signatureAlgorithm, hashFunction, x, y, bits, curve, exponent } = parseCertificate(cert); + console.log(parseCertificate(cert)); + const leaf_light = getLeaf(cert, n_dsc_ecdsa, k_dsc_ecdsa); + console.log('\x1b[34m', 'customHasher output: ', leaf_light, '\x1b[0m'); + + const passportData = genMockPassportData('ecdsa_sha256', 'FRA', '000101', '300101'); + const mock_inputs = generateCircuitInputsInCircuits(passportData, 'register'); + + const signatureAlgorithmIndex = SignatureAlgorithmIndex[`${signatureAlgorithm}_${curve || exponent}_${hashFunction}_${bits}`]; + console.log('\x1b[34m', 'signatureAlgorithmIndex: ', signatureAlgorithmIndex, '\x1b[0m'); + it('should extract and log certificate information', async () => { + const inputs = { + in: mock_inputs.pubKey, + sigAlg: signatureAlgorithmIndex, + }; + const witness = await circuit.calculateWitness(inputs, true); + const leafValueCircom = (await circuit.getOutput(witness, ['out'])).out; + console.log('\x1b[34m', 'leafValueCircom: ', leafValueCircom, '\x1b[0m'); + expect(leafValueCircom).to.equal(leaf_light); + }); + }); + + + // describe('CustomHasher - getLeaf RSA', async () => { + // const cert = mock_dsc_sha1_rsa_2048; + // const { signatureAlgorithm, hashFunction, modulus, x, y, bits, curve, exponent } = + // parseCertificate(cert); + // console.log(parseCertificate(cert)); + // const leaf_light = getLeaf(cert, n_dsc, k_dsc); + // console.log('\x1b[34m', 'customHasher: ', leaf_light, '\x1b[0m'); + // it('should extract and log certificate information', async () => { + // const inputs = { + // in: splitToWords(BigInt(hexToDecimal(modulus)), n_dsc, k_dsc), + // sigAlg: + // SignatureAlgorithmIndex[ + // `${signatureAlgorithm}_${curve || exponent}_${hashFunction}_${bits}` + // ], + // }; + // const witness = await circuit.calculateWitness(inputs, true); + // const leafValueCircom = (await circuit.getOutput(witness, ['out'])).out; + // expect(leafValueCircom).to.equal(leaf_light); + // }); + // }); +}); diff --git a/circuits/tests/utils/rsa_verifier.test.ts b/circuits/tests/other_circuits/rsa_verifier.test.ts similarity index 100% rename from circuits/tests/utils/rsa_verifier.test.ts rename to circuits/tests/other_circuits/rsa_verifier.test.ts diff --git a/circuits/tests/utils/rsapss_verifier.test.ts b/circuits/tests/other_circuits/rsapss_verifier.test.ts similarity index 100% rename from circuits/tests/utils/rsapss_verifier.test.ts rename to circuits/tests/other_circuits/rsapss_verifier.test.ts diff --git a/circuits/tests/utils/leaf_hasher.test.ts b/circuits/tests/utils/leaf_hasher.test.ts deleted file mode 100644 index d88d5c03..00000000 --- a/circuits/tests/utils/leaf_hasher.test.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { expect } from 'chai'; -import { X509Certificate } from 'crypto'; -import path from 'path'; -import { wasm as wasm_tester } from 'circom_tester'; -import forge from 'node-forge'; - -import { - mock_dsc_sha256_rsa_2048, - mock_csca_sha256_rsa_2048, - mock_dsc_sha1_rsa_2048, - mock_csca_sha1_rsa_2048, - mock_dsc_sha1_ecdsa, -} from '../../../common/src/constants/mockCertificates'; -import { hexToDecimal, splitToWords } from '../../../common/src/utils/utils'; -import { getLeaf, leafHasherLight } from '../../../common/src/utils/pubkeyTree'; -import { k_dsc, n_dsc, SignatureAlgorithmIndex } from '../../../common/src/constants/constants'; -import { - parseCertificate, - parseDSC, -} from '../../../common/src/utils/certificates/handleCertificate'; - -function loadCertificates(dscCertContent: string, cscaCertContent: string) { - const dscCert = new X509Certificate(dscCertContent); - const cscaCert = new X509Certificate(cscaCertContent); - const dscCert_forge = forge.pki.certificateFromPem(dscCertContent); - const cscaCert_forge = forge.pki.certificateFromPem(cscaCertContent); - - return { dscCert, cscaCert, dscCert_forge, cscaCert_forge }; -} - -describe('LeafHasher Light', function () { - this.timeout(0); - let circuit; - - this.beforeAll(async () => { - const circuitPath = path.resolve( - __dirname, - '../../circuits/tests/utils/leafHasherLight_tester.circom' - ); - circuit = await wasm_tester(circuitPath, { - include: [ - 'node_modules', - './node_modules/@zk-kit/binary-merkle-root.circom/src', - './node_modules/circomlib/circuits', - ], - }); - }); - // describe('Circuit', () => { - // it('should compile and load the circuit', () => { - // expect(circuit).not.to.be.undefined; - // }); - // }); - - describe('LeafHasherLight - getLeaf', async () => { - const cert = mock_dsc_sha1_rsa_2048; - const { signatureAlgorithm, hashFunction, modulus, x, y, bits, curve, exponent } = - parseCertificate(cert); - console.log(parseCertificate(cert)); - const leaf_light = getLeaf(cert, n_dsc, k_dsc); - console.log('\x1b[34m', 'leafHasherLight: ', leaf_light, '\x1b[0m'); - it('should extract and log certificate information', async () => { - const inputs = { - in: splitToWords(BigInt(hexToDecimal(modulus)), n_dsc, k_dsc), - sigAlg: - SignatureAlgorithmIndex[ - `${signatureAlgorithm}_${curve || exponent}_${hashFunction}_${bits}` - ], - }; - const witness = await circuit.calculateWitness(inputs, true); - const output = await circuit.getOutput(witness, ['out']); - console.log('\x1b[34m', 'output: ', output, '\x1b[0m'); - }); - }); -}); diff --git a/circuits/tests/utlis/generateMockInputsInCircuits.ts b/circuits/tests/utlis/generateMockInputsInCircuits.ts new file mode 100644 index 00000000..c63a15a2 --- /dev/null +++ b/circuits/tests/utlis/generateMockInputsInCircuits.ts @@ -0,0 +1,58 @@ +import { PassportData } from '../../../common/src/utils/types'; +import { CircuitName } from '../../../common/src/utils/appType'; +import { + DEFAULT_MAJORITY, + k_dsc, + k_dsc_ecdsa, + n_dsc, + n_dsc_ecdsa, + PASSPORT_ATTESTATION_ID, +} from '../../../common/src/constants/constants'; +import { + generateCircuitInputsProve, + generateCircuitInputsRegister, +} from '../../../common/src/utils/generateInputs'; +import { parseCertificate } from '../../../common/src/utils/certificates/handleCertificate'; + +const majority = DEFAULT_MAJORITY; +const scope = '@spaceShips'; + +export const generateCircuitInputsInCircuits = ( + passportData: PassportData, + circuit: CircuitName +): any => { + + const { signatureAlgorithm } = parseCertificate(passportData.dsc); + + + switch (circuit) { + case 'register': { + const secret = BigInt(0).toString(); + const dscSecret = BigInt(0).toString(); + const attestationId = PASSPORT_ATTESTATION_ID; + return generateCircuitInputsRegister( + secret, + dscSecret, + attestationId, + passportData, + signatureAlgorithm === 'ecdsa' ? n_dsc_ecdsa : n_dsc, + signatureAlgorithm === 'ecdsa' ? k_dsc_ecdsa : k_dsc + ); + } + case 'prove': { + // const bitmap = Array(90).fill('1'); + // const user_identifier = crypto.randomUUID(); + // return generateCircuitInputsProve( + // passportData, + // n_dsc, + // k_dsc, + // scope, + // bitmap, + // majority, + // user_identifier + // ); + } + default: + throw new Error('Invalid circuit'); + } +}; From f443a146d44c0dd70d137be11a5f66e85ec52d88 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Mon, 16 Sep 2024 16:49:12 +0200 Subject: [PATCH 06/60] fix typo in utils.ts --- common/src/utils/utils.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/common/src/utils/utils.ts b/common/src/utils/utils.ts index efcd32f6..bdc091e0 100644 --- a/common/src/utils/utils.ts +++ b/common/src/utils/utils.ts @@ -167,11 +167,11 @@ export function hexToDecimal(hex: string): string { } // hash logic here because the one in utils.ts only works with node -export function hash(hasFunction: string, bytesArray: number[]): number[] { +export function hash(hashFunction: string, bytesArray: number[]): number[] { const unsignedBytesArray = bytesArray.map((byte) => byte & 0xff); let hashResult: string; - switch (hasFunction) { + switch (hashFunction) { case 'sha1': hashResult = sha1(unsignedBytesArray); break; @@ -185,6 +185,7 @@ export function hash(hasFunction: string, bytesArray: number[]): number[] { hashResult = sha512_256(unsignedBytesArray); break; default: + console.log('\x1b[31m%s\x1b[0m', `${hashFunction} not found in hash`); // Log in red hashResult = sha256(unsignedBytesArray); // Default to sha256 } return hexToSignedBytes(hashResult); From 4702d3cde38379430446cf85a46e2653b854ae69 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Mon, 16 Sep 2024 16:57:15 +0200 Subject: [PATCH 07/60] rename LeafHashing functions --- .../customHashers.circom} | 19 +++---------------- common/src/utils/pubkeyTree.ts | 17 ++++++++++------- 2 files changed, 13 insertions(+), 23 deletions(-) rename circuits/circuits/utils/{leafHasherLight.circom => passport/customHashers.circom} (66%) diff --git a/circuits/circuits/utils/leafHasherLight.circom b/circuits/circuits/utils/passport/customHashers.circom similarity index 66% rename from circuits/circuits/utils/leafHasherLight.circom rename to circuits/circuits/utils/passport/customHashers.circom index 1a5204e1..ccb99dc5 100644 --- a/circuits/circuits/utils/leafHasherLight.circom +++ b/circuits/circuits/utils/passport/customHashers.circom @@ -2,7 +2,7 @@ pragma circom 2.1.6; include "@zk-email/circuits/lib/fp.circom"; include "circomlib/circuits/poseidon.circom"; -template LeafHasherLight(k) { +template CustomHasher(k) { signal input in[k]; var rounds = div_ceil(k, 16); assert(rounds < 17); @@ -29,26 +29,13 @@ template LeafHasherLight(k) { signal output out <== finalHash.out; } -template LeafHasherLightWithSigAlg(k) { +template LeafHasher(k) { signal input in[k]; signal input sigAlg; - component leafHasher = LeafHasherLight(k+1); + component leafHasher = CustomHasher(k+1); leafHasher.in[0] <== sigAlg; for (var i = 0; i < k; i++){ leafHasher.in[i+1] <== in[i]; } signal output out <== leafHasher.out; -} - -template LeafHasherLightWithSigAlgECDSA(k) { - signal input x[k]; - signal input y[k]; - signal input sigAlg; - component leafHasher = LeafHasherLight(2*k+1); - leafHasher.in[0] <== sigAlg; - for (var i = 0; i < k; i++){ - leafHasher.in[i+1] <== x[i]; - leafHasher.in[i+1+k] <== y[i]; - } - signal output out <== leafHasher.out; } \ No newline at end of file diff --git a/common/src/utils/pubkeyTree.ts b/common/src/utils/pubkeyTree.ts index d7419810..615e957c 100644 --- a/common/src/utils/pubkeyTree.ts +++ b/common/src/utils/pubkeyTree.ts @@ -6,7 +6,7 @@ import { hexToDecimal, splitToWords } from './utils'; import { parseCertificate } from "./certificates/handleCertificate"; import { flexiblePoseidon } from "./poseidon"; -export function leafHasherLight(pubKeyFormatted: string[]) { +export function customHasher(pubKeyFormatted: string[]) { const rounds = Math.ceil(pubKeyFormatted.length / 16); const hash = new Array(rounds); for (let i = 0; i < rounds; i++) { @@ -26,19 +26,22 @@ export function leafHasherLight(pubKeyFormatted: string[]) { export function getLeaf(dsc: string, n: number, k: number): string { const { signatureAlgorithm, hashFunction, modulus, x, y, bits, curve, exponent } = parseCertificate(dsc); console.log(`${signatureAlgorithm}_${curve || exponent}_${hashFunction}_${bits}`) - const sigAlgIndex = SignatureAlgorithmIndex[`${signatureAlgorithm}_${curve || exponent}_${hashFunction}_${bits}`] - if (sigAlgIndex === undefined) { - throw new Error(`Signature algorithm not found: ${signatureAlgorithm}_${curve || exponent}_${hashFunction}_${bits}`) - } + const sigAlgKey = `${signatureAlgorithm}_${curve || exponent}_${hashFunction}_${bits}`; + const sigAlgIndex = SignatureAlgorithmIndex[sigAlgKey]; + console.log("sigAlgIndex", sigAlgIndex) + if (sigAlgIndex == undefined) { + console.error(`\x1b[31mInvalid signature algorithm: ${sigAlgKey}\x1b[0m`); + throw new Error(`Invalid signature algorithm: ${sigAlgKey}`); + } if (signatureAlgorithm === 'ecdsa') { let qx = splitToWords(BigInt(hexToDecimal(x)), n, k); let qy = splitToWords(BigInt(hexToDecimal(y)), n, k); - return leafHasherLight([sigAlgIndex, ...qx, ...qy]) + return customHasher([sigAlgIndex, ...qx, ...qy]) } else { const pubkeyChunked = splitToWords(BigInt(hexToDecimal(modulus)), n, k); - return leafHasherLight([sigAlgIndex, ...pubkeyChunked]); + return customHasher([sigAlgIndex, ...pubkeyChunked]); } } From 22c92485d1f3b991a8756f55b22c167de3a64e75 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Mon, 16 Sep 2024 16:58:18 +0200 Subject: [PATCH 08/60] implement new leaf hashing functions in circuits --- circuits/circuits/dsc/dsc_rsa_65537_sha1.circom | 2 +- circuits/circuits/dsc/dsc_rsa_65537_sha256.circom | 2 +- circuits/circuits/dsc/dsc_rsapss_65537_sha256.circom | 2 +- circuits/circuits/tests/utils/leafHasherLight_tester.circom | 5 ----- circuits/circuits/tests/utils/leafHasher_tester.circom | 5 +++++ 5 files changed, 8 insertions(+), 8 deletions(-) delete mode 100644 circuits/circuits/tests/utils/leafHasherLight_tester.circom create mode 100644 circuits/circuits/tests/utils/leafHasher_tester.circom diff --git a/circuits/circuits/dsc/dsc_rsa_65537_sha1.circom b/circuits/circuits/dsc/dsc_rsa_65537_sha1.circom index 7d67e3cd..900108a7 100644 --- a/circuits/circuits/dsc/dsc_rsa_65537_sha1.circom +++ b/circuits/circuits/dsc/dsc_rsa_65537_sha1.circom @@ -25,7 +25,7 @@ template DSC_RSA_65537_SHA1(max_cert_bytes, n_dsc, k_dsc, n_csca, k_csca, dsc_mo signal output blinded_dsc_commitment; //verify the leaf - component leafHasher = LeafHasherLightWithSigAlg(k_csca); + component leafHasher = LeafHasher(k_csca); leafHasher.sigAlg <== signatureAlgorithm; leafHasher.in <== csca_modulus; signal leaf <== leafHasher.out; diff --git a/circuits/circuits/dsc/dsc_rsa_65537_sha256.circom b/circuits/circuits/dsc/dsc_rsa_65537_sha256.circom index 9a3184f8..a4239eeb 100644 --- a/circuits/circuits/dsc/dsc_rsa_65537_sha256.circom +++ b/circuits/circuits/dsc/dsc_rsa_65537_sha256.circom @@ -26,7 +26,7 @@ template DSC_RSA_65537_SHA256(max_cert_bytes, n_dsc, k_dsc, n_csca, k_csca, dsc_ signal output blinded_dsc_commitment; //verify the leaf - component leafHasher = LeafHasherLightWithSigAlg(k_csca); + component leafHasher = LeafHasher(k_csca); leafHasher.sigAlg <== signatureAlgorithm; leafHasher.in <== csca_modulus; signal leaf <== leafHasher.out; diff --git a/circuits/circuits/dsc/dsc_rsapss_65537_sha256.circom b/circuits/circuits/dsc/dsc_rsapss_65537_sha256.circom index e44cf62d..4d4e62ef 100644 --- a/circuits/circuits/dsc/dsc_rsapss_65537_sha256.circom +++ b/circuits/circuits/dsc/dsc_rsapss_65537_sha256.circom @@ -26,7 +26,7 @@ template DSC_RSAPSS_65537_SHA256(max_cert_bytes, n_dsc, k_dsc, n_csca, k_csca, m signal output blinded_dsc_commitment; //verify the leaf - component leafHasher = LeafHasherLightWithSigAlg(k_csca); + component leafHasher = LeafHasher(k_csca); leafHasher.sigAlg <== signatureAlgorithm; leafHasher.in <== csca_modulus; signal leaf <== leafHasher.out; diff --git a/circuits/circuits/tests/utils/leafHasherLight_tester.circom b/circuits/circuits/tests/utils/leafHasherLight_tester.circom deleted file mode 100644 index e5fbe079..00000000 --- a/circuits/circuits/tests/utils/leafHasherLight_tester.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.6; - -include "../../utils/leafHasherLight.circom"; - -component main = LeafHasherLightWithSigAlg(32); \ No newline at end of file diff --git a/circuits/circuits/tests/utils/leafHasher_tester.circom b/circuits/circuits/tests/utils/leafHasher_tester.circom new file mode 100644 index 00000000..4ebffb2b --- /dev/null +++ b/circuits/circuits/tests/utils/leafHasher_tester.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.6; + +include "../../utils/passport/customHashers.circom"; + +component main = LeafHasher(12); \ No newline at end of file From 448732b08c1c0532fc02d85dc91da6ee1e282ea4 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Mon, 16 Sep 2024 16:59:37 +0200 Subject: [PATCH 09/60] hardcode bits key length for ecdsa certificates --- common/src/utils/certificates/handleCertificate.ts | 8 +++++++- common/src/utils/certificates/publicKeyDetails.ts | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/common/src/utils/certificates/handleCertificate.ts b/common/src/utils/certificates/handleCertificate.ts index b4932c04..7afb18d5 100644 --- a/common/src/utils/certificates/handleCertificate.ts +++ b/common/src/utils/certificates/handleCertificate.ts @@ -133,7 +133,13 @@ export const parseDSC = (pemContent: string) => { const key = ec.keyFromPublic(publicKeyBuffer); const x = key.getPublic().getX().toString('hex'); const y = key.getPublic().getY().toString('hex'); - const bits = key.getPublic().getX().bitLength(); + + const fieldSizeMap: { [key: string]: number } = { + 'secp256r1': 256, + 'secp384r1': 384, + }; + const bits = fieldSizeMap[curve] + publicKeyDetails = { curve, x, y, bits }; } else { const publicKey = cert.subjectPublicKeyInfo.subjectPublicKey; diff --git a/common/src/utils/certificates/publicKeyDetails.ts b/common/src/utils/certificates/publicKeyDetails.ts index fb239142..42bb978e 100644 --- a/common/src/utils/certificates/publicKeyDetails.ts +++ b/common/src/utils/certificates/publicKeyDetails.ts @@ -50,7 +50,11 @@ export function parseECParameters(publicKeyInfo: any): PublicKeyDetailsECDSA { const key = ec.keyFromPublic(publicKeyBuffer); const x = key.getPublic().getX().toString('hex'); const y = key.getPublic().getY().toString('hex'); - const bits = key.getPublic().getX().bitLength(); + const fieldSizeMap: { [key: string]: number } = { + 'secp256r1': 256, + 'secp384r1': 384, + }; + const bits = fieldSizeMap[curve] const params = asn1.fromBER(algorithmParams.valueBeforeDecodeView).result; const valueBlock: any = params.valueBlock; From 8eb1115e9adda1dc0df7c3938ed7baf486eb085b Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Mon, 16 Sep 2024 17:00:05 +0200 Subject: [PATCH 10/60] hash data in generateInputs correctly --- common/src/utils/generateInputs.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index 781e1e16..8092e2e2 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -39,9 +39,6 @@ export function generateCircuitInputsRegister( const { mrz, eContent, signedAttr, encryptedDigest, dsc } = passportData; const { signatureAlgorithm, hashFunction, hashLen, x, y, modulus } = parseCertificate(passportData.dsc); - - - let pubKey: any; let signature: any; @@ -72,13 +69,15 @@ export function generateCircuitInputsRegister( const dg1 = formatMrz(mrz); - const dg1Hash = hash(signatureAlgorithm, dg1); + + const formattedMrz = formatMrz(mrz); + const dg1Hash = hash(hashFunction, formattedMrz); const dg1HashOffset = findSubarrayIndex(eContent, dg1Hash) console.log('dg1HashOffset', dg1HashOffset); assert(dg1HashOffset !== -1, `DG1 hash ${dg1Hash} not found in eContent`); - const eContentHash = hash(signatureAlgorithm, eContent); + const eContentHash = hash(hashFunction, eContent); const eContentHashOffset = findSubarrayIndex(signedAttr, eContentHash) console.log('eContentHashOffset', eContentHashOffset); assert(eContentHashOffset !== -1, `eContent hash ${eContentHash} not found in signedAttr`); @@ -111,7 +110,7 @@ export function generateCircuitInputsRegister( signed_attr_padded_length: [signedAttrPaddedLen.toString()], signed_attr_econtent_hash_offset: [eContentHashOffset.toString()], signature: signature, - pubkey: pubKey, + pubKey: pubKey, attestation_id: [attestation_id], }; } From 23515d1e7b662f6faf619bc7c8faba24944af95e Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Mon, 16 Sep 2024 17:00:47 +0200 Subject: [PATCH 11/60] add sha1 and rename constants --- circuits/circuits/utils/sha1/constants.circom | 53 ++++++++ circuits/circuits/utils/sha1/f.circom | 64 +++++++++ circuits/circuits/utils/sha1/parity.circom | 23 ++++ circuits/circuits/utils/sha1/rotate.circom | 10 ++ circuits/circuits/utils/sha1/sha1.circom | 74 ++++++++++ .../utils/sha1/sha1compression.circom | 127 ++++++++++++++++++ circuits/circuits/utils/sha1/t.circom | 69 ++++++++++ circuits/circuits/utils/sha1/xor4.circom | 29 ++++ 8 files changed, 449 insertions(+) create mode 100644 circuits/circuits/utils/sha1/constants.circom create mode 100644 circuits/circuits/utils/sha1/f.circom create mode 100644 circuits/circuits/utils/sha1/parity.circom create mode 100644 circuits/circuits/utils/sha1/rotate.circom create mode 100644 circuits/circuits/utils/sha1/sha1.circom create mode 100644 circuits/circuits/utils/sha1/sha1compression.circom create mode 100644 circuits/circuits/utils/sha1/t.circom create mode 100644 circuits/circuits/utils/sha1/xor4.circom diff --git a/circuits/circuits/utils/sha1/constants.circom b/circuits/circuits/utils/sha1/constants.circom new file mode 100644 index 00000000..d3a85cca --- /dev/null +++ b/circuits/circuits/utils/sha1/constants.circom @@ -0,0 +1,53 @@ +pragma circom 2.1.3; + +include "../node_modules/circomlib/circuits/bitify.circom"; + +template H_sha1(x) { + + signal output out[32]; + var c[5] = [ + 0x67452301, + 0xefcdab89, + 0x98badcfe, + 0x10325476, + 0xc3d2e1f0 + ]; + + component bitify = Num2Bits(32); + bitify.in <== c[x]; + + for (var k=0; k<32; k++) { + out[k] <== bitify.out[31-k]; + } + +} + +template K_sha1(t) { + signal output out[32]; + var k[4] = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6]; + + component bitify = Num2Bits(32); + + var i; + + if (0 <= t && t <= 19) { + bitify.in <== k[0]; + } + + if (20 <= t && t <= 39) { + bitify.in <== k[1]; + } + + if (40 <= t && t <= 59) { + bitify.in <== k[2]; + } + + if (60 <= t && t <= 79) { + bitify.in <== k[3]; + } + + for (var k=0; k<32; k++) { + out[k] <== bitify.out[31-k]; + } + +} \ No newline at end of file diff --git a/circuits/circuits/utils/sha1/f.circom b/circuits/circuits/utils/sha1/f.circom new file mode 100644 index 00000000..628be9e6 --- /dev/null +++ b/circuits/circuits/utils/sha1/f.circom @@ -0,0 +1,64 @@ +pragma circom 2.1.3; + +include "./parity.circom"; +include "../node_modules/circomlib/circuits/sha256/maj.circom"; +include "../node_modules/circomlib/circuits/sha256/ch.circom"; + +template f_t(t) { + + signal input b[32]; + signal input c[32]; + signal input d[32]; + signal output out[32]; + + component maj = Maj_t(32); + component parity = Parity_t(32); + component ch = Ch_t(32); + + var k; + + + // ch(x, y, z) + for (k=0; k<32; k++) { + ch.a[k] <== b[k]; + ch.b[k] <== c[k]; + ch.c[k] <== d[k]; + } + + // parity(x, y, z) + for (k=0; k < 32; k++) { + parity.a[k] <== b[k]; + parity.b[k] <== c[k]; + parity.c[k] <== d[k]; + } + + // maj(x, y, z) + for (k=0; k<32; k++) { + maj.a[k] <== b[k]; + maj.b[k] <== c[k]; + maj.c[k] <== d[k]; + } + + if (t <= 19) { + for (k=0; k <32; k++) { + out[k] <== ch.out[k]; + } + + } else { + + if (t <= 39 || t >= 60) { + + for (k=0; k < 32; k++) { + out[k] <== parity.out[k]; + } + + } else { + + for (k=0; k<32; k++) { + out[k] <== maj.out[k]; + } + + } + } + +} \ No newline at end of file diff --git a/circuits/circuits/utils/sha1/parity.circom b/circuits/circuits/utils/sha1/parity.circom new file mode 100644 index 00000000..03524453 --- /dev/null +++ b/circuits/circuits/utils/sha1/parity.circom @@ -0,0 +1,23 @@ +pragma circom 2.1.3; + +include "../node_modules/circomlib/circuits/sha256/xor3.circom"; + +template Parity_t(n) { + signal input a[n]; + signal input b[n]; + signal input c[n]; + signal output out[n]; + + component xor3 = Xor3(32); + var k; + + for (k=0; k<32; k++) { + xor3.a[k] <== a[k]; + xor3.b[k] <== b[k]; + xor3.c[k] <== c[k]; + } + + for (k=0; k<32; k++) { + out[k] <== xor3.out[k]; + } +} \ No newline at end of file diff --git a/circuits/circuits/utils/sha1/rotate.circom b/circuits/circuits/utils/sha1/rotate.circom new file mode 100644 index 00000000..7a7c8a9a --- /dev/null +++ b/circuits/circuits/utils/sha1/rotate.circom @@ -0,0 +1,10 @@ +pragma circom 2.1.3; + +template RotL(n, l) { + signal input in[n]; + signal output out[n]; + + for (var i=(n-1); i >= 0; i--) { + out[i] <== in[ (i+l)%n ]; + } +} \ No newline at end of file diff --git a/circuits/circuits/utils/sha1/sha1.circom b/circuits/circuits/utils/sha1/sha1.circom new file mode 100644 index 00000000..5d6e972d --- /dev/null +++ b/circuits/circuits/utils/sha1/sha1.circom @@ -0,0 +1,74 @@ +pragma circom 2.1.3; + +include "constants.circom"; +include "sha1compression.circom"; + +template Sha1(nBits) { + signal input in[nBits]; + signal output out[160]; + + var i; + var k; + var nBlocks; + var bitsLastBlock; + + nBlocks = ((nBits + 64) \ 512) + 1; + + signal paddedIn[nBlocks * 512]; + + for (k=0; k> k)&1; + } + + component ha0 = H_sha1(0); + component hb0 = H_sha1(1); + component hc0 = H_sha1(2); + component hd0 = H_sha1(3); + component he0 = H_sha1(4); + + component sha1compression[nBlocks]; + + for (i=0; i Date: Mon, 16 Sep 2024 17:04:33 +0200 Subject: [PATCH 12/60] implement generic shaBytes static functions --- .../utils/shaBytes/shaBytesStatic.circom | 16 ++++++++++++++++ .../{ => shaBytes/static}/Sha1BytesStatic.circom | 6 ++---- .../static}/Sha256BytesStatic.circom | 0 3 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 circuits/circuits/utils/shaBytes/shaBytesStatic.circom rename circuits/circuits/utils/{ => shaBytes/static}/Sha1BytesStatic.circom (91%) rename circuits/circuits/utils/{ => shaBytes/static}/Sha256BytesStatic.circom (100%) diff --git a/circuits/circuits/utils/shaBytes/shaBytesStatic.circom b/circuits/circuits/utils/shaBytes/shaBytesStatic.circom new file mode 100644 index 00000000..f49f1e4a --- /dev/null +++ b/circuits/circuits/utils/shaBytes/shaBytesStatic.circom @@ -0,0 +1,16 @@ +include "@zk-email/circuits/lib/sha.circom"; +include "./static/Sha256BytesStatic.circom"; +include "./static/Sha1BytesStatic.circom"; + +template ShaBytesStatic(hashLen, dataLen) { + signal input data[dataLen]; + signal output hash[hashLen]; + + if (hashLen == 256) { + hash <== Sha256BytesStatic(dataLen)(data); + } + if (hashLen == 160) { + hash <== Sha1BytesStatic(dataLen)(data); + } + +} \ No newline at end of file diff --git a/circuits/circuits/utils/Sha1BytesStatic.circom b/circuits/circuits/utils/shaBytes/static/Sha1BytesStatic.circom similarity index 91% rename from circuits/circuits/utils/Sha1BytesStatic.circom rename to circuits/circuits/utils/shaBytes/static/Sha1BytesStatic.circom index 4920207a..613b036f 100644 --- a/circuits/circuits/utils/Sha1BytesStatic.circom +++ b/circuits/circuits/utils/shaBytes/static/Sha1BytesStatic.circom @@ -1,9 +1,7 @@ pragma circom 2.1.5; include "circomlib/circuits/bitify.circom"; -include "dmpierre/sha1-circom/circuits/sha1.circom"; - - +include "../../sha1/sha1.circom"; // Static length sha160 bytes, adapted from zk-email template Sha1BytesStatic(max_num_bytes) { signal input in_padded[max_num_bytes]; @@ -13,7 +11,7 @@ template Sha1BytesStatic(max_num_bytes) { var num_bits = max_num_bytes * 8; // sha: component used to hash all bits from input signal - component sha = Sha1(num_bits); + component sha = Sha1(num_bits); // bytes: list of component used to convert bytes from input signal to bits component bytes[max_num_bytes]; diff --git a/circuits/circuits/utils/Sha256BytesStatic.circom b/circuits/circuits/utils/shaBytes/static/Sha256BytesStatic.circom similarity index 100% rename from circuits/circuits/utils/Sha256BytesStatic.circom rename to circuits/circuits/utils/shaBytes/static/Sha256BytesStatic.circom From 4850be941cc637df78e2be8536159514e9ea55db Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Mon, 16 Sep 2024 17:06:56 +0200 Subject: [PATCH 13/60] generic passportVerifier - dg1 check --- .../utils/passport/passportVerifier.circom | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 circuits/circuits/utils/passport/passportVerifier.circom diff --git a/circuits/circuits/utils/passport/passportVerifier.circom b/circuits/circuits/utils/passport/passportVerifier.circom new file mode 100644 index 00000000..bc9e4fbc --- /dev/null +++ b/circuits/circuits/utils/passport/passportVerifier.circom @@ -0,0 +1,35 @@ +pragma circom 2.1.6; + +include "@zk-email/circuits/lib/rsa.circom"; +include "@zk-email/circuits/utils/bytes.circom"; +include "@zk-email/circuits/utils/array.circom"; +include "../shaBytes/shaBytesStatic.circom"; +include "./signatureAlgorithm.circom"; + + +template PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_LEN, MAX_SIGNED_ATTR_LEN) { + var HASH_LEN_BITS = getHashLength(signatureAlgorithm); + var HASH_LEN_BYTES = HASH_LEN_BITS / 8; + + signal input dg1[93]; + signal input dg1_hash_offset; + signal input econtent[MAX_ECONTENT_LEN]; + // compute hash of DG1 + signal dg1Sha[HASH_LEN_BITS] <== ShaBytesStatic(HASH_LEN_BITS, 93)(dg1); + + + component dg1ShaBytes[HASH_LEN_BYTES]; + for (var i = 0; i < HASH_LEN_BYTES; i++) { + dg1ShaBytes[i] = Bits2Num(8); + for (var j = 0; j < 8; j++) { + dg1ShaBytes[i].in[7 - j] <== dg1Sha[i * 8 + j]; + } + } + + // assert DG1 hash matches the one in eContent input + signal dg1Hash[HASH_LEN_BYTES] <== SelectSubArray(MAX_ECONTENT_LEN, HASH_LEN_BYTES)(econtent, dg1_hash_offset, HASH_LEN_BYTES); + for(var i = 0; i < HASH_LEN_BYTES; i++) { + dg1Hash[i] === dg1ShaBytes[i].out; + } +} + From 2b1071ab8c3d8c72131882999d65cd753445f36b Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Mon, 16 Sep 2024 17:08:13 +0200 Subject: [PATCH 14/60] implement new features in openpassport_register --- .../circuits/register/openpassport_register.circom | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/circuits/circuits/register/openpassport_register.circom b/circuits/circuits/register/openpassport_register.circom index 7fb7430f..db1b4c7f 100644 --- a/circuits/circuits/register/openpassport_register.circom +++ b/circuits/circuits/register/openpassport_register.circom @@ -5,9 +5,10 @@ pragma circom 2.1.6; // include "./passport_verifier_sha256WithRSAEncryption_65537.circom"; // include "./utils/chunk_data.circom"; // include "./utils/compute_pubkey_leaf.circom"; -include "../utils/leafHasherLight.circom"; +include "../utils/passport/customHashers.circom"; include "../utils/computeCommitment.circom"; include "../utils/passport/signatureAlgorithm.circom"; +include "../utils/passport/passportVerifier.circom"; template OPENPASSPORT_REGISTER(signatureAlgorithm, n, k, max_padded_econtent_len, max_padded_signed_attr_len) { var kLengthFactor = getKLengthFactor(signatureAlgorithm); @@ -24,12 +25,17 @@ template OPENPASSPORT_REGISTER(signatureAlgorithm, n, k, max_padded_econtent_len signal input signed_attr_econtent_hash_offset; signal input signature[kScaled]; - signal input pubkey[kScaled]; + signal input pubKey[kScaled]; signal input attestation_id; + // var hashlen = getHashLength(signatureAlgorithm); + + // passport verifier + PassportVerifier(signatureAlgorithm, n, k, max_padded_econtent_len, max_padded_signed_attr_len)(dg1,dg1_hash_offset,econtent); + // leaf - signal leaf <== LeafHasherLightWithSigAlg(kScaled)(pubkey, signatureAlgorithm); + signal leaf <== LeafHasher(kScaled)(pubKey, signatureAlgorithm); // commitment signal output commitment <== ComputeCommitment()(secret, attestation_id, leaf, dg1); @@ -38,6 +44,6 @@ template OPENPASSPORT_REGISTER(signatureAlgorithm, n, k, max_padded_econtent_len signal output blinded_dsc_commitment <== Poseidon(2)([dsc_secret, leaf]); // nullifier - signal output nullifier <== LeafHasherLight(kScaled)(signature); + signal output nullifier <== CustomHasher(kScaled)(signature); } \ No newline at end of file From 6082ae552b87a679e896260bb51c3db787f23204 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Mon, 16 Sep 2024 17:09:06 +0200 Subject: [PATCH 15/60] add rsa_sha1 to new register circuits --- .../register/instances/register_rsa_65537_sha1.circom | 5 +++++ circuits/tests/register.test.ts | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 circuits/circuits/register/instances/register_rsa_65537_sha1.circom diff --git a/circuits/circuits/register/instances/register_rsa_65537_sha1.circom b/circuits/circuits/register/instances/register_rsa_65537_sha1.circom new file mode 100644 index 00000000..60d27d1b --- /dev/null +++ b/circuits/circuits/register/instances/register_rsa_65537_sha1.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.6; + +include "../openpassport_register.circom"; + +component main = OPENPASSPORT_REGISTER(3, 64, 32, 640, 512); \ No newline at end of file diff --git a/circuits/tests/register.test.ts b/circuits/tests/register.test.ts index ac3224da..82fe17b7 100644 --- a/circuits/tests/register.test.ts +++ b/circuits/tests/register.test.ts @@ -19,6 +19,7 @@ import { SignatureAlgorithm } from '../../common/src/utils/types'; const sigAlgs = [ { sigAlg: 'rsa', hashFunction: 'sha256' }, + { sigAlg: 'rsa', hashFunction: 'sha1' }, { sigAlg: 'ecdsa', hashFunction: 'sha256' }, ]; @@ -73,8 +74,8 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; console.log('\x1b[34m%s\x1b[0m', 'nullifier', nullifier); - // const commitment_circom = (await circuit.getOutput(w, ['commitment'])).commitment; - // console.log('\x1b[34m%s\x1b[0m', 'commitment', commitment_circom); + const commitment_circom = (await circuit.getOutput(w, ['commitment'])).commitment; + console.log('\x1b[34m%s\x1b[0m', 'commitment', commitment_circom); const blinded_dsc_commitment = (await circuit.getOutput(w, ['blinded_dsc_commitment'])) .blinded_dsc_commitment; From 865bfe0a72bdc51dc86c511188a73a11313cb5ee Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Tue, 17 Sep 2024 16:20:40 +0200 Subject: [PATCH 16/60] remove compute_pubkey_leaf.circom --- .../circuits/utils/compute_pubkey_leaf.circom | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 circuits/circuits/utils/compute_pubkey_leaf.circom diff --git a/circuits/circuits/utils/compute_pubkey_leaf.circom b/circuits/circuits/utils/compute_pubkey_leaf.circom deleted file mode 100644 index b22d8796..00000000 --- a/circuits/circuits/utils/compute_pubkey_leaf.circom +++ /dev/null @@ -1,20 +0,0 @@ -pragma circom 2.1.5; - -include "./chunk_data.circom"; - -// chunks the pubkey and hashes it with the signature algorithm -template ComputePubkeyLeaf(n, k, signatureAlgorithm) { - signal input pubkey[k]; - - // Converting pubkey (modulus) into 11 chunks of 192 bits, assuming original n, k are 64 and 32. - // This is because Poseidon circuit only supports an array of 16 elements. - var chunk_size = 11; // Since ceil(32 / 3) in integer division is 11 - signal chunk_data[chunk_size] <== ChunkData(n, k, chunk_size)(pubkey); - - signal leaf_hash_input[1 + chunk_size]; - leaf_hash_input[0] <== signatureAlgorithm; - for (var i = 0; i < chunk_size; i++) { - leaf_hash_input[i+1] <== chunk_data[i]; - } - signal output leaf <== Poseidon(1 + chunk_size)(leaf_hash_input); -} From 8750c268f0c7c12d2395acaa7b42347f61f080d2 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Tue, 17 Sep 2024 16:22:02 +0200 Subject: [PATCH 17/60] implement sha1 in shaBytes --- .../{ => shaBytes/dynamic}/Sha1Bytes.circom | 12 ++++++------ .../utils/shaBytes/shaBytesDynamic.circom | 19 +++++++++++++++++++ .../utils/shaBytes/shaBytesStatic.circom | 3 ++- .../shaBytes/static/Sha1BytesStatic.circom | 1 + 4 files changed, 28 insertions(+), 7 deletions(-) rename circuits/circuits/utils/{ => shaBytes/dynamic}/Sha1Bytes.circom (94%) create mode 100644 circuits/circuits/utils/shaBytes/shaBytesDynamic.circom diff --git a/circuits/circuits/utils/Sha1Bytes.circom b/circuits/circuits/utils/shaBytes/dynamic/Sha1Bytes.circom similarity index 94% rename from circuits/circuits/utils/Sha1Bytes.circom rename to circuits/circuits/utils/shaBytes/dynamic/Sha1Bytes.circom index a9404dec..67fa52e9 100644 --- a/circuits/circuits/utils/Sha1Bytes.circom +++ b/circuits/circuits/utils/shaBytes/dynamic/Sha1Bytes.circom @@ -1,6 +1,6 @@ pragma circom 2.1.5; -include "dmpierre/sha1-circom/circuits/sha1compression.circom"; +include "../../sha1/sha1compression.circom"; include "circomlib/circuits/bitify.circom"; include "circomlib/circuits/comparators.circom"; include "circomlib/circuits/mimcsponge.circom"; @@ -61,11 +61,11 @@ template Sha1General(maxBitsPadded) { bitLengthVerifier.in[1] <== maxBitsPadded; bitLengthVerifier.out === 1; - component ha0 = H(0); - component hb0 = H(1); - component hc0 = H(2); - component hd0 = H(3); - component he0 = H(4); + component ha0 = H_sha1(0); + component hb0 = H_sha1(1); + component hc0 = H_sha1(2); + component hd0 = H_sha1(3); + component he0 = H_sha1(4); component sha1compression[maxBlocks]; diff --git a/circuits/circuits/utils/shaBytes/shaBytesDynamic.circom b/circuits/circuits/utils/shaBytes/shaBytesDynamic.circom new file mode 100644 index 00000000..9cab8542 --- /dev/null +++ b/circuits/circuits/utils/shaBytes/shaBytesDynamic.circom @@ -0,0 +1,19 @@ +pragma circom 2.1.6; + +include "./dynamic/Sha1Bytes.circom"; +include "@zk-email/circuits/lib/sha.circom"; + +template ShaBytesDynamic(hashLen, max_num_bytes) { + signal input in_padded[max_num_bytes]; + signal input in_len_padded_bytes; + + signal output hash[hashLen]; + + if (hashLen == 256) { + hash <== Sha256Bytes(max_num_bytes)(in_padded, in_len_padded_bytes); + } + if (hashLen == 160) { + hash <== Sha1Bytes(max_num_bytes)(in_padded, in_len_padded_bytes); + } + +} \ No newline at end of file diff --git a/circuits/circuits/utils/shaBytes/shaBytesStatic.circom b/circuits/circuits/utils/shaBytes/shaBytesStatic.circom index f49f1e4a..bec982d1 100644 --- a/circuits/circuits/utils/shaBytes/shaBytesStatic.circom +++ b/circuits/circuits/utils/shaBytes/shaBytesStatic.circom @@ -1,4 +1,5 @@ -include "@zk-email/circuits/lib/sha.circom"; +pragma circom 2.1.6; + include "./static/Sha256BytesStatic.circom"; include "./static/Sha1BytesStatic.circom"; diff --git a/circuits/circuits/utils/shaBytes/static/Sha1BytesStatic.circom b/circuits/circuits/utils/shaBytes/static/Sha1BytesStatic.circom index 613b036f..150d09dd 100644 --- a/circuits/circuits/utils/shaBytes/static/Sha1BytesStatic.circom +++ b/circuits/circuits/utils/shaBytes/static/Sha1BytesStatic.circom @@ -2,6 +2,7 @@ pragma circom 2.1.5; include "circomlib/circuits/bitify.circom"; include "../../sha1/sha1.circom"; +// include "dmpierre/sha1-circom/circuits/sha1.circom"; // Static length sha160 bytes, adapted from zk-email template Sha1BytesStatic(max_num_bytes) { signal input in_padded[max_num_bytes]; From fa3a2e76d2b936e331655852942408e04d4ad301 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Tue, 17 Sep 2024 16:23:26 +0200 Subject: [PATCH 18/60] import fixed circom_tester lib --- circuits/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/circuits/package.json b/circuits/package.json index b28fdffb..114c57a3 100644 --- a/circuits/package.json +++ b/circuits/package.json @@ -25,7 +25,7 @@ "asn1": "^0.2.6", "asn1js": "^3.0.5", "chai-as-promised": "^7.1.1", - "circom_tester": "github:Atomic-Buy/circom_tester#main", + "circom_tester": "github:remicolin/circom_tester#main", "circomlib": "^2.0.5", "circomlibjs": "^0.1.7", "crypto": "^1.0.1", @@ -49,4 +49,4 @@ "ts-mocha": "^10.0.0", "ts-node": "^10.9.2" } -} +} \ No newline at end of file From d79f1c2eecb1cd3856ffa68255e3a6ed3e46962a Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Tue, 17 Sep 2024 16:24:24 +0200 Subject: [PATCH 19/60] update build_register_circuits.sh with new path --- circuits/scripts/build_register_circuits.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/circuits/scripts/build_register_circuits.sh b/circuits/scripts/build_register_circuits.sh index a7ce0b14..2b8243a7 100755 --- a/circuits/scripts/build_register_circuits.sh +++ b/circuits/scripts/build_register_circuits.sh @@ -8,7 +8,7 @@ build_circuit() { local START_TIME=$(date +%s) echo "compiling circuit: $CIRCUIT_NAME" - circom circuits/${CIRCUIT_TYPE}/${CIRCUIT_NAME}.circom -l node_modules -l ./node_modules/@zk-kit/binary-merkle-root.circom/src -l ./node_modules/circomlib/circuits --r1cs --O1 --wasm -c --output build + circom circuits/${CIRCUIT_TYPE}/instances/${CIRCUIT_NAME}.circom -l node_modules -l ./node_modules/@zk-kit/binary-merkle-root.circom/src -l ./node_modules/circomlib/circuits --r1cs --O1 --wasm -c --output build echo "building zkey" yarn snarkjs groth16 setup build/${CIRCUIT_NAME}.r1cs build/powersOfTau28_hez_final_20.ptau build/${CIRCUIT_NAME}.zkey @@ -35,7 +35,6 @@ CIRCUITS=( "register_rsa_65537_sha256:register:true" "register_rsa_65537_sha1:register:true" "register_rsapss_65537_sha256:register:true" - "disclose:disclose:false" ) TOTAL_START_TIME=$(date +%s) From efcf097a40ea4bf23a436769468d720f3a507524 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Tue, 17 Sep 2024 16:28:38 +0200 Subject: [PATCH 20/60] implement signature verification --- .../register/openpassport_register.circom | 17 +- .../{ => passport}/computeCommitment.circom | 1 - .../utils/passport/passportVerifier.circom | 42 +- .../utils/passport/secp256r1Verifier.circom | 46 +++ .../utils/passport/signatureAlgorithm.circom | 10 +- .../utils/passport/signatureVerifier.circom | 87 +++++ .../circuits/utils/{ => rsa}/rsaPkcs1.circom | 18 +- circuits/circuits/utils/rsapss/powMod.circom | 366 +++++++++--------- 8 files changed, 373 insertions(+), 214 deletions(-) rename circuits/circuits/utils/{ => passport}/computeCommitment.circom (96%) create mode 100644 circuits/circuits/utils/passport/secp256r1Verifier.circom create mode 100644 circuits/circuits/utils/passport/signatureVerifier.circom rename circuits/circuits/utils/{ => rsa}/rsaPkcs1.circom (92%) diff --git a/circuits/circuits/register/openpassport_register.circom b/circuits/circuits/register/openpassport_register.circom index db1b4c7f..b5f12793 100644 --- a/circuits/circuits/register/openpassport_register.circom +++ b/circuits/circuits/register/openpassport_register.circom @@ -1,16 +1,11 @@ pragma circom 2.1.6; -// include "circomlib/circuits/poseidon.circom"; -// include "@zk-email/circuits/utils/bytes.circom"; -// include "./passport_verifier_sha256WithRSAEncryption_65537.circom"; -// include "./utils/chunk_data.circom"; -// include "./utils/compute_pubkey_leaf.circom"; include "../utils/passport/customHashers.circom"; -include "../utils/computeCommitment.circom"; +include "../utils/passport/computeCommitment.circom"; include "../utils/passport/signatureAlgorithm.circom"; include "../utils/passport/passportVerifier.circom"; -template OPENPASSPORT_REGISTER(signatureAlgorithm, n, k, max_padded_econtent_len, max_padded_signed_attr_len) { +template OPENPASSPORT_REGISTER(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN) { var kLengthFactor = getKLengthFactor(signatureAlgorithm); var kScaled = k * kLengthFactor; @@ -18,9 +13,9 @@ template OPENPASSPORT_REGISTER(signatureAlgorithm, n, k, max_padded_econtent_len signal input dsc_secret; signal input dg1[93]; signal input dg1_hash_offset; - signal input econtent[max_padded_econtent_len]; + signal input econtent[MAX_ECONTENT_PADDED_LEN]; signal input econtent_padded_length; - signal input signed_attr[max_padded_signed_attr_len]; + signal input signed_attr[MAX_SIGNED_ATTR_PADDED_LEN]; signal input signed_attr_padded_length; signal input signed_attr_econtent_hash_offset; signal input signature[kScaled]; @@ -29,10 +24,8 @@ template OPENPASSPORT_REGISTER(signatureAlgorithm, n, k, max_padded_econtent_len signal input attestation_id; - // var hashlen = getHashLength(signatureAlgorithm); - // passport verifier - PassportVerifier(signatureAlgorithm, n, k, max_padded_econtent_len, max_padded_signed_attr_len)(dg1,dg1_hash_offset,econtent); + PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset,econtent,econtent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature); // leaf signal leaf <== LeafHasher(kScaled)(pubKey, signatureAlgorithm); diff --git a/circuits/circuits/utils/computeCommitment.circom b/circuits/circuits/utils/passport/computeCommitment.circom similarity index 96% rename from circuits/circuits/utils/computeCommitment.circom rename to circuits/circuits/utils/passport/computeCommitment.circom index c4454a78..33432168 100644 --- a/circuits/circuits/utils/computeCommitment.circom +++ b/circuits/circuits/utils/passport/computeCommitment.circom @@ -19,5 +19,4 @@ template ComputeCommitment() { poseidon_hasher.inputs[i + 3] <== dg1_packed[i]; } out <== poseidon_hasher.out; - // out <== leaf; } diff --git a/circuits/circuits/utils/passport/passportVerifier.circom b/circuits/circuits/utils/passport/passportVerifier.circom index bc9e4fbc..ddb066ba 100644 --- a/circuits/circuits/utils/passport/passportVerifier.circom +++ b/circuits/circuits/utils/passport/passportVerifier.circom @@ -1,23 +1,32 @@ pragma circom 2.1.6; -include "@zk-email/circuits/lib/rsa.circom"; include "@zk-email/circuits/utils/bytes.circom"; include "@zk-email/circuits/utils/array.circom"; include "../shaBytes/shaBytesStatic.circom"; +include "../shaBytes/shaBytesDynamic.circom"; include "./signatureAlgorithm.circom"; - +include "./signatureVerifier.circom"; template PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_LEN, MAX_SIGNED_ATTR_LEN) { + var kLengthFactor = getKLengthFactor(signatureAlgorithm); + var kScaled = k * kLengthFactor; + var HASH_LEN_BITS = getHashLength(signatureAlgorithm); var HASH_LEN_BYTES = HASH_LEN_BITS / 8; signal input dg1[93]; signal input dg1_hash_offset; signal input econtent[MAX_ECONTENT_LEN]; + signal input econtent_padded_length; + signal input signed_attr[MAX_SIGNED_ATTR_LEN]; + signal input signed_attr_padded_length; + signal input signed_attr_econtent_hash_offset; + signal input pubKey[kScaled]; + signal input signature[kScaled]; + // compute hash of DG1 signal dg1Sha[HASH_LEN_BITS] <== ShaBytesStatic(HASH_LEN_BITS, 93)(dg1); - component dg1ShaBytes[HASH_LEN_BYTES]; for (var i = 0; i < HASH_LEN_BYTES; i++) { dg1ShaBytes[i] = Bits2Num(8); @@ -26,10 +35,33 @@ template PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_LEN, MAX_SIGNED } } - // assert DG1 hash matches the one in eContent input - signal dg1Hash[HASH_LEN_BYTES] <== SelectSubArray(MAX_ECONTENT_LEN, HASH_LEN_BYTES)(econtent, dg1_hash_offset, HASH_LEN_BYTES); + // assert DG1 hash matches the one in econtent input + signal dg1Hash[HASH_LEN_BYTES] <== SelectSubArray(MAX_ECONTENT_LEN, HASH_LEN_BYTES)(econtent, dg1_hash_offset, HASH_LEN_BYTES); // TODO: use varShifLeft instead for(var i = 0; i < HASH_LEN_BYTES; i++) { dg1Hash[i] === dg1ShaBytes[i].out; } + + // compute hash of econtent + signal eContentSha[HASH_LEN_BITS] <== ShaBytesDynamic(HASH_LEN_BITS,MAX_ECONTENT_LEN)(econtent, econtent_padded_length); + component eContentShaBytes[HASH_LEN_BYTES]; + for (var i = 0; i < HASH_LEN_BYTES; i++) { + eContentShaBytes[i] = Bits2Num(8); + for (var j = 0; j < 8; j++) { + eContentShaBytes[i].in[7 - j] <== eContentSha[i * 8 + j]; + } + } + + // assert econtent hash matches the one in signedAttr + signal eContentHashInSignedAttr[HASH_LEN_BYTES] <== SelectSubArray(MAX_SIGNED_ATTR_LEN, HASH_LEN_BYTES)(signed_attr, signed_attr_econtent_hash_offset, HASH_LEN_BYTES); // TODO: use varShifLeft instead + for(var i = 0; i < HASH_LEN_BYTES; i++) { + eContentHashInSignedAttr[i] === eContentShaBytes[i].out; + } + + // compute hash of signedAttr + signal signedAttrSha[HASH_LEN_BITS] <== ShaBytesDynamic(HASH_LEN_BITS, MAX_SIGNED_ATTR_LEN)(signed_attr, signed_attr_padded_length); + + SignatureVerifier(signatureAlgorithm, n, k)(signedAttrSha, pubKey, signature); + + } diff --git a/circuits/circuits/utils/passport/secp256r1Verifier.circom b/circuits/circuits/utils/passport/secp256r1Verifier.circom new file mode 100644 index 00000000..e0b614f2 --- /dev/null +++ b/circuits/circuits/utils/passport/secp256r1Verifier.circom @@ -0,0 +1,46 @@ +pragma circom 2.1.6; + +include "./signatureAlgorithm.circom"; +include "../circom-ecdsa/ecdsa.circom"; + +template Secp256r1Verifier(signatureAlgorithm, n, k) { + var kLengthFactor = getKLengthFactor(signatureAlgorithm); + var kScaled = k * kLengthFactor; + + var HASH_LEN_BITS = getHashLength(signatureAlgorithm); + var msg_len = (HASH_LEN_BITS + n) \ n; + + signal input signature[kScaled]; + signal input pubKey[kScaled]; + signal input hashParsed[msg_len]; + + // 43 * 6 = 258; + signal msgHash[6]; + for(var i = 0; i < msg_len; i++) { + msgHash[i] <== hashParsed[i]; + } + + signal signature_r[k]; // ECDSA signature component r + signal signature_s[k]; // ECDSA signature component s + signal pubKey_x[k]; + signal pubKey_y[k]; + + for (var i = 0; i < k; i++) { + signature_r[i] <== signature[i]; + signature_s[i] <== signature[i + k]; + pubKey_x[i] <== pubKey[i]; + pubKey_y[i] <== pubKey[i + k]; + } + signal pubkey_xy[2][k] <== [pubKey_x, pubKey_y]; + + // verify eContentHash signature + component ecdsa_verify = ECDSAVerifyNoPubkeyCheck(n, k); + + ecdsa_verify.r <== signature_r; + ecdsa_verify.s <== signature_s; + ecdsa_verify.msghash <== msgHash; + ecdsa_verify.pubkey <== pubkey_xy; + + 1 === ecdsa_verify.result; + +} \ No newline at end of file diff --git a/circuits/circuits/utils/passport/signatureAlgorithm.circom b/circuits/circuits/utils/passport/signatureAlgorithm.circom index 0f32e116..45bc4d46 100644 --- a/circuits/circuits/utils/passport/signatureAlgorithm.circom +++ b/circuits/circuits/utils/passport/signatureAlgorithm.circom @@ -69,11 +69,15 @@ function getKLengthFactor(signatureAlgorithm) { } function getExponentBits(signatureAlgorithm) { + // returns the amounts of bits of the exponent of type 2^n +1 if (signatureAlgorithm == 1 ) { - return 16; + return 17; // 65537 } - if (signatureAlgorithm == 3) { - return 1; + if (signatureAlgorithm == 3 ) { + return 17; + } + if (signatureAlgorithm == 4 ) { + return 17; } return 0; diff --git a/circuits/circuits/utils/passport/signatureVerifier.circom b/circuits/circuits/utils/passport/signatureVerifier.circom new file mode 100644 index 00000000..2c61a630 --- /dev/null +++ b/circuits/circuits/utils/passport/signatureVerifier.circom @@ -0,0 +1,87 @@ +pragma circom 2.1.6; + +include "@zk-email/circuits/lib/rsa.circom"; +include "../rsa/rsaPkcs1.circom"; +include "../circom-ecdsa/ecdsa.circom"; +include "secp256r1Verifier.circom"; +include "../rsapss/rsapss.circom"; + +template SignatureVerifier(signatureAlgorithm, n, k) { + var kLengthFactor = getKLengthFactor(signatureAlgorithm); + var kScaled = k * kLengthFactor; + + var HASH_LEN_BITS = getHashLength(signatureAlgorithm); + + signal input hash[HASH_LEN_BITS]; + signal input pubKey[kScaled]; + signal input signature[kScaled]; + + var msg_len = (HASH_LEN_BITS + n) \ n; + + signal hashParsed[msg_len] <== HashParser(signatureAlgorithm, n, k)(hash); + + if (signatureAlgorithm == 1) { + component rsa = RSAVerifier65537(n, k); + for (var i = 0; i < msg_len; i++) { + rsa.message[i] <== hashParsed[i]; + } + for (var i = msg_len; i < k; i++) { + rsa.message[i] <== 0; + } + rsa.modulus <== pubKey; + rsa.signature <== signature; + } + if (signatureAlgorithm == 3 ) { + component rsa_pkcs1 = RSAVerifier65537_pkcs1(n, k); + for (var i = 0; i < msg_len; i++) { + rsa_pkcs1.message[i] <== hashParsed[i]; + } + for (var i = msg_len; i < k; i++) { + rsa_pkcs1.message[i] <== 0; + } + rsa_pkcs1.modulus <== pubKey; + rsa_pkcs1.signature <== signature; + + } + if (signatureAlgorithm == 4) { + var exponentBits = getExponentBits(signatureAlgorithm); + var pubKeyBitsLength = getKeyLength(signatureAlgorithm); + + component rsaPssSha256Verification = VerifyRsaPssSig(n, k, exponentBits, HASH_LEN_BITS, pubKeyBitsLength); + rsaPssSha256Verification.pubkey <== pubKey; + rsaPssSha256Verification.signature <== signature; + rsaPssSha256Verification.hashed <== hash; // send the raw hash + + } + if (signatureAlgorithm == 7) { + Secp256r1Verifier (signatureAlgorithm,n,k)(signature, pubKey,hashParsed); + } + if (signatureAlgorithm == 8) { + Secp256r1Verifier (signatureAlgorithm,n,k)(signature, pubKey,hashParsed); + } + if (signatureAlgorithm == 9) { + } +} + + +template HashParser(signatureAlgorithm, n, k) { + var HASH_LEN_BITS = getHashLength(signatureAlgorithm); + var msg_len = (HASH_LEN_BITS + n) \ n; + + component hashParser[msg_len]; + signal input hash[HASH_LEN_BITS]; + + for (var i = 0; i < msg_len; i++) { + hashParser[i] = Bits2Num(n); + } + for (var i = 0; i < HASH_LEN_BITS; i++) { + hashParser[i \ n].in[i % n] <== hash[HASH_LEN_BITS - 1 - i]; + } + for (var i = HASH_LEN_BITS; i < n * msg_len; i++) { + hashParser[i \ n].in[i % n] <== 0; + } + signal output hashParsed[msg_len]; + for (var i = 0; i < msg_len ; i++ ){ + hashParsed[i] <== hashParser[i].out; + } +} \ No newline at end of file diff --git a/circuits/circuits/utils/rsaPkcs1.circom b/circuits/circuits/utils/rsa/rsaPkcs1.circom similarity index 92% rename from circuits/circuits/utils/rsaPkcs1.circom rename to circuits/circuits/utils/rsa/rsaPkcs1.circom index 037a7ae8..71590530 100644 --- a/circuits/circuits/utils/rsaPkcs1.circom +++ b/circuits/circuits/utils/rsa/rsaPkcs1.circom @@ -5,7 +5,7 @@ include "@zk-email/circuits/lib/fp.circom"; // Computes base^65537 mod modulus // Does not necessarily reduce fully mod modulus (the answer could be // too big by a multiple of modulus) -template FpPow65537Mod(n, k) { +template FpPow65537Mod_pkcs1(n, k) { signal input base[k]; // Exponent is hardcoded at 65537 signal input modulus[k]; @@ -42,9 +42,9 @@ template FpPow65537Mod(n, k) { } } -template RSAPad(n, k) { +template RSAPad_pkcs1(n, k) { signal input modulus[k]; - signal input base_message[k]; + signal input message[k]; signal output padded_message[k]; var base_len = 280; @@ -58,7 +58,7 @@ template RSAPad(n, k) { signal base_message_bits[n*k]; for (var i = 0; i < k; i++) { base_message_n2b[i] = Num2Bits(n); - base_message_n2b[i].in <== base_message[i]; + base_message_n2b[i].in <== message[i]; for (var j = 0; j < n; j++) { base_message_bits[i*n+j] <== base_message_n2b[i].out[j]; } @@ -121,15 +121,15 @@ template RSAPad(n, k) { } } -template RSAVerify65537(n, k) { +template RSAVerifier65537_pkcs1(n, k) { signal input signature[k]; signal input modulus[k]; - signal input base_message[k]; + signal input message[k]; - component padder = RSAPad(n, k); + component padder = RSAPad_pkcs1(n, k); for (var i = 0; i < k; i++) { padder.modulus[i] <== modulus[i]; - padder.base_message[i] <== base_message[i]; + padder.message[i] <== message[i]; } // Check that the signature is in proper form and reduced mod modulus. @@ -143,7 +143,7 @@ template RSAVerify65537(n, k) { } bigLessThan.out === 1; - component bigPow = FpPow65537Mod(n, k); + component bigPow = FpPow65537Mod_pkcs1(n, k); for (var i = 0; i < k; i++) { bigPow.base[i] <== signature[i]; bigPow.modulus[i] <== modulus[i]; diff --git a/circuits/circuits/utils/rsapss/powMod.circom b/circuits/circuits/utils/rsapss/powMod.circom index 73a91c54..35e594b9 100644 --- a/circuits/circuits/utils/rsapss/powMod.circom +++ b/circuits/circuits/utils/rsapss/powMod.circom @@ -1,11 +1,9 @@ pragma circom 2.1.6; include "@zk-email/circuits/lib/bigint.circom"; +include "../circom-ecdsa/bigInt.circom"; +include "../circom-ecdsa/bigInt_func.circom"; -// w = 32 -// e_bits = 17 -// nb is the length of the base and modulus -// calculates (base^exp) % modulus, exp = 2^(e_bits - 1) + 1 = 2^16 + 1 template PowerMod(w, nb, e_bits) { assert(e_bits >= 2); @@ -17,7 +15,7 @@ template PowerMod(w, nb, e_bits) { component muls[e_bits]; for (var i = 0; i < e_bits; i++) { - muls[i] = BigMultModP(w, nb); + muls[i] = BigMultModP_rsapss(w, nb); for (var j = 0; j < nb; j++) { muls[i].p[j] <== modulus[j]; @@ -46,8 +44,8 @@ template PowerMod(w, nb, e_bits) { } } -// Note: deprecated -template BigMultModP(n, k) { +// // Note: deprecated +template BigMultModP_rsapss(n, k) { assert(n <= 252); signal input a[k]; signal input b[k]; @@ -59,7 +57,7 @@ template BigMultModP(n, k) { big_mult.a[i] <== a[i]; big_mult.b[i] <== b[i]; } - component big_mod = BigMod(n, k); + component big_mod = BigMod_rsapss(n, k); for (var i = 0; i < 2 * k; i++) { big_mod.a[i] <== big_mult.out[i]; } @@ -71,121 +69,121 @@ template BigMultModP(n, k) { } } -template BigMult(n, k) { - signal input a[k]; - signal input b[k]; - signal output out[2 * k]; - - var LOGK = log_ceil(k); - component mult = BigMultShortLong(n, k, 2*n + LOGK); - for (var i = 0; i < k; i++) { - mult.a[i] <== a[i]; - mult.b[i] <== b[i]; - } - - // no carry is possible in the highest order register - component longshort = LongToShortNoEndCarry(n, 2 * k - 1); - for (var i = 0; i < 2 * k - 1; i++) { - longshort.in[i] <== mult.out[i]; - } - for (var i = 0; i < 2 * k; i++) { - out[i] <== longshort.out[i]; - } -} - -template LongToShortNoEndCarry(n, k) { - assert(n <= 126); - signal input in[k]; - signal output out[k+1]; - - var split[k][3]; - for (var i = 0; i < k; i++) { - split[i] = SplitThreeFn(in[i], n, n, n); - } - - var carry[k]; - carry[0] = 0; - out[0] <-- split[0][0]; - if (k > 1) { - var sumAndCarry[2] = SplitFn(split[0][1] + split[1][0], n, n); - out[1] <-- sumAndCarry[0]; - carry[1] = sumAndCarry[1]; - } - if (k > 2) { - for (var i = 2; i < k; i++) { - var sumAndCarry[2] = SplitFn(split[i][0] + split[i-1][1] + split[i-2][2] + carry[i-1], n, n); - out[i] <-- sumAndCarry[0]; - carry[i] = sumAndCarry[1]; - } - out[k] <-- split[k-1][1] + split[k-2][2] + carry[k-1]; - } - - component outRangeChecks[k+1]; - for (var i = 0; i < k+1; i++) { - outRangeChecks[i] = Num2Bits(n); - outRangeChecks[i].in <== out[i]; - } - - signal runningCarry[k]; - component runningCarryRangeChecks[k]; - runningCarry[0] <-- (in[0] - out[0]) / (1 << n); - runningCarryRangeChecks[0] = Num2Bits(n + log_ceil(k)); - runningCarryRangeChecks[0].in <== runningCarry[0]; - runningCarry[0] * (1 << n) === in[0] - out[0]; - for (var i = 1; i < k; i++) { - runningCarry[i] <-- (in[i] - out[i] + runningCarry[i-1]) / (1 << n); - runningCarryRangeChecks[i] = Num2Bits(n + log_ceil(k)); - runningCarryRangeChecks[i].in <== runningCarry[i]; - runningCarry[i] * (1 << n) === in[i] - out[i] + runningCarry[i-1]; - } - runningCarry[k-1] === out[k]; -} -template BigMultShortLong(n, k, m_out) { - assert(n <= 126); - signal input a[k]; - signal input b[k]; - signal output out[2 * k - 1]; - - var prod_val[2 * k - 1]; - for (var i = 0; i < 2 * k - 1; i++) { - prod_val[i] = 0; - if (i < k) { - for (var a_idx = 0; a_idx <= i; a_idx++) { - prod_val[i] = prod_val[i] + a[a_idx] * b[i - a_idx]; - } - } else { - for (var a_idx = i - k + 1; a_idx < k; a_idx++) { - prod_val[i] = prod_val[i] + a[a_idx] * b[i - a_idx]; - } - } - out[i] <-- prod_val[i]; - } - - var k2 = 2 * k - 1; - var pow[k2][k2]; // we cache the exponent values because it makes a big difference in witness generation time - for(var i = 0; i 1) { +// var sumAndCarry[2] = SplitFn(split[0][1] + split[1][0], n, n); +// out[1] <-- sumAndCarry[0]; +// carry[1] = sumAndCarry[1]; +// } +// if (k > 2) { +// for (var i = 2; i < k; i++) { +// var sumAndCarry[2] = SplitFn(split[i][0] + split[i-1][1] + split[i-2][2] + carry[i-1], n, n); +// out[i] <-- sumAndCarry[0]; +// carry[i] = sumAndCarry[1]; +// } +// out[k] <-- split[k-1][1] + split[k-2][2] + carry[k-1]; +// } + +// component outRangeChecks[k+1]; +// for (var i = 0; i < k+1; i++) { +// outRangeChecks[i] = Num2Bits(n); +// outRangeChecks[i].in <== out[i]; +// } + +// signal runningCarry[k]; +// component runningCarryRangeChecks[k]; +// runningCarry[0] <-- (in[0] - out[0]) / (1 << n); +// runningCarryRangeChecks[0] = Num2Bits(n + log_ceil(k)); +// runningCarryRangeChecks[0].in <== runningCarry[0]; +// runningCarry[0] * (1 << n) === in[0] - out[0]; +// for (var i = 1; i < k; i++) { +// runningCarry[i] <-- (in[i] - out[i] + runningCarry[i-1]) / (1 << n); +// runningCarryRangeChecks[i] = Num2Bits(n + log_ceil(k)); +// runningCarryRangeChecks[i].in <== runningCarry[i]; +// runningCarry[i] * (1 << n) === in[i] - out[i] + runningCarry[i-1]; +// } +// runningCarry[k-1] === out[k]; +// } +// template BigMultShortLong(n, k, m_out) { +// assert(n <= 126); +// signal input a[k]; +// signal input b[k]; +// signal output out[2 * k - 1]; + +// var prod_val[2 * k - 1]; +// for (var i = 0; i < 2 * k - 1; i++) { +// prod_val[i] = 0; +// if (i < k) { +// for (var a_idx = 0; a_idx <= i; a_idx++) { +// prod_val[i] = prod_val[i] + a[a_idx] * b[i - a_idx]; +// } +// } else { +// for (var a_idx = i - k + 1; a_idx < k; a_idx++) { +// prod_val[i] = prod_val[i] + a[a_idx] * b[i - a_idx]; +// } +// } +// out[i] <-- prod_val[i]; +// } + +// var k2 = 2 * k - 1; +// var pow[k2][k2]; // we cache the exponent values because it makes a big difference in witness generation time +// for(var i = 0; i Date: Tue, 17 Sep 2024 16:29:14 +0200 Subject: [PATCH 21/60] update MAX_PADDED_SIGNED_ATTR_LEN --- .../circuits/register/instances/register_ecdsa_sha256.circom | 2 +- .../register/instances/register_rsa_65537_sha1.circom | 2 +- .../register/instances/register_rsa_65537_sha256.circom | 2 +- common/src/constants/constants.ts | 4 +++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/circuits/circuits/register/instances/register_ecdsa_sha256.circom b/circuits/circuits/register/instances/register_ecdsa_sha256.circom index 456304c6..ec7de15d 100644 --- a/circuits/circuits/register/instances/register_ecdsa_sha256.circom +++ b/circuits/circuits/register/instances/register_ecdsa_sha256.circom @@ -2,4 +2,4 @@ pragma circom 2.1.6; include "../openpassport_register.circom"; -component main = OPENPASSPORT_REGISTER(8, 43, 6, 640, 512); \ No newline at end of file +component main = OPENPASSPORT_REGISTER(8, 43, 6, 640, 576); \ No newline at end of file diff --git a/circuits/circuits/register/instances/register_rsa_65537_sha1.circom b/circuits/circuits/register/instances/register_rsa_65537_sha1.circom index 60d27d1b..52b9f43d 100644 --- a/circuits/circuits/register/instances/register_rsa_65537_sha1.circom +++ b/circuits/circuits/register/instances/register_rsa_65537_sha1.circom @@ -2,4 +2,4 @@ pragma circom 2.1.6; include "../openpassport_register.circom"; -component main = OPENPASSPORT_REGISTER(3, 64, 32, 640, 512); \ No newline at end of file +component main = OPENPASSPORT_REGISTER(3, 64, 32, 640, 576); \ No newline at end of file diff --git a/circuits/circuits/register/instances/register_rsa_65537_sha256.circom b/circuits/circuits/register/instances/register_rsa_65537_sha256.circom index bf7123c8..463dbcc8 100644 --- a/circuits/circuits/register/instances/register_rsa_65537_sha256.circom +++ b/circuits/circuits/register/instances/register_rsa_65537_sha256.circom @@ -2,4 +2,4 @@ pragma circom 2.1.6; include "../openpassport_register.circom"; -component main = OPENPASSPORT_REGISTER(1, 64, 32, 640, 512); \ No newline at end of file +component main = OPENPASSPORT_REGISTER(1, 64, 32, 640, 576); \ No newline at end of file diff --git a/common/src/constants/constants.ts b/common/src/constants/constants.ts index 530e7b17..d9055281 100644 --- a/common/src/constants/constants.ts +++ b/common/src/constants/constants.ts @@ -22,7 +22,9 @@ export const DEFAULT_MAJORITY = "18" export const MAX_PADDED_ECONTENT_LEN = 640; -export const MAX_PADDED_SIGNED_ATTR_LEN = 512; +export const MAX_PADDED_SIGNED_ATTR_LEN = 576; +// targetted value : 512 +// possible values because of sha1 constaints: 448, 576, 640 export enum SignatureAlgorithmIndex { rsa_65537_sha256_2048 = 1, From 272dea53203f98401bc10f78f8b25c3ba9d3f70b Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Tue, 17 Sep 2024 16:29:47 +0200 Subject: [PATCH 22/60] add rsa-pss register circuit --- .../register/instances/register_rsapss_65537_sha256.circom | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 circuits/circuits/register/instances/register_rsapss_65537_sha256.circom diff --git a/circuits/circuits/register/instances/register_rsapss_65537_sha256.circom b/circuits/circuits/register/instances/register_rsapss_65537_sha256.circom new file mode 100644 index 00000000..77997fae --- /dev/null +++ b/circuits/circuits/register/instances/register_rsapss_65537_sha256.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.6; + +include "../openpassport_register.circom"; + +component main = OPENPASSPORT_REGISTER(4, 64, 32, 640, 576); \ No newline at end of file From 9883afc1c44350f5642601da345feb494595262e Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Tue, 17 Sep 2024 16:32:59 +0200 Subject: [PATCH 23/60] move passport date templates --- circuits/circuits/utils/{ => passport/date}/dateIsLess.circom | 0 circuits/circuits/utils/{ => passport/date}/isOlderThan.circom | 0 circuits/circuits/utils/{ => passport/date}/isValid.circom | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename circuits/circuits/utils/{ => passport/date}/dateIsLess.circom (100%) rename circuits/circuits/utils/{ => passport/date}/isOlderThan.circom (100%) rename circuits/circuits/utils/{ => passport/date}/isValid.circom (100%) diff --git a/circuits/circuits/utils/dateIsLess.circom b/circuits/circuits/utils/passport/date/dateIsLess.circom similarity index 100% rename from circuits/circuits/utils/dateIsLess.circom rename to circuits/circuits/utils/passport/date/dateIsLess.circom diff --git a/circuits/circuits/utils/isOlderThan.circom b/circuits/circuits/utils/passport/date/isOlderThan.circom similarity index 100% rename from circuits/circuits/utils/isOlderThan.circom rename to circuits/circuits/utils/passport/date/isOlderThan.circom diff --git a/circuits/circuits/utils/isValid.circom b/circuits/circuits/utils/passport/date/isValid.circom similarity index 100% rename from circuits/circuits/utils/isValid.circom rename to circuits/circuits/utils/passport/date/isValid.circom From f488265080b47a92ac4f06155c123a48b92c4bab Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Tue, 17 Sep 2024 18:33:37 +0200 Subject: [PATCH 24/60] update functions and template names with _ecdsa ending --- .../circuits/utils/circom-ecdsa/bigInt.circom | 1766 ++++++++--------- .../utils/circom-ecdsa/bigInt_func.circom | 276 +-- .../circuits/utils/circom-ecdsa/curve.circom | 24 +- .../circuits/utils/circom-ecdsa/ecdsa.circom | 2 +- .../circom-ecdsa/field_elements_func.circom | 12 +- 5 files changed, 1040 insertions(+), 1040 deletions(-) diff --git a/circuits/circuits/utils/circom-ecdsa/bigInt.circom b/circuits/circuits/utils/circom-ecdsa/bigInt.circom index f89e14a0..359e9b00 100644 --- a/circuits/circuits/utils/circom-ecdsa/bigInt.circom +++ b/circuits/circuits/utils/circom-ecdsa/bigInt.circom @@ -7,392 +7,392 @@ include "../../../node_modules/circomlib/circuits/gates.circom"; include "bigInt_func.circom"; -// addition mod 2**n with carry bit -template ModSum(n) { - assert(n <= 252); - signal input a; - signal input b; - signal output sum; - signal output carry; - - component n2b = Num2Bits(n + 1); - n2b.in <== a + b; - carry <== n2b.out[n]; - sum <== a + b - carry * (1 << n); -} - -// check if k-register variables a, b are equal everywhere -template BigIsEqual(k) { - signal input a[k]; - signal input b[k]; - signal output out; - - component isEquals[k]; - var total = k; - for (var i = 0; i < k; i ++) { - isEquals[i] = IsEqual(); - isEquals[i].in[0] <== a[i]; - isEquals[i].in[1] <== b[i]; - total -= isEquals[i].out; - } - component checkZero = IsZero(); - checkZero.in <== total; - out <== checkZero.out; -} - -// check if k-register variable a is equal to zero -template BigIsZero(k) { - signal input in[k]; - signal output out; - - component isZeros[k]; - var total = k; - for (var i = 0; i < k; i ++) { - isZeros[i] = IsZero(); - isZeros[i].in <== in[i]; - total -= isZeros[i].out; - } - component checkZero = IsZero(); - checkZero.in <== total; - out <== checkZero.out; -} - - -// a - b -template ModSub(n) { - assert(n <= 252); - signal input a; - signal input b; - signal output out; - signal output borrow; - component lt = LessThan(n); - lt.in[0] <== a; - lt.in[1] <== b; - borrow <== lt.out; - out <== borrow * (1 << n) + a - b; -} - -// a - b - c -// assume a - b - c + 2**n >= 0 -template ModSubThree(n) { - assert(n + 2 <= 253); - signal input a; - signal input b; - signal input c; - assert(a - b - c + (1 << n) >= 0); - signal output out; - signal output borrow; - signal b_plus_c; - b_plus_c <== b + c; - component lt = LessThan(n + 1); - lt.in[0] <== a; - lt.in[1] <== b_plus_c; - borrow <== lt.out; - out <== borrow * (1 << n) + a - b_plus_c; -} - -template ModSumThree(n) { - assert(n + 2 <= 253); - signal input a; - signal input b; - signal input c; - signal output sum; - signal output carry; - - component n2b = Num2Bits(n + 2); - n2b.in <== a + b + c; - carry <== n2b.out[n] + 2 * n2b.out[n + 1]; - sum <== a + b + c - carry * (1 << n); -} - -template ModSumFour(n) { - assert(n + 2 <= 253); - signal input a; - signal input b; - signal input c; - signal input d; - signal output sum; - signal output carry; - - component n2b = Num2Bits(n + 2); - n2b.in <== a + b + c + d; - carry <== n2b.out[n] + 2 * n2b.out[n + 1]; - sum <== a + b + c + d - carry * (1 << n); -} - -// product mod 2**n with carry -template ModProd(n) { - assert(n <= 126); - signal input a; - signal input b; - signal output prod; - signal output carry; - - component n2b = Num2Bits(2 * n); - n2b.in <== a * b; - - component b2n1 = Bits2Num(n); - component b2n2 = Bits2Num(n); - var i; - for (i = 0; i < n; i++) { - b2n1.in[i] <== n2b.out[i]; - b2n2.in[i] <== n2b.out[i + n]; - } - prod <== b2n1.out; - carry <== b2n2.out; -} - -// split a n + m bit input into two outputs -template Split(n, m) { - assert(n <= 126); - signal input in; - signal output small; - signal output big; - - small <-- in % (1 << n); - big <-- in \ (1 << n); - - component n2b_small = Num2Bits(n); - n2b_small.in <== small; - component n2b_big = Num2Bits(m); - n2b_big.in <== big; - - in === small + big * (1 << n); -} - -// split a n + m + k bit input into three outputs -template SplitThree(n, m, k) { - assert(n <= 126); - signal input in; - signal output small; - signal output medium; - signal output big; - - small <-- in % (1 << n); - medium <-- (in \ (1 << n)) % (1 << m); - big <-- in \ (1 << n + m); - - component n2b_small = Num2Bits(n); - n2b_small.in <== small; - component n2b_medium = Num2Bits(m); - n2b_medium.in <== medium; - component n2b_big = Num2Bits(k); - n2b_big.in <== big; - - in === small + medium * (1 << n) + big * (1 << n + m); -} - -// a[i], b[i] in 0... 2**n-1 -// represent a = a[0] + a[1] * 2**n + .. + a[k - 1] * 2**(n * k) -template BigAdd(n, k) { - assert(n <= 252); - signal input a[k]; - signal input b[k]; - signal output out[k + 1]; - - component unit0 = ModSum(n); - unit0.a <== a[0]; - unit0.b <== b[0]; - out[0] <== unit0.sum; - - component unit[k - 1]; - for (var i = 1; i < k; i++) { - unit[i - 1] = ModSumThree(n); - unit[i - 1].a <== a[i]; - unit[i - 1].b <== b[i]; - if (i == 1) { - unit[i - 1].c <== unit0.carry; - } else { - unit[i - 1].c <== unit[i - 2].carry; - } - out[i] <== unit[i - 1].sum; - } - out[k] <== unit[k - 2].carry; -} - -/* -Polynomial Multiplication -Inputs: - - a = a[0] + a[1] * X + ... + a[k-1] * X^{k-1} - - b = b[0] + b[1] * X + ... + b[k-1] * X^{k-1} -Output: - - out = out[0] + out[1] * X + ... + out[2 * k - 2] * X^{2*k - 2} - - out = a * b as polynomials in X -Notes: - - Optimization due to xJsnark: - -- witness is calculated by normal polynomial multiplication - -- out is contrained by evaluating out(X) === a(X) * b(X) at X = 0, ..., 2*k - 2 - - If a[i], b[j] have absolute value < B, then out[i] has absolute value < k * B^2 -m_out is the expected max number of bits in the output registers -*/ -template BigMultShortLong(n, k, m_out) { - assert(n <= 126); - signal input a[k]; - signal input b[k]; - signal output out[2 * k - 1]; - - var prod_val[2 * k - 1]; - for (var i = 0; i < 2 * k - 1; i++) { - prod_val[i] = 0; - if (i < k) { - for (var a_idx = 0; a_idx <= i; a_idx++) { - prod_val[i] = prod_val[i] + a[a_idx] * b[i - a_idx]; - } - } else { - for (var a_idx = i - k + 1; a_idx < k; a_idx++) { - prod_val[i] = prod_val[i] + a[a_idx] * b[i - a_idx]; - } - } - out[i] <-- prod_val[i]; - } - - var k2 = 2 * k - 1; - var pow[k2][k2]; // we cache the exponent values because it makes a big difference in witness generation time - for(var i = 0; i= 0 +// template ModSubThree(n) { +// assert(n + 2 <= 253); +// signal input a; +// signal input b; +// signal input c; +// assert(a - b - c + (1 << n) >= 0); +// signal output out; +// signal output borrow; +// signal b_plus_c; +// b_plus_c <== b + c; +// component lt = LessThan(n + 1); +// lt.in[0] <== a; +// lt.in[1] <== b_plus_c; +// borrow <== lt.out; +// out <== borrow * (1 << n) + a - b_plus_c; +// } + +// template ModSumThree(n) { +// assert(n + 2 <= 253); +// signal input a; +// signal input b; +// signal input c; +// signal output sum; +// signal output carry; + +// component n2b = Num2Bits(n + 2); +// n2b.in <== a + b + c; +// carry <== n2b.out[n] + 2 * n2b.out[n + 1]; +// sum <== a + b + c - carry * (1 << n); +// } + +// template ModSumFour(n) { +// assert(n + 2 <= 253); +// signal input a; +// signal input b; +// signal input c; +// signal input d; +// signal output sum; +// signal output carry; + +// component n2b = Num2Bits(n + 2); +// n2b.in <== a + b + c + d; +// carry <== n2b.out[n] + 2 * n2b.out[n + 1]; +// sum <== a + b + c + d - carry * (1 << n); +// } + +// // product mod 2**n with carry +// template ModProd(n) { +// assert(n <= 126); +// signal input a; +// signal input b; +// signal output prod; +// signal output carry; + +// component n2b = Num2Bits(2 * n); +// n2b.in <== a * b; + +// component b2n1 = Bits2Num(n); +// component b2n2 = Bits2Num(n); +// var i; +// for (i = 0; i < n; i++) { +// b2n1.in[i] <== n2b.out[i]; +// b2n2.in[i] <== n2b.out[i + n]; +// } +// prod <== b2n1.out; +// carry <== b2n2.out; +// } + +// // split a n + m bit input into two outputs +// template Split(n, m) { +// assert(n <= 126); +// signal input in; +// signal output small; +// signal output big; + +// small <-- in % (1 << n); +// big <-- in \ (1 << n); + +// component n2b_small = Num2Bits(n); +// n2b_small.in <== small; +// component n2b_big = Num2Bits(m); +// n2b_big.in <== big; + +// in === small + big * (1 << n); +// } + +// // split a n + m + k bit input into three outputs +// template SplitThree(n, m, k) { +// assert(n <= 126); +// signal input in; +// signal output small; +// signal output medium; +// signal output big; + +// small <-- in % (1 << n); +// medium <-- (in \ (1 << n)) % (1 << m); +// big <-- in \ (1 << n + m); + +// component n2b_small = Num2Bits(n); +// n2b_small.in <== small; +// component n2b_medium = Num2Bits(m); +// n2b_medium.in <== medium; +// component n2b_big = Num2Bits(k); +// n2b_big.in <== big; + +// in === small + medium * (1 << n) + big * (1 << n + m); +// } + +// // a[i], b[i] in 0... 2**n-1 +// // represent a = a[0] + a[1] * 2**n + .. + a[k - 1] * 2**(n * k) +// template BigAdd(n, k) { +// assert(n <= 252); +// signal input a[k]; +// signal input b[k]; +// signal output out[k + 1]; + +// component unit0 = ModSum(n); +// unit0.a <== a[0]; +// unit0.b <== b[0]; +// out[0] <== unit0.sum; + +// component unit[k - 1]; +// for (var i = 1; i < k; i++) { +// unit[i - 1] = ModSumThree(n); +// unit[i - 1].a <== a[i]; +// unit[i - 1].b <== b[i]; +// if (i == 1) { +// unit[i - 1].c <== unit0.carry; +// } else { +// unit[i - 1].c <== unit[i - 2].carry; +// } +// out[i] <== unit[i - 1].sum; +// } +// out[k] <== unit[k - 2].carry; +// } + +// /* +// Polynomial Multiplication +// Inputs: +// - a = a[0] + a[1] * X + ... + a[k-1] * X^{k-1} +// - b = b[0] + b[1] * X + ... + b[k-1] * X^{k-1} +// Output: +// - out = out[0] + out[1] * X + ... + out[2 * k - 2] * X^{2*k - 2} +// - out = a * b as polynomials in X +// Notes: +// - Optimization due to xJsnark: +// -- witness is calculated by normal polynomial multiplication +// -- out is contrained by evaluating out(X) === a(X) * b(X) at X = 0, ..., 2*k - 2 +// - If a[i], b[j] have absolute value < B, then out[i] has absolute value < k * B^2 +// m_out is the expected max number of bits in the output registers +// */ +// template BigMultShortLong(n, k, m_out) { +// assert(n <= 126); +// signal input a[k]; +// signal input b[k]; +// signal output out[2 * k - 1]; + +// var prod_val[2 * k - 1]; +// for (var i = 0; i < 2 * k - 1; i++) { +// prod_val[i] = 0; +// if (i < k) { +// for (var a_idx = 0; a_idx <= i; a_idx++) { +// prod_val[i] = prod_val[i] + a[a_idx] * b[i - a_idx]; +// } +// } else { +// for (var a_idx = i - k + 1; a_idx < k; a_idx++) { +// prod_val[i] = prod_val[i] + a[a_idx] * b[i - a_idx]; +// } +// } +// out[i] <-- prod_val[i]; +// } + +// var k2 = 2 * k - 1; +// var pow[k2][k2]; // we cache the exponent values because it makes a big difference in witness generation time +// for(var i = 0; i 1) { - var sumAndCarry[2] = SplitFn(split[0][1] + split[1][0], n, n); - out[1] <-- sumAndCarry[0]; - carry[1] = sumAndCarry[1]; - } - if (k > 2) { - for (var i = 2; i < k; i++) { - var sumAndCarry[2] = SplitFn(split[i][0] + split[i-1][1] + split[i-2][2] + carry[i-1], n, n); - out[i] <-- sumAndCarry[0]; - carry[i] = sumAndCarry[1]; - } - out[k] <-- split[k-1][1] + split[k-2][2] + carry[k-1]; - } - - component outRangeChecks[k+1]; - for (var i = 0; i < k+1; i++) { - outRangeChecks[i] = Num2Bits(n); - outRangeChecks[i].in <== out[i]; - } - - signal runningCarry[k]; - component runningCarryRangeChecks[k]; - runningCarry[0] <-- (in[0] - out[0]) / (1 << n); - runningCarryRangeChecks[0] = Num2Bits(n + log_ceil_ecdsa(k)); - runningCarryRangeChecks[0].in <== runningCarry[0]; - runningCarry[0] * (1 << n) === in[0] - out[0]; - for (var i = 1; i < k; i++) { - runningCarry[i] <-- (in[i] - out[i] + runningCarry[i-1]) / (1 << n); - runningCarryRangeChecks[i] = Num2Bits(n + log_ceil_ecdsa(k)); - runningCarryRangeChecks[i].in <== runningCarry[i]; - runningCarry[i] * (1 << n) === in[i] - out[i] + runningCarry[i-1]; - } - runningCarry[k-1] === out[k]; -} - -template BigMult(n, k) { - signal input a[k]; - signal input b[k]; - signal output out[2 * k]; - - var LOGK = log_ceil_ecdsa(k); - component mult = BigMultShortLong(n, k, 2*n + LOGK); - for (var i = 0; i < k; i++) { - mult.a[i] <== a[i]; - mult.b[i] <== b[i]; - } - - // no carry is possible in the highest order register - component longshort = LongToShortNoEndCarry(n, 2 * k - 1); - for (var i = 0; i < 2 * k - 1; i++) { - longshort.in[i] <== mult.out[i]; - } - for (var i = 0; i < 2 * k; i++) { - out[i] <== longshort.out[i]; - } -} +// var prod_val[ka + kb - 1]; +// for (var i = 0; i < ka + kb - 1; i++) { +// prod_val[i] = 0; +// } +// for (var i = 0; i < ka; i++) { +// for (var j = 0; j < kb; j++) { +// prod_val[i + j] = prod_val[i + j] + a[i] * b[j]; +// } +// } +// for (var i = 0; i < ka + kb - 1; i++) { +// out[i] <-- prod_val[i]; +// } + +// var k2 = ka + kb - 1; +// var pow[k2][k2]; +// for(var i = 0; i 1) { +// var sumAndCarry[2] = SplitFn(split[0][1] + split[1][0], n, n); +// out[1] <-- sumAndCarry[0]; +// carry[1] = sumAndCarry[1]; +// } +// if (k > 2) { +// for (var i = 2; i < k; i++) { +// var sumAndCarry[2] = SplitFn(split[i][0] + split[i-1][1] + split[i-2][2] + carry[i-1], n, n); +// out[i] <-- sumAndCarry[0]; +// carry[i] = sumAndCarry[1]; +// } +// out[k] <-- split[k-1][1] + split[k-2][2] + carry[k-1]; +// } + +// component outRangeChecks[k+1]; +// for (var i = 0; i < k+1; i++) { +// outRangeChecks[i] = Num2Bits(n); +// outRangeChecks[i].in <== out[i]; +// } + +// signal runningCarry[k]; +// component runningCarryRangeChecks[k]; +// runningCarry[0] <-- (in[0] - out[0]) / (1 << n); +// runningCarryRangeChecks[0] = Num2Bits(n + log_ceil_ecdsa(k)); +// runningCarryRangeChecks[0].in <== runningCarry[0]; +// runningCarry[0] * (1 << n) === in[0] - out[0]; +// for (var i = 1; i < k; i++) { +// runningCarry[i] <-- (in[i] - out[i] + runningCarry[i-1]) / (1 << n); +// runningCarryRangeChecks[i] = Num2Bits(n + log_ceil_ecdsa(k)); +// runningCarryRangeChecks[i].in <== runningCarry[i]; +// runningCarry[i] * (1 << n) === in[i] - out[i] + runningCarry[i-1]; +// } +// runningCarry[k-1] === out[k]; +// } + +// template BigMult(n, k) { +// signal input a[k]; +// signal input b[k]; +// signal output out[2 * k]; + +// var LOGK = log_ceil_ecdsa(k); +// component mult = BigMultShortLong(n, k, 2*n + LOGK); +// for (var i = 0; i < k; i++) { +// mult.a[i] <== a[i]; +// mult.b[i] <== b[i]; +// } + +// // no carry is possible in the highest order register +// component longshort = LongToShortNoEndCarry(n, 2 * k - 1); +// for (var i = 0; i < 2 * k - 1; i++) { +// longshort.in[i] <== mult.out[i]; +// } +// for (var i = 0; i < 2 * k; i++) { +// out[i] <== longshort.out[i]; +// } +// } /* Inputs: @@ -446,302 +446,302 @@ template BigLessThanEcdsa(n, k){ out <== ors[0].out; } -// leading register of b should be non-zero -template BigMod(n, k) { - assert(n <= 126); - signal input a[2 * k]; - signal input b[k]; - - signal output div[k + 1]; - signal output mod[k]; - - var longdiv[2][50] = long_div_ecdsa(n, k, a, b); - for (var i = 0; i < k; i++) { - div[i] <-- longdiv[0][i]; - mod[i] <-- longdiv[1][i]; - } - div[k] <-- longdiv[0][k]; - component div_range_checks[k + 1]; - for (var i = 0; i <= k; i++) { - div_range_checks[i] = Num2Bits(n); - div_range_checks[i].in <== div[i]; - } - component mod_range_checks[k]; - for (var i = 0; i < k; i++) { - mod_range_checks[i] = Num2Bits(n); - mod_range_checks[i].in <== mod[i]; - } - - component mul = BigMult(n, k + 1); - for (var i = 0; i < k; i++) { - mul.a[i] <== div[i]; - mul.b[i] <== b[i]; - } - mul.a[k] <== div[k]; - mul.b[k] <== 0; - - for (var i = 0; i < 2 * k + 2; i++) { - //log(mul.out[i]); - } - - component add = BigAdd(n, 2 * k + 2); - for (var i = 0; i < 2 * k; i++) { - add.a[i] <== mul.out[i]; - if (i < k) { - add.b[i] <== mod[i]; - } else { - add.b[i] <== 0; - } - } - add.a[2 * k] <== mul.out[2 * k]; - add.a[2 * k + 1] <== mul.out[2 * k + 1]; - add.b[2 * k] <== 0; - add.b[2 * k + 1] <== 0; - - for (var i = 0; i < 2 * k + 2; i++) { - //log(add.out[i]); - } - - for (var i = 0; i < 2 * k; i++) { - add.out[i] === a[i]; - } - add.out[2 * k] === 0; - add.out[2 * k + 1] === 0; - - component lt = BigLessThanEcdsa(n, k); - for (var i = 0; i < k; i++) { - lt.a[i] <== mod[i]; - lt.b[i] <== b[i]; - } - lt.out === 1; -} - -// copied from BigMod to allow a to have m registers and use long_div2 -template BigMod2(n, k, m) { - assert(n <= 126); - signal input a[m]; - signal input b[k]; - - signal output div[m - k + 1]; - signal output mod[k]; - - var longdiv[2][50] = long_div2(n, k, m-k, a, b); - for (var i = 0; i < k; i++) { - mod[i] <-- longdiv[1][i]; - } - for (var i = 0; i <= m-k; i++) { - div[i] <-- longdiv[0][i]; - } - component div_range_checks[m - k + 1]; - for (var i = 0; i <= m-k; i++) { - div_range_checks[i] = Num2Bits(n); - div_range_checks[i].in <== div[i]; - } - component mod_range_checks[k]; - for (var i = 0; i < k; i++) { - mod_range_checks[i] = Num2Bits(n); - mod_range_checks[i].in <== mod[i]; - } - - component mul = BigMult(n, m-k + 1); - // this might need to be optimized since b has less registers than div - for (var i = 0; i < k; i++) { - mul.a[i] <== div[i]; - mul.b[i] <== b[i]; - } - for (var i = k; i <= m-k; i++) { - mul.a[i] <== div[i]; - mul.b[i] <== 0; - } - - // mul shouldn't have more registers than a - for (var i = m; i < 2*(m-k)+2; i++) { - mul.out[i] === 0; - } - - component add = BigAdd(n, m); - for (var i = 0; i < m; i++) { - add.a[i] <== mul.out[i]; - if (i < k) { - add.b[i] <== mod[i]; - } else { - add.b[i] <== 0; - } - } - - for (var i = 0; i < m; i++) { - add.out[i] === a[i]; - } - add.out[m] === 0; - - component lt = BigLessThanEcdsa(n, k); - for (var i = 0; i < k; i++) { - lt.a[i] <== mod[i]; - lt.b[i] <== b[i]; - } - lt.out === 1; -} - - - -// a[i], b[i] in 0... 2**n-1 -// represent a = a[0] + a[1] * 2**n + .. + a[k - 1] * 2**(n * k) -// calculates (a+b)%p, where 0<= a,b < p -template BigAddModP(n, k){ - assert(n <= 252); - signal input a[k]; - signal input b[k]; - signal input p[k]; - signal output out[k]; - - component add = BigAdd(n,k); - for (var i = 0; i < k; i++) { - add.a[i] <== a[i]; - add.b[i] <== b[i]; - } - component lt = BigLessThanEcdsa(n, k+1); - for (var i = 0; i < k; i++) { - lt.a[i] <== add.out[i]; - lt.b[i] <== p[i]; - } - lt.a[k] <== add.out[k]; - lt.b[k] <== 0; - - component sub = BigSub(n,k+1); - for (var i = 0; i < k; i++) { - sub.a[i] <== add.out[i]; - sub.b[i] <== (1-lt.out) * p[i]; - } - sub.a[k] <== add.out[k]; - sub.b[k] <== 0; +// // leading register of b should be non-zero +// template BigMod(n, k) { +// assert(n <= 126); +// signal input a[2 * k]; +// signal input b[k]; + +// signal output div[k + 1]; +// signal output mod[k]; + +// var longdiv[2][50] = long_div_ecdsa(n, k, a, b); +// for (var i = 0; i < k; i++) { +// div[i] <-- longdiv[0][i]; +// mod[i] <-- longdiv[1][i]; +// } +// div[k] <-- longdiv[0][k]; +// component div_range_checks[k + 1]; +// for (var i = 0; i <= k; i++) { +// div_range_checks[i] = Num2Bits(n); +// div_range_checks[i].in <== div[i]; +// } +// component mod_range_checks[k]; +// for (var i = 0; i < k; i++) { +// mod_range_checks[i] = Num2Bits(n); +// mod_range_checks[i].in <== mod[i]; +// } + +// component mul = BigMult(n, k + 1); +// for (var i = 0; i < k; i++) { +// mul.a[i] <== div[i]; +// mul.b[i] <== b[i]; +// } +// mul.a[k] <== div[k]; +// mul.b[k] <== 0; + +// for (var i = 0; i < 2 * k + 2; i++) { +// //log(mul.out[i]); +// } + +// component add = BigAdd(n, 2 * k + 2); +// for (var i = 0; i < 2 * k; i++) { +// add.a[i] <== mul.out[i]; +// if (i < k) { +// add.b[i] <== mod[i]; +// } else { +// add.b[i] <== 0; +// } +// } +// add.a[2 * k] <== mul.out[2 * k]; +// add.a[2 * k + 1] <== mul.out[2 * k + 1]; +// add.b[2 * k] <== 0; +// add.b[2 * k + 1] <== 0; + +// for (var i = 0; i < 2 * k + 2; i++) { +// //log(add.out[i]); +// } + +// for (var i = 0; i < 2 * k; i++) { +// add.out[i] === a[i]; +// } +// add.out[2 * k] === 0; +// add.out[2 * k + 1] === 0; + +// component lt = BigLessThanEcdsa(n, k); +// for (var i = 0; i < k; i++) { +// lt.a[i] <== mod[i]; +// lt.b[i] <== b[i]; +// } +// lt.out === 1; +// } + +// // copied from BigMod to allow a to have m registers and use long_div2 +// template BigMod2(n, k, m) { +// assert(n <= 126); +// signal input a[m]; +// signal input b[k]; + +// signal output div[m - k + 1]; +// signal output mod[k]; + +// var longdiv[2][50] = long_div2(n, k, m-k, a, b); +// for (var i = 0; i < k; i++) { +// mod[i] <-- longdiv[1][i]; +// } +// for (var i = 0; i <= m-k; i++) { +// div[i] <-- longdiv[0][i]; +// } +// component div_range_checks[m - k + 1]; +// for (var i = 0; i <= m-k; i++) { +// div_range_checks[i] = Num2Bits(n); +// div_range_checks[i].in <== div[i]; +// } +// component mod_range_checks[k]; +// for (var i = 0; i < k; i++) { +// mod_range_checks[i] = Num2Bits(n); +// mod_range_checks[i].in <== mod[i]; +// } + +// component mul = BigMult(n, m-k + 1); +// // this might need to be optimized since b has less registers than div +// for (var i = 0; i < k; i++) { +// mul.a[i] <== div[i]; +// mul.b[i] <== b[i]; +// } +// for (var i = k; i <= m-k; i++) { +// mul.a[i] <== div[i]; +// mul.b[i] <== 0; +// } + +// // mul shouldn't have more registers than a +// for (var i = m; i < 2*(m-k)+2; i++) { +// mul.out[i] === 0; +// } + +// component add = BigAdd(n, m); +// for (var i = 0; i < m; i++) { +// add.a[i] <== mul.out[i]; +// if (i < k) { +// add.b[i] <== mod[i]; +// } else { +// add.b[i] <== 0; +// } +// } + +// for (var i = 0; i < m; i++) { +// add.out[i] === a[i]; +// } +// add.out[m] === 0; + +// component lt = BigLessThanEcdsa(n, k); +// for (var i = 0; i < k; i++) { +// lt.a[i] <== mod[i]; +// lt.b[i] <== b[i]; +// } +// lt.out === 1; +// } + + + +// // a[i], b[i] in 0... 2**n-1 +// // represent a = a[0] + a[1] * 2**n + .. + a[k - 1] * 2**(n * k) +// // calculates (a+b)%p, where 0<= a,b < p +// template BigAddModP(n, k){ +// assert(n <= 252); +// signal input a[k]; +// signal input b[k]; +// signal input p[k]; +// signal output out[k]; + +// component add = BigAdd(n,k); +// for (var i = 0; i < k; i++) { +// add.a[i] <== a[i]; +// add.b[i] <== b[i]; +// } +// component lt = BigLessThanEcdsa(n, k+1); +// for (var i = 0; i < k; i++) { +// lt.a[i] <== add.out[i]; +// lt.b[i] <== p[i]; +// } +// lt.a[k] <== add.out[k]; +// lt.b[k] <== 0; + +// component sub = BigSub(n,k+1); +// for (var i = 0; i < k; i++) { +// sub.a[i] <== add.out[i]; +// sub.b[i] <== (1-lt.out) * p[i]; +// } +// sub.a[k] <== add.out[k]; +// sub.b[k] <== 0; - sub.out[k] === 0; - for (var i = 0; i < k; i++) { - out[i] <== sub.out[i]; - } -} - -/* -Inputs: - - BigInts a, b - - Assume a >= b -Output: - - BigInt out = a - b - - underflow = how much is borrowed at the highest digit of subtraction, only nonzero if a < b -*/ -template BigSub(n, k) { - assert(n <= 252); - signal input a[k]; - signal input b[k]; - signal output out[k]; - signal output underflow; - - component unit0 = ModSub(n); - unit0.a <== a[0]; - unit0.b <== b[0]; - out[0] <== unit0.out; - - component unit[k - 1]; - for (var i = 1; i < k; i++) { - unit[i - 1] = ModSubThree(n); - unit[i - 1].a <== a[i]; - unit[i - 1].b <== b[i]; - if (i == 1) { - unit[i - 1].c <== unit0.borrow; - } else { - unit[i - 1].c <== unit[i - 2].borrow; - } - out[i] <== unit[i - 1].out; - } - underflow <== unit[k - 2].borrow; -} - -// calculates (a - b) % p, where a, b < p -// note: does not assume a >= b -template BigSubModP(n, k){ - assert(n <= 252); - signal input a[k]; - signal input b[k]; - signal input p[k]; - signal output out[k]; - component sub = BigSub(n, k); - for (var i = 0; i < k; i++){ - sub.a[i] <== a[i]; - sub.b[i] <== b[i]; - } - signal flag; - flag <== sub.underflow; - component add = BigAdd(n, k); - for (var i = 0; i < k; i++){ - add.a[i] <== sub.out[i]; - add.b[i] <== p[i]; - } - signal tmp[k]; - for (var i = 0; i < k; i++){ - tmp[i] <== (1 - flag) * sub.out[i]; - out[i] <== tmp[i] + flag * add.out[i]; - } -} - -// Note: deprecated -template BigMultModP(n, k) { - assert(n <= 252); - signal input a[k]; - signal input b[k]; - signal input p[k]; - signal output out[k]; - - component big_mult = BigMult(n, k); - for (var i = 0; i < k; i++) { - big_mult.a[i] <== a[i]; - big_mult.b[i] <== b[i]; - } - component big_mod = BigMod(n, k); - for (var i = 0; i < 2 * k; i++) { - big_mod.a[i] <== big_mult.out[i]; - } - for (var i = 0; i < k; i++) { - big_mod.b[i] <== p[i]; - } - for (var i = 0; i < k; i++) { - out[i] <== big_mod.mod[i]; - } -} - -template BigModInv(n, k) { - assert(n <= 252); - signal input in[k]; - signal input p[k]; - signal output out[k]; - - // length k - var inv[50] = mod_inv(n, k, in, p); - for (var i = 0; i < k; i++) { - out[i] <-- inv[i]; - } - component range_checks[k]; - for (var i = 0; i < k; i++) { - range_checks[i] = Num2Bits(n); - range_checks[i].in <== out[i]; - } - - component mult = BigMult(n, k); - for (var i = 0; i < k; i++) { - mult.a[i] <== in[i]; - mult.b[i] <== out[i]; - } - component mod = BigMod(n, k); - for (var i = 0; i < 2 * k; i++) { - mod.a[i] <== mult.out[i]; - } - for (var i = 0; i < k; i++) { - mod.b[i] <== p[i]; - } - mod.mod[0] === 1; - for (var i = 1; i < k; i++) { - mod.mod[i] === 0; - } -} +// sub.out[k] === 0; +// for (var i = 0; i < k; i++) { +// out[i] <== sub.out[i]; +// } +// } + +// /* +// Inputs: +// - BigInts a, b +// - Assume a >= b +// Output: +// - BigInt out = a - b +// - underflow = how much is borrowed at the highest digit of subtraction, only nonzero if a < b +// */ +// template BigSub(n, k) { +// assert(n <= 252); +// signal input a[k]; +// signal input b[k]; +// signal output out[k]; +// signal output underflow; + +// component unit0 = ModSub(n); +// unit0.a <== a[0]; +// unit0.b <== b[0]; +// out[0] <== unit0.out; + +// component unit[k - 1]; +// for (var i = 1; i < k; i++) { +// unit[i - 1] = ModSubThree(n); +// unit[i - 1].a <== a[i]; +// unit[i - 1].b <== b[i]; +// if (i == 1) { +// unit[i - 1].c <== unit0.borrow; +// } else { +// unit[i - 1].c <== unit[i - 2].borrow; +// } +// out[i] <== unit[i - 1].out; +// } +// underflow <== unit[k - 2].borrow; +// } + +// // calculates (a - b) % p, where a, b < p +// // note: does not assume a >= b +// template BigSubModP(n, k){ +// assert(n <= 252); +// signal input a[k]; +// signal input b[k]; +// signal input p[k]; +// signal output out[k]; +// component sub = BigSub(n, k); +// for (var i = 0; i < k; i++){ +// sub.a[i] <== a[i]; +// sub.b[i] <== b[i]; +// } +// signal flag; +// flag <== sub.underflow; +// component add = BigAdd(n, k); +// for (var i = 0; i < k; i++){ +// add.a[i] <== sub.out[i]; +// add.b[i] <== p[i]; +// } +// signal tmp[k]; +// for (var i = 0; i < k; i++){ +// tmp[i] <== (1 - flag) * sub.out[i]; +// out[i] <== tmp[i] + flag * add.out[i]; +// } +// } + +// // Note: deprecated +// template BigMultModP(n, k) { +// assert(n <= 252); +// signal input a[k]; +// signal input b[k]; +// signal input p[k]; +// signal output out[k]; + +// component big_mult = BigMult(n, k); +// for (var i = 0; i < k; i++) { +// big_mult.a[i] <== a[i]; +// big_mult.b[i] <== b[i]; +// } +// component big_mod = BigMod(n, k); +// for (var i = 0; i < 2 * k; i++) { +// big_mod.a[i] <== big_mult.out[i]; +// } +// for (var i = 0; i < k; i++) { +// big_mod.b[i] <== p[i]; +// } +// for (var i = 0; i < k; i++) { +// out[i] <== big_mod.mod[i]; +// } +// } + +// template BigModInv(n, k) { +// assert(n <= 252); +// signal input in[k]; +// signal input p[k]; +// signal output out[k]; + +// // length k +// var inv[50] = mod_inv(n, k, in, p); +// for (var i = 0; i < k; i++) { +// out[i] <-- inv[i]; +// } +// component range_checks[k]; +// for (var i = 0; i < k; i++) { +// range_checks[i] = Num2Bits(n); +// range_checks[i].in <== out[i]; +// } + +// component mult = BigMult(n, k); +// for (var i = 0; i < k; i++) { +// mult.a[i] <== in[i]; +// mult.b[i] <== out[i]; +// } +// component mod = BigMod(n, k); +// for (var i = 0; i < 2 * k; i++) { +// mod.a[i] <== mult.out[i]; +// } +// for (var i = 0; i < k; i++) { +// mod.b[i] <== p[i]; +// } +// mod.mod[0] === 1; +// for (var i = 1; i < k; i++) { +// mod.mod[i] === 0; +// } +// } /* Taken from circom-ecdsa Input: @@ -778,213 +778,213 @@ template CheckCarryToZeroEcdsa(n, m, k) { } -/* -Let X = 2^n -Input: - - in is length k + m array in signed overflow representation - - in = in[0] + in[1] * X + ... + in[k+m-1] * X^{k+m-1} - - Assume each in[i] is a signed integer such that abs(in[i] * 2^n) < 2^252 - - p is prime in BigInt format passed as parameter -Output: - - out = out[0] + out[1] * X + ... + out[k-1] * X^{k-1} is BigInt congruent to in (mod p) -Implementation: - - For i >= k, we precompute X^i = r[i] mod p, where r[i] represented as k registers with r[i][j] in [0, 2^n) - - in[i] * X^i is replaced by sum_j in[i] * r[i][j] * X^j -Notes: - - If each in[i] has absolute value = k, we precompute X^i = r[i] mod p, where r[i] represented as k registers with r[i][j] in [0, 2^n) +// - in[i] * X^i is replaced by sum_j in[i] * r[i][j] * X^j +// Notes: +// - If each in[i] has absolute value 2*l-1) ? 2*k-1 : 2*l-1; - var pow[k2][k2]; - for(var i = 0; i 2*l-1) ? 2*k-1 : 2*l-1; +// var pow[k2][k2]; +// for(var i = 0; i la + lb -1) ? ka + kb - 1 : la + lb -1; - var pow[k2][k2]; - for(var i = 0; i la + lb -1) ? ka + kb - 1 : la + lb -1; +// var pow[k2][k2]; +// for(var i = 0; i b) - return a; - return b; -} +// function min(a, b) { +// if(a < b) +// return a; +// return b; +// } + +// function max(a, b) { +// if(a > b) +// return a; +// return b; +// } function div_ceil_ecdsa(m, n) { var ret = 0; @@ -33,13 +33,13 @@ function log_ceil_ecdsa(n) { return 254; } -function SplitFn(in, n, m) { - return [in % (1 << n), (in \ (1 << n)) % (1 << m)]; -} +// function SplitFn(in, n, m) { +// return [in % (1 << n), (in \ (1 << n)) % (1 << m)]; +// } -function SplitThreeFn(in, n, m, k) { - return [in % (1 << n), (in \ (1 << n)) % (1 << m), (in \ (1 << n + m)) % (1 << k)]; -} +// function SplitThreeFn(in, n, m, k) { +// return [in % (1 << n), (in \ (1 << n)) % (1 << m), (in \ (1 << n + m)) % (1 << k)]; +// } // 1 if true, 0 if false function long_gt_ecdsa(n, k, a, b) { @@ -54,19 +54,19 @@ function long_gt_ecdsa(n, k, a, b) { return 0; } -function long_is_zero(k, a){ - for(var idx=0; idx k2 -// output has k1+1 registers -function long_add_unequal(n, k1, k2, a, b){ - var carry = 0; - var sum[50]; - for(var i=0; i k2 +// // output has k1+1 registers +// function long_add_unequal(n, k1, k2, a, b){ +// var carry = 0; +// var sum[50]; +// for(var i=0; i 1) { - sumAndCarry[j] = SplitFn(split[j][0][1] + split[j][1][0], n, n); - out[j][1] = sumAndCarry[j][0]; - carry[j][1] = sumAndCarry[j][1]; - } - if (2 * k - 1 > 2) { - for (var i = 2; i < 2 * k - 1; i++) { - sumAndCarry[j] = SplitFn(split[j][i][0] + split[j][i-1][1] + split[j][i-2][2] + carry[j][i-1], n, n); - out[j][i] = sumAndCarry[j][0]; - carry[j][i] = sumAndCarry[j][1]; - } - out[j][2 * k - 1] = split[j][2*k-2][1] + split[j][2*k-3][2] + carry[j][2*k-2]; - } - } - - return out; -} - -// Put all modular arithmetic, aka F_p field stuff, at the end - -function long_add_mod(n, k, a, b, p) { - var sum[50] = long_add(n,k,a,b); - var temp[2][50] = long_div2(n,k,1,sum,p); +// // n bits per register +// // a and b both have l x k registers +// // out has length 2l - 1 x 2k +// // adapted from BigMultShortLong2D and LongToShortNoEndCarry2 witness computation +// function prod2D(n, k, l, a, b) { +// // first compute the intermediate values. taken from BigMulShortLong +// var prod_val[20][50]; // length is 2l - 1 by 2k - 1 +// for (var i = 0; i < 2 * k - 1; i++) { +// for (var j = 0; j < 2 * l - 1; j ++) { +// prod_val[j][i] = 0; +// } +// } +// for (var i1 = 0; i1 < k; i1 ++) { +// for (var i2 = 0; i2 < k; i2 ++) { +// for (var j1 = 0; j1 < l; j1 ++) { +// for (var j2 = 0; j2 < l; j2 ++) { +// prod_val[j1+j2][i1+i2] = prod_val[j1+j2][i1+i2] + a[j1][i1] * b[j2][i2]; +// } +// } +// } +// } + +// // now do a bunch of carrying to make sure registers not overflowed. taken from LongToShortNoEndCarry2 +// var out[20][50]; // length is 2 * l by 2 * k + +// var split[20][50][3]; // second dimension has length 2 * k - 1 +// for (var j = 0; j < 2 * l - 1; j ++) { +// for (var i = 0; i < 2 * k - 1; i++) { +// split[j][i] = SplitThreeFn(prod_val[j][i], n, n, n); +// } +// } + +// var carry[20][50]; // length is 2l-1 x 2k +// var sumAndCarry[20][2]; +// for ( var j = 0; j < 2 * l - 1; j ++) { +// carry[j][0] = 0; +// out[j][0] = split[j][0][0]; +// if (2 * k - 1 > 1) { +// sumAndCarry[j] = SplitFn(split[j][0][1] + split[j][1][0], n, n); +// out[j][1] = sumAndCarry[j][0]; +// carry[j][1] = sumAndCarry[j][1]; +// } +// if (2 * k - 1 > 2) { +// for (var i = 2; i < 2 * k - 1; i++) { +// sumAndCarry[j] = SplitFn(split[j][i][0] + split[j][i-1][1] + split[j][i-2][2] + carry[j][i-1], n, n); +// out[j][i] = sumAndCarry[j][0]; +// carry[j][i] = sumAndCarry[j][1]; +// } +// out[j][2 * k - 1] = split[j][2*k-2][1] + split[j][2*k-3][2] + carry[j][2*k-2]; +// } +// } + +// return out; +// } + +// // Put all modular arithmetic, aka F_p field stuff, at the end + +function long_add_mod_ecdsa(n, k, a, b, p) { + var sum[50] = long_add_ecdsa(n,k,a,b); + var temp[2][50] = long_div2_ecdsa(n,k,1,sum,p); return temp[1]; } -function long_sub_mod(n, k, a, b, p) { +function long_sub_mod_ecdsa(n, k, a, b, p) { if(long_gt_ecdsa(n, k, b, a) == 1){ - return long_add(n, k, a, long_sub_ecdsa(n,k,p,b)); + return long_add_ecdsa(n, k, a, long_sub_ecdsa(n,k,p,b)); }else{ return long_sub_ecdsa(n, k, a, b); } } -function prod_mod(n, k, a, b, p) { - var prod[50] = prod(n,k,a,b); - var temp[2][50] = long_div_ecdsa(n,k,prod,p); +function prod_mod_ecdsa(n, k, a, b, p) { + var prod_ecdsa[50] = prod_ecdsa(n,k,a,b); + var temp[2][50] = long_div_ecdsa(n,k,prod_ecdsa,p); return temp[1]; } @@ -443,7 +443,7 @@ function prod_mod(n, k, a, b, p) { // k * n <= 500 // p is a prime // computes a^e mod p -function mod_exp(n, k, a, p, e) { +function mod_exp_ecdsa(n, k, a, p, e) { var eBits[500]; // length is k * n var bitlength; for (var i = 0; i < k; i++) { @@ -465,7 +465,7 @@ function mod_exp(n, k, a, p, e) { // multiply by a if bit is 0 if (eBits[i] == 1) { var temp[50]; // length 2 * k - temp = prod(n, k, out, a); + temp = prod_ecdsa(n, k, out, a); var temp2[2][50]; temp2 = long_div_ecdsa(n, k, temp, p); out = temp2[1]; @@ -474,7 +474,7 @@ function mod_exp(n, k, a, p, e) { // square, unless we're at the end if (i > 0) { var temp[50]; // length 2 * k - temp = prod(n, k, out, out); + temp = prod_ecdsa(n, k, out, out); var temp2[2][50]; temp2 = long_div_ecdsa(n, k, temp, p); out = temp2[1]; @@ -491,7 +491,7 @@ function mod_exp(n, k, a, p, e) { // p is a prime // if a == 0 mod p, returns 0 // else computes inv = a^(p-2) mod p -function mod_inv(n, k, a, p) { +function mod_inv_ecdsa(n, k, a, p) { var isZero = 1; for (var i = 0; i < k; i++) { if (a[i] != 0) { diff --git a/circuits/circuits/utils/circom-ecdsa/curve.circom b/circuits/circuits/utils/circom-ecdsa/curve.circom index ae35240e..cbad407a 100644 --- a/circuits/circuits/utils/circom-ecdsa/curve.circom +++ b/circuits/circuits/utils/circom-ecdsa/curve.circom @@ -173,15 +173,15 @@ template EllipticCurveAddUnequal(n, k, p) { assert(4*n + LOGK3 < 251); // precompute lambda and x_3 and then y_3 - var dy[50] = long_sub_mod(n, k, b[1], a[1], p); - var dx[50] = long_sub_mod(n, k, b[0], a[0], p); - var dx_inv[50] = mod_inv(n, k, dx, p); - var lambda[50] = prod_mod(n, k, dy, dx_inv, p); - var lambda_sq[50] = prod_mod(n, k, lambda, lambda, p); + var dy[50] = long_sub_mod_ecdsa(n, k, b[1], a[1], p); + var dx[50] = long_sub_mod_ecdsa(n, k, b[0], a[0], p); + var dx_inv[50] = mod_inv_ecdsa(n, k, dx, p); + var lambda[50] = prod_mod_ecdsa(n, k, dy, dx_inv, p); + var lambda_sq[50] = prod_mod_ecdsa(n, k, lambda, lambda, p); // out[0] = x_3 = lamb^2 - a[0] - b[0] % p // out[1] = y_3 = lamb * (a[0] - x_3) - a[1] % p - var x3[50] = long_sub_mod(n, k, long_sub_mod(n, k, lambda_sq, a[0], p), b[0], p); - var y3[50] = long_sub_mod(n, k, prod_mod(n, k, lambda, long_sub_mod(n, k, a[0], x3, p), p), a[1], p); + var x3[50] = long_sub_mod_ecdsa(n, k, long_sub_mod_ecdsa(n, k, lambda_sq, a[0], p), b[0], p); + var y3[50] = long_sub_mod_ecdsa(n, k, prod_mod_ecdsa(n, k, lambda, long_sub_mod_ecdsa(n, k, a[0], x3, p), p), a[1], p); for(var i = 0; i < k; i++){ out[0][i] <-- x3[i]; @@ -265,13 +265,13 @@ template EllipticCurveDouble(n, k, a, b, p) { } // precompute lambda - var lamb_num[50] = long_add_mod(n, k, a, prod_mod(n, k, long_3, prod_mod(n, k, in[0], in[0], p), p), p); - var lamb_denom[50] = long_add_mod(n, k, in[1], in[1], p); - var lamb[50] = prod_mod(n, k, lamb_num, mod_inv(n, k, lamb_denom, p), p); + var lamb_num[50] = long_add_mod_ecdsa(n, k, a, prod_mod_ecdsa(n, k, long_3, prod_mod_ecdsa(n, k, in[0], in[0], p), p), p); + var lamb_denom[50] = long_add_mod_ecdsa(n, k, in[1], in[1], p); + var lamb[50] = prod_mod_ecdsa(n, k, lamb_num, mod_inv_ecdsa(n, k, lamb_denom, p), p); // precompute x_3, y_3 - var x3[50] = long_sub_mod(n, k, prod_mod(n, k, lamb, lamb, p), long_add_mod(n, k, in[0], in[0], p), p); - var y3[50] = long_sub_mod(n, k, prod_mod(n, k, lamb, long_sub_mod(n, k, in[0], x3, p), p), in[1], p); + var x3[50] = long_sub_mod_ecdsa(n, k, prod_mod_ecdsa(n, k, lamb, lamb, p), long_add_mod_ecdsa(n, k, in[0], in[0], p), p); + var y3[50] = long_sub_mod_ecdsa(n, k, prod_mod_ecdsa(n, k, lamb, long_sub_mod_ecdsa(n, k, in[0], x3, p), p), in[1], p); for(var i=0; i Date: Tue, 17 Sep 2024 18:50:39 +0200 Subject: [PATCH 25/60] add bigInt/bytes/array/functions templates --- circuits/circuits/utils/other/array.circom | 164 +++ circuits/circuits/utils/other/bigInt.circom | 988 ++++++++++++++++++ .../circuits/utils/other/bigIntFunc.circom | 615 +++++++++++ .../utils/other/bigint_4x64_mult.circom | 101 ++ circuits/circuits/utils/other/bytes.circom | 112 ++ .../circuits/utils/other/constants.circom | 15 + circuits/circuits/utils/other/fp.circom | 165 +++ .../circuits/utils/other/functions.circom | 17 + 8 files changed, 2177 insertions(+) create mode 100644 circuits/circuits/utils/other/array.circom create mode 100644 circuits/circuits/utils/other/bigInt.circom create mode 100644 circuits/circuits/utils/other/bigIntFunc.circom create mode 100644 circuits/circuits/utils/other/bigint_4x64_mult.circom create mode 100644 circuits/circuits/utils/other/bytes.circom create mode 100644 circuits/circuits/utils/other/constants.circom create mode 100644 circuits/circuits/utils/other/fp.circom create mode 100644 circuits/circuits/utils/other/functions.circom diff --git a/circuits/circuits/utils/other/array.circom b/circuits/circuits/utils/other/array.circom new file mode 100644 index 00000000..d743aaa9 --- /dev/null +++ b/circuits/circuits/utils/other/array.circom @@ -0,0 +1,164 @@ +pragma circom 2.1.6; + +include "circomlib/circuits/comparators.circom"; +include "circomlib/circuits/bitify.circom"; +include "./functions.circom"; + + +/// @title ItemAtIndex +/// @notice Select item at given index from the input array +/// @notice This template that the index is valid +/// @notice This is a modified version of QuinSelector from MACI https://github.com/privacy-scaling-explorations/maci/ +/// @param maxArrayLen The number of elements in the array +/// @input in The input array +/// @input index The index of the element to select +/// @output out The selected element +template ItemAtIndex(maxArrayLen) { + signal input in[maxArrayLen]; + signal input index; + + signal output out; + + component calcTotalValue = CalculateTotal(maxArrayLen); + component calcTotalIndex = CalculateTotal(maxArrayLen); + component eqs[maxArrayLen]; + + // For each item, check whether its index equals the input index. + for (var i = 0; i < maxArrayLen; i ++) { + eqs[i] = IsEqual(); + eqs[i].in[0] <== i; + eqs[i].in[1] <== index; + + // eqs[i].out is 1 if the index matches - so calcTotal is sum of 0s + 1 * valueAtIndex + calcTotalValue.nums[i] <== eqs[i].out * in[i]; + + // Take the sum of all eqs[i].out and assert that it is at most 1. + calcTotalIndex.nums[i] <== eqs[i].out; + } + + // Assert that the sum of eqs[i].out is 1. This is to ensure the index passed is valid. + calcTotalIndex.sum === 1; + + out <== calcTotalValue.sum; +} + + +/// @title CalculateTotal +/// @notice Calculate the sum of an array +/// @param n The number of elements in the array +/// @input nums The input array; assumes elements are small enough that their sum does not overflow the field +/// @output sum The sum of the input array +template CalculateTotal(n) { + signal input nums[n]; + + signal output sum; + + signal sums[n]; + sums[0] <== nums[0]; + + for (var i=1; i < n; i++) { + sums[i] <== sums[i - 1] + nums[i]; + } + + sum <== sums[n - 1]; +} + + +/// @title SelectSubArray +/// @notice Select sub array from an array given a `startIndex` and `length` +/// @notice This is same as `VarShiftLeft` but with elements after `length` set to zero +/// @notice This is not used in core ZK-Email circuits at the moment +/// @param maxArrayLen: the maximum number of bytes in the input array +/// @param maxSubArrayLen: the maximum number of integers in the output array +/// @input in: the input array +/// @input startIndex: the start index of the sub array; assumes a valid index +/// @input length: the length of the sub array; assumes to fit in `ceil(log2(maxArrayLen))` bits +/// @output out: array of `maxSubArrayLen` size, items starting from `startIndex`, and items after `length` set to zero +template SelectSubArray(maxArrayLen, maxSubArrayLen) { + assert(maxSubArrayLen < maxArrayLen); + + signal input in[maxArrayLen]; + signal input startIndex; + signal input length; + + signal output out[maxSubArrayLen]; + + component shifter = VarShiftLeft(maxArrayLen, maxSubArrayLen); + shifter.in <== in; + shifter.shift <== startIndex; + + // Set value after length to zero + component gts[maxSubArrayLen]; + for (var i = 0; i < maxSubArrayLen; i++) { + gts[i] = GreaterThan(log2Ceil(maxSubArrayLen)); + gts[i].in[0] <== length; + gts[i].in[1] <== i; + + out[i] <== gts[i].out * shifter.out[i]; + } +} + + +/// @title VarShiftLeft +/// @notice Shift input array by `shift` indices to the left +/// @notice Output array length can be reduced by setting `maxOutArrayLen` +/// @notice Based on https://demo.hedgedoc.org/s/Le0R3xUhB +/// @param maxArrayLen The maximum length of the input array +/// @param maxOutArrayLen The maximum length of the output array +/// @input in The input array +/// @input shift The number of indices to shift the array to the left +/// @output out hifted subarray +template VarShiftLeft(maxArrayLen, maxOutArrayLen) { + assert(maxOutArrayLen <= maxArrayLen); + + var bitLength = log2Ceil(maxArrayLen); + + signal input in[maxArrayLen]; + signal input shift; + + signal output out[maxOutArrayLen]; + + component n2b = Num2Bits(bitLength); + n2b.in <== shift; + + signal tmp[bitLength][maxArrayLen]; + for (var j = 0; j < bitLength; j++) { + for (var i = 0; i < maxArrayLen; i++) { + var offset = (i + (1 << j)) % maxArrayLen; + // Shift left by 2^j indices if bit is 1 + if (j == 0) { + tmp[j][i] <== n2b.out[j] * (in[offset] - in[i]) + in[i]; + } else { + tmp[j][i] <== n2b.out[j] * (tmp[j-1][offset] - tmp[j-1][i]) + tmp[j-1][i]; + } + } + } + + // Return last row + for (var i = 0; i < maxOutArrayLen; i++) { + out[i] <== tmp[bitLength - 1][i]; + } +} + + +/// @title AssertZeroPadding +/// @notice Assert that the input array is zero-padded from the given `startIndex` +/// @param maxArrayLen The maximum number of elements in the input array +/// @input in The input array; +/// @input startIndex The index from which the elements should be 0; assumes `startIndex - 1` to fit in `ceil(log2(maxArrayLen))` bits +template AssertZeroPadding(maxArrayLen) { + var bitLength = log2Ceil(maxArrayLen); + + signal input in[maxArrayLen]; + signal input startIndex; + + component lessThans[maxArrayLen]; + + for (var i = 0; i < maxArrayLen; i++) { + lessThans[i] = LessThan(bitLength); + lessThans[i].in[0] <== startIndex - 1; + lessThans[i].in[1] <== i; + + lessThans[i].out * in[i] === 0; + } +} diff --git a/circuits/circuits/utils/other/bigInt.circom b/circuits/circuits/utils/other/bigInt.circom new file mode 100644 index 00000000..a3581ad3 --- /dev/null +++ b/circuits/circuits/utils/other/bigInt.circom @@ -0,0 +1,988 @@ +pragma circom 2.0.3; + +include "circomlib/circuits/comparators.circom"; +include "circomlib/circuits/bitify.circom"; +include "circomlib/circuits/gates.circom"; + +include "bigIntFunc.circom"; + +// addition mod 2**CHUNK_SIZE with carry bit +template ModSum(CHUNK_SIZE) { + assert(CHUNK_SIZE <= 252); + signal input a; + signal input b; + signal output sum; + signal output carry; + + component n2b = Num2Bits(CHUNK_SIZE + 1); + n2b.in <== a + b; + carry <== n2b.out[CHUNK_SIZE]; + sum <== a + b - carry * (1 << CHUNK_SIZE); +} + +// check if CHUNK_NUMBER-register variables a, b are equal everywhere +template BigIsEqual(CHUNK_NUMBER) { + signal input a[CHUNK_NUMBER]; + signal input b[CHUNK_NUMBER]; + signal output out; + + component isEquals[CHUNK_NUMBER]; + var total = CHUNK_NUMBER; + for (var i = 0; i < CHUNK_NUMBER; i ++) { + isEquals[i] = IsEqual(); + isEquals[i].in[0] <== a[i]; + isEquals[i].in[1] <== b[i]; + total -= isEquals[i].out; + } + component checkZero = IsZero(); + checkZero.in <== total; + out <== checkZero.out; +} + +// check if CHUNK_NUMBER-register variable a is equal to zero +template BigIsZero(CHUNK_NUMBER) { + signal input in[CHUNK_NUMBER]; + signal output out; + + component isZeros[CHUNK_NUMBER]; + var total = CHUNK_NUMBER; + for (var i = 0; i < CHUNK_NUMBER; i ++) { + isZeros[i] = IsZero(); + isZeros[i].in <== in[i]; + total -= isZeros[i].out; + } + component checkZero = IsZero(); + checkZero.in <== total; + out <== checkZero.out; +} + + +// a - b +template ModSub(CHUNK_SIZE) { + assert(CHUNK_SIZE <= 252); + signal input a; + signal input b; + signal output out; + signal output borrow; + component lt = LessThan(CHUNK_SIZE); + lt.in[0] <== a; + lt.in[1] <== b; + borrow <== lt.out; + out <== borrow * (1 << CHUNK_SIZE) + a - b; +} + +// a - b - c +// assume a - b - c + 2**CHUNK_SIZE >= 0 +template ModSubThree(CHUNK_SIZE) { + assert(CHUNK_SIZE + 2 <= 253); + signal input a; + signal input b; + signal input c; + assert(a - b - c + (1 << CHUNK_SIZE) >= 0); + signal output out; + signal output borrow; + signal bPlusC; + bPlusC <== b + c; + component lt = LessThan(CHUNK_SIZE + 1); + lt.in[0] <== a; + lt.in[1] <== bPlusC; + borrow <== lt.out; + out <== borrow * (1 << CHUNK_SIZE) + a - bPlusC; +} + +template ModSumThree(CHUNK_SIZE) { + assert(CHUNK_SIZE + 2 <= 253); + signal input a; + signal input b; + signal input c; + signal output sum; + signal output carry; + + component n2b = Num2Bits(CHUNK_SIZE + 2); + n2b.in <== a + b + c; + carry <== n2b.out[CHUNK_SIZE] + 2 * n2b.out[CHUNK_SIZE + 1]; + sum <== a + b + c - carry * (1 << CHUNK_SIZE); +} + +template ModSumFour(CHUNK_SIZE) { + assert(CHUNK_SIZE + 2 <= 253); + signal input a; + signal input b; + signal input c; + signal input d; + signal output sum; + signal output carry; + + component n2b = Num2Bits(CHUNK_SIZE + 2); + n2b.in <== a + b + c + d; + carry <== n2b.out[CHUNK_SIZE] + 2 * n2b.out[CHUNK_SIZE + 1]; + sum <== a + b + c + d - carry * (1 << CHUNK_SIZE); +} + +// product mod 2**CHUNK_SIZE with carry +template ModProd(CHUNK_SIZE) { + assert(CHUNK_SIZE <= 126); + signal input a; + signal input b; + signal output prod; + signal output carry; + + component n2b = Num2Bits(2 * CHUNK_SIZE); + n2b.in <== a * b; + + component b2n1 = Bits2Num(CHUNK_SIZE); + component b2n2 = Bits2Num(CHUNK_SIZE); + var i; + for (i = 0; i < CHUNK_SIZE; i++) { + b2n1.in[i] <== n2b.out[i]; + b2n2.in[i] <== n2b.out[i + CHUNK_SIZE]; + } + prod <== b2n1.out; + carry <== b2n2.out; +} + +// split a CHUNK_SIZE + M bit input into TWO outputs +template Split(CHUNK_SIZE, M) { + assert(CHUNK_SIZE <= 126); + signal input in; + signal output small; + signal output big; + + small <-- in % (1 << CHUNK_SIZE); + big <-- in \ (1 << CHUNK_SIZE); + + component n2bSmall = Num2Bits(CHUNK_SIZE); + n2bSmall.in <== small; + component n2bBig = Num2Bits(M); + n2bBig.in <== big; + + in === small + big * (1 << CHUNK_SIZE); +} + +// split a CHUNK_SIZE + M + CHUNK_NUMBER bit input into three outputs +template SplitThree(CHUNK_SIZE, M, CHUNK_NUMBER) { + assert(CHUNK_SIZE <= 126); + signal input in; + signal output small; + signal output medium; + signal output big; + + small <-- in % (1 << CHUNK_SIZE); + medium <-- (in \ (1 << CHUNK_SIZE)) % (1 << M); + big <-- in \ (1 << CHUNK_SIZE + M); + + component n2bSmall = Num2Bits(CHUNK_SIZE); + n2bSmall.in <== small; + component n2bMedium = Num2Bits(M); + n2bMedium.in <== medium; + component n2bBig = Num2Bits(CHUNK_NUMBER); + n2bBig.in <== big; + + in === small + medium * (1 << CHUNK_SIZE) + big * (1 << CHUNK_SIZE + M); +} + +// a[i], b[i] in 0... 2**CHUNK_SIZE-1 +// represent a = a[0] + a[1] * 2**CHUNK_SIZE + .. + a[CHUNK_NUMBER - 1] * 2**(CHUNK_SIZE * CHUNK_NUMBER) +template BigAdd(CHUNK_SIZE, CHUNK_NUMBER) { + assert(CHUNK_SIZE <= 252); + signal input a[CHUNK_NUMBER]; + signal input b[CHUNK_NUMBER]; + signal output out[CHUNK_NUMBER + 1]; + + component unit0 = ModSum(CHUNK_SIZE); + unit0.a <== a[0]; + unit0.b <== b[0]; + out[0] <== unit0.sum; + + component unit[CHUNK_NUMBER - 1]; + for (var i = 1; i < CHUNK_NUMBER; i++) { + unit[i - 1] = ModSumThree(CHUNK_SIZE); + unit[i - 1].a <== a[i]; + unit[i - 1].b <== b[i]; + if (i == 1) { + unit[i - 1].c <== unit0.carry; + } else { + unit[i - 1].c <== unit[i - 2].carry; + } + out[i] <== unit[i - 1].sum; + } + out[CHUNK_NUMBER] <== unit[CHUNK_NUMBER - 2].carry; +} + +/* +Polynomial Multiplication +Inputs: + - a = a[0] + a[1] * X + ... + a[CHUNK_NUMBER-1] * X^{CHUNK_NUMBER-1} + - b = b[0] + b[1] * X + ... + b[CHUNK_NUMBER-1] * X^{CHUNK_NUMBER-1} +Output: + - out = out[0] + out[1] * X + ... + out[2 * CHUNK_NUMBER - 2] * X^{2*CHUNK_NUMBER - 2} + - out = a * b as polynomials in X +Notes: + - Optimization due to xJsnark: + -- witness is calculated by normal polynomial multiplication + -- out is contrained by evaluating out(X) === a(X) * b(X) at X = 0, ..., 2*CHUNK_NUMBER - 2 + - If a[i], b[j] have absolute value < B, then out[i] has absolute value < CHUNK_NUMBER * B^2 +M_OUT is the expected max number of bits in the output registers +*/ +template BigMultShortLong(CHUNK_SIZE, CHUNK_NUMBER, M_OUT) { + assert(CHUNK_SIZE <= 126); + signal input a[CHUNK_NUMBER]; + signal input b[CHUNK_NUMBER]; + signal output out[2 * CHUNK_NUMBER - 1]; + + var PROD_VAL[2 * CHUNK_NUMBER - 1]; + for (var i = 0; i < 2 * CHUNK_NUMBER - 1; i++) { + PROD_VAL[i] = 0; + if (i < CHUNK_NUMBER) { + for (var a_idx = 0; a_idx <= i; a_idx++) { + PROD_VAL[i] = PROD_VAL[i] + a[a_idx] * b[i - a_idx]; + } + } else { + for (var a_idx = i - CHUNK_NUMBER + 1; a_idx < CHUNK_NUMBER; a_idx++) { + PROD_VAL[i] = PROD_VAL[i] + a[a_idx] * b[i - a_idx]; + } + } + out[i] <-- PROD_VAL[i]; + } + + var k2 = 2 * CHUNK_NUMBER - 1; + var pow[k2][k2]; // we cache the exponent values because it makes a big difference in witness generation time + for(var i = 0; i 1) { + var sumAndCarry[2] = SplitFn(split[0][1] + split[1][0], CHUNK_SIZE, CHUNK_SIZE); + out[1] <-- sumAndCarry[0]; + carry[1] = sumAndCarry[1]; + } + if (CHUNK_NUMBER > 2) { + for (var i = 2; i < CHUNK_NUMBER; i++) { + var sumAndCarry[2] = SplitFn(split[i][0] + split[i-1][1] + split[i-2][2] + carry[i-1], CHUNK_SIZE, CHUNK_SIZE); + out[i] <-- sumAndCarry[0]; + carry[i] = sumAndCarry[1]; + } + out[CHUNK_NUMBER] <-- split[CHUNK_NUMBER-1][1] + split[CHUNK_NUMBER-2][2] + carry[CHUNK_NUMBER-1]; + } + + component outRangeChecks[CHUNK_NUMBER+1]; + for (var i = 0; i < CHUNK_NUMBER+1; i++) { + outRangeChecks[i] = Num2Bits(CHUNK_SIZE); + outRangeChecks[i].in <== out[i]; + } + + signal runningCarry[CHUNK_NUMBER]; + component runningCarryRangeChecks[CHUNK_NUMBER]; + runningCarry[0] <-- (in[0] - out[0]) / (1 << CHUNK_SIZE); + runningCarryRangeChecks[0] = Num2Bits(CHUNK_SIZE + log_ceil(CHUNK_NUMBER)); + runningCarryRangeChecks[0].in <== runningCarry[0]; + runningCarry[0] * (1 << CHUNK_SIZE) === in[0] - out[0]; + for (var i = 1; i < CHUNK_NUMBER; i++) { + runningCarry[i] <-- (in[i] - out[i] + runningCarry[i-1]) / (1 << CHUNK_SIZE); + runningCarryRangeChecks[i] = Num2Bits(CHUNK_SIZE + log_ceil(CHUNK_NUMBER)); + runningCarryRangeChecks[i].in <== runningCarry[i]; + runningCarry[i] * (1 << CHUNK_SIZE) === in[i] - out[i] + runningCarry[i-1]; + } + runningCarry[CHUNK_NUMBER-1] === out[CHUNK_NUMBER]; +} + +template BigMult(CHUNK_SIZE, CHUNK_NUMBER) { + signal input a[CHUNK_NUMBER]; + signal input b[CHUNK_NUMBER]; + signal output out[2 * CHUNK_NUMBER]; + + var LOGK = log_ceil(CHUNK_NUMBER); + component mult = BigMultShortLong(CHUNK_SIZE, CHUNK_NUMBER, 2*CHUNK_SIZE + LOGK); + for (var i = 0; i < CHUNK_NUMBER; i++) { + mult.a[i] <== a[i]; + mult.b[i] <== b[i]; + } + + // no carry is possible in the highest order register + component longshort = LongToShortNoEndCarry(CHUNK_SIZE, 2 * CHUNK_NUMBER - 1); + for (var i = 0; i < 2 * CHUNK_NUMBER - 1; i++) { + longshort.in[i] <== mult.out[i]; + } + for (var i = 0; i < 2 * CHUNK_NUMBER; i++) { + out[i] <== longshort.out[i]; + } +} + +/* +Inputs: + - BigInts a, b +Output: + - out = (a < b) ? 1 : 0 +*/ +template BigLessThan(CHUNK_SIZE, CHUNK_NUMBER){ + signal input a[CHUNK_NUMBER]; + signal input b[CHUNK_NUMBER]; + signal output out; + + component lt[CHUNK_NUMBER]; + component eq[CHUNK_NUMBER]; + for (var i = 0; i < CHUNK_NUMBER; i++) { + lt[i] = LessThan(CHUNK_SIZE); + lt[i].in[0] <== a[i]; + lt[i].in[1] <== b[i]; + eq[i] = IsEqual(); + eq[i].in[0] <== a[i]; + eq[i].in[1] <== b[i]; + } + + // ors[i] holds (lt[CHUNK_NUMBER - 1] || (eq[CHUNK_NUMBER - 1] && lt[CHUNK_NUMBER - 2]) .. || (eq[CHUNK_NUMBER - 1] && .. && lt[i])) + // ands[i] holds (eq[CHUNK_NUMBER - 1] && .. && lt[i]) + // eqAnds[i] holds (eq[CHUNK_NUMBER - 1] && .. && eq[i]) + component ors[CHUNK_NUMBER - 1]; + component ands[CHUNK_NUMBER - 1]; + component eqAnds[CHUNK_NUMBER - 1]; + for (var i = CHUNK_NUMBER - 2; i >= 0; i--) { + ands[i] = AND(); + eqAnds[i] = AND(); + ors[i] = OR(); + + if (i == CHUNK_NUMBER - 2) { + ands[i].a <== eq[CHUNK_NUMBER - 1].out; + ands[i].b <== lt[CHUNK_NUMBER - 2].out; + eqAnds[i].a <== eq[CHUNK_NUMBER - 1].out; + eqAnds[i].b <== eq[CHUNK_NUMBER - 2].out; + ors[i].a <== lt[CHUNK_NUMBER - 1].out; + ors[i].b <== ands[i].out; + } else { + ands[i].a <== eqAnds[i + 1].out; + ands[i].b <== lt[i].out; + eqAnds[i].a <== eqAnds[i + 1].out; + eqAnds[i].b <== eq[i].out; + ors[i].a <== ors[i + 1].out; + ors[i].b <== ands[i].out; + } + } + out <== ors[0].out; +} + +// leading register of b should be non-zero +template BigMod(CHUNK_SIZE, CHUNK_NUMBER) { + assert(CHUNK_SIZE <= 126); + signal input a[2 * CHUNK_NUMBER]; + signal input b[CHUNK_NUMBER]; + + signal output div[CHUNK_NUMBER + 1]; + signal output mod[CHUNK_NUMBER]; + + var LONG_DIV[2][150] = long_div(CHUNK_SIZE, CHUNK_NUMBER, a, b); + for (var i = 0; i < CHUNK_NUMBER; i++) { + div[i] <-- LONG_DIV[0][i]; + mod[i] <-- LONG_DIV[1][i]; + } + div[CHUNK_NUMBER] <-- LONG_DIV[0][CHUNK_NUMBER]; + component div_range_checks[CHUNK_NUMBER + 1]; + for (var i = 0; i <= CHUNK_NUMBER; i++) { + div_range_checks[i] = Num2Bits(CHUNK_SIZE); + div_range_checks[i].in <== div[i]; + } + component mod_range_checks[CHUNK_NUMBER]; + for (var i = 0; i < CHUNK_NUMBER; i++) { + mod_range_checks[i] = Num2Bits(CHUNK_SIZE); + mod_range_checks[i].in <== mod[i]; + } + + component mul = BigMult(CHUNK_SIZE, CHUNK_NUMBER + 1); + for (var i = 0; i < CHUNK_NUMBER; i++) { + mul.a[i] <== div[i]; + mul.b[i] <== b[i]; + } + mul.a[CHUNK_NUMBER] <== div[CHUNK_NUMBER]; + mul.b[CHUNK_NUMBER] <== 0; + + for (var i = 0; i < 2 * CHUNK_NUMBER + 2; i++) { + //log(mul.out[i]); + } + + component add = BigAdd(CHUNK_SIZE, 2 * CHUNK_NUMBER + 2); + for (var i = 0; i < 2 * CHUNK_NUMBER; i++) { + add.a[i] <== mul.out[i]; + if (i < CHUNK_NUMBER) { + add.b[i] <== mod[i]; + } else { + add.b[i] <== 0; + } + } + add.a[2 * CHUNK_NUMBER] <== mul.out[2 * CHUNK_NUMBER]; + add.a[2 * CHUNK_NUMBER + 1] <== mul.out[2 * CHUNK_NUMBER + 1]; + add.b[2 * CHUNK_NUMBER] <== 0; + add.b[2 * CHUNK_NUMBER + 1] <== 0; + + for (var i = 0; i < 2 * CHUNK_NUMBER + 2; i++) { + //log(add.out[i]); + } + + for (var i = 0; i < 2 * CHUNK_NUMBER; i++) { + add.out[i] === a[i]; + } + add.out[2 * CHUNK_NUMBER] === 0; + add.out[2 * CHUNK_NUMBER + 1] === 0; + + component lt = BigLessThan(CHUNK_SIZE, CHUNK_NUMBER); + for (var i = 0; i < CHUNK_NUMBER; i++) { + lt.a[i] <== mod[i]; + lt.b[i] <== b[i]; + } + lt.out === 1; +} + +// copied from BigMod to allow a to have M registers and use long_div2 +template BigMod2(CHUNK_SIZE, CHUNK_NUMBER, M) { + assert(CHUNK_SIZE <= 126); + signal input a[M]; + signal input b[CHUNK_NUMBER]; + + signal output div[M - CHUNK_NUMBER + 1]; + signal output mod[CHUNK_NUMBER]; + + var LONG_DIV[2][150] = long_div2(CHUNK_SIZE, CHUNK_NUMBER, M-CHUNK_NUMBER, a, b); + for (var i = 0; i < CHUNK_NUMBER; i++) { + mod[i] <-- LONG_DIV[1][i]; + } + for (var i = 0; i <= M-CHUNK_NUMBER; i++) { + div[i] <-- LONG_DIV[0][i]; + } + component div_range_checks[M - CHUNK_NUMBER + 1]; + for (var i = 0; i <= M-CHUNK_NUMBER; i++) { + div_range_checks[i] = Num2Bits(CHUNK_SIZE); + div_range_checks[i].in <== div[i]; + } + component mod_range_checks[CHUNK_NUMBER]; + for (var i = 0; i < CHUNK_NUMBER; i++) { + mod_range_checks[i] = Num2Bits(CHUNK_SIZE); + mod_range_checks[i].in <== mod[i]; + } + + component mul = BigMult(CHUNK_SIZE, M-CHUNK_NUMBER + 1); + // this might need to be optimized since b has less registers than div + for (var i = 0; i < CHUNK_NUMBER; i++) { + mul.a[i] <== div[i]; + mul.b[i] <== b[i]; + } + for (var i = CHUNK_NUMBER; i <= M-CHUNK_NUMBER; i++) { + mul.a[i] <== div[i]; + mul.b[i] <== 0; + } + + // mul shouldn't have more registers than a + for (var i = M; i < 2*(M-CHUNK_NUMBER)+2; i++) { + mul.out[i] === 0; + } + + component add = BigAdd(CHUNK_SIZE, M); + for (var i = 0; i < M; i++) { + add.a[i] <== mul.out[i]; + if (i < CHUNK_NUMBER) { + add.b[i] <== mod[i]; + } else { + add.b[i] <== 0; + } + } + + for (var i = 0; i < M; i++) { + add.out[i] === a[i]; + } + add.out[M] === 0; + + component lt = BigLessThan(CHUNK_SIZE, CHUNK_NUMBER); + for (var i = 0; i < CHUNK_NUMBER; i++) { + lt.a[i] <== mod[i]; + lt.b[i] <== b[i]; + } + lt.out === 1; +} + + + +// a[i], b[i] in 0... 2**CHUNK_SIZE-1 +// represent a = a[0] + a[1] * 2**CHUNK_SIZE + .. + a[CHUNK_NUMBER - 1] * 2**(CHUNK_SIZE * CHUNK_NUMBER) +// calculates (a+b)%P, where 0<= a,b < P +template BigAddModP(CHUNK_SIZE, CHUNK_NUMBER){ + assert(CHUNK_SIZE <= 252); + signal input a[CHUNK_NUMBER]; + signal input b[CHUNK_NUMBER]; + signal input p[CHUNK_NUMBER]; + signal output out[CHUNK_NUMBER]; + + component add = BigAdd(CHUNK_SIZE,CHUNK_NUMBER); + for (var i = 0; i < CHUNK_NUMBER; i++) { + add.a[i] <== a[i]; + add.b[i] <== b[i]; + } + component lt = BigLessThan(CHUNK_SIZE, CHUNK_NUMBER+1); + for (var i = 0; i < CHUNK_NUMBER; i++) { + lt.a[i] <== add.out[i]; + lt.b[i] <== p[i]; + } + lt.a[CHUNK_NUMBER] <== add.out[CHUNK_NUMBER]; + lt.b[CHUNK_NUMBER] <== 0; + + component sub = BigSub(CHUNK_SIZE,CHUNK_NUMBER+1); + for (var i = 0; i < CHUNK_NUMBER; i++) { + sub.a[i] <== add.out[i]; + sub.b[i] <== (1-lt.out) * p[i]; + } + sub.a[CHUNK_NUMBER] <== add.out[CHUNK_NUMBER]; + sub.b[CHUNK_NUMBER] <== 0; + + sub.out[CHUNK_NUMBER] === 0; + for (var i = 0; i < CHUNK_NUMBER; i++) { + out[i] <== sub.out[i]; + } +} + +/* +Inputs: + - BigInts a, b + - Assume a >= b +Output: + - BigInt out = a - b + - underflow = how much is borrowed at the highest digit of subtraction, only nonzero if a < b +*/ +template BigSub(CHUNK_SIZE, CHUNK_NUMBER) { + assert(CHUNK_SIZE <= 252); + signal input a[CHUNK_NUMBER]; + signal input b[CHUNK_NUMBER]; + signal output out[CHUNK_NUMBER]; + signal output underflow; + + component unit0 = ModSub(CHUNK_SIZE); + unit0.a <== a[0]; + unit0.b <== b[0]; + out[0] <== unit0.out; + + component unit[CHUNK_NUMBER - 1]; + for (var i = 1; i < CHUNK_NUMBER; i++) { + unit[i - 1] = ModSubThree(CHUNK_SIZE); + unit[i - 1].a <== a[i]; + unit[i - 1].b <== b[i]; + if (i == 1) { + unit[i - 1].c <== unit0.borrow; + } else { + unit[i - 1].c <== unit[i - 2].borrow; + } + out[i] <== unit[i - 1].out; + } + underflow <== unit[CHUNK_NUMBER - 2].borrow; +} + +// calculates (a - b) % p, where a, b < p +// note: does not assume a >= b +template BigSubModP(CHUNK_SIZE, CHUNK_NUMBER){ + assert(CHUNK_SIZE <= 252); + signal input a[CHUNK_NUMBER]; + signal input b[CHUNK_NUMBER]; + signal input p[CHUNK_NUMBER]; + signal output out[CHUNK_NUMBER]; + component sub = BigSub(CHUNK_SIZE, CHUNK_NUMBER); + for (var i = 0; i < CHUNK_NUMBER; i++){ + sub.a[i] <== a[i]; + sub.b[i] <== b[i]; + } + signal flag; + flag <== sub.underflow; + component add = BigAdd(CHUNK_SIZE, CHUNK_NUMBER); + for (var i = 0; i < CHUNK_NUMBER; i++){ + add.a[i] <== sub.out[i]; + add.b[i] <== p[i]; + } + signal tmp[CHUNK_NUMBER]; + for (var i = 0; i < CHUNK_NUMBER; i++){ + tmp[i] <== (1 - flag) * sub.out[i]; + out[i] <== tmp[i] + flag * add.out[i]; + } +} + +// Note: deprecated +template BigMultModP(CHUNK_SIZE, CHUNK_NUMBER) { + assert(CHUNK_SIZE <= 252); + signal input a[CHUNK_NUMBER]; + signal input b[CHUNK_NUMBER]; + signal input p[CHUNK_NUMBER]; + signal output out[CHUNK_NUMBER]; + + component big_mult = BigMult(CHUNK_SIZE, CHUNK_NUMBER); + for (var i = 0; i < CHUNK_NUMBER; i++) { + big_mult.a[i] <== a[i]; + big_mult.b[i] <== b[i]; + } + component big_mod = BigMod(CHUNK_SIZE, CHUNK_NUMBER); + for (var i = 0; i < 2 * CHUNK_NUMBER; i++) { + big_mod.a[i] <== big_mult.out[i]; + } + for (var i = 0; i < CHUNK_NUMBER; i++) { + big_mod.b[i] <== p[i]; + } + for (var i = 0; i < CHUNK_NUMBER; i++) { + out[i] <== big_mod.mod[i]; + } +} + +template BigModInv(CHUNK_SIZE, CHUNK_NUMBER) { + assert(CHUNK_SIZE <= 252); + signal input in[CHUNK_NUMBER]; + signal input p[CHUNK_NUMBER]; + signal output out[CHUNK_NUMBER]; + + // length CHUNK_NUMBER + var inv[150] = mod_inv(CHUNK_SIZE, CHUNK_NUMBER, in, p); + for (var i = 0; i < CHUNK_NUMBER; i++) { + out[i] <-- inv[i]; + } + component rangeChecks[CHUNK_NUMBER]; + for (var i = 0; i < CHUNK_NUMBER; i++) { + rangeChecks[i] = Num2Bits(CHUNK_SIZE); + rangeChecks[i].in <== out[i]; + } + + component mult = BigMult(CHUNK_SIZE, CHUNK_NUMBER); + for (var i = 0; i < CHUNK_NUMBER; i++) { + mult.a[i] <== in[i]; + mult.b[i] <== out[i]; + } + component mod = BigMod(CHUNK_SIZE, CHUNK_NUMBER); + for (var i = 0; i < 2 * CHUNK_NUMBER; i++) { + mod.a[i] <== mult.out[i]; + } + for (var i = 0; i < CHUNK_NUMBER; i++) { + mod.b[i] <== p[i]; + } + mod.mod[0] === 1; + for (var i = 1; i < CHUNK_NUMBER; i++) { + mod.mod[i] === 0; + } +} + +/* Taken from circom-ecdsa +Input: + - in = in[0] + in[1] * X + ... + in[CHUNK_NUMBER-1] * X^{CHUNK_NUMBER-1} as signed overflow representation + - Assume each in[i] is in range (-2^{M-1}, 2^{M-1}) +Implements: + - constrain that in[] evaluated at X = 2^CHUNK_SIZE as a big integer equals zero +*/ +template CheckCarryToZero(CHUNK_SIZE, M, CHUNK_NUMBER) { + assert(CHUNK_NUMBER >= 2); + + var EPSILON = 1; // see below for why 1 is ok + + signal input in[CHUNK_NUMBER]; + + signal carry[CHUNK_NUMBER]; + component carryRangeChecks[CHUNK_NUMBER]; + for (var i = 0; i < CHUNK_NUMBER-1; i++){ + carryRangeChecks[i] = Num2Bits(M + EPSILON - CHUNK_SIZE); + if( i == 0 ){ + carry[i] <-- in[i] / (1<= CHUNK_NUMBER, we precompute X^i = r[i] mod P, where r[i] represented as CHUNK_NUMBER registers with r[i][j] in [0, 2^CHUNK_SIZE) + - in[i] * X^i is replaced by sum_j in[i] * r[i][j] * X^j +Notes: + - If each in[i] has absolute value 2*l-1) ? 2*CHUNK_NUMBER-1 : 2*l-1; + var pow[k2][k2]; + for(var i = 0; i L_A + L_B -1) ? K_A + K_B - 1 : L_A + L_B -1; + var pow[k2][k2]; + for(var i = 0; i B) + return A; + return B; +} + +function log_ceil(CHUNK_SIZE) { + var n_temp = CHUNK_SIZE; + for (var i = 0; i < 254; i++) { + if (n_temp == 0) { + return i; + } + n_temp = n_temp \ 2; + } + return 254; +} + +function SplitFn(IN, CHUNK_SIZE, M) { + return [IN % (1 << CHUNK_SIZE), (IN \ (1 << CHUNK_SIZE)) % (1 << M)]; +} + +function SplitThreeFn(IN, CHUNK_SIZE, M, CHUNK_NUMBER) { + return [IN % (1 << CHUNK_SIZE), (IN \ (1 << CHUNK_SIZE)) % (1 << M), (IN \ (1 << CHUNK_SIZE + M)) % (1 << CHUNK_NUMBER)]; +} + +// 1 if true, 0 if false +function long_gt(CHUNK_SIZE, CHUNK_NUMBER, A, B) { + for (var i = CHUNK_NUMBER - 1; i >= 0; i--) { + if (A[i] > B[i]) { + return 1; + } + if (A[i] < B[i]) { + return 0; + } + } + return 0; +} + +function long_is_zero(CHUNK_NUMBER, A){ + for(var idx=0; idx K2 +// output has K1+1 registers +function long_add_unequal(CHUNK_SIZE, K1, K2, A, B){ + var carry = 0; + var sum[150]; + for(var i=0; i= B +function long_sub(CHUNK_SIZE, CHUNK_NUMBER, A, B) { + var diff[150]; + var borrow[150]; + for (var i = 0; i < CHUNK_NUMBER; i++) { + if (i == 0) { + if (A[i] >= B[i]) { + diff[i] = A[i] - B[i]; + borrow[i] = 0; + } else { + diff[i] = A[i] - B[i] + (1 << CHUNK_SIZE); + borrow[i] = 1; + } + } else { + if (A[i] >= B[i] + borrow[i - 1]) { + diff[i] = A[i] - B[i] - borrow[i - 1]; + borrow[i] = 0; + } else { + diff[i] = (1 << CHUNK_SIZE) + A[i] - B[i] - borrow[i - 1]; + borrow[i] = 1; + } + } + } + return diff; +} + +// A is A CHUNK_SIZE-bit scalar +// B has CHUNK_NUMBER registers +function long_scalar_mult(CHUNK_SIZE, CHUNK_NUMBER, A, B) { + var out[150]; + for (var i = 0; i < 150; i++) { + out[i] = 0; + } + for (var i = 0; i < CHUNK_NUMBER; i++) { + var temp = out[i] + (A * B[i]); + out[i] = temp % (1 << CHUNK_SIZE); + out[i + 1] = out[i + 1] + temp \ (1 << CHUNK_SIZE); + } + return out; +} + + +// CHUNK_SIZE bits per register +// A has CHUNK_NUMBER + M registers +// B has CHUNK_NUMBER registers +// out[0] has length M + 1 -- quotient +// out[1] has length CHUNK_NUMBER -- remainder +// implements algorithm of https://people.eecs.berkeley.edu/~fateman/282/F%20Wright%20notes/week4.pdf +// B[CHUNK_NUMBER-1] must be nonzero! +function long_div2(CHUNK_SIZE, CHUNK_NUMBER, M, A, B){ + var out[2][150]; + // assume CHUNK_NUMBER+M < 150 + var remainder[150]; + for (var i = 0; i < M + CHUNK_NUMBER; i++) { + remainder[i] = A[i]; + } + + var dividend[150]; + for (var i = M; i >= 0; i--) { + if (i == M) { + dividend[CHUNK_NUMBER] = 0; + for (var j = CHUNK_NUMBER - 1; j >= 0; j--) { + dividend[j] = remainder[j + M]; + } + } else { + for (var j = CHUNK_NUMBER; j >= 0; j--) { + dividend[j] = remainder[j + i]; + } + } + out[0][i] = short_div(CHUNK_SIZE, CHUNK_NUMBER, dividend, B); + var MULT_SHIFT[150] = long_scalar_mult(CHUNK_SIZE, CHUNK_NUMBER, out[0][i], B); + var subtrahend[150]; + for (var j = 0; j < M + CHUNK_NUMBER; j++) { + subtrahend[j] = 0; + } + for (var j = 0; j <= CHUNK_NUMBER; j++) { + if (i + j < M + CHUNK_NUMBER) { + subtrahend[i + j] = MULT_SHIFT[j]; + } + } + remainder = long_sub(CHUNK_SIZE, M + CHUNK_NUMBER, remainder, subtrahend); + } + for (var i = 0; i < CHUNK_NUMBER; i++) { + out[1][i] = remainder[i]; + } + out[1][CHUNK_NUMBER] = 0; + return out; +} + +function long_div(CHUNK_SIZE, CHUNK_NUMBER, A, B) { + return long_div2(CHUNK_SIZE, CHUNK_NUMBER, CHUNK_NUMBER, A, B); +} + +// CHUNK_SIZE bits per register +// A has CHUNK_NUMBER + 1 registers +// B has CHUNK_NUMBER registers +// assumes leading digit of B is at least 2^(CHUNK_SIZE - 1) +// 0 <= A < (2**CHUNK_SIZE) * B +function short_div_norm(CHUNK_SIZE, CHUNK_NUMBER, A, B) { + var qhat = (A[CHUNK_NUMBER] * (1 << CHUNK_SIZE) + A[CHUNK_NUMBER - 1]) \ B[CHUNK_NUMBER - 1]; + if (qhat > (1 << CHUNK_SIZE) - 1) { + qhat = (1 << CHUNK_SIZE) - 1; + } + + var MULT[150] = long_scalar_mult(CHUNK_SIZE, CHUNK_NUMBER, qhat, B); + if (long_gt(CHUNK_SIZE, CHUNK_NUMBER + 1, MULT, A) == 1) { + MULT = long_sub(CHUNK_SIZE, CHUNK_NUMBER + 1, MULT, B); + if (long_gt(CHUNK_SIZE, CHUNK_NUMBER + 1, MULT, A) == 1) { + return qhat - 2; + } else { + return qhat - 1; + } + } else { + return qhat; + } +} + +// CHUNK_SIZE bits per register +// A has CHUNK_NUMBER + 1 registers +// B has CHUNK_NUMBER registers +// assumes leading digit of B is non-zero +// 0 <= A < B * 2^CHUNK_SIZE +function short_div(CHUNK_SIZE, CHUNK_NUMBER, A, B) { + var scale = (1 << CHUNK_SIZE) \ (1 + B[CHUNK_NUMBER - 1]); + // CHUNK_NUMBER + 2 registers now + var norm_a[150] = long_scalar_mult(CHUNK_SIZE, CHUNK_NUMBER + 1, scale, A); + // CHUNK_NUMBER + 1 registers now + var norm_b[150] = long_scalar_mult(CHUNK_SIZE, CHUNK_NUMBER, scale, B); + + var ret; + if (norm_b[CHUNK_NUMBER] != 0) { + ret = short_div_norm(CHUNK_SIZE, CHUNK_NUMBER + 1, norm_a, norm_b); + } else { + ret = short_div_norm(CHUNK_SIZE, CHUNK_NUMBER, norm_a, norm_b); + } + return ret; +} + +// A = a0 + a1 * X + ... + A[CHUNK_NUMBER-1] * X^{CHUNK_NUMBER-1} with X = 2^CHUNK_SIZE +// a_i can be "negative" assume a_i IN (-2^251, 2^251) +// output is the value of A with a_i all of the same sign +// out[150] = 0 if positive, 1 if negative +function signed_long_to_short(CHUNK_SIZE, CHUNK_NUMBER, A){ + var out[151]; + var MAXL = 150; + var temp[151]; + + // is A positive? + for(var i=0; i= 0){ // circom automatically takes care of signs IN comparator + out[i] = temp[i] % X; + temp[i+1] += temp[i] \ X; + }else{ + var borrow = (-temp[i] + X - 1 ) \ X; + out[i] = temp[i] + borrow * X; + temp[i+1] -= borrow; + } + } + if(temp[MAXL] >= 0){ + assert(temp[MAXL]==0); // otherwise not enough registers! + out[MAXL] = 0; + return out; + } + + // must be negative then, reset + for(var i=0; i 1) { + var sumAndCarry[2] = SplitFn(SPLIT[0][1] + SPLIT[1][0], CHUNK_SIZE, CHUNK_SIZE); + out[1] = sumAndCarry[0]; + carry[1] = sumAndCarry[1]; + } + if (2 * CHUNK_NUMBER - 1 > 2) { + for (var i = 2; i < 2 * CHUNK_NUMBER - 1; i++) { + var sumAndCarry[2] = SplitFn(SPLIT[i][0] + SPLIT[i-1][1] + SPLIT[i-2][2] + carry[i-1], CHUNK_SIZE, CHUNK_SIZE); + out[i] = sumAndCarry[0]; + carry[i] = sumAndCarry[1]; + } + out[2 * CHUNK_NUMBER - 1] = SPLIT[2*CHUNK_NUMBER-2][1] + SPLIT[2*CHUNK_NUMBER-3][2] + carry[2*CHUNK_NUMBER-2]; + } + return out; +} + + +// CHUNK_SIZE bits per register +// A and B both have SMALL_CHUNK_SIZE x CHUNK_NUMBER registers +// out has length 2l - 1 x 2k +// adapted from BigMultShortLong2D and LongToShortNoEndCarry2 witness computation +function prod2D(CHUNK_SIZE, CHUNK_NUMBER, SMALL_CHUNK_SIZE, A, B) { + // first compute the intermediate values. taken from BigMulShortLong + var prod_val[20][150]; // length is 2l - 1 by 2k - 1 + for (var i = 0; i < 2 * CHUNK_NUMBER - 1; i++) { + for (var j = 0; j < 2 * SMALL_CHUNK_SIZE - 1; j ++) { + prod_val[j][i] = 0; + } + } + for (var i1 = 0; i1 < CHUNK_NUMBER; i1 ++) { + for (var i2 = 0; i2 < CHUNK_NUMBER; i2 ++) { + for (var j1 = 0; j1 < SMALL_CHUNK_SIZE; j1 ++) { + for (var j2 = 0; j2 < SMALL_CHUNK_SIZE; j2 ++) { + prod_val[j1+j2][i1+i2] = prod_val[j1+j2][i1+i2] + A[j1][i1] * B[j2][i2]; + } + } + } + } + + // now do A bunch of carrying to make sure registers not overflowed. taken from LongToShortNoEndCarry2 + var out[20][150]; // length is 2 * SMALL_CHUNK_SIZE by 2 * CHUNK_NUMBER + + var SPLIT[20][150][3]; // second dimension has length 2 * CHUNK_NUMBER - 1 + for (var j = 0; j < 2 * SMALL_CHUNK_SIZE - 1; j ++) { + for (var i = 0; i < 2 * CHUNK_NUMBER - 1; i++) { + SPLIT[j][i] = SplitThreeFn(prod_val[j][i], CHUNK_SIZE, CHUNK_SIZE, CHUNK_SIZE); + } + } + + var carry[20][150]; // length is 2l-1 x 2k + var sumAndCarry[20][2]; + for ( var j = 0; j < 2 * SMALL_CHUNK_SIZE - 1; j ++) { + carry[j][0] = 0; + out[j][0] = SPLIT[j][0][0]; + if (2 * CHUNK_NUMBER - 1 > 1) { + sumAndCarry[j] = SplitFn(SPLIT[j][0][1] + SPLIT[j][1][0], CHUNK_SIZE, CHUNK_SIZE); + out[j][1] = sumAndCarry[j][0]; + carry[j][1] = sumAndCarry[j][1]; + } + if (2 * CHUNK_NUMBER - 1 > 2) { + for (var i = 2; i < 2 * CHUNK_NUMBER - 1; i++) { + sumAndCarry[j] = SplitFn(SPLIT[j][i][0] + SPLIT[j][i-1][1] + SPLIT[j][i-2][2] + carry[j][i-1], CHUNK_SIZE, CHUNK_SIZE); + out[j][i] = sumAndCarry[j][0]; + carry[j][i] = sumAndCarry[j][1]; + } + out[j][2 * CHUNK_NUMBER - 1] = SPLIT[j][2*CHUNK_NUMBER-2][1] + SPLIT[j][2*CHUNK_NUMBER-3][2] + carry[j][2*CHUNK_NUMBER-2]; + } + } + + return out; +} + +// Put all modular arithmetic, aka F_p field stuff, at the end + +function long_add_mod(CHUNK_SIZE, CHUNK_NUMBER, A, B, P) { + var sum[150] = long_add(CHUNK_SIZE,CHUNK_NUMBER,A,B); + var temp[2][150] = long_div2(CHUNK_SIZE,CHUNK_NUMBER,1,sum,P); + return temp[1]; +} + +function long_sub_mod(CHUNK_SIZE, CHUNK_NUMBER, A, B, P) { + if(long_gt(CHUNK_SIZE, CHUNK_NUMBER, B, A) == 1){ + return long_add(CHUNK_SIZE, CHUNK_NUMBER, A, long_sub(CHUNK_SIZE,CHUNK_NUMBER,P,B)); + }else{ + return long_sub(CHUNK_SIZE, CHUNK_NUMBER, A, B); + } +} + +function prod_mod(CHUNK_SIZE, CHUNK_NUMBER, A, B, P) { + var prod[150] = prod(CHUNK_SIZE,CHUNK_NUMBER,A,B); + var temp[2][150] = long_div(CHUNK_SIZE,CHUNK_NUMBER,prod,P); + return temp[1]; +} + + +// CHUNK_SIZE bits per register +// A has CHUNK_NUMBER registers +// P has CHUNK_NUMBER registers +// EXP has CHUNK_NUMBER registers +// CHUNK_NUMBER * CHUNK_SIZE <= 500 +// P is A prime +// computes A^EXP mod P +function mod_exp(CHUNK_SIZE, CHUNK_NUMBER, A, P, EXP) { + var eBits[500]; // length is CHUNK_NUMBER * CHUNK_SIZE + var BIT_LENGTH; + for (var i = 0; i < CHUNK_NUMBER; i++) { + for (var j = 0; j < CHUNK_SIZE; j++) { + eBits[j + CHUNK_SIZE * i] = (EXP[i] >> j) & 1; + if(eBits[j + CHUNK_SIZE * i] == 1) + BIT_LENGTH = j + CHUNK_SIZE * i + 1; + } + } + + var out[150]; // length is CHUNK_NUMBER + for (var i = 0; i < 150; i++) { + out[i] = 0; + } + out[0] = 1; + + // repeated squaring + for (var i = BIT_LENGTH-1; i >= 0; i--) { + // multiply by A if bit is 0 + if (eBits[i] == 1) { + var temp[150]; // length 2 * CHUNK_NUMBER + temp = prod(CHUNK_SIZE, CHUNK_NUMBER, out, A); + var temp2[2][150]; + temp2 = long_div(CHUNK_SIZE, CHUNK_NUMBER, temp, P); + out = temp2[1]; + } + + // square, unless we're at the end + if (i > 0) { + var temp[150]; // length 2 * CHUNK_NUMBER + temp = prod(CHUNK_SIZE, CHUNK_NUMBER, out, out); + var temp2[2][150]; + temp2 = long_div(CHUNK_SIZE, CHUNK_NUMBER, temp, P); + out = temp2[1]; + } + + } + return out; +} + +// CHUNK_SIZE bits per register +// A has CHUNK_NUMBER registers +// P has CHUNK_NUMBER registers +// CHUNK_NUMBER * CHUNK_SIZE <= 500 +// P is A prime +// if A == 0 mod P, returns 0 +// else computes inv = A^(P-2) mod P +function mod_inv(CHUNK_SIZE, CHUNK_NUMBER, A, P) { + var isZero = 1; + for (var i = 0; i < CHUNK_NUMBER; i++) { + if (A[i] != 0) { + isZero = 0; + } + } + if (isZero == 1) { + var ret[150]; + for (var i = 0; i < CHUNK_NUMBER; i++) { + ret[i] = 0; + } + return ret; + } + + var pCopy[150]; + for (var i = 0; i < 150; i++) { + if (i < CHUNK_NUMBER) { + pCopy[i] = P[i]; + } else { + pCopy[i] = 0; + } + } + + var two[150]; + for (var i = 0; i < 150; i++) { + two[i] = 0; + } + two[0] = 2; + + var pMinusTwo[150]; + pMinusTwo = long_sub(CHUNK_SIZE, CHUNK_NUMBER, pCopy, two); // length CHUNK_NUMBER + var out[150]; + out = mod_exp(CHUNK_SIZE, CHUNK_NUMBER, A, pCopy, pMinusTwo); + return out; +} + + +function long_div_5args(n, k, m, a, b){ + var out[2][100]; + m += k; + while (b[k-1] == 0) { + out[1][k] = 0; + k--; + assert(k > 0); + } + m -= k; + + var remainder[100]; + for (var i = 0; i < m + k; i++) { + remainder[i] = a[i]; + } + + var mult[200]; + var dividend[200]; + for (var i = m; i >= 0; i--) { + if (i == m) { + dividend[k] = 0; + for (var j = k - 1; j >= 0; j--) { + dividend[j] = remainder[j + m]; + } + } else { + for (var j = k; j >= 0; j--) { + dividend[j] = remainder[j + i]; + } + } + + out[0][i] = short_div(n, k, dividend, b); + + var mult_shift[100] = long_scalar_mult_100(n, k, out[0][i], b); + var subtrahend[200]; + for (var j = 0; j < m + k; j++) { + subtrahend[j] = 0; + } + for (var j = 0; j <= k; j++) { + if (i + j < m + k) { + subtrahend[i + j] = mult_shift[j]; + } + } + remainder = long_sub_100(n, m + k, remainder, subtrahend); + } + for (var i = 0; i < k; i++) { + out[1][i] = remainder[i]; + } + out[1][k] = 0; + + return out; +} + +// a is a n-bit scalar +// b has k registers +function long_scalar_mult_100(n, k, a, b) { + var out[100]; + for (var i = 0; i < 100; i++) { + out[i] = 0; + } + for (var i = 0; i < k; i++) { + var temp = out[i] + (a * b[i]); + out[i] = temp % (1 << n); + out[i + 1] = out[i + 1] + temp \ (1 << n); + } + return out; +} + +// n bits per register +// a has k registers +// b has k registers +// a >= b +function long_sub_100(n, k, a, b) { + var diff[100]; + var borrow[100]; + for (var i = 0; i < k; i++) { + if (i == 0) { + if (a[i] >= b[i]) { + diff[i] = a[i] - b[i]; + borrow[i] = 0; + } else { + diff[i] = a[i] - b[i] + (1 << n); + borrow[i] = 1; + } + } else { + if (a[i] >= b[i] + borrow[i - 1]) { + diff[i] = a[i] - b[i] - borrow[i - 1]; + borrow[i] = 0; + } else { + diff[i] = (1 << n) + a[i] - b[i] - borrow[i - 1]; + borrow[i] = 1; + } + } + } + return diff; +} \ No newline at end of file diff --git a/circuits/circuits/utils/other/bigint_4x64_mult.circom b/circuits/circuits/utils/other/bigint_4x64_mult.circom new file mode 100644 index 00000000..58bd0af6 --- /dev/null +++ b/circuits/circuits/utils/other/bigint_4x64_mult.circom @@ -0,0 +1,101 @@ +pragma circom 2.0.2; + +include "bigint.circom"; + +template A2NoCarry() { + signal input a[4]; + + // these representations have overflowed, nonnegative registers + signal output a2[7]; + component a2Comp = BigMultNoCarry(64, 64, 64, 4, 4); + for (var i = 0; i < 4; i++) { + a2Comp.a[i] <== a[i]; + a2Comp.b[i] <== a[i]; + } + for (var i = 0; i < 7; i++) { + a2[i] <== a2Comp.out[i]; // 130 bits + } +} + +template A3NoCarry() { + signal input a[4]; + + // these representations have overflowed, nonnegative registers + signal a2[7]; + component a2Comp = BigMultNoCarry(64, 64, 64, 4, 4); + for (var i = 0; i < 4; i++) { + a2Comp.a[i] <== a[i]; + a2Comp.b[i] <== a[i]; + } + for (var i = 0; i < 7; i++) { + a2[i] <== a2Comp.out[i]; // 130 bits + } + signal output a3[10]; + component a3Comp = BigMultNoCarry(64, 130, 64, 7, 4); + for (var i = 0; i < 7; i++) { + a3Comp.a[i] <== a2[i]; + } + for (var i = 0; i < 4; i++) { + a3Comp.b[i] <== a[i]; + } + for (var i = 0; i < 10; i++) { + a3[i] <== a3Comp.out[i]; // 197 bits + } +} + +template A2B1NoCarry() { + signal input a[4]; + signal input b[4]; + + // these representations have overflowed, nonnegative registers + signal a2[7]; + component a2Comp = BigMultNoCarry(64, 64, 64, 4, 4); + for (var i = 0; i < 4; i++) { + a2Comp.a[i] <== a[i]; + a2Comp.b[i] <== a[i]; + } + for (var i = 0; i < 7; i++) { + a2[i] <== a2Comp.out[i]; // 130 bits + } + + signal output a2b1[10]; + component a2b1Comp = BigMultNoCarry(64, 130, 64, 7, 4); + for (var i = 0; i < 7; i++) { + a2b1Comp.a[i] <== a2[i]; + } + for (var i = 0; i < 4; i++) { + a2b1Comp.b[i] <== b[i]; + } + for (var i = 0; i < 10; i++) { + a2b1[i] <== a2b1Comp.out[i]; // 197 bits + } +} + +template A1B1C1NoCarry() { + signal input a[4]; + signal input b[4]; + signal input c[4]; + + // these representations have overflowed, nonnegative registers + signal a1b1[7]; + component a1b1Comp = BigMultNoCarry(64, 64, 64, 4, 4); + for (var i = 0; i < 4; i++) { + a1b1Comp.a[i] <== a[i]; + a1b1Comp.b[i] <== b[i]; + } + for (var i = 0; i < 7; i++) { + a1b1[i] <== a1b1Comp.out[i]; // 130 bits + } + + signal output a1b1c1[10]; + component a1b1c1Comp = BigMultNoCarry(64, 130, 64, 7, 4); + for (var i = 0; i < 7; i++) { + a1b1c1Comp.a[i] <== a1b1[i]; + } + for (var i = 0; i < 4; i++) { + a1b1c1Comp.b[i] <== c[i]; + } + for (var i = 0; i < 10; i++) { + a1b1c1[i] <== a1b1c1Comp.out[i]; // 197 bits + } +} \ No newline at end of file diff --git a/circuits/circuits/utils/other/bytes.circom b/circuits/circuits/utils/other/bytes.circom new file mode 100644 index 00000000..b1d56681 --- /dev/null +++ b/circuits/circuits/utils/other/bytes.circom @@ -0,0 +1,112 @@ +pragma circom 2.1.6; + +include "circomlib/circuits/bitify.circom"; +include "circomlib/circuits/comparators.circom"; +include "./array.circom"; +include "./functions.circom"; +include "./constants.circom"; + +function computeIntChunkLength(byteLength) { + var packSize = MAX_BYTES_IN_FIELD(); + + var remain = byteLength % packSize; + var numChunks = (byteLength - remain) / packSize; + if (remain > 0) { + numChunks += 1; + } + + return numChunks; +} + + +/// @title PackBytes +/// @notice Pack an array of bytes to numbers that fit in the field +/// @param maxBytes the maximum number of bytes in the input array +/// @input in the input byte array; assumes elements to be bytes +/// @output out the output integer array +template PackBytes(maxBytes) { + var packSize = MAX_BYTES_IN_FIELD(); + var maxInts = computeIntChunkLength(maxBytes); + + signal input in[maxBytes]; + signal output out[maxInts]; + + signal intSums[maxInts][packSize]; + + for (var i = 0; i < maxInts; i++) { + for(var j=0; j < packSize; j++) { + var idx = packSize * i + j; + + // Copy the previous value if we are out of bounds - we take last item as final result + if(idx >= maxBytes) { + intSums[i][j] <== intSums[i][j-1]; + } + // First item of each chunk is the byte itself + else if (j == 0){ + intSums[i][j] <== in[idx]; + } + // Every other item is 256^j * byte + else { + intSums[i][j] <== intSums[i][j-1] + (1 << (8*j)) * in[idx]; + } + } + } + + // Last item of each chunk is the final sum + for (var i = 0; i < maxInts; i++) { + out[i] <== intSums[i][packSize-1]; + } +} + + +/// @title PackByteSubArray +/// @notice Select sub array from the input array and pack it to numbers that fit in the field +/// @notice This is not used in ZK-Email circuits anywhere +/// @param maxArrayLen the maximum number of elements in the input array +/// @param maxSubArrayLen the maximum number of elements in the sub array +/// @input in the input byte array; assumes elements to be bytes +/// @input startIndex the start index of the sub array; assumes to be a valid index +/// @input length the length of the sub array; assumes to fit in `ceil(log2(maxSubArrayLen))` bits +/// @output out the output integer array +template PackByteSubArray(maxArrayLen, maxSubArrayLen) { + assert(maxSubArrayLen < maxArrayLen); + var chunkLength = computeIntChunkLength(maxSubArrayLen); + + signal input in[maxArrayLen]; + signal input startIndex; + signal input length; + + signal output out[chunkLength]; + + component SelectSubArray = SelectSubArray(maxArrayLen, maxSubArrayLen); + SelectSubArray.in <== in; + SelectSubArray.startIndex <== startIndex; + SelectSubArray.length <== length; + + component packer = PackBytes(maxSubArrayLen); + packer.in <== SelectSubArray.out; + + out <== packer.out; +} + + +/// @title DigitBytesToInt +/// @notice Converts a byte array representing digits to an integer +/// @notice Assumes the output number fits in the field +/// @param n The number of bytes in the input array +/// @input in The input byte array; assumes elements are between 48 and 57 (ASCII numbers) +/// @output out The output integer; assumes to fit in the field +template DigitBytesToInt(n) { + signal input in[n]; + + signal output out; + + signal sums[n+1]; + sums[0] <== 0; + + for(var i = 0; i < n; i++) { + sums[i + 1] <== 10 * sums[i] + (in[i] - 48); + } + + out <== sums[n]; +} diff --git a/circuits/circuits/utils/other/constants.circom b/circuits/circuits/utils/other/constants.circom new file mode 100644 index 00000000..69b0c993 --- /dev/null +++ b/circuits/circuits/utils/other/constants.circom @@ -0,0 +1,15 @@ +pragma circom 2.1.6; + + +function EMAIL_ADDR_MAX_BYTES() { + return 256; +} + +function DOMAIN_MAX_BYTES() { + return 255; +} + +// Field support maximum of ~253 bit +function MAX_BYTES_IN_FIELD() { + return 31; +} diff --git a/circuits/circuits/utils/other/fp.circom b/circuits/circuits/utils/other/fp.circom new file mode 100644 index 00000000..63493091 --- /dev/null +++ b/circuits/circuits/utils/other/fp.circom @@ -0,0 +1,165 @@ +pragma circom 2.1.6; + +include "circomlib/circuits/bitify.circom"; +include "circomlib/circuits/comparators.circom"; +include "circomlib/circuits/sign.circom"; +include "./bigInt.circom"; +include "./bigIntFunc.circom"; + + +/// @title FpMul +/// @notice Multiple two numbers in Fp +/// @param a Input 1 to FpMul; assumes to consist of `k` chunks, each of which must fit in `n` bits +/// @param b Input 2 to FpMul; assumes to consist of `k` chunks, each of which must fit in `n` bits +/// @param p The modulus; assumes to consist of `k` chunks, each of which must fit in `n` bits +/// @output out The result of the FpMul +template FpMul(n, k) { + assert(n + n + log_ceil(k) + 2 <= 252); + + signal input a[k]; + signal input b[k]; + signal input p[k]; + + signal output out[k]; + + signal v_ab[2*k-1]; + for (var x = 0; x < 2*k-1; x++) { + var v_a = poly_eval(k, a, x); + var v_b = poly_eval(k, b, x); + v_ab[x] <== v_a * v_b; + } + + var ab[200] = poly_interp(2*k-1, v_ab); + // ab_proper has length 2*k + var ab_proper[100] = getProperRepresentation(n + n + log_ceil(k), n, 2*k-1, ab); + + var long_div_out[2][100] = long_div_5args(n, k, k, ab_proper, p); + + // Since we're only computing a*b, we know that q < p will suffice, so we + // know it fits into k chunks and can do size n range checks. + signal q[k]; + component q_range_check[k]; + signal r[k]; + component r_range_check[k]; + for (var i = 0; i < k; i++) { + q[i] <-- long_div_out[0][i]; + q_range_check[i] = Num2Bits(n); + q_range_check[i].in <== q[i]; + + r[i] <-- long_div_out[1][i]; + r_range_check[i] = Num2Bits(n); + r_range_check[i].in <== r[i]; + } + + signal v_pq_r[2*k-1]; + for (var x = 0; x < 2*k-1; x++) { + var v_p = poly_eval(k, p, x); + var v_q = poly_eval(k, q, x); + var v_r = poly_eval(k, r, x); + v_pq_r[x] <== v_p * v_q + v_r; + } + + signal v_t[2*k-1]; + for (var x = 0; x < 2*k-1; x++) { + v_t[x] <== v_ab[x] - v_pq_r[x]; + } + + var t[200] = poly_interp(2*k-1, v_t); + component tCheck = CheckCarryToZero(n, n + n + log_ceil(k) + 2, 2*k-1); + for (var i = 0; i < 2*k-1; i++) { + tCheck.in[i] <== t[i]; + } + + for (var i = 0; i < k; i++) { + out[i] <== r[i]; + } +} +function div_ceil(m, n) { + var ret = 0; + if (m % n == 0) { + ret = m \ n; + } else { + ret = m \ n + 1; + } + return ret; +} + +// m bits per overflowed register (values are potentially negative) +// n bits per properly-sized register +// in has k registers +// out has k + ceil(m/n) - 1 + 1 registers. highest-order potentially negative, +// all others are positive +// - 1 since the last register is included in the last ceil(m/n) array +// + 1 since the carries from previous registers could push you over +function getProperRepresentation(m, n, k, in) { + var ceilMN = div_ceil(m, n); + + var out[100]; // should be out[k + ceilMN] + assert(k + ceilMN < 100); + for (var i = 0; i < k; i++) { + out[i] = in[i]; + } + for (var i = k; i < 100; i++) { + out[i] = 0; + } + assert(n <= m); + for (var i = 0; i+1 < k + ceilMN; i++) { + assert((1 << m) >= out[i] && out[i] >= -(1 << m)); + var shifted_val = out[i] + (1 << m); + assert(0 <= shifted_val && shifted_val <= (1 << (m+1))); + out[i] = shifted_val & ((1 << n) - 1); + out[i+1] += (shifted_val >> n) - (1 << (m - n)); + } + + return out; +} + +// Evaluate polynomial a at point x +function poly_eval(len, a, x) { + var v = 0; + for (var i = 0; i < len; i++) { + v += a[i] * (x ** i); + } + return v; +} + +// Interpolate a degree len-1 polynomial given its evaluations at 0..len-1 +function poly_interp(len, v) { + assert(len <= 200); + var out[200]; + for (var i = 0; i < len; i++) { + out[i] = 0; + } + + // Product_{i=0..len-1} (x-i) + var full_poly[201]; + full_poly[0] = 1; + for (var i = 0; i < len; i++) { + full_poly[i+1] = 0; + for (var j = i; j >= 0; j--) { + full_poly[j+1] += full_poly[j]; + full_poly[j] *= -i; + } + } + + for (var i = 0; i < len; i++) { + var cur_v = 1; + for (var j = 0; j < len; j++) { + if (i == j) { + // do nothing + } else { + cur_v *= i-j; + } + } + cur_v = v[i] / cur_v; + + var cur_rem = full_poly[len]; + for (var j = len-1; j >= 0; j--) { + out[j] += cur_v * cur_rem; + cur_rem = full_poly[j] + i * cur_rem; + } + assert(cur_rem == 0); + } + + return out; +} diff --git a/circuits/circuits/utils/other/functions.circom b/circuits/circuits/utils/other/functions.circom new file mode 100644 index 00000000..7c76024f --- /dev/null +++ b/circuits/circuits/utils/other/functions.circom @@ -0,0 +1,17 @@ +pragma circom 2.1.6; + +/// @function log2Ceil +/// @notice Calculate log2 of a number and round it up +/// @param a The input value +/// @return The result of the log2Ceil +function log2Ceil(a) { + var n = a - 1; + var r = 0; + + while (n > 0) { + r++; + n \= 2; + } + + return r; +} From dc000c3bc2d8cbbe867b200ada954dcca1d756e9 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Tue, 17 Sep 2024 18:53:40 +0200 Subject: [PATCH 26/60] remove zkemail imports --- .../utils/passport/computeCommitment.circom | 2 +- .../utils/passport/customHashers.circom | 2 +- .../utils/passport/passportVerifier.circom | 4 +- .../utils/passport/signatureVerifier.circom | 19 +- circuits/circuits/utils/rsa/powMod.circom | 47 +++ circuits/circuits/utils/rsa/rsaPkcs1.circom | 13 +- .../circuits/utils/rsa/rsaPkcs1v15.circom | 56 +++ circuits/circuits/utils/rsa/rsaVerify.circom | 5 + circuits/circuits/utils/rsapss/powMod.circom | 356 ------------------ circuits/circuits/utils/rsapss/rsapss.circom | 2 +- .../utils/shaBytes/dynamic/Sha1Bytes.circom | 6 +- .../utils/shaBytes/dynamic/Sha256Bytes.circom | 164 ++++++++ .../utils/shaBytes/shaBytesDynamic.circom | 3 +- 13 files changed, 298 insertions(+), 381 deletions(-) create mode 100644 circuits/circuits/utils/rsa/powMod.circom create mode 100644 circuits/circuits/utils/rsa/rsaPkcs1v15.circom create mode 100644 circuits/circuits/utils/rsa/rsaVerify.circom delete mode 100644 circuits/circuits/utils/rsapss/powMod.circom create mode 100644 circuits/circuits/utils/shaBytes/dynamic/Sha256Bytes.circom diff --git a/circuits/circuits/utils/passport/computeCommitment.circom b/circuits/circuits/utils/passport/computeCommitment.circom index 33432168..fa4468d2 100644 --- a/circuits/circuits/utils/passport/computeCommitment.circom +++ b/circuits/circuits/utils/passport/computeCommitment.circom @@ -1,7 +1,7 @@ pragma circom 2.1.9; include "circomlib/circuits/poseidon.circom"; -include "@zk-email/circuits/utils/bytes.circom"; +include "../other/bytes.circom"; template ComputeCommitment() { signal input secret; signal input attestation_id; diff --git a/circuits/circuits/utils/passport/customHashers.circom b/circuits/circuits/utils/passport/customHashers.circom index ccb99dc5..56906fc3 100644 --- a/circuits/circuits/utils/passport/customHashers.circom +++ b/circuits/circuits/utils/passport/customHashers.circom @@ -1,5 +1,5 @@ pragma circom 2.1.6; -include "@zk-email/circuits/lib/fp.circom"; +include "../other/fp.circom"; include "circomlib/circuits/poseidon.circom"; template CustomHasher(k) { diff --git a/circuits/circuits/utils/passport/passportVerifier.circom b/circuits/circuits/utils/passport/passportVerifier.circom index ddb066ba..51860fde 100644 --- a/circuits/circuits/utils/passport/passportVerifier.circom +++ b/circuits/circuits/utils/passport/passportVerifier.circom @@ -1,7 +1,7 @@ pragma circom 2.1.6; -include "@zk-email/circuits/utils/bytes.circom"; -include "@zk-email/circuits/utils/array.circom"; +include "../other/array.circom"; +include "../other/bytes.circom"; include "../shaBytes/shaBytesStatic.circom"; include "../shaBytes/shaBytesDynamic.circom"; include "./signatureAlgorithm.circom"; diff --git a/circuits/circuits/utils/passport/signatureVerifier.circom b/circuits/circuits/utils/passport/signatureVerifier.circom index 2c61a630..ed871327 100644 --- a/circuits/circuits/utils/passport/signatureVerifier.circom +++ b/circuits/circuits/utils/passport/signatureVerifier.circom @@ -1,8 +1,9 @@ pragma circom 2.1.6; -include "@zk-email/circuits/lib/rsa.circom"; +// include "@zk-email/circuits/lib/rsa.circom"; include "../rsa/rsaPkcs1.circom"; -include "../circom-ecdsa/ecdsa.circom"; +include "../rsa/rsaPkcs1v15.circom"; +// include "../circom-ecdsa/ecdsa.circom"; include "secp256r1Verifier.circom"; include "../rsapss/rsapss.circom"; @@ -21,18 +22,14 @@ template SignatureVerifier(signatureAlgorithm, n, k) { signal hashParsed[msg_len] <== HashParser(signatureAlgorithm, n, k)(hash); if (signatureAlgorithm == 1) { - component rsa = RSAVerifier65537(n, k); - for (var i = 0; i < msg_len; i++) { - rsa.message[i] <== hashParsed[i]; - } - for (var i = msg_len; i < k; i++) { - rsa.message[i] <== 0; - } - rsa.modulus <== pubKey; + var exponentBits = getExponentBits(signatureAlgorithm); + component rsa = RsaVerifierPkcs1v15(n, k, exponentBits, HASH_LEN_BITS); + rsa.hashed <== hash; + rsa.pubkey <== pubKey; rsa.signature <== signature; } if (signatureAlgorithm == 3 ) { - component rsa_pkcs1 = RSAVerifier65537_pkcs1(n, k); + component rsa_pkcs1 = RSAVerifier65537Pkcs1(n, k); for (var i = 0; i < msg_len; i++) { rsa_pkcs1.message[i] <== hashParsed[i]; } diff --git a/circuits/circuits/utils/rsa/powMod.circom b/circuits/circuits/utils/rsa/powMod.circom new file mode 100644 index 00000000..8ac08e18 --- /dev/null +++ b/circuits/circuits/utils/rsa/powMod.circom @@ -0,0 +1,47 @@ +pragma circom 2.1.6; + +include "../other/bigInt.circom"; + +// CHUNK_SIZE = 32 +// E_BITS = 17 +// CHUNK_NUMBER is the length of the base and modulus +// calculates (base^exp) % modulus, exp = 2^(E_BITS - 1) + 1 = 2^16 + 1 +template PowerMod(CHUNK_SIZE, CHUNK_NUMBER, E_BITS) { + assert(E_BITS >= 2); + + signal input base[CHUNK_NUMBER]; + signal input modulus[CHUNK_NUMBER]; + + signal output out[CHUNK_NUMBER]; + + component muls[E_BITS]; + + for (var i = 0; i < E_BITS; i++) { + muls[i] = BigMultModP(CHUNK_SIZE, CHUNK_NUMBER); + + for (var j = 0; j < CHUNK_NUMBER; j++) { + muls[i].p[j] <== modulus[j]; + } + } + + for (var i = 0; i < CHUNK_NUMBER; i++) { + muls[0].a[i] <== base[i]; + muls[0].b[i] <== base[i]; + } + + for (var i = 1; i < E_BITS - 1; i++) { + for (var j = 0; j < CHUNK_NUMBER; j++) { + muls[i].a[j] <== muls[i - 1].out[j]; + muls[i].b[j] <== muls[i - 1].out[j]; + } + } + + for (var i = 0; i < CHUNK_NUMBER; i++) { + muls[E_BITS - 1].a[i] <== base[i]; + muls[E_BITS - 1].b[i] <== muls[E_BITS - 2].out[i]; + } + + for (var i = 0; i < CHUNK_NUMBER; i++) { + out[i] <== muls[E_BITS - 1].out[i]; + } +} diff --git a/circuits/circuits/utils/rsa/rsaPkcs1.circom b/circuits/circuits/utils/rsa/rsaPkcs1.circom index 71590530..8393cc0c 100644 --- a/circuits/circuits/utils/rsa/rsaPkcs1.circom +++ b/circuits/circuits/utils/rsa/rsaPkcs1.circom @@ -1,11 +1,12 @@ pragma circom 2.1.5; -include "@zk-email/circuits/lib/fp.circom"; +//include "@zk-email/circuits/lib/fp.circom"; +include "../other/fp.circom"; // Computes base^65537 mod modulus // Does not necessarily reduce fully mod modulus (the answer could be // too big by a multiple of modulus) -template FpPow65537Mod_pkcs1(n, k) { +template FpPow65537ModPkcs1(n, k) { signal input base[k]; // Exponent is hardcoded at 65537 signal input modulus[k]; @@ -42,7 +43,7 @@ template FpPow65537Mod_pkcs1(n, k) { } } -template RSAPad_pkcs1(n, k) { +template RSAPadPkcs1(n, k) { signal input modulus[k]; signal input message[k]; signal output padded_message[k]; @@ -121,12 +122,12 @@ template RSAPad_pkcs1(n, k) { } } -template RSAVerifier65537_pkcs1(n, k) { +template RSAVerifier65537Pkcs1(n, k) { signal input signature[k]; signal input modulus[k]; signal input message[k]; - component padder = RSAPad_pkcs1(n, k); + component padder = RSAPadPkcs1(n, k); for (var i = 0; i < k; i++) { padder.modulus[i] <== modulus[i]; padder.message[i] <== message[i]; @@ -143,7 +144,7 @@ template RSAVerifier65537_pkcs1(n, k) { } bigLessThan.out === 1; - component bigPow = FpPow65537Mod_pkcs1(n, k); + component bigPow = FpPow65537ModPkcs1(n, k); for (var i = 0; i < k; i++) { bigPow.base[i] <== signature[i]; bigPow.modulus[i] <== modulus[i]; diff --git a/circuits/circuits/utils/rsa/rsaPkcs1v15.circom b/circuits/circuits/utils/rsa/rsaPkcs1v15.circom new file mode 100644 index 00000000..ca21d8f6 --- /dev/null +++ b/circuits/circuits/utils/rsa/rsaPkcs1v15.circom @@ -0,0 +1,56 @@ +pragma circom 2.1.6; + +include "./powMod.circom"; +include "circomlib/circuits/bitify.circom"; + +// Pkcs1v15 + Sha256, e = 65537 +template RsaVerifierPkcs1v15(CHUNK_SIZE, CHUNK_NUMBER, E_BITS, HASH_TYPE) { + signal input signature[CHUNK_NUMBER]; + signal input pubkey[CHUNK_NUMBER]; //aka modulus + + signal input hashed[HASH_TYPE]; + + // signature ** exp mod modulus + component pm = PowerMod(CHUNK_SIZE, CHUNK_NUMBER, E_BITS); + for (var i = 0; i < CHUNK_NUMBER; i++) { + pm.base[i] <== signature[i]; + pm.modulus[i] <== pubkey[i]; + } + + signal hashed_chunks[4]; + + component bits2num[4]; + for(var i = 0; i< 4; i++){ + bits2num[3-i] = Bits2Num(64); + for (var j = 0; j< 64; j++){ + bits2num[3-i].in[j] <== hashed[i*64 + 63 - j]; + } + bits2num[3-i].out ==> hashed_chunks[3-i]; + } + + // 1. Check hashed data + for (var i = 0; i < 4; i++) { + hashed_chunks[i] === pm.out[i]; + } + + // 2. Check hash prefix and 1 byte 0x00 + pm.out[4] === 217300885422736416; + pm.out[5] === 938447882527703397; + + // remain 24 bit + component num2bits_6 = Num2Bits(CHUNK_SIZE); + num2bits_6.in <== pm.out[6]; + var remainsBits[32] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0]; + for (var i = 0; i < 32; i++) { + num2bits_6.out[i] === remainsBits[31 - i]; + } + + // 3. Check PS and em[1] = 1 + for (var i = 32; i < CHUNK_SIZE; i++) { + num2bits_6.out[i] === 1; + } + + for (var i = 7; i < CHUNK_NUMBER-1; i++) { + pm.out[i] === 18446744073709551615; // 0b1111111111111111111111111111111111111111111111111111111111111111 + } +} diff --git a/circuits/circuits/utils/rsa/rsaVerify.circom b/circuits/circuits/utils/rsa/rsaVerify.circom new file mode 100644 index 00000000..3838fa18 --- /dev/null +++ b/circuits/circuits/utils/rsa/rsaVerify.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.6; + +include "./rsa.circom"; + +component main = RsaVerifyPkcs1v15(64, 32, 17, 256); \ No newline at end of file diff --git a/circuits/circuits/utils/rsapss/powMod.circom b/circuits/circuits/utils/rsapss/powMod.circom deleted file mode 100644 index 35e594b9..00000000 --- a/circuits/circuits/utils/rsapss/powMod.circom +++ /dev/null @@ -1,356 +0,0 @@ -pragma circom 2.1.6; - -include "@zk-email/circuits/lib/bigint.circom"; -include "../circom-ecdsa/bigInt.circom"; -include "../circom-ecdsa/bigInt_func.circom"; - -template PowerMod(w, nb, e_bits) { - assert(e_bits >= 2); - - signal input base[nb]; - signal input modulus[nb]; - - signal output out[nb]; - - component muls[e_bits]; - - for (var i = 0; i < e_bits; i++) { - muls[i] = BigMultModP_rsapss(w, nb); - - for (var j = 0; j < nb; j++) { - muls[i].p[j] <== modulus[j]; - } - } - - for (var i = 0; i < nb; i++) { - muls[0].a[i] <== base[i]; - muls[0].b[i] <== base[i]; - } - - for (var i = 1; i < e_bits - 1; i++) { - for (var j = 0; j < nb; j++) { - muls[i].a[j] <== muls[i - 1].out[j]; - muls[i].b[j] <== muls[i - 1].out[j]; - } - } - - for (var i = 0; i < nb; i++) { - muls[e_bits - 1].a[i] <== base[i]; - muls[e_bits - 1].b[i] <== muls[e_bits - 2].out[i]; - } - - for (var i = 0; i < nb; i++) { - out[i] <== muls[e_bits - 1].out[i]; - } -} - -// // Note: deprecated -template BigMultModP_rsapss(n, k) { - assert(n <= 252); - signal input a[k]; - signal input b[k]; - signal input p[k]; - signal output out[k]; - - component big_mult = BigMult(n, k); - for (var i = 0; i < k; i++) { - big_mult.a[i] <== a[i]; - big_mult.b[i] <== b[i]; - } - component big_mod = BigMod_rsapss(n, k); - for (var i = 0; i < 2 * k; i++) { - big_mod.a[i] <== big_mult.out[i]; - } - for (var i = 0; i < k; i++) { - big_mod.b[i] <== p[i]; - } - for (var i = 0; i < k; i++) { - out[i] <== big_mod.mod[i]; - } -} - -// template BigMult(n, k) { -// signal input a[k]; -// signal input b[k]; -// signal output out[2 * k]; - -// var LOGK = log_ceil(k); -// component mult = BigMultShortLong(n, k, 2*n + LOGK); -// for (var i = 0; i < k; i++) { -// mult.a[i] <== a[i]; -// mult.b[i] <== b[i]; -// } - -// // no carry is possible in the highest order register -// component longshort = LongToShortNoEndCarry(n, 2 * k - 1); -// for (var i = 0; i < 2 * k - 1; i++) { -// longshort.in[i] <== mult.out[i]; -// } -// for (var i = 0; i < 2 * k; i++) { -// out[i] <== longshort.out[i]; -// } -// } - -// template LongToShortNoEndCarry(n, k) { -// assert(n <= 126); -// signal input in[k]; -// signal output out[k+1]; - -// var split[k][3]; -// for (var i = 0; i < k; i++) { -// split[i] = SplitThreeFn(in[i], n, n, n); -// } - -// var carry[k]; -// carry[0] = 0; -// out[0] <-- split[0][0]; -// if (k > 1) { -// var sumAndCarry[2] = SplitFn(split[0][1] + split[1][0], n, n); -// out[1] <-- sumAndCarry[0]; -// carry[1] = sumAndCarry[1]; -// } -// if (k > 2) { -// for (var i = 2; i < k; i++) { -// var sumAndCarry[2] = SplitFn(split[i][0] + split[i-1][1] + split[i-2][2] + carry[i-1], n, n); -// out[i] <-- sumAndCarry[0]; -// carry[i] = sumAndCarry[1]; -// } -// out[k] <-- split[k-1][1] + split[k-2][2] + carry[k-1]; -// } - -// component outRangeChecks[k+1]; -// for (var i = 0; i < k+1; i++) { -// outRangeChecks[i] = Num2Bits(n); -// outRangeChecks[i].in <== out[i]; -// } - -// signal runningCarry[k]; -// component runningCarryRangeChecks[k]; -// runningCarry[0] <-- (in[0] - out[0]) / (1 << n); -// runningCarryRangeChecks[0] = Num2Bits(n + log_ceil(k)); -// runningCarryRangeChecks[0].in <== runningCarry[0]; -// runningCarry[0] * (1 << n) === in[0] - out[0]; -// for (var i = 1; i < k; i++) { -// runningCarry[i] <-- (in[i] - out[i] + runningCarry[i-1]) / (1 << n); -// runningCarryRangeChecks[i] = Num2Bits(n + log_ceil(k)); -// runningCarryRangeChecks[i].in <== runningCarry[i]; -// runningCarry[i] * (1 << n) === in[i] - out[i] + runningCarry[i-1]; -// } -// runningCarry[k-1] === out[k]; -// } -// template BigMultShortLong(n, k, m_out) { -// assert(n <= 126); -// signal input a[k]; -// signal input b[k]; -// signal output out[2 * k - 1]; - -// var prod_val[2 * k - 1]; -// for (var i = 0; i < 2 * k - 1; i++) { -// prod_val[i] = 0; -// if (i < k) { -// for (var a_idx = 0; a_idx <= i; a_idx++) { -// prod_val[i] = prod_val[i] + a[a_idx] * b[i - a_idx]; -// } -// } else { -// for (var a_idx = i - k + 1; a_idx < k; a_idx++) { -// prod_val[i] = prod_val[i] + a[a_idx] * b[i - a_idx]; -// } -// } -// out[i] <-- prod_val[i]; -// } - -// var k2 = 2 * k - 1; -// var pow[k2][k2]; // we cache the exponent values because it makes a big difference in witness generation time -// for(var i = 0; i= 0; i--) { - if (i == m) { - dividend[k] = 0; - for (var j = k - 1; j >= 0; j--) { - dividend[j] = remainder[j + m]; - } - } else { - for (var j = k; j >= 0; j--) { - dividend[j] = remainder[j + i]; - } - } - out[0][i] = short_div(n, k, dividend, b); - var mult_shift[150] = long_scalar_mult(n, k, out[0][i], b); - var subtrahend[150]; - for (var j = 0; j < m + k; j++) { - subtrahend[j] = 0; - } - for (var j = 0; j <= k; j++) { - if (i + j < m + k) { - subtrahend[i + j] = mult_shift[j]; - } - } - remainder = long_sub(n, m + k, remainder, subtrahend); - } - for (var i = 0; i < k; i++) { - out[1][i] = remainder[i]; - } - out[1][k] = 0; - return out; -} \ No newline at end of file diff --git a/circuits/circuits/utils/rsapss/rsapss.circom b/circuits/circuits/utils/rsapss/rsapss.circom index 3dc4d76b..b982eda2 100644 --- a/circuits/circuits/utils/rsapss/rsapss.circom +++ b/circuits/circuits/utils/rsapss/rsapss.circom @@ -1,6 +1,6 @@ pragma circom 2.1.6; -include "./powMod.circom"; +include "../rsa/powMod.circom"; include "./mgf1.circom"; include "./xor2.circom"; include "../sha2/sha256/sha256_hash_bits.circom"; diff --git a/circuits/circuits/utils/shaBytes/dynamic/Sha1Bytes.circom b/circuits/circuits/utils/shaBytes/dynamic/Sha1Bytes.circom index 67fa52e9..ee5bcfba 100644 --- a/circuits/circuits/utils/shaBytes/dynamic/Sha1Bytes.circom +++ b/circuits/circuits/utils/shaBytes/dynamic/Sha1Bytes.circom @@ -4,8 +4,10 @@ include "../../sha1/sha1compression.circom"; include "circomlib/circuits/bitify.circom"; include "circomlib/circuits/comparators.circom"; include "circomlib/circuits/mimcsponge.circom"; -include "@zk-email/circuits/lib/fp.circom"; -include "@zk-email/circuits/utils/array.circom"; +// include "@zk-email/circuits/lib/fp.circom"; +// include "@zk-email/circuits/utils/array.circom"; +include "../../other/fp.circom"; +include "../../other/array.circom"; //Adapted from @zk-email/circuits/helpers/sha.circom template Sha1Bytes(max_num_bytes) { diff --git a/circuits/circuits/utils/shaBytes/dynamic/Sha256Bytes.circom b/circuits/circuits/utils/shaBytes/dynamic/Sha256Bytes.circom new file mode 100644 index 00000000..003fd6ef --- /dev/null +++ b/circuits/circuits/utils/shaBytes/dynamic/Sha256Bytes.circom @@ -0,0 +1,164 @@ +pragma circom 2.1.6; + +include "circomlib/circuits/bitify.circom"; +include "circomlib/circuits/sha256/constants.circom"; +include "circomlib/circuits/sha256/sha256compression.circom"; +include "circomlib/circuits/comparators.circom"; +// include "./fp.circom"; +// include "../utils/array.circom"; +// include "../utils/functions.circom"; +// include "@zk-email/circuits/lib/fp.circom"; +// include "@zk-email/circuits/utils/array.circom"; +include "../../other/fp.circom"; +include "../../other/array.circom"; + +/// @title Sha256Bytes +/// @notice Computes the SHA256 hash of input bytes +/// @input paddedIn Message to hash, padded as per the SHA256 specification; assumes to consist of bytes +/// @input paddedInLength Length of the padded message; assumes to be in `ceil(log2(8 * maxByteLength))` bits +/// @output out The 256-bit hash of the input message +template Sha256Bytes(maxByteLength) { + signal input paddedIn[maxByteLength]; + signal input paddedInLength; + signal output out[256]; + + var maxBits = maxByteLength * 8; + component sha = Sha256General(maxBits); + + component bytes[maxByteLength]; + for (var i = 0; i < maxByteLength; i++) { + bytes[i] = Num2Bits(8); + bytes[i].in <== paddedIn[i]; + for (var j = 0; j < 8; j++) { + sha.paddedIn[i*8+j] <== bytes[i].out[7-j]; + } + } + sha.paddedInLength <== paddedInLength * 8; + + for (var i = 0; i < 256; i++) { + out[i] <== sha.out[i]; + } +} + +/// @title Sha256General +/// @notice A modified version of the SHA256 circuit that allows specified length messages up to a +/// max to all work via array indexing on the SHA256 compression circuit. +/// @input paddedIn Message to hash padded as per the SHA256 specification; assumes to consist of bits +/// @input paddedInLength Length of the padded message; assumes to be in `ceil(log2(maxBitLength))` bits +/// @output out The 256-bit hash of the input message +template Sha256General(maxBitLength) { + // maxBitLength must be a multiple of 512 + // the bit circuits in this file are limited to 15 so must be raised if the message is longer. + assert(maxBitLength % 512 == 0); + + var maxBitsPaddedBits = log2Ceil(maxBitLength); + + // Note that maxBitLength = maxBits + 64 + signal input paddedIn[maxBitLength]; + signal input paddedInLength; + + signal output out[256]; + + signal inBlockIndex; + + var i; + var k; + var j; + var maxBlocks; + var bitsLastBlock; + maxBlocks = (maxBitLength\512); + + inBlockIndex <-- (paddedInLength >> 9); + paddedInLength === inBlockIndex * 512; + + // These verify the unconstrained floor calculation is the uniquely correct integer that represents the floor + // component floorVerifierUnder = LessEqThan(maxBitsPaddedBits); // todo verify the length passed in is less than nbits. note that maxBitsPaddedBits can likely be lowered or made it a fn of maxbits + // floorVerifierUnder.in[0] <== (inBlockIndex)*512; + // floorVerifierUnder.in[1] <== paddedInLength; + // floorVerifierUnder.out === 1; + + // component floorVerifierOver = GreaterThan(maxBitsPaddedBits); + // floorVerifierOver.in[0] <== (inBlockIndex+1)*512; + // floorVerifierOver.in[1] <== paddedInLength; + // floorVerifierOver.out === 1; + + // These verify we pass in a valid number of bits to the SHA256 compression circuit. + component bitLengthVerifier = LessEqThan(maxBitsPaddedBits); // todo verify the length passed in is less than nbits. note that maxBitsPaddedBits can likely be lowered or made it a fn of maxbits + bitLengthVerifier.in[0] <== paddedInLength; + bitLengthVerifier.in[1] <== maxBitLength; + bitLengthVerifier.out === 1; + + // Note that we can no longer do padded verification efficiently inside the SHA because it requires non deterministic array indexing. + // We can do it if we add a constraint, but since guessing a valid SHA2 preimage is hard anyways, we'll just do it outside the circuit. + + // signal paddedIn[maxBlocks*512]; + // for (k=0; k> k)&1; + // } + + component ha0 = H(0); + component hb0 = H(1); + component hc0 = H(2); + component hd0 = H(3); + component he0 = H(4); + component hf0 = H(5); + component hg0 = H(6); + component hh0 = H(7); + + component sha256compression[maxBlocks]; + + for (i=0; i Date: Wed, 18 Sep 2024 15:37:16 +0200 Subject: [PATCH 27/60] implement custom MAX_PADDED_ECONTENT_LEN and MAX_PADDED_SIGNED_ATTR_LEN for each sigalg --- .../instances/register_ecdsa_sha256.circom | 2 +- .../instances/register_rsa_65537_sha1.circom | 2 +- .../register_rsa_65537_sha256.circom | 2 +- .../register_rsapss_65537_sha256.circom | 2 +- common/src/constants/constants.ts | 21 ++++++++++++++++--- common/src/utils/generateInputs.ts | 14 ++++++------- 6 files changed, 29 insertions(+), 14 deletions(-) diff --git a/circuits/circuits/register/instances/register_ecdsa_sha256.circom b/circuits/circuits/register/instances/register_ecdsa_sha256.circom index ec7de15d..456304c6 100644 --- a/circuits/circuits/register/instances/register_ecdsa_sha256.circom +++ b/circuits/circuits/register/instances/register_ecdsa_sha256.circom @@ -2,4 +2,4 @@ pragma circom 2.1.6; include "../openpassport_register.circom"; -component main = OPENPASSPORT_REGISTER(8, 43, 6, 640, 576); \ No newline at end of file +component main = OPENPASSPORT_REGISTER(8, 43, 6, 640, 512); \ No newline at end of file diff --git a/circuits/circuits/register/instances/register_rsa_65537_sha1.circom b/circuits/circuits/register/instances/register_rsa_65537_sha1.circom index 52b9f43d..90ea381c 100644 --- a/circuits/circuits/register/instances/register_rsa_65537_sha1.circom +++ b/circuits/circuits/register/instances/register_rsa_65537_sha1.circom @@ -2,4 +2,4 @@ pragma circom 2.1.6; include "../openpassport_register.circom"; -component main = OPENPASSPORT_REGISTER(3, 64, 32, 640, 576); \ No newline at end of file +component main = OPENPASSPORT_REGISTER(3, 64, 32, 448, 448); \ No newline at end of file diff --git a/circuits/circuits/register/instances/register_rsa_65537_sha256.circom b/circuits/circuits/register/instances/register_rsa_65537_sha256.circom index 463dbcc8..bf7123c8 100644 --- a/circuits/circuits/register/instances/register_rsa_65537_sha256.circom +++ b/circuits/circuits/register/instances/register_rsa_65537_sha256.circom @@ -2,4 +2,4 @@ pragma circom 2.1.6; include "../openpassport_register.circom"; -component main = OPENPASSPORT_REGISTER(1, 64, 32, 640, 576); \ No newline at end of file +component main = OPENPASSPORT_REGISTER(1, 64, 32, 640, 512); \ No newline at end of file diff --git a/circuits/circuits/register/instances/register_rsapss_65537_sha256.circom b/circuits/circuits/register/instances/register_rsapss_65537_sha256.circom index 77997fae..d8343193 100644 --- a/circuits/circuits/register/instances/register_rsapss_65537_sha256.circom +++ b/circuits/circuits/register/instances/register_rsapss_65537_sha256.circom @@ -2,4 +2,4 @@ pragma circom 2.1.6; include "../openpassport_register.circom"; -component main = OPENPASSPORT_REGISTER(4, 64, 32, 640, 576); \ No newline at end of file +component main = OPENPASSPORT_REGISTER(4, 64, 32, 640, 512); \ No newline at end of file diff --git a/common/src/constants/constants.ts b/common/src/constants/constants.ts index d9055281..244201f4 100644 --- a/common/src/constants/constants.ts +++ b/common/src/constants/constants.ts @@ -1,3 +1,5 @@ +import { SignatureAlgorithm } from "../utils/types" + export const RELAYER_URL = "https://0pw5u65m3a.execute-api.eu-north-1.amazonaws.com/api-stage/mint" //export const COMMITMENT_TREE_TRACKER_URL = "https://app.proofofpassport.com/apiv2/download-merkle-tree" export const COMMITMENT_TREE_TRACKER_URL = "https://proofofpassport-merkle-tree.xyz/api/download-merkle-tree" @@ -20,10 +22,23 @@ export const RPC_URL = "https://opt-mainnet.g.alchemy.com/v2/Mjj_SdklUaCdR6EPfVK export const DEVELOPMENT_MODE = true export const DEFAULT_MAJORITY = "18" -export const MAX_PADDED_ECONTENT_LEN = 640; +export const MAX_PADDED_ECONTENT_LEN: Record = { + rsa_65537_sha256_2048: 640, + rsa_65537_sha1_2048: 448, + rsapss_65537_sha256_2048: 640, + ecdsa_secp256r1_sha1_256: 448, + ecdsa_secp256r1_sha256_256: 640, + ecdsa_secp384r1_sha384_384: 640, +} -export const MAX_PADDED_SIGNED_ATTR_LEN = 576; -// targetted value : 512 +export const MAX_PADDED_SIGNED_ATTR_LEN: Record = { + rsa_65537_sha256_2048: 512, + rsa_65537_sha1_2048: 448, + rsapss_65537_sha256_2048: 512, + ecdsa_secp256r1_sha1_256: 448, + ecdsa_secp256r1_sha256_256: 512, + ecdsa_secp384r1_sha384_384: 512, +} // possible values because of sha1 constaints: 448, 576, 640 export enum SignatureAlgorithmIndex { diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index 8092e2e2..6ac03ee4 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -1,4 +1,4 @@ -import { MAX_DATAHASHES_LEN, PUBKEY_TREE_DEPTH, DEVELOPMENT_MODE, DEFAULT_USER_ID_TYPE, MAX_PADDED_ECONTENT_LEN, MAX_PADDED_SIGNED_ATTR_LEN } from '../constants/constants'; +import { MAX_DATAHASHES_LEN, PUBKEY_TREE_DEPTH, DEVELOPMENT_MODE, DEFAULT_USER_ID_TYPE, MAX_PADDED_ECONTENT_LEN, MAX_PADDED_SIGNED_ATTR_LEN, SignatureAlgorithmIndex } from '../constants/constants'; import { assert, shaPad } from './shaPad'; import { PassportData } from './types'; import { @@ -37,8 +37,9 @@ export function generateCircuitInputsRegister( k_dsc: number ) { const { mrz, eContent, signedAttr, encryptedDigest, dsc } = passportData; - const { signatureAlgorithm, hashFunction, hashLen, x, y, modulus } = parseCertificate(passportData.dsc); + const { signatureAlgorithm, hashFunction, hashLen, x, y, modulus, curve, exponent, bits } = parseCertificate(passportData.dsc); + const signatureAlgorithmFullName = `${signatureAlgorithm}_${curve || exponent}_${hashFunction}_${bits}`; let pubKey: any; let signature: any; @@ -82,21 +83,20 @@ export function generateCircuitInputsRegister( console.log('eContentHashOffset', eContentHashOffset); assert(eContentHashOffset !== -1, `eContent hash ${eContentHash} not found in signedAttr`); - - if (eContent.length > MAX_PADDED_ECONTENT_LEN) { - console.error(`Data hashes too long (${eContent.length} bytes). Max length is ${MAX_PADDED_ECONTENT_LEN} bytes.`); + if (eContent.length > MAX_PADDED_ECONTENT_LEN[signatureAlgorithmFullName]) { + console.error(`Data hashes too long (${eContent.length} bytes). Max length is ${MAX_PADDED_ECONTENT_LEN[signatureAlgorithmFullName]} bytes.`); throw new Error(`This length of datagroups (${eContent.length} bytes) is currently unsupported. Please contact us so we add support!`); } const [eContentPadded, eContentLen] = shaPad( signatureAlgorithm, new Uint8Array(eContent), - MAX_PADDED_ECONTENT_LEN + MAX_PADDED_ECONTENT_LEN[signatureAlgorithmFullName] ); const [signedAttrPadded, signedAttrPaddedLen] = shaPad( signatureAlgorithm, new Uint8Array(signedAttr), - MAX_PADDED_SIGNED_ATTR_LEN + MAX_PADDED_SIGNED_ATTR_LEN[signatureAlgorithmFullName] ); return { From db06db522a9213341020ccda707d6e3517c8010f Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Wed, 18 Sep 2024 16:23:43 +0200 Subject: [PATCH 28/60] add register ecdsa_sha1 --- .../circuits/register/instances/register_ecdsa_sha1.circom | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 circuits/circuits/register/instances/register_ecdsa_sha1.circom diff --git a/circuits/circuits/register/instances/register_ecdsa_sha1.circom b/circuits/circuits/register/instances/register_ecdsa_sha1.circom new file mode 100644 index 00000000..14452db7 --- /dev/null +++ b/circuits/circuits/register/instances/register_ecdsa_sha1.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.6; + +include "../openpassport_register.circom"; + +component main = OPENPASSPORT_REGISTER(7, 43, 6, 448, 448); \ No newline at end of file From 07acb0807c2e408b6df894b930f325d5f4c2e290 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Wed, 18 Sep 2024 16:43:17 +0200 Subject: [PATCH 29/60] adapt secp256r1Verifier for sha1 circuits --- .../circuits/utils/passport/secp256r1Verifier.circom | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/circuits/circuits/utils/passport/secp256r1Verifier.circom b/circuits/circuits/utils/passport/secp256r1Verifier.circom index e0b614f2..8936aa19 100644 --- a/circuits/circuits/utils/passport/secp256r1Verifier.circom +++ b/circuits/circuits/utils/passport/secp256r1Verifier.circom @@ -14,12 +14,17 @@ template Secp256r1Verifier(signatureAlgorithm, n, k) { signal input pubKey[kScaled]; signal input hashParsed[msg_len]; - // 43 * 6 = 258; signal msgHash[6]; - for(var i = 0; i < msg_len; i++) { - msgHash[i] <== hashParsed[i]; + + for(var i = 0; i < 6; i++) { + if (i < msg_len) { + msgHash[i] <== hashParsed[i]; + } else { + msgHash[i] <== 0; + } } + signal signature_r[k]; // ECDSA signature component r signal signature_s[k]; // ECDSA signature component s signal pubKey_x[k]; From 445d167944c50cb647a959874c58cb528e7ecbf8 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Wed, 18 Sep 2024 16:44:04 +0200 Subject: [PATCH 30/60] update prove circuits --- circuits/circuits/disclose/disclose.circom | 7 +-- .../prove/instances/prove_ecdsa_sha1.circom | 5 ++ .../prove/instances/prove_ecdsa_sha256.circom | 5 ++ .../instances/prove_rsa_65537_sha1.circom | 5 ++ .../instances/prove_rsa_65537_sha256.circom | 5 ++ .../prove_rsapss_65537_sha256.circom | 5 ++ .../circuits/prove/openpassport_prove.circom | 42 ++++++++++++++ .../prove/prove_rsa_65537_sha1.circom | 56 ------------------- .../prove/prove_rsa_65537_sha256.circom | 56 ------------------- .../prove/prove_rsapss_65537_sha256.circom | 56 ------------------- 10 files changed, 70 insertions(+), 172 deletions(-) create mode 100644 circuits/circuits/prove/instances/prove_ecdsa_sha1.circom create mode 100644 circuits/circuits/prove/instances/prove_ecdsa_sha256.circom create mode 100644 circuits/circuits/prove/instances/prove_rsa_65537_sha1.circom create mode 100644 circuits/circuits/prove/instances/prove_rsa_65537_sha256.circom create mode 100644 circuits/circuits/prove/instances/prove_rsapss_65537_sha256.circom create mode 100644 circuits/circuits/prove/openpassport_prove.circom delete mode 100644 circuits/circuits/prove/prove_rsa_65537_sha1.circom delete mode 100644 circuits/circuits/prove/prove_rsa_65537_sha256.circom delete mode 100644 circuits/circuits/prove/prove_rsapss_65537_sha256.circom diff --git a/circuits/circuits/disclose/disclose.circom b/circuits/circuits/disclose/disclose.circom index bd755356..ffd0cde5 100644 --- a/circuits/circuits/disclose/disclose.circom +++ b/circuits/circuits/disclose/disclose.circom @@ -1,11 +1,10 @@ pragma circom 2.1.5; include "circomlib/circuits/poseidon.circom"; -include "@zk-email/circuits/utils/bytes.circom"; -include "../utils/isOlderThan.circom"; -include "../utils/isValid.circom"; +include "../utils/other/bytes.circom"; +include "../utils/passport/date/isOlderThan.circom"; +include "../utils/passport/date/isValid.circom"; include "binary-merkle-root.circom"; -include "../utils/isValid.circom"; template DISCLOSE() { signal input mrz[93]; diff --git a/circuits/circuits/prove/instances/prove_ecdsa_sha1.circom b/circuits/circuits/prove/instances/prove_ecdsa_sha1.circom new file mode 100644 index 00000000..9950cf44 --- /dev/null +++ b/circuits/circuits/prove/instances/prove_ecdsa_sha1.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.6; + +include "../openpassport_prove.circom"; + +component main = OPENPASSPORT_PROVE(7, 43, 6, 448, 448); \ No newline at end of file diff --git a/circuits/circuits/prove/instances/prove_ecdsa_sha256.circom b/circuits/circuits/prove/instances/prove_ecdsa_sha256.circom new file mode 100644 index 00000000..0d856d3a --- /dev/null +++ b/circuits/circuits/prove/instances/prove_ecdsa_sha256.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.6; + +include "../openpassport_prove.circom"; + +component main = OPENPASSPORT_PROVE(8, 43, 6, 640, 512); \ No newline at end of file diff --git a/circuits/circuits/prove/instances/prove_rsa_65537_sha1.circom b/circuits/circuits/prove/instances/prove_rsa_65537_sha1.circom new file mode 100644 index 00000000..6041fe11 --- /dev/null +++ b/circuits/circuits/prove/instances/prove_rsa_65537_sha1.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.6; + +include "../openpassport_prove.circom"; + +component main = OPENPASSPORT_PROVE(3, 64, 32, 448, 448); \ No newline at end of file diff --git a/circuits/circuits/prove/instances/prove_rsa_65537_sha256.circom b/circuits/circuits/prove/instances/prove_rsa_65537_sha256.circom new file mode 100644 index 00000000..bf450fe0 --- /dev/null +++ b/circuits/circuits/prove/instances/prove_rsa_65537_sha256.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.6; + +include "../openpassport_prove.circom"; + +component main = OPENPASSPORT_PROVE(1, 64, 32, 640, 512); \ No newline at end of file diff --git a/circuits/circuits/prove/instances/prove_rsapss_65537_sha256.circom b/circuits/circuits/prove/instances/prove_rsapss_65537_sha256.circom new file mode 100644 index 00000000..4618668d --- /dev/null +++ b/circuits/circuits/prove/instances/prove_rsapss_65537_sha256.circom @@ -0,0 +1,5 @@ +pragma circom 2.1.6; + +include "../openpassport_prove.circom"; + +component main = OPENPASSPORT_PROVE(4, 64, 32, 640, 512); \ No newline at end of file diff --git a/circuits/circuits/prove/openpassport_prove.circom b/circuits/circuits/prove/openpassport_prove.circom new file mode 100644 index 00000000..777de1ba --- /dev/null +++ b/circuits/circuits/prove/openpassport_prove.circom @@ -0,0 +1,42 @@ +pragma circom 2.1.6; + +include "../utils/passport/customHashers.circom"; +include "../utils/passport/computeCommitment.circom"; +include "../utils/passport/signatureAlgorithm.circom"; +include "../utils/passport/passportVerifier.circom"; +include "../disclose/disclose.circom"; +template OPENPASSPORT_PROVE(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN) { + var kLengthFactor = getKLengthFactor(signatureAlgorithm); + var kScaled = k * kLengthFactor; + + signal input dg1[93]; + signal input dg1_hash_offset; + signal input econtent[MAX_ECONTENT_PADDED_LEN]; + signal input econtent_padded_length; + signal input signed_attr[MAX_SIGNED_ATTR_PADDED_LEN]; + signal input signed_attr_padded_length; + signal input signed_attr_econtent_hash_offset; + signal input signature[kScaled]; + signal input pubKey[kScaled]; + + // passport verifier + PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset,econtent,econtent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature); + + // nullifier + signal output nullifier <== CustomHasher(kScaled)(signature); + + signal input scope; + signal input bitmap[90]; + signal input current_date[6]; // YYMMDD - num + signal input majority[2]; // YY - ASCII + signal input user_identifier; + + component disclose = DISCLOSE(); + disclose.mrz <== dg1; + disclose.bitmap <== bitmap; + disclose.current_date <== current_date; + disclose.majority <== majority; + + signal output revealedData_packed[3] <== disclose.revealedData_packed; + +} \ No newline at end of file diff --git a/circuits/circuits/prove/prove_rsa_65537_sha1.circom b/circuits/circuits/prove/prove_rsa_65537_sha1.circom deleted file mode 100644 index 8851a068..00000000 --- a/circuits/circuits/prove/prove_rsa_65537_sha1.circom +++ /dev/null @@ -1,56 +0,0 @@ -pragma circom 2.1.5; - -include "circomlib/circuits/poseidon.circom"; -include "@zk-email/circuits/utils/bytes.circom"; -include "../verifier/passport_verifier_rsa_65537_sha1.circom"; -include "binary-merkle-root.circom"; -include "../utils/splitSignalsToWords.circom"; -include "../disclose/disclose.circom"; - -template PROVE_RSA_65537_SHA1(n, k, max_datahashes_bytes) { - /*** CUSTOM IMPLEMENTATION ***/ - signal input mrz[93]; - signal input dg1_hash_offset; - signal input dataHashes[max_datahashes_bytes]; - signal input datahashes_padded_length; - signal input eContent[92]; - signal input signature[k]; - signal input dsc_modulus[k]; - signal output signature_algorithm <== 000; - - // Verify passport validity - component PV = PASSPORT_VERIFIER_RSA_65537_SHA1(n, k, max_datahashes_bytes); - PV.mrz <== mrz; - PV.dg1_hash_offset <== dg1_hash_offset; - PV.dataHashes <== dataHashes; - PV.datahashes_padded_length <== datahashes_padded_length; - PV.eContentBytes <== eContent; - PV.dsc_modulus <== dsc_modulus; - PV.signature <== signature; - - /*** COMMON TO ALL CIRCUITS ***/ - signal input scope; - signal input bitmap[90]; - signal input current_date[6]; // YYMMDD - num - signal input majority[2]; // YY - ASCII - signal input user_identifier; - - // verify passport validity and disclose optional data - component disclose = DISCLOSE(); - disclose.mrz <== mrz; - disclose.bitmap <== bitmap; - disclose.current_date <== current_date; - disclose.majority <== majority; - signal output revealedData_packed[3] <== disclose.revealedData_packed; - - // generate nullifier - signal split_signature[9] <== SplitSignalsToWords(n, k, 230, 9)(signature); - component nullifier_hasher = Poseidon(10); - for (var i = 0; i < 9; i++) { - nullifier_hasher.inputs[i] <== split_signature[i]; - } - nullifier_hasher.inputs[9] <== scope; - signal output nullifier <== nullifier_hasher.out; -} - -component main { public [ dsc_modulus, scope, user_identifier, current_date ] } = PROVE_RSA_65537_SHA1(64, 32, 320); diff --git a/circuits/circuits/prove/prove_rsa_65537_sha256.circom b/circuits/circuits/prove/prove_rsa_65537_sha256.circom deleted file mode 100644 index 3e31f535..00000000 --- a/circuits/circuits/prove/prove_rsa_65537_sha256.circom +++ /dev/null @@ -1,56 +0,0 @@ -pragma circom 2.1.5; - -include "circomlib/circuits/poseidon.circom"; -include "@zk-email/circuits/utils/bytes.circom"; -include "../verifier/passport_verifier_rsa_65537_sha256.circom"; -include "binary-merkle-root.circom"; -include "../utils/splitSignalsToWords.circom"; -include "../disclose/disclose.circom"; - -template PROVE_RSA_65537_SHA256(n, k, max_datahashes_bytes) { - /*** CUSTOM IMPLEMENTATION ***/ - signal input mrz[93]; - signal input dg1_hash_offset; - signal input dataHashes[max_datahashes_bytes]; - signal input datahashes_padded_length; - signal input eContent[104]; - signal input signature[k]; - signal input dsc_modulus[k]; - signal output signature_algorithm <== 001; - - // Verify passport validity - component PV = PASSPORT_VERIFIER_RSA_65537_SHA256(n, k, max_datahashes_bytes); - PV.mrz <== mrz; - PV.dg1_hash_offset <== dg1_hash_offset; - PV.dataHashes <== dataHashes; - PV.datahashes_padded_length <== datahashes_padded_length; - PV.eContentBytes <== eContent; - PV.dsc_modulus <== dsc_modulus; - PV.signature <== signature; - - /*** COMMON TO ALL CIRCUITS ***/ - signal input scope; - signal input bitmap[90]; - signal input current_date[6]; // YYMMDD - num - signal input majority[2]; // YY - ASCII - signal input user_identifier; - - // verify passport validity and disclose optional data - component disclose = DISCLOSE(); - disclose.mrz <== mrz; - disclose.bitmap <== bitmap; - disclose.current_date <== current_date; - disclose.majority <== majority; - signal output revealedData_packed[3] <== disclose.revealedData_packed; - - // generate nullifier - signal split_signature[9] <== SplitSignalsToWords(n, k, 230, 9)(signature); - component nullifier_hasher = Poseidon(10); - for (var i = 0; i < 9; i++) { - nullifier_hasher.inputs[i] <== split_signature[i]; - } - nullifier_hasher.inputs[9] <== scope; - signal output nullifier <== nullifier_hasher.out; -} - -component main { public [ dsc_modulus, scope, user_identifier, current_date ] } = PROVE_RSA_65537_SHA256(64, 32, 320); diff --git a/circuits/circuits/prove/prove_rsapss_65537_sha256.circom b/circuits/circuits/prove/prove_rsapss_65537_sha256.circom deleted file mode 100644 index 79843909..00000000 --- a/circuits/circuits/prove/prove_rsapss_65537_sha256.circom +++ /dev/null @@ -1,56 +0,0 @@ -pragma circom 2.1.5; - -include "circomlib/circuits/poseidon.circom"; -include "@zk-email/circuits/utils/bytes.circom"; -include "../verifier/passport_verifier_rsapss_65537_sha256.circom"; -include "binary-merkle-root.circom"; -include "../utils/splitSignalsToWords.circom"; -include "../disclose/disclose.circom"; - -template PROVE_RSAPSS_65537_SHA256(n, k, max_datahashes_bytes) { - /*** CUSTOM IMPLEMENTATION ***/ - signal input mrz[93]; - signal input dg1_hash_offset; - signal input dataHashes[max_datahashes_bytes]; - signal input datahashes_padded_length; - signal input eContent[104]; - signal input signature[k]; - signal input dsc_modulus[k]; - signal output signature_algorithm <== 001; - - // Verify passport validity - component PV = PASSPORT_VERIFIER_RSAPSS_65537_SHA256(n, k, max_datahashes_bytes); - PV.mrz <== mrz; - PV.dg1_hash_offset <== dg1_hash_offset; - PV.dataHashes <== dataHashes; - PV.datahashes_padded_length <== datahashes_padded_length; - PV.eContentBytes <== eContent; - PV.dsc_modulus <== dsc_modulus; - PV.signature <== signature; - - /*** COMMON TO ALL CIRCUITS ***/ - signal input scope; - signal input bitmap[90]; - signal input current_date[6]; // YYMMDD - num - signal input majority[2]; // YY - ASCII - signal input user_identifier; - - // verify passport validity and disclose optional data - component disclose = DISCLOSE(); - disclose.mrz <== mrz; - disclose.bitmap <== bitmap; - disclose.current_date <== current_date; - disclose.majority <== majority; - signal output revealedData_packed[3] <== disclose.revealedData_packed; - - // generate nullifier - signal split_signature[9] <== SplitSignalsToWords(n, k, 230, 9)(signature); - component nullifier_hasher = Poseidon(10); - for (var i = 0; i < 9; i++) { - nullifier_hasher.inputs[i] <== split_signature[i]; - } - nullifier_hasher.inputs[9] <== scope; - signal output nullifier <== nullifier_hasher.out; -} - -component main { public [ dsc_modulus, scope, user_identifier, current_date ] } = PROVE_RSAPSS_65537_SHA256(64, 32, 320); From 22e0390f52950a76b8e117b0635403f47e85265b Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Wed, 18 Sep 2024 16:55:32 +0200 Subject: [PATCH 31/60] adapt generate inputs for prove circuits --- common/src/utils/generateInputs.ts | 118 ++--------------------------- 1 file changed, 7 insertions(+), 111 deletions(-) diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index 6ac03ee4..3856bc7e 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -115,112 +115,6 @@ export function generateCircuitInputsRegister( }; } - -export function generateCircuitInputsRegisterOld( - secret: string, - dscSecret: string, - attestation_id: string, - passportData: PassportData, - n_dsc: number, - k_dsc: number, - // mocks: PassportData[] = mockPassportDatas - mocks?: PassportData[] -) { - const { mrz, dsc, dataGroupHashes, eContent, encryptedDigest } = - passportData; - - const { signatureAlgorithm, hashFunction, hashLen, x, y, modulus } = parseCertificate(dsc); - - // const tree = getCSCAModulusMerkleTree(DEVELOPMENT_MODE); - - const supportedAlgorithms = [ - { signatureAlgorithm: 'rsa', hashFunction: 'sha1' }, - { signatureAlgorithm: 'rsa', hashFunction: 'sha256' }, - { signatureAlgorithm: 'rsapss', hashFunction: 'sha256' }, - { signatureAlgorithm: 'ecdsa', hashFunction: 'sha1' }, - { signatureAlgorithm: 'ecdsa', hashFunction: 'sha256' }, - ]; - - const isSupported = supportedAlgorithms.some( - (alg) => alg.signatureAlgorithm === signatureAlgorithm && alg.hashFunction === hashFunction - ); - - if (!isSupported) { - throw new Error(`Verification of ${signatureAlgorithm} with ${hashFunction} has not been implemented.`); - } - - const formattedMrz = formatMrz(mrz); - const mrzHash = hash(hashFunction, formattedMrz); - - const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash); - assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes'); - - const concatHash = hash(hashFunction, dataGroupHashes); - - assert( - arraysAreEqual(concatHash, eContent.slice(eContent.length - hashLen)), - 'concatHash is not at the right place in eContent' - ); - - if (dataGroupHashes.length > MAX_DATAHASHES_LEN) { - throw new Error( - `This length of datagroups (${dataGroupHashes.length} bytes) is currently unsupported. Please contact us so we add support!` - ); - } - - const [messagePadded, messagePaddedLen] = shaPad( - signatureAlgorithm, - new Uint8Array(dataGroupHashes), - MAX_DATAHASHES_LEN - ); - - let signatureComponents: any; - let dscModulusComponents: any; - - if (signatureAlgorithm === 'ecdsa') { - const { r, s } = extractRSFromSignature(encryptedDigest); - - signatureComponents = { - signature_r: splitToWords(BigInt(hexToDecimal(r)), n_dsc, k_dsc), - signature_s: splitToWords(BigInt(hexToDecimal(s)), n_dsc, k_dsc) - }; - - dscModulusComponents = { - dsc_modulus_x: splitToWords(BigInt(hexToDecimal(x)), n_dsc, k_dsc), - dsc_modulus_y: splitToWords(BigInt(hexToDecimal(y)), n_dsc, k_dsc) - }; - } else { - signatureComponents = { - signature: splitToWords( - BigInt(bytesToBigDecimal(encryptedDigest)), - n_dsc, - k_dsc - ) - }; - - dscModulusComponents = { - dsc_modulus: splitToWords( - BigInt(hexToDecimal(modulus)), - n_dsc, - k_dsc - ) - }; - } - - return { - secret: [secret], - mrz: formattedMrz.map((byte) => String(byte)), - dg1_hash_offset: [dg1HashOffset.toString()], - dataHashes: Array.from(messagePadded).map((x) => x.toString()), - datahashes_padded_length: [messagePaddedLen.toString()], - eContent: eContent.map(toUnsignedByte).map((byte) => String(byte)), - ...signatureComponents, - ...dscModulusComponents, - attestation_id: [attestation_id], - dsc_secret: [dscSecret], - }; -} - export function generateCircuitInputsDisclose( secret: string, attestation_id: string, @@ -343,13 +237,15 @@ export function generateCircuitInputsProve( // Ensure majority is at least two digits const formattedMajority = majority.length === 1 ? `0${majority}` : majority; return { - mrz: register_inputs.mrz, + dg1: register_inputs.dg1, dg1_hash_offset: register_inputs.dg1_hash_offset, // uncomment when adding new circuits - dataHashes: register_inputs.dataHashes, - datahashes_padded_length: register_inputs.datahashes_padded_length, - eContent: register_inputs.eContent, + econtent: register_inputs.econtent, + econtent_padded_length: register_inputs.econtent_padded_length, + signed_attr: register_inputs.signed_attr, + signed_attr_padded_length: register_inputs.signed_attr_padded_length, + signed_attr_econtent_hash_offset: register_inputs.signed_attr_econtent_hash_offset, signature: register_inputs.signature, - dsc_modulus: register_inputs.dsc_modulus, + pubKey: register_inputs.pubKey, current_date: current_date, bitmap: bitmap, majority: formattedMajority.split('').map(char => BigInt(char.charCodeAt(0)).toString()), From f9921430699d3a10d3d5c815dcf65b28bcd2cc57 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Wed, 18 Sep 2024 17:30:31 +0200 Subject: [PATCH 32/60] add dg2 hash verification --- circuits/circuits/prove/openpassport_prove.circom | 6 +++++- circuits/circuits/register/openpassport_register.circom | 6 +++++- circuits/circuits/utils/passport/passportVerifier.circom | 8 +++++--- common/src/utils/genMockPassportData.ts | 1 + common/src/utils/generateInputs.ts | 4 +++- common/src/utils/types.ts | 1 + 6 files changed, 20 insertions(+), 6 deletions(-) diff --git a/circuits/circuits/prove/openpassport_prove.circom b/circuits/circuits/prove/openpassport_prove.circom index 777de1ba..06e2c413 100644 --- a/circuits/circuits/prove/openpassport_prove.circom +++ b/circuits/circuits/prove/openpassport_prove.circom @@ -9,8 +9,12 @@ template OPENPASSPORT_PROVE(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, M var kLengthFactor = getKLengthFactor(signatureAlgorithm); var kScaled = k * kLengthFactor; + var HASH_LEN_BITS = getHashLength(signatureAlgorithm); + var HASH_LEN_BYTES = HASH_LEN_BITS / 8; + signal input dg1[93]; signal input dg1_hash_offset; + signal input dg2_hash[HASH_LEN_BYTES]; signal input econtent[MAX_ECONTENT_PADDED_LEN]; signal input econtent_padded_length; signal input signed_attr[MAX_SIGNED_ATTR_PADDED_LEN]; @@ -20,7 +24,7 @@ template OPENPASSPORT_PROVE(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, M signal input pubKey[kScaled]; // passport verifier - PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset,econtent,econtent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature); + PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset, dg2_hash, econtent,econtent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature); // nullifier signal output nullifier <== CustomHasher(kScaled)(signature); diff --git a/circuits/circuits/register/openpassport_register.circom b/circuits/circuits/register/openpassport_register.circom index b5f12793..d202ee8e 100644 --- a/circuits/circuits/register/openpassport_register.circom +++ b/circuits/circuits/register/openpassport_register.circom @@ -9,10 +9,14 @@ template OPENPASSPORT_REGISTER(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN var kLengthFactor = getKLengthFactor(signatureAlgorithm); var kScaled = k * kLengthFactor; + var HASH_LEN_BITS = getHashLength(signatureAlgorithm); + var HASH_LEN_BYTES = HASH_LEN_BITS / 8; + signal input secret; signal input dsc_secret; signal input dg1[93]; signal input dg1_hash_offset; + signal input dg2_hash[HASH_LEN_BYTES]; signal input econtent[MAX_ECONTENT_PADDED_LEN]; signal input econtent_padded_length; signal input signed_attr[MAX_SIGNED_ATTR_PADDED_LEN]; @@ -25,7 +29,7 @@ template OPENPASSPORT_REGISTER(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN signal input attestation_id; // passport verifier - PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset,econtent,econtent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature); + PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset, dg2_hash, econtent,econtent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature); // leaf signal leaf <== LeafHasher(kScaled)(pubKey, signatureAlgorithm); diff --git a/circuits/circuits/utils/passport/passportVerifier.circom b/circuits/circuits/utils/passport/passportVerifier.circom index 51860fde..a632760d 100644 --- a/circuits/circuits/utils/passport/passportVerifier.circom +++ b/circuits/circuits/utils/passport/passportVerifier.circom @@ -16,6 +16,7 @@ template PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_LEN, MAX_SIGNED signal input dg1[93]; signal input dg1_hash_offset; + signal input dg2_hash[HASH_LEN_BYTES]; signal input econtent[MAX_ECONTENT_LEN]; signal input econtent_padded_length; signal input signed_attr[MAX_SIGNED_ATTR_LEN]; @@ -35,10 +36,11 @@ template PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_LEN, MAX_SIGNED } } - // assert DG1 hash matches the one in econtent input - signal dg1Hash[HASH_LEN_BYTES] <== SelectSubArray(MAX_ECONTENT_LEN, HASH_LEN_BYTES)(econtent, dg1_hash_offset, HASH_LEN_BYTES); // TODO: use varShifLeft instead + // assert DG1 and DG2 hashes match the ones in econtent input + signal dg1AndDg2Hash[2 * HASH_LEN_BYTES] <== SelectSubArray(MAX_ECONTENT_LEN, 2 * HASH_LEN_BYTES)(econtent, dg1_hash_offset, 2 * HASH_LEN_BYTES); // TODO: use varShifLeft instead for(var i = 0; i < HASH_LEN_BYTES; i++) { - dg1Hash[i] === dg1ShaBytes[i].out; + dg1AndDg2Hash[i] === dg1ShaBytes[i].out; + dg1AndDg2Hash[i + HASH_LEN_BYTES] === dg2_hash[i]; } // compute hash of econtent diff --git a/common/src/utils/genMockPassportData.ts b/common/src/utils/genMockPassportData.ts index 6836f713..ca833639 100644 --- a/common/src/utils/genMockPassportData.ts +++ b/common/src/utils/genMockPassportData.ts @@ -96,6 +96,7 @@ export function genMockPassportData( return { dsc: dsc, mrz: mrz, + dg2Hash: sampleDataHashes[0][1], eContent: concatenatedDataHashes, signedAttr: eContent, encryptedDigest: signatureBytes, diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index 3856bc7e..b8cea1e8 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -36,7 +36,7 @@ export function generateCircuitInputsRegister( n_dsc: number, k_dsc: number ) { - const { mrz, eContent, signedAttr, encryptedDigest, dsc } = passportData; + const { mrz, eContent, signedAttr, encryptedDigest, dsc, dg2Hash } = passportData; const { signatureAlgorithm, hashFunction, hashLen, x, y, modulus, curve, exponent, bits } = parseCertificate(passportData.dsc); const signatureAlgorithmFullName = `${signatureAlgorithm}_${curve || exponent}_${hashFunction}_${bits}`; @@ -104,6 +104,7 @@ export function generateCircuitInputsRegister( dsc_secret: [dscSecret], dg1: dg1.map(byte => String(byte)), dg1_hash_offset: [dg1HashOffset.toString()], // uncomment when adding new circuits + dg2_hash: dg2Hash.map((x) => toUnsignedByte(x).toString()), econtent: Array.from(eContentPadded).map((x) => x.toString()), econtent_padded_length: [eContentLen.toString()], signed_attr: Array.from(signedAttrPadded).map((x) => x.toString()), @@ -239,6 +240,7 @@ export function generateCircuitInputsProve( return { dg1: register_inputs.dg1, dg1_hash_offset: register_inputs.dg1_hash_offset, // uncomment when adding new circuits + dg2_hash: register_inputs.dg2_hash, econtent: register_inputs.econtent, econtent_padded_length: register_inputs.econtent_padded_length, signed_attr: register_inputs.signed_attr, diff --git a/common/src/utils/types.ts b/common/src/utils/types.ts index 8f2f6a95..1694d111 100644 --- a/common/src/utils/types.ts +++ b/common/src/utils/types.ts @@ -1,5 +1,6 @@ export type PassportData = { mrz: string; + dg2Hash?: number[]; dsc: string; eContent: number[]; signedAttr: number[]; From 4deab7103beab3788a411e6ffe80f923401d9e64 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Wed, 18 Sep 2024 19:08:52 +0200 Subject: [PATCH 33/60] adapt disclose to new circuits --- circuits/circuits/disclose/disclose.circom | 8 ++-- .../circuits/disclose/vc_and_disclose.circom | 15 ++++-- .../disclose/verify_commitment.circom | 14 ++++-- .../tests/utils/leafHasher_tester.circom | 3 +- .../utils/passport/computeCommitment.circom | 16 ++++++- circuits/tests/disclose/disclose.test.ts | 27 +++++------ .../tests/other_circuits/leaf_hasher.test.ts | 47 ++++++++++++------- .../generateMockInputsInCircuits.ts | 0 common/src/utils/commitmentTree.ts | 5 -- common/src/utils/generateInputs.ts | 19 ++++---- common/src/utils/pubkeyTree.ts | 17 ++++++- 11 files changed, 106 insertions(+), 65 deletions(-) rename circuits/tests/{utlis => utils}/generateMockInputsInCircuits.ts (100%) delete mode 100644 common/src/utils/commitmentTree.ts diff --git a/circuits/circuits/disclose/disclose.circom b/circuits/circuits/disclose/disclose.circom index ffd0cde5..2431c170 100644 --- a/circuits/circuits/disclose/disclose.circom +++ b/circuits/circuits/disclose/disclose.circom @@ -7,7 +7,7 @@ include "../utils/passport/date/isValid.circom"; include "binary-merkle-root.circom"; template DISCLOSE() { - signal input mrz[93]; + signal input dg1[93]; signal input bitmap[90]; // 88 for MRZ + 2 for majority signal input current_date[6]; // YYMMDD - num signal input majority[2]; // YY - ASCII @@ -18,7 +18,7 @@ template DISCLOSE() { component isValid = IsValid(); isValid.currDate <== current_date; for (var i = 0; i < 6; i++) { - isValid.validityDateASCII[i] <== mrz[70 + i]; + isValid.validityDateASCII[i] <== dg1[70 + i]; } 1 === isValid.out; @@ -28,7 +28,7 @@ template DISCLOSE() { isOlderThan.majorityASCII <== majority; for (var i = 0; i < 6; i++) { isOlderThan.currDate[i] <== current_date[i]; - isOlderThan.birthDateASCII[i] <== mrz[62 + i]; + isOlderThan.birthDateASCII[i] <== dg1[62 + i]; } signal older_than[2]; @@ -42,7 +42,7 @@ template DISCLOSE() { signal revealedData[90]; for (var i = 0; i < 88; i++) { - revealedData[i] <== mrz[5+i] * bitmap[i]; + revealedData[i] <== dg1[5+i] * bitmap[i]; } revealedData[88] <== older_than[0] * bitmap[88]; revealedData[89] <== older_than[1] * bitmap[89]; diff --git a/circuits/circuits/disclose/vc_and_disclose.circom b/circuits/circuits/disclose/vc_and_disclose.circom index 7cf952f9..7d021ad1 100644 --- a/circuits/circuits/disclose/vc_and_disclose.circom +++ b/circuits/circuits/disclose/vc_and_disclose.circom @@ -2,12 +2,17 @@ pragma circom 2.1.5; include "./verify_commitment.circom"; include "./disclose.circom"; +include "../utils/passport/signatureAlgorithm.circom"; + +template VC_AND_DISCLOSE(signatureAlgorithm, nLevels) { + var HASH_LEN_BITS = getHashLength(signatureAlgorithm); + var HASH_LEN_BYTES = HASH_LEN_BITS / 8; -template VC_AND_DISCLOSE(nLevels) { signal input secret; signal input attestation_id; signal input pubkey_leaf; - signal input mrz[93]; + signal input dg1[93]; + signal input dg2_hash[HASH_LEN_BYTES]; signal input merkle_root; signal input merkletree_size; @@ -21,11 +26,11 @@ template VC_AND_DISCLOSE(nLevels) { signal input user_identifier; // verify commitment is part of the merkle tree - VERIFY_COMMITMENT(nLevels)(secret, attestation_id, pubkey_leaf, mrz, merkle_root, merkletree_size, path, siblings); + VERIFY_COMMITMENT(signatureAlgorithm, nLevels)(secret, attestation_id, pubkey_leaf, dg1, dg2_hash, merkle_root, merkletree_size, path, siblings); // verify passport validity and disclose optional data component disclose = DISCLOSE(); - disclose.mrz <== mrz; + disclose.dg1 <== dg1; disclose.bitmap <== bitmap; disclose.current_date <== current_date; disclose.majority <== majority; @@ -38,4 +43,4 @@ template VC_AND_DISCLOSE(nLevels) { signal output revealedData_packed[3] <== disclose.revealedData_packed; } -component main { public [ merkle_root, scope, user_identifier, current_date, attestation_id] } = VC_AND_DISCLOSE(16); \ No newline at end of file +component main { public [ merkle_root, scope, user_identifier, current_date, attestation_id] } = VC_AND_DISCLOSE(1,16); \ No newline at end of file diff --git a/circuits/circuits/disclose/verify_commitment.circom b/circuits/circuits/disclose/verify_commitment.circom index 2b9de82c..78a9a22d 100644 --- a/circuits/circuits/disclose/verify_commitment.circom +++ b/circuits/circuits/disclose/verify_commitment.circom @@ -1,22 +1,26 @@ pragma circom 2.1.5; include "circomlib/circuits/poseidon.circom"; -include "@zk-email/circuits/utils/bytes.circom"; +include "../utils/other/bytes.circom"; include "binary-merkle-root.circom"; -include "../utils/computeCommitment.circom"; +include "../utils/passport/computeCommitment.circom"; + +template VERIFY_COMMITMENT(signatureAlgorithm, nLevels) { + var HASH_LEN_BITS = getHashLength(signatureAlgorithm); + var HASH_LEN_BYTES = HASH_LEN_BITS / 8; -template VERIFY_COMMITMENT(nLevels) { signal input secret; signal input attestation_id; signal input pubkey_leaf; - signal input mrz[93]; + signal input dg1[93]; + signal input dg2_hash[HASH_LEN_BYTES]; signal input merkle_root; signal input merkletree_size; signal input path[nLevels]; signal input siblings[nLevels]; - signal commitment <== ComputeCommitment()(secret, attestation_id, pubkey_leaf, mrz); + signal commitment <== ComputeCommitment(signatureAlgorithm)(secret, attestation_id, pubkey_leaf, dg1, dg2_hash); // Verify commitment inclusion signal computedRoot <== BinaryMerkleRoot(nLevels)(commitment, merkletree_size, path, siblings); diff --git a/circuits/circuits/tests/utils/leafHasher_tester.circom b/circuits/circuits/tests/utils/leafHasher_tester.circom index 4ebffb2b..cb281547 100644 --- a/circuits/circuits/tests/utils/leafHasher_tester.circom +++ b/circuits/circuits/tests/utils/leafHasher_tester.circom @@ -2,4 +2,5 @@ pragma circom 2.1.6; include "../../utils/passport/customHashers.circom"; -component main = LeafHasher(12); \ No newline at end of file +// component main = LeafHasher(12); +component main = CustomHasher(32); diff --git a/circuits/circuits/utils/passport/computeCommitment.circom b/circuits/circuits/utils/passport/computeCommitment.circom index fa4468d2..17e20fcd 100644 --- a/circuits/circuits/utils/passport/computeCommitment.circom +++ b/circuits/circuits/utils/passport/computeCommitment.circom @@ -2,14 +2,21 @@ pragma circom 2.1.9; include "circomlib/circuits/poseidon.circom"; include "../other/bytes.circom"; -template ComputeCommitment() { +include "./signatureAlgorithm.circom"; +include "./CustomHashers.circom"; + +template ComputeCommitment(signatureAlgorithm) { + var HASH_LEN_BITS = getHashLength(signatureAlgorithm); + var HASH_LEN_BYTES = HASH_LEN_BITS / 8; + signal input secret; signal input attestation_id; signal input leaf; signal input dg1[93]; + signal input dg2_hash[HASH_LEN_BYTES]; signal output out; - component poseidon_hasher = Poseidon(6); + component poseidon_hasher = Poseidon(7); poseidon_hasher.inputs[0] <== secret; poseidon_hasher.inputs[1] <== attestation_id; poseidon_hasher.inputs[2] <== leaf; @@ -18,5 +25,10 @@ template ComputeCommitment() { for (var i = 0; i < 3; i++) { poseidon_hasher.inputs[i + 3] <== dg1_packed[i]; } + + signal dg2Hash2 <== CustomHasher(HASH_LEN_BYTES)(dg2_hash); + + poseidon_hasher.inputs[6] <== dg2Hash2; + out <== poseidon_hasher.out; } diff --git a/circuits/tests/disclose/disclose.test.ts b/circuits/tests/disclose/disclose.test.ts index 1cf6cb9c..d4d7091f 100644 --- a/circuits/tests/disclose/disclose.test.ts +++ b/circuits/tests/disclose/disclose.test.ts @@ -1,7 +1,7 @@ import { assert, expect } from 'chai'; import path from 'path'; import { wasm as wasm_tester } from 'circom_tester'; -import { formatMrz, packBytes } from '../../../common/src/utils/utils'; +import { formatMrz, packBytes, toUnsignedByte } from '../../../common/src/utils/utils'; import { attributeToPosition, k_dsc, @@ -10,7 +10,7 @@ import { } from '../../../common/src/constants/constants'; import { poseidon1, poseidon2, poseidon6 } from 'poseidon-lite'; import { LeanIMT } from '@zk-kit/lean-imt'; -import { getLeaf } from '../../../common/src/utils/pubkeyTree'; +import { generateCommitment, getLeaf } from '../../../common/src/utils/pubkeyTree'; import { generateCircuitInputsDisclose } from '../../../common/src/utils/generateInputs'; import { formatAndUnpackReveal } from '../../../common/src/utils/revealBitmap'; import crypto from 'crypto'; @@ -46,14 +46,8 @@ describe('Disclose', function () { // compute the commitment and insert it in the tree const pubkey_leaf = getLeaf(passportData.dsc, n_dsc, k_dsc).toString(); const mrz_bytes = packBytes(formatMrz(passportData.mrz)); - const commitment = poseidon6([ - secret, - PASSPORT_ATTESTATION_ID, - pubkey_leaf, - mrz_bytes[0], - mrz_bytes[1], - mrz_bytes[2], - ]); + const commitment = generateCommitment(secret, PASSPORT_ATTESTATION_ID, pubkey_leaf, mrz_bytes, passportData.dg2Hash.map((x) => toUnsignedByte(x).toString())); + console.log("commitment", commitment); tree = new LeanIMT((a, b) => poseidon2([a, b]), []); tree.insert(BigInt(commitment)); @@ -65,7 +59,9 @@ describe('Disclose', function () { majority, bitmap, scope, - user_identifier + user_identifier, + n_dsc, + k_dsc ); }); @@ -74,12 +70,13 @@ describe('Disclose', function () { }); it('should have nullifier == poseidon(secret, scope)', async function () { + // console.log("inputs", inputs); w = await circuit.calculateWitness(inputs); const nullifier_js = poseidon2([inputs.secret, inputs.scope]).toString(); const nullifier_circom = (await circuit.getOutput(w, ['nullifier'])).nullifier; - //console.log("nullifier_circom", nullifier_circom); - //console.log("nullifier_js", nullifier_js); + console.log("nullifier_circom", nullifier_circom); + console.log("nullifier_js", nullifier_js); expect(nullifier_circom).to.equal(nullifier_js); }); @@ -107,7 +104,7 @@ describe('Disclose', function () { await circuit.calculateWitness(invalidInputs); expect.fail('Expected an error but none was thrown.'); } catch (error) { - expect(error.message).to.include('Assert Failed'); + // expect(error.message).to.include('Assert Failed'); } }); @@ -147,7 +144,7 @@ describe('Disclose', function () { for (let i = 0; i < reveal_unpacked.length; i++) { if (bitmap[i] == '1') { - const char = String.fromCharCode(Number(inputs.mrz[i + 5])); + const char = String.fromCharCode(Number(inputs.dg1[i + 5])); assert(reveal_unpacked[i] == char, 'Should reveal the right character'); } else { assert(reveal_unpacked[i] == '\x00', 'Should not reveal'); diff --git a/circuits/tests/other_circuits/leaf_hasher.test.ts b/circuits/tests/other_circuits/leaf_hasher.test.ts index 9802dd69..6fd74b58 100644 --- a/circuits/tests/other_circuits/leaf_hasher.test.ts +++ b/circuits/tests/other_circuits/leaf_hasher.test.ts @@ -11,7 +11,7 @@ import { mock_csca_sha1_rsa_2048, mock_dsc_sha256_ecdsa, } from '../../../common/src/constants/mockCertificates'; -import { hexToDecimal, splitToWords } from '../../../common/src/utils/utils'; +import { hexToDecimal, splitToWords, toUnsignedByte } from '../../../common/src/utils/utils'; import { getLeaf, customHasher } from '../../../common/src/utils/pubkeyTree'; import { k_dsc, k_dsc_ecdsa, n_dsc, n_dsc_ecdsa, SignatureAlgorithmIndex } from '../../../common/src/constants/constants'; import { @@ -19,7 +19,7 @@ import { parseDSC, } from '../../../common/src/utils/certificates/handleCertificate'; import { genMockPassportData } from '../../../common/src/utils/genMockPassportData'; -import { generateCircuitInputsInCircuits } from '../utlis/generateMockInputsInCircuits'; +import { generateCircuitInputsInCircuits } from '../utils/generateMockInputsInCircuits'; function loadCertificates(dscCertContent: string, cscaCertContent: string) { const dscCert = new X509Certificate(dscCertContent); @@ -49,27 +49,42 @@ describe('LeafHasher Light', function () { }); - describe('CustomHasher - getLeaf ECDSA', async () => { - const cert = mock_dsc_sha256_ecdsa; - const { signatureAlgorithm, hashFunction, x, y, bits, curve, exponent } = parseCertificate(cert); - console.log(parseCertificate(cert)); - const leaf_light = getLeaf(cert, n_dsc_ecdsa, k_dsc_ecdsa); - console.log('\x1b[34m', 'customHasher output: ', leaf_light, '\x1b[0m'); + // describe('CustomHasher - getLeaf ECDSA', async () => { + // const cert = mock_dsc_sha256_ecdsa; + // const { signatureAlgorithm, hashFunction, x, y, bits, curve, exponent } = parseCertificate(cert); + // console.log(parseCertificate(cert)); + // const leaf_light = getLeaf(cert, n_dsc_ecdsa, k_dsc_ecdsa); + // console.log('\x1b[34m', 'customHasher output: ', leaf_light, '\x1b[0m'); - const passportData = genMockPassportData('ecdsa_sha256', 'FRA', '000101', '300101'); - const mock_inputs = generateCircuitInputsInCircuits(passportData, 'register'); + // const passportData = genMockPassportData('ecdsa_sha256', 'FRA', '000101', '300101'); + // const mock_inputs = generateCircuitInputsInCircuits(passportData, 'register'); - const signatureAlgorithmIndex = SignatureAlgorithmIndex[`${signatureAlgorithm}_${curve || exponent}_${hashFunction}_${bits}`]; - console.log('\x1b[34m', 'signatureAlgorithmIndex: ', signatureAlgorithmIndex, '\x1b[0m'); + // const signatureAlgorithmIndex = SignatureAlgorithmIndex[`${signatureAlgorithm}_${curve || exponent}_${hashFunction}_${bits}`]; + // console.log('\x1b[34m', 'signatureAlgorithmIndex: ', signatureAlgorithmIndex, '\x1b[0m'); + // it('should extract and log certificate information', async () => { + // const inputs = { + // in: mock_inputs.pubKey, + // sigAlg: signatureAlgorithmIndex, + // }; + // const witness = await circuit.calculateWitness(inputs, true); + // const leafValueCircom = (await circuit.getOutput(witness, ['out'])).out; + // console.log('\x1b[34m', 'leafValueCircom: ', leafValueCircom, '\x1b[0m'); + // expect(leafValueCircom).to.equal(leaf_light); + // }); + // }); + + describe('CustomHasher - customHasher', async () => { + const passportData = genMockPassportData('rsa_sha256', 'FRA', '000101', '300101'); it('should extract and log certificate information', async () => { const inputs = { - in: mock_inputs.pubKey, - sigAlg: signatureAlgorithmIndex, + in: passportData.dg2Hash.map((x) => toUnsignedByte(x).toString()), }; const witness = await circuit.calculateWitness(inputs, true); const leafValueCircom = (await circuit.getOutput(witness, ['out'])).out; - console.log('\x1b[34m', 'leafValueCircom: ', leafValueCircom, '\x1b[0m'); - expect(leafValueCircom).to.equal(leaf_light); + console.log('\x1b[34m', 'hashValueCircom: ', leafValueCircom, '\x1b[0m'); + + const hashValue = customHasher(passportData.dg2Hash.map((x) => toUnsignedByte(x).toString())); + console.log('\x1b[34m', 'hashValue: ', hashValue, '\x1b[0m'); }); }); diff --git a/circuits/tests/utlis/generateMockInputsInCircuits.ts b/circuits/tests/utils/generateMockInputsInCircuits.ts similarity index 100% rename from circuits/tests/utlis/generateMockInputsInCircuits.ts rename to circuits/tests/utils/generateMockInputsInCircuits.ts diff --git a/common/src/utils/commitmentTree.ts b/common/src/utils/commitmentTree.ts deleted file mode 100644 index fa28286b..00000000 --- a/common/src/utils/commitmentTree.ts +++ /dev/null @@ -1,5 +0,0 @@ -// import { LeanIMT } from "@zk-kit/lean-imt"; -// import { poseidon2 } from "poseidon-lite"; -// import axios from "axios"; -// import { COMMITMENT_TREE_TRACKER_URL } from "../constants/constants"; - diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index b8cea1e8..1b34aba1 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -19,7 +19,7 @@ import { parseUIDToBigInt, } from './utils'; import { LeanIMT } from "@zk-kit/lean-imt"; -import { getLeaf } from "./pubkeyTree"; +import { generateCommitment, getLeaf } from "./pubkeyTree"; import { getNameLeaf, getNameDobLeaf, getPassportNumberLeaf } from "./ofacTree"; import { poseidon6 } from "poseidon-lite"; import { packBytes } from "../utils/utils"; @@ -124,20 +124,16 @@ export function generateCircuitInputsDisclose( majority: string, bitmap: string[], scope: string, - user_identifier: string + user_identifier: string, + n_dsc: number, + k_dsc: number ) { const pubkey_leaf = getLeaf(passportData.dsc, n_dsc, k_dsc); const formattedMrz = formatMrz(passportData.mrz); const mrz_bytes = packBytes(formattedMrz); - const commitment = poseidon6([ - secret, - attestation_id, - pubkey_leaf, - mrz_bytes[0], - mrz_bytes[1], - mrz_bytes[2], - ]); + + const commitment = generateCommitment(secret, attestation_id, pubkey_leaf, mrz_bytes, passportData.dg2Hash.map((x) => toUnsignedByte(x).toString())); const index = findIndexInTree(merkletree, commitment); @@ -151,7 +147,8 @@ export function generateCircuitInputsDisclose( secret: [secret], attestation_id: [attestation_id], pubkey_leaf: [pubkey_leaf.toString()], - mrz: formattedMrz.map((byte) => String(byte)), + dg1: formattedMrz.map((byte) => String(byte)), + dg2_hash: passportData.dg2Hash.map((x) => toUnsignedByte(x).toString()), merkle_root: [merkletree.root.toString()], merkletree_size: [BigInt(depthForThisOne).toString()], path: merkleProofIndices.map((index) => BigInt(index).toString()), diff --git a/common/src/utils/pubkeyTree.ts b/common/src/utils/pubkeyTree.ts index 615e957c..1eeadc4f 100644 --- a/common/src/utils/pubkeyTree.ts +++ b/common/src/utils/pubkeyTree.ts @@ -1,7 +1,7 @@ import { PUBKEY_TREE_DEPTH, COMMITMENT_TREE_TRACKER_URL, SignatureAlgorithmIndex } from "../constants/constants"; import { LeanIMT } from '@zk-kit/imt' import axios from "axios"; -import { poseidon16, poseidon2 } from 'poseidon-lite'; +import { poseidon16, poseidon2, poseidon6, poseidon7 } from 'poseidon-lite'; import { hexToDecimal, splitToWords } from './utils'; import { parseCertificate } from "./certificates/handleCertificate"; import { flexiblePoseidon } from "./poseidon"; @@ -53,4 +53,19 @@ export async function getTreeFromTracker(): Promise { ); imt.import(response.data) return imt +} + +export function generateCommitment(secret: string, attestation_id: string, pubkey_leaf: string, mrz_bytes: any[], dg2Hash: any[]) { + const dg2Hash2 = customHasher(dg2Hash); + console.log("dg2Hash in js", dg2Hash2); + const commitment = poseidon7([ + secret, + attestation_id, + pubkey_leaf, + mrz_bytes[0], + mrz_bytes[1], + mrz_bytes[2], + dg2Hash2 + ]); + return commitment; } \ No newline at end of file From eb465057a4a2b6c76d8e0d3e571d2e729067ad5a Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Wed, 18 Sep 2024 20:16:29 +0200 Subject: [PATCH 34/60] pad dg2_hash to length 64, fix commitment generation --- .../circuits/disclose/vc_and_disclose.circom | 11 +- .../disclose/verify_commitment.circom | 9 +- .../circuits/prove/openpassport_prove.circom | 5 +- .../register/openpassport_register.circom | 5 +- .../utils/passport/computeCommitment.circom | 9 +- .../utils/passport/passportVerifier.circom | 2 +- circuits/scripts/build_register_circuits.sh | 6 +- circuits/tests/disclose/disclose.test.ts | 6 +- circuits/tests/prove.test.ts | 14 +- circuits/tests/register.test.ts | 128 ++++++++---------- common/src/utils/generateInputs.ts | 7 +- common/src/utils/pubkeyTree.ts | 5 +- common/src/utils/utils.ts | 8 ++ 13 files changed, 106 insertions(+), 109 deletions(-) diff --git a/circuits/circuits/disclose/vc_and_disclose.circom b/circuits/circuits/disclose/vc_and_disclose.circom index 7d021ad1..005a06a4 100644 --- a/circuits/circuits/disclose/vc_and_disclose.circom +++ b/circuits/circuits/disclose/vc_and_disclose.circom @@ -2,17 +2,14 @@ pragma circom 2.1.5; include "./verify_commitment.circom"; include "./disclose.circom"; -include "../utils/passport/signatureAlgorithm.circom"; -template VC_AND_DISCLOSE(signatureAlgorithm, nLevels) { - var HASH_LEN_BITS = getHashLength(signatureAlgorithm); - var HASH_LEN_BYTES = HASH_LEN_BITS / 8; +template VC_AND_DISCLOSE( nLevels) { signal input secret; signal input attestation_id; signal input pubkey_leaf; signal input dg1[93]; - signal input dg2_hash[HASH_LEN_BYTES]; + signal input dg2_hash[64]; signal input merkle_root; signal input merkletree_size; @@ -26,7 +23,7 @@ template VC_AND_DISCLOSE(signatureAlgorithm, nLevels) { signal input user_identifier; // verify commitment is part of the merkle tree - VERIFY_COMMITMENT(signatureAlgorithm, nLevels)(secret, attestation_id, pubkey_leaf, dg1, dg2_hash, merkle_root, merkletree_size, path, siblings); + VERIFY_COMMITMENT(nLevels)(secret, attestation_id, pubkey_leaf, dg1, dg2_hash, merkle_root, merkletree_size, path, siblings); // verify passport validity and disclose optional data component disclose = DISCLOSE(); @@ -43,4 +40,4 @@ template VC_AND_DISCLOSE(signatureAlgorithm, nLevels) { signal output revealedData_packed[3] <== disclose.revealedData_packed; } -component main { public [ merkle_root, scope, user_identifier, current_date, attestation_id] } = VC_AND_DISCLOSE(1,16); \ No newline at end of file +component main { public [ merkle_root, scope, user_identifier, current_date, attestation_id] } = VC_AND_DISCLOSE(16); \ No newline at end of file diff --git a/circuits/circuits/disclose/verify_commitment.circom b/circuits/circuits/disclose/verify_commitment.circom index 78a9a22d..b0b55a34 100644 --- a/circuits/circuits/disclose/verify_commitment.circom +++ b/circuits/circuits/disclose/verify_commitment.circom @@ -5,23 +5,20 @@ include "../utils/other/bytes.circom"; include "binary-merkle-root.circom"; include "../utils/passport/computeCommitment.circom"; -template VERIFY_COMMITMENT(signatureAlgorithm, nLevels) { - var HASH_LEN_BITS = getHashLength(signatureAlgorithm); - var HASH_LEN_BYTES = HASH_LEN_BITS / 8; +template VERIFY_COMMITMENT( nLevels) { signal input secret; signal input attestation_id; signal input pubkey_leaf; signal input dg1[93]; - signal input dg2_hash[HASH_LEN_BYTES]; + signal input dg2_hash[64]; signal input merkle_root; signal input merkletree_size; signal input path[nLevels]; signal input siblings[nLevels]; - signal commitment <== ComputeCommitment(signatureAlgorithm)(secret, attestation_id, pubkey_leaf, dg1, dg2_hash); - + signal commitment <== ComputeCommitment()(secret, attestation_id, pubkey_leaf, dg1, dg2_hash); // Verify commitment inclusion signal computedRoot <== BinaryMerkleRoot(nLevels)(commitment, merkletree_size, path, siblings); merkle_root === computedRoot; diff --git a/circuits/circuits/prove/openpassport_prove.circom b/circuits/circuits/prove/openpassport_prove.circom index 06e2c413..d8b6f54c 100644 --- a/circuits/circuits/prove/openpassport_prove.circom +++ b/circuits/circuits/prove/openpassport_prove.circom @@ -5,6 +5,7 @@ include "../utils/passport/computeCommitment.circom"; include "../utils/passport/signatureAlgorithm.circom"; include "../utils/passport/passportVerifier.circom"; include "../disclose/disclose.circom"; + template OPENPASSPORT_PROVE(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN) { var kLengthFactor = getKLengthFactor(signatureAlgorithm); var kScaled = k * kLengthFactor; @@ -14,7 +15,7 @@ template OPENPASSPORT_PROVE(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, M signal input dg1[93]; signal input dg1_hash_offset; - signal input dg2_hash[HASH_LEN_BYTES]; + signal input dg2_hash[64]; signal input econtent[MAX_ECONTENT_PADDED_LEN]; signal input econtent_padded_length; signal input signed_attr[MAX_SIGNED_ATTR_PADDED_LEN]; @@ -36,7 +37,7 @@ template OPENPASSPORT_PROVE(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, M signal input user_identifier; component disclose = DISCLOSE(); - disclose.mrz <== dg1; + disclose.dg1 <== dg1; disclose.bitmap <== bitmap; disclose.current_date <== current_date; disclose.majority <== majority; diff --git a/circuits/circuits/register/openpassport_register.circom b/circuits/circuits/register/openpassport_register.circom index d202ee8e..b2632128 100644 --- a/circuits/circuits/register/openpassport_register.circom +++ b/circuits/circuits/register/openpassport_register.circom @@ -16,7 +16,7 @@ template OPENPASSPORT_REGISTER(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN signal input dsc_secret; signal input dg1[93]; signal input dg1_hash_offset; - signal input dg2_hash[HASH_LEN_BYTES]; + signal input dg2_hash[64]; signal input econtent[MAX_ECONTENT_PADDED_LEN]; signal input econtent_padded_length; signal input signed_attr[MAX_SIGNED_ATTR_PADDED_LEN]; @@ -35,8 +35,7 @@ template OPENPASSPORT_REGISTER(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN signal leaf <== LeafHasher(kScaled)(pubKey, signatureAlgorithm); // commitment - signal output commitment <== ComputeCommitment()(secret, attestation_id, leaf, dg1); - + signal output commitment <== ComputeCommitment()(secret, attestation_id, leaf, dg1, dg2_hash); // blinded dsc commitment signal output blinded_dsc_commitment <== Poseidon(2)([dsc_secret, leaf]); diff --git a/circuits/circuits/utils/passport/computeCommitment.circom b/circuits/circuits/utils/passport/computeCommitment.circom index 17e20fcd..a622d26f 100644 --- a/circuits/circuits/utils/passport/computeCommitment.circom +++ b/circuits/circuits/utils/passport/computeCommitment.circom @@ -2,18 +2,15 @@ pragma circom 2.1.9; include "circomlib/circuits/poseidon.circom"; include "../other/bytes.circom"; -include "./signatureAlgorithm.circom"; include "./CustomHashers.circom"; -template ComputeCommitment(signatureAlgorithm) { - var HASH_LEN_BITS = getHashLength(signatureAlgorithm); - var HASH_LEN_BYTES = HASH_LEN_BITS / 8; +template ComputeCommitment() { signal input secret; signal input attestation_id; signal input leaf; signal input dg1[93]; - signal input dg2_hash[HASH_LEN_BYTES]; + signal input dg2_hash[64]; signal output out; component poseidon_hasher = Poseidon(7); @@ -26,7 +23,7 @@ template ComputeCommitment(signatureAlgorithm) { poseidon_hasher.inputs[i + 3] <== dg1_packed[i]; } - signal dg2Hash2 <== CustomHasher(HASH_LEN_BYTES)(dg2_hash); + signal dg2Hash2 <== CustomHasher(64)(dg2_hash); poseidon_hasher.inputs[6] <== dg2Hash2; diff --git a/circuits/circuits/utils/passport/passportVerifier.circom b/circuits/circuits/utils/passport/passportVerifier.circom index a632760d..7c28626f 100644 --- a/circuits/circuits/utils/passport/passportVerifier.circom +++ b/circuits/circuits/utils/passport/passportVerifier.circom @@ -16,7 +16,7 @@ template PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_LEN, MAX_SIGNED signal input dg1[93]; signal input dg1_hash_offset; - signal input dg2_hash[HASH_LEN_BYTES]; + signal input dg2_hash[64]; signal input econtent[MAX_ECONTENT_LEN]; signal input econtent_padded_length; signal input signed_attr[MAX_SIGNED_ATTR_LEN]; diff --git a/circuits/scripts/build_register_circuits.sh b/circuits/scripts/build_register_circuits.sh index 2b8243a7..80ea0fa5 100755 --- a/circuits/scripts/build_register_circuits.sh +++ b/circuits/scripts/build_register_circuits.sh @@ -32,9 +32,11 @@ build_circuit() { # name:folder:build_flag # set build_flag to false if you want to skip the build CIRCUITS=( - "register_rsa_65537_sha256:register:true" + "register_rsa_65537_sha256:register:false" "register_rsa_65537_sha1:register:true" - "register_rsapss_65537_sha256:register:true" + "register_rsapss_65537_sha256:register:false" + "register_ecdsa_sha256:register:false" + "register_ecdsa_sha1:register:false" ) TOTAL_START_TIME=$(date +%s) diff --git a/circuits/tests/disclose/disclose.test.ts b/circuits/tests/disclose/disclose.test.ts index d4d7091f..8fa02f10 100644 --- a/circuits/tests/disclose/disclose.test.ts +++ b/circuits/tests/disclose/disclose.test.ts @@ -1,7 +1,7 @@ import { assert, expect } from 'chai'; import path from 'path'; import { wasm as wasm_tester } from 'circom_tester'; -import { formatMrz, packBytes, toUnsignedByte } from '../../../common/src/utils/utils'; +import { formatDg2Hash, formatMrz, packBytes, toUnsignedByte } from '../../../common/src/utils/utils'; import { attributeToPosition, k_dsc, @@ -46,8 +46,8 @@ describe('Disclose', function () { // compute the commitment and insert it in the tree const pubkey_leaf = getLeaf(passportData.dsc, n_dsc, k_dsc).toString(); const mrz_bytes = packBytes(formatMrz(passportData.mrz)); - const commitment = generateCommitment(secret, PASSPORT_ATTESTATION_ID, pubkey_leaf, mrz_bytes, passportData.dg2Hash.map((x) => toUnsignedByte(x).toString())); - console.log("commitment", commitment); + const commitment = generateCommitment(secret, PASSPORT_ATTESTATION_ID, pubkey_leaf, mrz_bytes, passportData.dg2Hash); + console.log("commitment in js ", commitment); tree = new LeanIMT((a, b) => poseidon2([a, b]), []); tree.insert(BigInt(commitment)); diff --git a/circuits/tests/prove.test.ts b/circuits/tests/prove.test.ts index e7526dfb..cae63194 100644 --- a/circuits/tests/prove.test.ts +++ b/circuits/tests/prove.test.ts @@ -13,6 +13,8 @@ const sigAlgs = [ { sigAlg: 'rsa', hashFunction: 'sha1' }, { sigAlg: 'rsa', hashFunction: 'sha256' }, { sigAlg: 'rsapss', hashFunction: 'sha256' }, + { sigAlg: 'ecdsa', hashFunction: 'sha256' }, + { sigAlg: 'ecdsa', hashFunction: 'sha1' }, ]; sigAlgs.forEach(({ sigAlg, hashFunction }) => { @@ -45,7 +47,7 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { circuit = await wasm_tester( path.join( __dirname, - `../circuits/prove/${getCircuitName('prove', sigAlg, hashFunction)}.circom` + `../circuits/prove/instances/${getCircuitName('prove', sigAlg, hashFunction)}.circom` ), { include: [ @@ -64,8 +66,8 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { it('should calculate the witness with correct inputs', async function () { const w = await circuit.calculateWitness(inputs); await circuit.checkConstraints(w); - const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; + console.log('\x1b[34m%s\x1b[0m', 'nullifier', nullifier); expect(nullifier).to.be.not.null; }); @@ -73,7 +75,7 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { try { const invalidInputs = { ...inputs, - mrz: Array(93) + dg1: Array(93) .fill(0) .map((byte) => BigInt(byte).toString()), }; @@ -84,11 +86,11 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { } }); - it('should fail to calculate witness with invalid dataHashes', async function () { + it('should fail to calculate witness with invalid econtent', async function () { try { const invalidInputs = { ...inputs, - dataHashes: inputs.dataHashes.map((byte: string) => + econtent: inputs.econtent.map((byte: string) => String((parseInt(byte, 10) + 1) % 256) ), }; @@ -111,5 +113,7 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { expect(error.message).to.include('Assert Failed'); } }); + + }); }); diff --git a/circuits/tests/register.test.ts b/circuits/tests/register.test.ts index 82fe17b7..f6a96d25 100644 --- a/circuits/tests/register.test.ts +++ b/circuits/tests/register.test.ts @@ -4,7 +4,7 @@ import path from 'path'; import { wasm as wasm_tester } from 'circom_tester'; import { poseidon6 } from 'poseidon-lite'; import { generateCircuitInputsRegister } from '../../common/src/utils/generateInputs'; -import { hexToDecimal, packBytes } from '../../common/src/utils/utils'; +import { formatMrz, hexToDecimal, packBytes } from '../../common/src/utils/utils'; import { n_dsc, k_dsc, @@ -14,13 +14,15 @@ import { } from '../../common/src/constants/constants'; import { genMockPassportData } from '../../common/src/utils/genMockPassportData'; import { getCircuitName, parseDSC } from '../../common/src/utils/certificates/handleCertificate'; -import { getLeaf } from '../../common/src/utils/pubkeyTree'; +import { generateCommitment, getLeaf } from '../../common/src/utils/pubkeyTree'; import { SignatureAlgorithm } from '../../common/src/utils/types'; const sigAlgs = [ { sigAlg: 'rsa', hashFunction: 'sha256' }, { sigAlg: 'rsa', hashFunction: 'sha1' }, { sigAlg: 'ecdsa', hashFunction: 'sha256' }, + { sigAlg: 'rsapss', hashFunction: 'sha256' }, + { sigAlg: 'ecdsa', hashFunction: 'sha1' }, ]; sigAlgs.forEach(({ sigAlg, hashFunction }) => { @@ -67,9 +69,11 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { }); it('should calculate the witness with correct inputs', async function () { - console.log('inputs', inputs); + // console.log('inputs', inputs); const w = await circuit.calculateWitness(inputs); - await circuit.checkConstraints(w); + // await circuit.checkConstraints(w); + + // const output = await circuit.getOutput(w); const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; console.log('\x1b[34m%s\x1b[0m', 'nullifier', nullifier); @@ -81,71 +85,59 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { .blinded_dsc_commitment; console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment', blinded_dsc_commitment); - // const n = sigAlg === 'ecdsa' ? n_dsc_ecdsa : n_dsc; - // const k = sigAlg === 'ecdsa' ? k_dsc_ecdsa : k_dsc; - // const mrz_bytes = packBytes(inputs.mrz); - // const leaf = getLeaf(passportData.dsc, n, k).toString(); - - // const commitment_bytes = poseidon6([ - // inputs.secret[0], - // PASSPORT_ATTESTATION_ID, - // leaf, - // mrz_bytes[0], - // mrz_bytes[1], - // mrz_bytes[2], - // ]); - // const commitment_js = commitment_bytes.toString(); - // console.log('commitment_js', commitment_js); - // console.log('commitment_circom', commitment_circom); - // expect(commitment_circom).to.be.equal(commitment_js); + const n = sigAlg === 'ecdsa' ? n_dsc_ecdsa : n_dsc; + const k = sigAlg === 'ecdsa' ? k_dsc_ecdsa : k_dsc; + const mrz_bytes = packBytes(inputs.dg1); + const leaf = getLeaf(passportData.dsc, n, k).toString(); + const commitment_bytes = generateCommitment(secret, PASSPORT_ATTESTATION_ID, leaf, mrz_bytes, passportData.dg2Hash); + const commitment_js = commitment_bytes.toString(); + console.log('commitment_js', commitment_js); + console.log('commitment_circom', commitment_circom); + expect(commitment_circom).to.be.equal(commitment_js); + }); + + it('should fail to calculate witness with invalid mrz', async function () { + try { + const invalidInputs = { + ...inputs, + dg1: Array(93) + .fill(0) + .map((byte) => BigInt(byte).toString()), + }; + await circuit.calculateWitness(invalidInputs); + expect.fail(); + } catch (error) { + // expect(error.message).to.include('Assert Failed'); + } + }); + + it('should fail to calculate witness with invalid econtent', async function () { + try { + const invalidInputs = { + ...inputs, + econtent: inputs.econtent.map((byte: string) => + String((parseInt(byte, 10) + 1) % 256) + ), + }; + await circuit.calculateWitness(invalidInputs); + expect.fail('Expected an error but none was thrown.'); + } catch (error) { + // expect(error.message).to.include('Assert Failed'); + } + }); + + it('should fail to calculate witness with invalid signature', async function () { + try { + const invalidInputs = { + ...inputs, + signature: inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), + }; + await circuit.calculateWitness(invalidInputs); + expect.fail('Expected an error but none was thrown.'); + } catch (error) { + // expect(error.message).to.include('Assert Failed'); + } }); - // it('should fail to calculate witness with invalid mrz', async function () { - // try { - // const invalidInputs = { - // ...inputs, - // mrz: Array(93) - // .fill(0) - // .map((byte) => BigInt(byte).toString()), - // }; - // await circuit.calculateWitness(invalidInputs); - // expect.fail('Expected an error but none was thrown.'); - // } catch (error) { - // expect(error.message).to.include('Assert Failed'); - // } - // }); - - // it('should fail to calculate witness with invalid dataHashes', async function () { - // try { - // const invalidInputs = { - // ...inputs, - // dataHashes: inputs.dataHashes.map((byte: string) => - // String((parseInt(byte, 10) + 1) % 256) - // ), - // }; - // await circuit.calculateWitness(invalidInputs); - // expect.fail('Expected an error but none was thrown.'); - // } catch (error) { - // expect(error.message).to.include('Assert Failed'); - // } - // }); - - // it('should fail to calculate witness with invalid signature', async function () { - // try { - // const invalidInputs = { - // ...inputs, - // signature: inputs.signature - // ? inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)) - // : undefined, - // signature_s: inputs.signature_s - // ? inputs.signature_s.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)) - // : undefined, - // }; - // await circuit.calculateWitness(invalidInputs); - // expect.fail('Expected an error but none was thrown.'); - // } catch (error) { - // expect(error.message).to.include('Assert Failed'); - // } - // }); }); }); diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index 1b34aba1..b13e739e 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -17,6 +17,7 @@ import { castFromUUID, castFromScope, parseUIDToBigInt, + formatDg2Hash, } from './utils'; import { LeanIMT } from "@zk-kit/lean-imt"; import { generateCommitment, getLeaf } from "./pubkeyTree"; @@ -104,7 +105,7 @@ export function generateCircuitInputsRegister( dsc_secret: [dscSecret], dg1: dg1.map(byte => String(byte)), dg1_hash_offset: [dg1HashOffset.toString()], // uncomment when adding new circuits - dg2_hash: dg2Hash.map((x) => toUnsignedByte(x).toString()), + dg2_hash: formatDg2Hash(dg2Hash), econtent: Array.from(eContentPadded).map((x) => x.toString()), econtent_padded_length: [eContentLen.toString()], signed_attr: Array.from(signedAttrPadded).map((x) => x.toString()), @@ -133,7 +134,7 @@ export function generateCircuitInputsDisclose( const formattedMrz = formatMrz(passportData.mrz); const mrz_bytes = packBytes(formattedMrz); - const commitment = generateCommitment(secret, attestation_id, pubkey_leaf, mrz_bytes, passportData.dg2Hash.map((x) => toUnsignedByte(x).toString())); + const commitment = generateCommitment(secret, attestation_id, pubkey_leaf, mrz_bytes, passportData.dg2Hash); const index = findIndexInTree(merkletree, commitment); @@ -148,7 +149,7 @@ export function generateCircuitInputsDisclose( attestation_id: [attestation_id], pubkey_leaf: [pubkey_leaf.toString()], dg1: formattedMrz.map((byte) => String(byte)), - dg2_hash: passportData.dg2Hash.map((x) => toUnsignedByte(x).toString()), + dg2_hash: formatDg2Hash(passportData.dg2Hash), merkle_root: [merkletree.root.toString()], merkletree_size: [BigInt(depthForThisOne).toString()], path: merkleProofIndices.map((index) => BigInt(index).toString()), diff --git a/common/src/utils/pubkeyTree.ts b/common/src/utils/pubkeyTree.ts index 1eeadc4f..791082dd 100644 --- a/common/src/utils/pubkeyTree.ts +++ b/common/src/utils/pubkeyTree.ts @@ -2,7 +2,7 @@ import { PUBKEY_TREE_DEPTH, COMMITMENT_TREE_TRACKER_URL, SignatureAlgorithmIndex import { LeanIMT } from '@zk-kit/imt' import axios from "axios"; import { poseidon16, poseidon2, poseidon6, poseidon7 } from 'poseidon-lite'; -import { hexToDecimal, splitToWords } from './utils'; +import { formatDg2Hash, hexToDecimal, splitToWords } from './utils'; import { parseCertificate } from "./certificates/handleCertificate"; import { flexiblePoseidon } from "./poseidon"; @@ -56,8 +56,7 @@ export async function getTreeFromTracker(): Promise { } export function generateCommitment(secret: string, attestation_id: string, pubkey_leaf: string, mrz_bytes: any[], dg2Hash: any[]) { - const dg2Hash2 = customHasher(dg2Hash); - console.log("dg2Hash in js", dg2Hash2); + const dg2Hash2 = customHasher(formatDg2Hash(dg2Hash).map(x => x.toString())); const commitment = poseidon7([ secret, attestation_id, diff --git a/common/src/utils/utils.ts b/common/src/utils/utils.ts index bdc091e0..c1d4d392 100644 --- a/common/src/utils/utils.ts +++ b/common/src/utils/utils.ts @@ -16,6 +16,14 @@ export function formatMrz(mrz: string) { return mrzCharcodes; } +export function formatDg2Hash(dg2Hash: number[]) { + const unsignedBytesDg2Hash = dg2Hash.map((x) => toUnsignedByte(x)); + while (unsignedBytesDg2Hash.length < 64) { // pad it to 64 bytes to correspond to the hash length of sha512 and avoid multiplying circuits + unsignedBytesDg2Hash.push(0); + } + return unsignedBytesDg2Hash; +} + export function formatAndConcatenateDataHashes( dataHashes: [number, number[]][], hashLen: number, From 67f124b6fba6adaa0a087a79cd5a8b699b6995bb Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Wed, 18 Sep 2024 20:25:30 +0200 Subject: [PATCH 35/60] fix ofac tests --- circuits/circuits/ofac/ofac_name.circom | 7 ++-- circuits/circuits/ofac/ofac_name_dob.circom | 9 ++--- .../circuits/ofac/ofac_passport_number.circom | 9 ++--- circuits/circuits/utils/smt.circom | 2 +- circuits/tests/ofac/ofac.test.ts | 35 +++++++++++-------- common/src/utils/generateInputs.ts | 4 ++- 6 files changed, 38 insertions(+), 28 deletions(-) diff --git a/circuits/circuits/ofac/ofac_name.circom b/circuits/circuits/ofac/ofac_name.circom index 43a5050f..a92e6666 100644 --- a/circuits/circuits/ofac/ofac_name.circom +++ b/circuits/circuits/ofac/ofac_name.circom @@ -11,7 +11,8 @@ template OFAC_NAME(nLevels) { signal input secret; signal input attestation_id; signal input pubkey_leaf; - signal input mrz[93]; + signal input dg1[93]; + signal input dg2_hash[64]; signal input merkle_root; signal input merkletree_size; signal input path[nLevels]; @@ -25,14 +26,14 @@ template OFAC_NAME(nLevels) { signal output proofLevel; // Verify commitment is part of the merkle tree - VERIFY_COMMITMENT(nLevels)(secret, attestation_id, pubkey_leaf, mrz, merkle_root, merkletree_size, path, siblings); + VERIFY_COMMITMENT(nLevels)(secret, attestation_id, pubkey_leaf, dg1, dg2_hash, merkle_root, merkletree_size, path, siblings); // Name Hash component poseidon_hasher[3]; for (var j = 0; j < 3; j++) { poseidon_hasher[j] = Poseidon(13); for (var i = 0; i < 13; i++) { - poseidon_hasher[j].inputs[i] <== mrz[10 + 13 * j + i]; + poseidon_hasher[j].inputs[i] <== dg1[10 + 13 * j + i]; } } diff --git a/circuits/circuits/ofac/ofac_name_dob.circom b/circuits/circuits/ofac/ofac_name_dob.circom index 5be8071b..32b7925e 100644 --- a/circuits/circuits/ofac/ofac_name_dob.circom +++ b/circuits/circuits/ofac/ofac_name_dob.circom @@ -12,7 +12,8 @@ template OFAC_NAME_DOB(nLevels) { signal input secret; signal input attestation_id; signal input pubkey_leaf; - signal input mrz[93]; + signal input dg1[93]; + signal input dg2_hash[64]; signal input merkle_root; signal input merkletree_size; signal input path[nLevels]; @@ -25,14 +26,14 @@ template OFAC_NAME_DOB(nLevels) { signal output proofLevel; // Verify commitment is part of the merkle tree - VERIFY_COMMITMENT(nLevels)(secret, attestation_id, pubkey_leaf, mrz, merkle_root, merkletree_size, path, siblings); + VERIFY_COMMITMENT(nLevels)(secret, attestation_id, pubkey_leaf, dg1, dg2_hash, merkle_root, merkletree_size, path, siblings); // Name Hash component poseidon_hasher[3]; for (var j = 0; j < 3; j++) { poseidon_hasher[j] = Poseidon(13); for (var i = 0; i < 13; i++) { - poseidon_hasher[j].inputs[i] <== mrz[10 + 13 * j + i]; + poseidon_hasher[j].inputs[i] <== dg1[10 + 13 * j + i]; } } signal name_hash <== Poseidon(3)([poseidon_hasher[0].out, poseidon_hasher[1].out, poseidon_hasher[2].out]); @@ -40,7 +41,7 @@ template OFAC_NAME_DOB(nLevels) { // Dob hash component pos_dob = Poseidon(6); for(var i = 0; i < 6; i++) { - pos_dob.inputs[i] <== mrz[62 + i]; + pos_dob.inputs[i] <== dg1[62 + i]; } // NameDob hash diff --git a/circuits/circuits/ofac/ofac_passport_number.circom b/circuits/circuits/ofac/ofac_passport_number.circom index 48d79ed1..bbc414ee 100644 --- a/circuits/circuits/ofac/ofac_passport_number.circom +++ b/circuits/circuits/ofac/ofac_passport_number.circom @@ -3,7 +3,7 @@ pragma circom 2.1.5; include "circomlib/circuits/poseidon.circom"; include "circomlib/circuits/comparators.circom"; include "circomlib/circuits/bitify.circom"; -include "@zk-email/circuits/utils/array.circom"; +include "../utils/other/array.circom"; include "binary-merkle-root.circom"; include "../utils/getCommonLength.circom"; include "../disclose/verify_commitment.circom"; @@ -13,7 +13,8 @@ template OFAC_PASSPORT_NUMBER(nLevels) { signal input secret; signal input attestation_id; signal input pubkey_leaf; - signal input mrz[93]; + signal input dg1[93]; + signal input dg2_hash[64]; signal input merkle_root; signal input merkletree_size; signal input path[nLevels]; @@ -26,12 +27,12 @@ template OFAC_PASSPORT_NUMBER(nLevels) { signal output proofLevel; // Verify commitment is part of the merkle tree - VERIFY_COMMITMENT(nLevels)(secret, attestation_id, pubkey_leaf, mrz, merkle_root, merkletree_size, path, siblings); + VERIFY_COMMITMENT(nLevels)(secret, attestation_id, pubkey_leaf, dg1, dg2_hash, merkle_root, merkletree_size, path, siblings); // PassportNo Hash component poseidon_hasher = Poseidon(9); for (var i = 0; i < 9; i++) { - poseidon_hasher.inputs[i] <== mrz[49 + i]; + poseidon_hasher.inputs[i] <== dg1[49 + i]; } signal smtleaf_hash <== Poseidon(3)([poseidon_hasher.out, 1,1]); diff --git a/circuits/circuits/utils/smt.circom b/circuits/circuits/utils/smt.circom index 612d106a..14bffa06 100644 --- a/circuits/circuits/utils/smt.circom +++ b/circuits/circuits/utils/smt.circom @@ -3,7 +3,7 @@ pragma circom 2.1.5; include "circomlib/circuits/poseidon.circom"; include "circomlib/circuits/comparators.circom"; include "circomlib/circuits/bitify.circom"; -include "@zk-email/circuits/utils/array.circom"; +include "./other/array.circom"; include "binary-merkle-root.circom"; include "getCommonLength.circom"; diff --git a/circuits/tests/ofac/ofac.test.ts b/circuits/tests/ofac/ofac.test.ts index e8e978b9..cf2127cb 100644 --- a/circuits/tests/ofac/ofac.test.ts +++ b/circuits/tests/ofac/ofac.test.ts @@ -2,7 +2,7 @@ import { expect } from 'chai'; import path from 'path'; import { wasm as wasm_tester } from 'circom_tester'; import { generateCircuitInputsOfac } from '../../../common/src/utils/generateInputs'; -import { getLeaf } from '../../../common/src/utils/pubkeyTree'; +import { generateCommitment, getLeaf } from '../../../common/src/utils/pubkeyTree'; import { SMT } from '@ashpect/smt'; import { poseidon1, poseidon2, poseidon6 } from 'poseidon-lite'; import { LeanIMT } from '@zk-kit/lean-imt'; @@ -40,14 +40,7 @@ function getPassportInputs(passportData: PassportData) { const pubkey_leaf = getLeaf(passportData.dsc, n_dsc, k_dsc); const mrz_bytes = packBytes(formatMrz(passportData.mrz)); - const commitment = poseidon6([ - secret, - PASSPORT_ATTESTATION_ID, - pubkey_leaf, - mrz_bytes[0], - mrz_bytes[1], - mrz_bytes[2], - ]); + const commitment = generateCommitment(secret, PASSPORT_ATTESTATION_ID, pubkey_leaf, mrz_bytes, passportData.dg2Hash); return { secret: secret, @@ -106,7 +99,9 @@ describe('OFAC - Passport number match', function () { inputs.scope, inputs.user_identifier, passno_smt, - proofLevel + proofLevel, + n_dsc, + k_dsc ); nonMemSmtInputs = generateCircuitInputsOfac( @@ -120,7 +115,9 @@ describe('OFAC - Passport number match', function () { mockInputs.scope, mockInputs.user_identifier, passno_smt, - proofLevel + proofLevel, + n_dsc, + k_dsc ); }); @@ -193,7 +190,9 @@ describe('OFAC - Name and DOB match', function () { inputs.scope, inputs.user_identifier, namedob_smt, - proofLevel + proofLevel, + n_dsc, + k_dsc ); nonMemSmtInputs = generateCircuitInputsOfac( @@ -207,7 +206,9 @@ describe('OFAC - Name and DOB match', function () { mockInputs.scope, mockInputs.user_identifier, namedob_smt, - proofLevel + proofLevel, + n_dsc, + k_dsc ); }); @@ -280,7 +281,9 @@ describe('OFAC - Name match', function () { inputs.scope, inputs.user_identifier, name_smt, - proofLevel + proofLevel, + n_dsc, + k_dsc ); nonMemSmtInputs = generateCircuitInputsOfac( @@ -294,7 +297,9 @@ describe('OFAC - Name match', function () { mockInputs.scope, mockInputs.user_identifier, name_smt, - proofLevel + proofLevel, + n_dsc, + k_dsc ); }); diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index b13e739e..c6213e20 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -173,9 +173,11 @@ export function generateCircuitInputsOfac( user_identifier: string, sparsemerkletree: SMT, proofLevel: number, + n_dsc: number, + k_dsc: number, ) { - const result = generateCircuitInputsDisclose(secret, attestation_id, passportData, merkletree, majority, bitmap, scope, user_identifier); + const result = generateCircuitInputsDisclose(secret, attestation_id, passportData, merkletree, majority, bitmap, scope, user_identifier, n_dsc, k_dsc); const { majority: _, scope: __, bitmap: ___, user_identifier: ____, ...finalResult } = result; const mrz_bytes = formatMrz(passportData.mrz); From 4521b3bd57825719e6a27633aba0f0044b4b85da Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Thu, 19 Sep 2024 10:59:25 +0200 Subject: [PATCH 36/60] move n and k out of generate inputs functions --- circuits/tests/disclose/disclose.test.ts | 8 +--- circuits/tests/ofac/ofac.test.ts | 30 +++++---------- circuits/tests/prove.test.ts | 3 -- circuits/tests/register.test.ts | 17 +++----- common/src/utils/generateInputs.ts | 49 +++++++++--------------- common/src/utils/pubkeyTree.ts | 5 ++- common/src/utils/utils.ts | 7 ++++ 7 files changed, 44 insertions(+), 75 deletions(-) diff --git a/circuits/tests/disclose/disclose.test.ts b/circuits/tests/disclose/disclose.test.ts index 8fa02f10..63c03237 100644 --- a/circuits/tests/disclose/disclose.test.ts +++ b/circuits/tests/disclose/disclose.test.ts @@ -1,11 +1,9 @@ import { assert, expect } from 'chai'; import path from 'path'; import { wasm as wasm_tester } from 'circom_tester'; -import { formatDg2Hash, formatMrz, packBytes, toUnsignedByte } from '../../../common/src/utils/utils'; +import { formatMrz, packBytes } from '../../../common/src/utils/utils'; import { attributeToPosition, - k_dsc, - n_dsc, PASSPORT_ATTESTATION_ID, } from '../../../common/src/constants/constants'; import { poseidon1, poseidon2, poseidon6 } from 'poseidon-lite'; @@ -44,7 +42,7 @@ describe('Disclose', function () { const scope = '@coboyApp'; // compute the commitment and insert it in the tree - const pubkey_leaf = getLeaf(passportData.dsc, n_dsc, k_dsc).toString(); + const pubkey_leaf = getLeaf(passportData.dsc).toString(); const mrz_bytes = packBytes(formatMrz(passportData.mrz)); const commitment = generateCommitment(secret, PASSPORT_ATTESTATION_ID, pubkey_leaf, mrz_bytes, passportData.dg2Hash); console.log("commitment in js ", commitment); @@ -60,8 +58,6 @@ describe('Disclose', function () { bitmap, scope, user_identifier, - n_dsc, - k_dsc ); }); diff --git a/circuits/tests/ofac/ofac.test.ts b/circuits/tests/ofac/ofac.test.ts index cf2127cb..b0cdbbbb 100644 --- a/circuits/tests/ofac/ofac.test.ts +++ b/circuits/tests/ofac/ofac.test.ts @@ -4,14 +4,14 @@ import { wasm as wasm_tester } from 'circom_tester'; import { generateCircuitInputsOfac } from '../../../common/src/utils/generateInputs'; import { generateCommitment, getLeaf } from '../../../common/src/utils/pubkeyTree'; import { SMT } from '@ashpect/smt'; -import { poseidon1, poseidon2, poseidon6 } from 'poseidon-lite'; +import { poseidon2 } from 'poseidon-lite'; import { LeanIMT } from '@zk-kit/lean-imt'; -import { castFromUUID, formatMrz, packBytes } from '../../../common/src/utils/utils'; +import { formatMrz, packBytes } from '../../../common/src/utils/utils'; import passportNojson from '../../../common/ofacdata/outputs/passportNoSMT.json'; import nameDobjson from '../../../common/ofacdata/outputs/nameDobSMT.json'; import namejson from '../../../common/ofacdata/outputs/nameSMT.json'; import { PassportData } from '../../../common/src/utils/types'; -import { k_dsc, n_dsc, PASSPORT_ATTESTATION_ID } from '../../../common/src/constants/constants'; +import { PASSPORT_ATTESTATION_ID } from '../../../common/src/constants/constants'; import crypto from 'crypto'; import { genMockPassportData } from '../../../common/src/utils/genMockPassportData'; @@ -38,7 +38,7 @@ function getPassportInputs(passportData: PassportData) { const bitmap = Array(90).fill('1'); const scope = '@coboyApp'; - const pubkey_leaf = getLeaf(passportData.dsc, n_dsc, k_dsc); + const pubkey_leaf = getLeaf(passportData.dsc); const mrz_bytes = packBytes(formatMrz(passportData.mrz)); const commitment = generateCommitment(secret, PASSPORT_ATTESTATION_ID, pubkey_leaf, mrz_bytes, passportData.dg2Hash); @@ -99,9 +99,7 @@ describe('OFAC - Passport number match', function () { inputs.scope, inputs.user_identifier, passno_smt, - proofLevel, - n_dsc, - k_dsc + proofLevel ); nonMemSmtInputs = generateCircuitInputsOfac( @@ -115,9 +113,7 @@ describe('OFAC - Passport number match', function () { mockInputs.scope, mockInputs.user_identifier, passno_smt, - proofLevel, - n_dsc, - k_dsc + proofLevel ); }); @@ -191,8 +187,6 @@ describe('OFAC - Name and DOB match', function () { inputs.user_identifier, namedob_smt, proofLevel, - n_dsc, - k_dsc ); nonMemSmtInputs = generateCircuitInputsOfac( @@ -206,9 +200,7 @@ describe('OFAC - Name and DOB match', function () { mockInputs.scope, mockInputs.user_identifier, namedob_smt, - proofLevel, - n_dsc, - k_dsc + proofLevel ); }); @@ -281,9 +273,7 @@ describe('OFAC - Name match', function () { inputs.scope, inputs.user_identifier, name_smt, - proofLevel, - n_dsc, - k_dsc + proofLevel ); nonMemSmtInputs = generateCircuitInputsOfac( @@ -297,9 +287,7 @@ describe('OFAC - Name match', function () { mockInputs.scope, mockInputs.user_identifier, name_smt, - proofLevel, - n_dsc, - k_dsc + proofLevel ); }); diff --git a/circuits/tests/prove.test.ts b/circuits/tests/prove.test.ts index cae63194..dd58b18d 100644 --- a/circuits/tests/prove.test.ts +++ b/circuits/tests/prove.test.ts @@ -3,7 +3,6 @@ import { expect } from 'chai'; import path from 'path'; import { wasm as wasm_tester } from 'circom_tester'; import { generateCircuitInputsProve } from '../../common/src/utils/generateInputs'; -import { n_dsc, k_dsc, k_dsc_ecdsa, n_dsc_ecdsa } from '../../common/src/constants/constants'; import { genMockPassportData } from '../../common/src/utils/genMockPassportData'; import { getCircuitName } from '../../common/src/utils/certificates/handleCertificate'; import { SignatureAlgorithm } from '../../common/src/utils/types'; @@ -35,8 +34,6 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { const inputs = generateCircuitInputsProve( passportData, - sigAlg === 'ecdsa' ? n_dsc_ecdsa : n_dsc, - sigAlg === 'ecdsa' ? k_dsc_ecdsa : k_dsc, scope, bitmap, majority, diff --git a/circuits/tests/register.test.ts b/circuits/tests/register.test.ts index f6a96d25..b9422849 100644 --- a/circuits/tests/register.test.ts +++ b/circuits/tests/register.test.ts @@ -2,14 +2,10 @@ import { describe } from 'mocha'; import { assert, expect } from 'chai'; import path from 'path'; import { wasm as wasm_tester } from 'circom_tester'; -import { poseidon6 } from 'poseidon-lite'; +import { } from 'poseidon-lite'; import { generateCircuitInputsRegister } from '../../common/src/utils/generateInputs'; -import { formatMrz, hexToDecimal, packBytes } from '../../common/src/utils/utils'; +import { packBytes } from '../../common/src/utils/utils'; import { - n_dsc, - k_dsc, - n_dsc_ecdsa, - k_dsc_ecdsa, PASSPORT_ATTESTATION_ID, } from '../../common/src/constants/constants'; import { genMockPassportData } from '../../common/src/utils/genMockPassportData'; @@ -43,9 +39,8 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { secret, dscSecret, PASSPORT_ATTESTATION_ID, - passportData, - sigAlg === 'ecdsa' ? n_dsc_ecdsa : n_dsc, - sigAlg === 'ecdsa' ? k_dsc_ecdsa : k_dsc + passportData + ); before(async () => { @@ -85,10 +80,8 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { .blinded_dsc_commitment; console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment', blinded_dsc_commitment); - const n = sigAlg === 'ecdsa' ? n_dsc_ecdsa : n_dsc; - const k = sigAlg === 'ecdsa' ? k_dsc_ecdsa : k_dsc; const mrz_bytes = packBytes(inputs.dg1); - const leaf = getLeaf(passportData.dsc, n, k).toString(); + const leaf = getLeaf(passportData.dsc).toString(); const commitment_bytes = generateCommitment(secret, PASSPORT_ATTESTATION_ID, leaf, mrz_bytes, passportData.dg2Hash); const commitment_js = commitment_bytes.toString(); console.log('commitment_js', commitment_js); diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index c6213e20..82d07498 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -1,13 +1,11 @@ -import { MAX_DATAHASHES_LEN, PUBKEY_TREE_DEPTH, DEVELOPMENT_MODE, DEFAULT_USER_ID_TYPE, MAX_PADDED_ECONTENT_LEN, MAX_PADDED_SIGNED_ATTR_LEN, SignatureAlgorithmIndex } from '../constants/constants'; +import { PUBKEY_TREE_DEPTH, DEFAULT_USER_ID_TYPE, MAX_PADDED_ECONTENT_LEN, MAX_PADDED_SIGNED_ATTR_LEN } from '../constants/constants'; import { assert, shaPad } from './shaPad'; import { PassportData } from './types'; import { - arraysAreEqual, bytesToBigDecimal, formatMrz, hash, splitToWords, - toUnsignedByte, getCurrentDateYYMMDD, generateMerkleProof, generateSMTProof, @@ -18,13 +16,12 @@ import { castFromScope, parseUIDToBigInt, formatDg2Hash, + getNAndK, } from './utils'; import { LeanIMT } from "@zk-kit/lean-imt"; import { generateCommitment, getLeaf } from "./pubkeyTree"; import { getNameLeaf, getNameDobLeaf, getPassportNumberLeaf } from "./ofacTree"; -import { poseidon6 } from "poseidon-lite"; import { packBytes } from "../utils/utils"; -import { getCSCAModulusMerkleTree } from "./csca"; import { SMT } from "@ashpect/smt" import { parseCertificate } from './certificates/handleCertificate'; @@ -33,9 +30,7 @@ export function generateCircuitInputsRegister( secret: string, dscSecret: string, attestation_id: string, - passportData: PassportData, - n_dsc: number, - k_dsc: number + passportData: PassportData ) { const { mrz, eContent, signedAttr, encryptedDigest, dsc, dg2Hash } = passportData; const { signatureAlgorithm, hashFunction, hashLen, x, y, modulus, curve, exponent, bits } = parseCertificate(passportData.dsc); @@ -44,34 +39,32 @@ export function generateCircuitInputsRegister( let pubKey: any; let signature: any; + const { n, k } = getNAndK(signatureAlgorithm); + if (signatureAlgorithm === 'ecdsa') { const { r, s } = extractRSFromSignature(encryptedDigest); - - const signature_r = splitToWords(BigInt(hexToDecimal(r)), n_dsc, k_dsc) - const signature_s = splitToWords(BigInt(hexToDecimal(s)), n_dsc, k_dsc) - + const signature_r = splitToWords(BigInt(hexToDecimal(r)), n, k) + const signature_s = splitToWords(BigInt(hexToDecimal(s)), n, k) signature = [...signature_r, ...signature_s] - const dsc_modulus_x = splitToWords(BigInt(hexToDecimal(x)), n_dsc, k_dsc) - const dsc_modulus_y = splitToWords(BigInt(hexToDecimal(y)), n_dsc, k_dsc) + const dsc_modulus_x = splitToWords(BigInt(hexToDecimal(x)), n, k) + const dsc_modulus_y = splitToWords(BigInt(hexToDecimal(y)), n, k) pubKey = [...dsc_modulus_x, ...dsc_modulus_y] } else { signature = splitToWords( BigInt(bytesToBigDecimal(encryptedDigest)), - n_dsc, - k_dsc + n, + k ) pubKey = splitToWords( BigInt(hexToDecimal(modulus)), - n_dsc, - k_dsc + n, + k ) } - const dg1 = formatMrz(mrz); - const formattedMrz = formatMrz(mrz); const dg1Hash = hash(hashFunction, formattedMrz); @@ -125,11 +118,10 @@ export function generateCircuitInputsDisclose( majority: string, bitmap: string[], scope: string, - user_identifier: string, - n_dsc: number, - k_dsc: number + user_identifier: string ) { - const pubkey_leaf = getLeaf(passportData.dsc, n_dsc, k_dsc); + + const pubkey_leaf = getLeaf(passportData.dsc); const formattedMrz = formatMrz(passportData.mrz); const mrz_bytes = packBytes(formattedMrz); @@ -173,11 +165,9 @@ export function generateCircuitInputsOfac( user_identifier: string, sparsemerkletree: SMT, proofLevel: number, - n_dsc: number, - k_dsc: number, ) { - const result = generateCircuitInputsDisclose(secret, attestation_id, passportData, merkletree, majority, bitmap, scope, user_identifier, n_dsc, k_dsc); + const result = generateCircuitInputsDisclose(secret, attestation_id, passportData, merkletree, majority, bitmap, scope, user_identifier); const { majority: _, scope: __, bitmap: ___, user_identifier: ____, ...finalResult } = result; const mrz_bytes = formatMrz(passportData.mrz); @@ -223,8 +213,6 @@ export function findIndexInTree(tree: LeanIMT, commitment: bigint): number { export function generateCircuitInputsProve( passportData: PassportData, - n_dsc: number, - k_dsc: number, scope: string, bitmap: string[], majority: string, @@ -232,8 +220,7 @@ export function generateCircuitInputsProve( user_identifier_type: 'uuid' | 'hex' | 'ascii' = DEFAULT_USER_ID_TYPE ) { - - const register_inputs = generateCircuitInputsRegister('0', '0', '0', passportData, n_dsc, k_dsc); + const register_inputs = generateCircuitInputsRegister('0', '0', '0', passportData); const current_date = getCurrentDateYYMMDD().map(datePart => BigInt(datePart).toString()); // Ensure majority is at least two digits const formattedMajority = majority.length === 1 ? `0${majority}` : majority; diff --git a/common/src/utils/pubkeyTree.ts b/common/src/utils/pubkeyTree.ts index 791082dd..1e4d59ef 100644 --- a/common/src/utils/pubkeyTree.ts +++ b/common/src/utils/pubkeyTree.ts @@ -2,7 +2,7 @@ import { PUBKEY_TREE_DEPTH, COMMITMENT_TREE_TRACKER_URL, SignatureAlgorithmIndex import { LeanIMT } from '@zk-kit/imt' import axios from "axios"; import { poseidon16, poseidon2, poseidon6, poseidon7 } from 'poseidon-lite'; -import { formatDg2Hash, hexToDecimal, splitToWords } from './utils'; +import { formatDg2Hash, getNAndK, hexToDecimal, splitToWords } from './utils'; import { parseCertificate } from "./certificates/handleCertificate"; import { flexiblePoseidon } from "./poseidon"; @@ -23,8 +23,9 @@ export function customHasher(pubKeyFormatted: string[]) { return finalHash.toString(); } -export function getLeaf(dsc: string, n: number, k: number): string { +export function getLeaf(dsc: string): string { const { signatureAlgorithm, hashFunction, modulus, x, y, bits, curve, exponent } = parseCertificate(dsc); + const { n, k } = getNAndK(signatureAlgorithm); console.log(`${signatureAlgorithm}_${curve || exponent}_${hashFunction}_${bits}`) const sigAlgKey = `${signatureAlgorithm}_${curve || exponent}_${hashFunction}_${bits}`; const sigAlgIndex = SignatureAlgorithmIndex[sigAlgKey]; diff --git a/common/src/utils/utils.ts b/common/src/utils/utils.ts index c1d4d392..6f28e11c 100644 --- a/common/src/utils/utils.ts +++ b/common/src/utils/utils.ts @@ -4,6 +4,7 @@ import { sha1 } from 'js-sha1'; import { sha384, sha512_256 } from 'js-sha512'; import { SMT } from '@ashpect/smt'; import forge from 'node-forge'; +import { n_dsc, k_dsc, n_dsc_ecdsa, k_dsc_ecdsa } from '../constants/constants'; export function formatMrz(mrz: string) { const mrzCharcodes = [...mrz].map((char) => char.charCodeAt(0)); @@ -16,6 +17,12 @@ export function formatMrz(mrz: string) { return mrzCharcodes; } +export function getNAndK(sigAlg: 'rsa' | 'ecdsa' | 'rsapss') { + const n = sigAlg === 'ecdsa' ? n_dsc_ecdsa : n_dsc; + const k = sigAlg === 'ecdsa' ? k_dsc_ecdsa : k_dsc; + return { n, k }; +} + export function formatDg2Hash(dg2Hash: number[]) { const unsignedBytesDg2Hash = dg2Hash.map((x) => toUnsignedByte(x)); while (unsignedBytesDg2Hash.length < 64) { // pad it to 64 bytes to correspond to the hash length of sha512 and avoid multiplying circuits From ae6b08956a6db71a6c18e02d959c82c91fc4a2ed Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Thu, 19 Sep 2024 13:06:42 +0200 Subject: [PATCH 37/60] add scope to public inputs --- .../prove/instances/prove_ecdsa_sha1.circom | 2 +- .../prove/instances/prove_ecdsa_sha256.circom | 2 +- .../prove/instances/prove_rsa_65537_sha1.circom | 2 +- .../instances/prove_rsa_65537_sha256.circom | 2 +- .../instances/prove_rsapss_65537_sha256.circom | 2 +- .../circuits/prove/openpassport_prove.circom | 16 +++++++++------- 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/circuits/circuits/prove/instances/prove_ecdsa_sha1.circom b/circuits/circuits/prove/instances/prove_ecdsa_sha1.circom index 9950cf44..7aaecd61 100644 --- a/circuits/circuits/prove/instances/prove_ecdsa_sha1.circom +++ b/circuits/circuits/prove/instances/prove_ecdsa_sha1.circom @@ -2,4 +2,4 @@ pragma circom 2.1.6; include "../openpassport_prove.circom"; -component main = OPENPASSPORT_PROVE(7, 43, 6, 448, 448); \ No newline at end of file +component main { public [ user_identifier, scope ] } = OPENPASSPORT_PROVE(7, 43, 6, 448, 448); \ No newline at end of file diff --git a/circuits/circuits/prove/instances/prove_ecdsa_sha256.circom b/circuits/circuits/prove/instances/prove_ecdsa_sha256.circom index 0d856d3a..fd47f4b2 100644 --- a/circuits/circuits/prove/instances/prove_ecdsa_sha256.circom +++ b/circuits/circuits/prove/instances/prove_ecdsa_sha256.circom @@ -2,4 +2,4 @@ pragma circom 2.1.6; include "../openpassport_prove.circom"; -component main = OPENPASSPORT_PROVE(8, 43, 6, 640, 512); \ No newline at end of file +component main { public [ user_identifier, scope ] } = OPENPASSPORT_PROVE(8, 43, 6, 640, 512); \ No newline at end of file diff --git a/circuits/circuits/prove/instances/prove_rsa_65537_sha1.circom b/circuits/circuits/prove/instances/prove_rsa_65537_sha1.circom index 6041fe11..f097057a 100644 --- a/circuits/circuits/prove/instances/prove_rsa_65537_sha1.circom +++ b/circuits/circuits/prove/instances/prove_rsa_65537_sha1.circom @@ -2,4 +2,4 @@ pragma circom 2.1.6; include "../openpassport_prove.circom"; -component main = OPENPASSPORT_PROVE(3, 64, 32, 448, 448); \ No newline at end of file +component main { public [ user_identifier, scope ] } = OPENPASSPORT_PROVE(3, 64, 32, 448, 448); \ No newline at end of file diff --git a/circuits/circuits/prove/instances/prove_rsa_65537_sha256.circom b/circuits/circuits/prove/instances/prove_rsa_65537_sha256.circom index bf450fe0..b2d0e6c5 100644 --- a/circuits/circuits/prove/instances/prove_rsa_65537_sha256.circom +++ b/circuits/circuits/prove/instances/prove_rsa_65537_sha256.circom @@ -2,4 +2,4 @@ pragma circom 2.1.6; include "../openpassport_prove.circom"; -component main = OPENPASSPORT_PROVE(1, 64, 32, 640, 512); \ No newline at end of file +component main { public [ user_identifier, scope ] } = OPENPASSPORT_PROVE(1, 64, 32, 640, 512); \ No newline at end of file diff --git a/circuits/circuits/prove/instances/prove_rsapss_65537_sha256.circom b/circuits/circuits/prove/instances/prove_rsapss_65537_sha256.circom index 4618668d..4c1832fa 100644 --- a/circuits/circuits/prove/instances/prove_rsapss_65537_sha256.circom +++ b/circuits/circuits/prove/instances/prove_rsapss_65537_sha256.circom @@ -2,4 +2,4 @@ pragma circom 2.1.6; include "../openpassport_prove.circom"; -component main = OPENPASSPORT_PROVE(4, 64, 32, 640, 512); \ No newline at end of file +component main { public [ user_identifier, scope ] } = OPENPASSPORT_PROVE(4, 64, 32, 640, 512); \ No newline at end of file diff --git a/circuits/circuits/prove/openpassport_prove.circom b/circuits/circuits/prove/openpassport_prove.circom index d8b6f54c..af4e7f84 100644 --- a/circuits/circuits/prove/openpassport_prove.circom +++ b/circuits/circuits/prove/openpassport_prove.circom @@ -24,18 +24,20 @@ template OPENPASSPORT_PROVE(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, M signal input signature[kScaled]; signal input pubKey[kScaled]; - // passport verifier - PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset, dg2_hash, econtent,econtent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature); - - // nullifier - signal output nullifier <== CustomHasher(kScaled)(signature); - - signal input scope; + // dislose related inputs signal input bitmap[90]; signal input current_date[6]; // YYMMDD - num signal input majority[2]; // YY - ASCII signal input user_identifier; + signal input scope; + + + signal output nullifier <== CustomHasher(kScaled)(signature); // generate nullifier + + // verify passport signature + PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset, dg2_hash, econtent,econtent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature); + // optionally disclose data component disclose = DISCLOSE(); disclose.dg1 <== dg1; disclose.bitmap <== bitmap; From e39925ca5d91ca2173a189bb110cbb0f3286e3d3 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Thu, 19 Sep 2024 13:13:00 +0200 Subject: [PATCH 38/60] switch econtent for eContent --- circuits/circuits/prove/openpassport_prove.circom | 6 +++--- .../circuits/register/openpassport_register.circom | 6 +++--- .../utils/passport/passportVerifier.circom | 14 +++++++------- circuits/tests/prove.test.ts | 4 ++-- circuits/tests/register.test.ts | 4 ++-- common/src/utils/generateInputs.ts | 8 ++++---- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/circuits/circuits/prove/openpassport_prove.circom b/circuits/circuits/prove/openpassport_prove.circom index af4e7f84..9d68322e 100644 --- a/circuits/circuits/prove/openpassport_prove.circom +++ b/circuits/circuits/prove/openpassport_prove.circom @@ -16,8 +16,8 @@ template OPENPASSPORT_PROVE(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, M signal input dg1[93]; signal input dg1_hash_offset; signal input dg2_hash[64]; - signal input econtent[MAX_ECONTENT_PADDED_LEN]; - signal input econtent_padded_length; + signal input eContent[MAX_ECONTENT_PADDED_LEN]; + signal input eContent_padded_length; signal input signed_attr[MAX_SIGNED_ATTR_PADDED_LEN]; signal input signed_attr_padded_length; signal input signed_attr_econtent_hash_offset; @@ -35,7 +35,7 @@ template OPENPASSPORT_PROVE(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, M signal output nullifier <== CustomHasher(kScaled)(signature); // generate nullifier // verify passport signature - PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset, dg2_hash, econtent,econtent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature); + PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset, dg2_hash, eContent,eContent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature); // optionally disclose data component disclose = DISCLOSE(); diff --git a/circuits/circuits/register/openpassport_register.circom b/circuits/circuits/register/openpassport_register.circom index b2632128..9e0dc7f9 100644 --- a/circuits/circuits/register/openpassport_register.circom +++ b/circuits/circuits/register/openpassport_register.circom @@ -17,8 +17,8 @@ template OPENPASSPORT_REGISTER(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN signal input dg1[93]; signal input dg1_hash_offset; signal input dg2_hash[64]; - signal input econtent[MAX_ECONTENT_PADDED_LEN]; - signal input econtent_padded_length; + signal input eContent[MAX_ECONTENT_PADDED_LEN]; + signal input eContent_padded_length; signal input signed_attr[MAX_SIGNED_ATTR_PADDED_LEN]; signal input signed_attr_padded_length; signal input signed_attr_econtent_hash_offset; @@ -29,7 +29,7 @@ template OPENPASSPORT_REGISTER(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN signal input attestation_id; // passport verifier - PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset, dg2_hash, econtent,econtent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature); + PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset, dg2_hash, eContent,eContent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature); // leaf signal leaf <== LeafHasher(kScaled)(pubKey, signatureAlgorithm); diff --git a/circuits/circuits/utils/passport/passportVerifier.circom b/circuits/circuits/utils/passport/passportVerifier.circom index 7c28626f..af577c01 100644 --- a/circuits/circuits/utils/passport/passportVerifier.circom +++ b/circuits/circuits/utils/passport/passportVerifier.circom @@ -17,8 +17,8 @@ template PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_LEN, MAX_SIGNED signal input dg1[93]; signal input dg1_hash_offset; signal input dg2_hash[64]; - signal input econtent[MAX_ECONTENT_LEN]; - signal input econtent_padded_length; + signal input eContent[MAX_ECONTENT_LEN]; + signal input eContent_padded_length; signal input signed_attr[MAX_SIGNED_ATTR_LEN]; signal input signed_attr_padded_length; signal input signed_attr_econtent_hash_offset; @@ -36,15 +36,15 @@ template PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_LEN, MAX_SIGNED } } - // assert DG1 and DG2 hashes match the ones in econtent input - signal dg1AndDg2Hash[2 * HASH_LEN_BYTES] <== SelectSubArray(MAX_ECONTENT_LEN, 2 * HASH_LEN_BYTES)(econtent, dg1_hash_offset, 2 * HASH_LEN_BYTES); // TODO: use varShifLeft instead + // assert DG1 and DG2 hashes match the ones in eContent input + signal dg1AndDg2Hash[2 * HASH_LEN_BYTES] <== SelectSubArray(MAX_ECONTENT_LEN, 2 * HASH_LEN_BYTES)(eContent, dg1_hash_offset, 2 * HASH_LEN_BYTES); // TODO: use varShifLeft instead for(var i = 0; i < HASH_LEN_BYTES; i++) { dg1AndDg2Hash[i] === dg1ShaBytes[i].out; dg1AndDg2Hash[i + HASH_LEN_BYTES] === dg2_hash[i]; } - // compute hash of econtent - signal eContentSha[HASH_LEN_BITS] <== ShaBytesDynamic(HASH_LEN_BITS,MAX_ECONTENT_LEN)(econtent, econtent_padded_length); + // compute hash of eContent + signal eContentSha[HASH_LEN_BITS] <== ShaBytesDynamic(HASH_LEN_BITS,MAX_ECONTENT_LEN)(eContent, eContent_padded_length); component eContentShaBytes[HASH_LEN_BYTES]; for (var i = 0; i < HASH_LEN_BYTES; i++) { eContentShaBytes[i] = Bits2Num(8); @@ -53,7 +53,7 @@ template PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_LEN, MAX_SIGNED } } - // assert econtent hash matches the one in signedAttr + // assert eContent hash matches the one in signedAttr signal eContentHashInSignedAttr[HASH_LEN_BYTES] <== SelectSubArray(MAX_SIGNED_ATTR_LEN, HASH_LEN_BYTES)(signed_attr, signed_attr_econtent_hash_offset, HASH_LEN_BYTES); // TODO: use varShifLeft instead for(var i = 0; i < HASH_LEN_BYTES; i++) { eContentHashInSignedAttr[i] === eContentShaBytes[i].out; diff --git a/circuits/tests/prove.test.ts b/circuits/tests/prove.test.ts index dd58b18d..fb3e3465 100644 --- a/circuits/tests/prove.test.ts +++ b/circuits/tests/prove.test.ts @@ -83,11 +83,11 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { } }); - it('should fail to calculate witness with invalid econtent', async function () { + it('should fail to calculate witness with invalid eContent', async function () { try { const invalidInputs = { ...inputs, - econtent: inputs.econtent.map((byte: string) => + eContent: inputs.eContent.map((byte: string) => String((parseInt(byte, 10) + 1) % 256) ), }; diff --git a/circuits/tests/register.test.ts b/circuits/tests/register.test.ts index b9422849..b3981673 100644 --- a/circuits/tests/register.test.ts +++ b/circuits/tests/register.test.ts @@ -104,11 +104,11 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { } }); - it('should fail to calculate witness with invalid econtent', async function () { + it('should fail to calculate witness with invalid eContent', async function () { try { const invalidInputs = { ...inputs, - econtent: inputs.econtent.map((byte: string) => + eContent: inputs.eContent.map((byte: string) => String((parseInt(byte, 10) + 1) % 256) ), }; diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index 82d07498..ed0df6af 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -99,8 +99,8 @@ export function generateCircuitInputsRegister( dg1: dg1.map(byte => String(byte)), dg1_hash_offset: [dg1HashOffset.toString()], // uncomment when adding new circuits dg2_hash: formatDg2Hash(dg2Hash), - econtent: Array.from(eContentPadded).map((x) => x.toString()), - econtent_padded_length: [eContentLen.toString()], + eContent: Array.from(eContentPadded).map((x) => x.toString()), + eContent_padded_length: [eContentLen.toString()], signed_attr: Array.from(signedAttrPadded).map((x) => x.toString()), signed_attr_padded_length: [signedAttrPaddedLen.toString()], signed_attr_econtent_hash_offset: [eContentHashOffset.toString()], @@ -228,8 +228,8 @@ export function generateCircuitInputsProve( dg1: register_inputs.dg1, dg1_hash_offset: register_inputs.dg1_hash_offset, // uncomment when adding new circuits dg2_hash: register_inputs.dg2_hash, - econtent: register_inputs.econtent, - econtent_padded_length: register_inputs.econtent_padded_length, + eContent: register_inputs.eContent, + eContent_padded_length: register_inputs.eContent_padded_length, signed_attr: register_inputs.signed_attr, signed_attr_padded_length: register_inputs.signed_attr_padded_length, signed_attr_econtent_hash_offset: register_inputs.signed_attr_econtent_hash_offset, From 9c3d497f5a7fba5462e7b51c7a46b16f9de14420 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Thu, 19 Sep 2024 13:18:13 +0200 Subject: [PATCH 39/60] remove passport_verifier circuits --- .../passport_verifier_ecdsa_sha1.circom | 102 ------------------ .../passport_verifier_ecdsa_sha256.circom | 99 ----------------- .../passport_verifier_rsa_65537_sha1.circom | 96 ----------------- .../passport_verifier_rsa_65537_sha256.circom | 96 ----------------- ...ssport_verifier_rsapss_65537_sha256.circom | 76 ------------- 5 files changed, 469 deletions(-) delete mode 100644 circuits/circuits/verifier/passport_verifier_ecdsa_sha1.circom delete mode 100644 circuits/circuits/verifier/passport_verifier_ecdsa_sha256.circom delete mode 100644 circuits/circuits/verifier/passport_verifier_rsa_65537_sha1.circom delete mode 100644 circuits/circuits/verifier/passport_verifier_rsa_65537_sha256.circom delete mode 100644 circuits/circuits/verifier/passport_verifier_rsapss_65537_sha256.circom diff --git a/circuits/circuits/verifier/passport_verifier_ecdsa_sha1.circom b/circuits/circuits/verifier/passport_verifier_ecdsa_sha1.circom deleted file mode 100644 index b6ff31ab..00000000 --- a/circuits/circuits/verifier/passport_verifier_ecdsa_sha1.circom +++ /dev/null @@ -1,102 +0,0 @@ -pragma circom 2.1.5; - -include "@zk-email/circuits/utils/bytes.circom"; -include "../utils/Sha1BytesStatic.circom"; -include "../utils/Sha1Bytes.circom"; -include "../utils/rsaPkcs1.circom"; -include "dmpierre/sha1-circom/circuits/sha1.circom"; -include "../utils/circom-ecdsa/ecdsa.circom"; - -template PASSPORT_VERIFIER_ECDSA_SHA1(n, k, max_datahashes_bytes) { - var hashLen = 20; - var eContentBytesLength = 72 + hashLen; // 92 - - signal input mrz[93]; // formatted mrz (5 + 88) chars - signal input dg1_hash_offset; - signal input dataHashes[max_datahashes_bytes]; - - signal input datahashes_padded_length; - signal input eContentBytes[eContentBytesLength]; - - signal input dsc_modulus[2][k]; // Public Key (split into Qx and Qy) - - signal input signature_r[k]; // ECDSA signature component r - signal input signature_s[k]; // ECDSA signature component s - - // compute sha1 of formatted mrz - signal mrzSha[160] <== Sha1BytesStatic(93)(mrz); - - // mrzSha_bytes: list of 32 Bits2Num - component mrzSha_bytes[hashLen]; - - // cast the 160 bits from mrzSha into a list of 20 bytes - for (var i = 0; i < hashLen; i++) { - mrzSha_bytes[i] = Bits2Num(8); - - for (var j = 0; j < 8; j++) { - mrzSha_bytes[i].in[7 - j] <== mrzSha[i * 8 + j]; - } - } - - // assert mrz_hash equals the one extracted from dataHashes input (bytes dg1_hash_offset to dg1_hash_offset + hashLen) - signal dg1Hash[hashLen] <== SelectSubArray(max_datahashes_bytes, hashLen)(dataHashes, dg1_hash_offset, hashLen); - for(var i = 0; i < hashLen; i++) { - dg1Hash[i] === mrzSha_bytes[i].out; - } - - // hash dataHashes dynamically - signal dataHashesSha[160] <== Sha1Bytes(max_datahashes_bytes)(dataHashes, datahashes_padded_length); - - // get output of dataHashes into bytes to check against eContent - component dataHashesSha_bytes[hashLen]; - for (var i = 0; i < hashLen; i++) { - dataHashesSha_bytes[i] = Bits2Num(8); - for (var j = 0; j < 8; j++) { - dataHashesSha_bytes[i].in[7 - j] <== dataHashesSha[i * 8 + j]; - } - } - - // assert dataHashesSha is in eContentBytes in range bytes 72 to 92 - for(var i = 0; i < hashLen; i++) { - eContentBytes[eContentBytesLength - hashLen + i] === dataHashesSha_bytes[i].out; - } - - // hash eContentBytes - signal eContentSha[160] <== Sha1BytesStatic(eContentBytesLength)(eContentBytes); - - // get output of eContentBytes sha1 into k chunks of n bits each - var msg_len = (160 + n) \ n; - - //eContentHash: list of length 160/n +1 of components of n bits - component eContentHash[msg_len]; - for (var i = 0; i < msg_len; i++) { - eContentHash[i] = Bits2Num(n); - } - - for (var i = 0; i < 160; i++) { - eContentHash[i \ n].in[i % n] <== eContentSha[159 - i]; - } - - for (var i = 160; i < n * msg_len; i++) { - eContentHash[i \ n].in[i % n] <== 0; - } - - // 43 * 6 = 258; - signal msgHash[6]; - for(var i = 0; i < 4; i++) { - msgHash[i] <== eContentHash[i].out; - } - msgHash[4] <== 0; - msgHash[5] <== 0; - - // verify eContentHash signature - component ecdsa_verify = ECDSAVerifyNoPubkeyCheck(n, k); - - ecdsa_verify.r <== signature_r; - ecdsa_verify.s <== signature_s; - ecdsa_verify.msghash <== msgHash; - ecdsa_verify.pubkey <== dsc_modulus; - - 1 === ecdsa_verify.result; -} - diff --git a/circuits/circuits/verifier/passport_verifier_ecdsa_sha256.circom b/circuits/circuits/verifier/passport_verifier_ecdsa_sha256.circom deleted file mode 100644 index 7df88bee..00000000 --- a/circuits/circuits/verifier/passport_verifier_ecdsa_sha256.circom +++ /dev/null @@ -1,99 +0,0 @@ -pragma circom 2.1.5; - -include "@zk-email/circuits/utils/bytes.circom"; -include "../utils/circom-ecdsa/ecdsa.circom"; -include "../utils/Sha256BytesStatic.circom"; -include "@zk-email/circuits/lib/sha.circom"; - -template PASSPORT_VERIFIER_ECDSA_SHA256(n, k, max_datahashes_bytes) { - var hashLen = 32; - var eContentBytesLength = 72 + hashLen; // 104 - - signal input mrz[93]; // formatted mrz (5 + 88) chars - signal input dg1_hash_offset; - signal input dataHashes[max_datahashes_bytes]; - - signal input datahashes_padded_length; - signal input eContentBytes[eContentBytesLength]; - - signal input dsc_modulus[2][k]; // Public Key (split into Qx and Qy) - - signal input signature_r[k]; // ECDSA signature component r - signal input signature_s[k]; // ECDSA signature component s - - // compute sha256 of formatted mrz - signal mrzSha[256] <== Sha256BytesStatic(93)(mrz); - - // mrzSha_bytes: list of 32 Bits2Num - component mrzSha_bytes[hashLen]; - - // cast the 256 bits from mrzSha into a list of 32 bytes - for (var i = 0; i < hashLen; i++) { - mrzSha_bytes[i] = Bits2Num(8); - - for (var j = 0; j < 8; j++) { - mrzSha_bytes[i].in[7 - j] <== mrzSha[i * 8 + j]; - } - } - - // assert mrz_hash equals the one extracted from dataHashes input (bytes dg1_hash_offset to dg1_hash_offset + hashLen) - signal dg1Hash[hashLen] <== SelectSubArray(max_datahashes_bytes, hashLen)(dataHashes, dg1_hash_offset, hashLen); - for(var i = 0; i < hashLen; i++) { - dg1Hash[i] === mrzSha_bytes[i].out; - } - - // hash dataHashes dynamically - signal dataHashesSha[256] <== Sha256Bytes(max_datahashes_bytes)(dataHashes, datahashes_padded_length); - - // get output of dataHashes into bytes to check against eContent - component dataHashesSha_bytes[hashLen]; - for (var i = 0; i < hashLen; i++) { - dataHashesSha_bytes[i] = Bits2Num(8); - for (var j = 0; j < 8; j++) { - dataHashesSha_bytes[i].in[7 - j] <== dataHashesSha[i * 8 + j]; - } - } - - // assert dataHashesSha is in eContentBytes in range bytes 72 to 92 - for(var i = 0; i < hashLen; i++) { - eContentBytes[eContentBytesLength - hashLen + i] === dataHashesSha_bytes[i].out; - } - - // hash eContentBytes - signal eContentSha[256] <== Sha256BytesStatic(104)(eContentBytes); - - // get output of eContentBytes sha256 into k chunks of n bits each - var msg_len = (256 + n) \ n; - - //eContentHash: list of length 256/n +1 of components of n bits - component eContentHash[msg_len]; - for (var i = 0; i < msg_len; i++) { - eContentHash[i] = Bits2Num(n); - } - - for (var i = 0; i < 256; i++) { - eContentHash[i \ n].in[i % n] <== eContentSha[255 - i]; - } - - for (var i = 256; i < n * msg_len; i++) { - eContentHash[i \ n].in[i % n] <== 0; - } - - - // 43 * 6 = 258; - signal msgHash[6]; - for(var i = 0; i < msg_len; i++) { - msgHash[i] <== eContentHash[i].out; - } - - // verify eContentHash signature - component ecdsa_verify = ECDSAVerifyNoPubkeyCheck(n, k); - - ecdsa_verify.r <== signature_r; - ecdsa_verify.s <== signature_s; - ecdsa_verify.msghash <== msgHash; - ecdsa_verify.pubkey <== dsc_modulus; - - 1 === ecdsa_verify.result; -} - diff --git a/circuits/circuits/verifier/passport_verifier_rsa_65537_sha1.circom b/circuits/circuits/verifier/passport_verifier_rsa_65537_sha1.circom deleted file mode 100644 index f8033a95..00000000 --- a/circuits/circuits/verifier/passport_verifier_rsa_65537_sha1.circom +++ /dev/null @@ -1,96 +0,0 @@ -pragma circom 2.1.5; - -include "@zk-email/circuits/utils/bytes.circom"; -include "../utils/Sha1BytesStatic.circom"; -include "../utils/Sha1Bytes.circom"; -include "../utils/rsaPkcs1.circom"; -include "dmpierre/sha1-circom/circuits/sha1.circom"; - -template PASSPORT_VERIFIER_RSA_65537_SHA1(n, k, max_datahashes_bytes) { - var hashLen = 20; - var eContentBytesLength = 72 + hashLen; // 92 - - signal input mrz[93]; // formatted mrz (5 + 88) chars - signal input dg1_hash_offset; - signal input dataHashes[max_datahashes_bytes]; - signal input datahashes_padded_length; - signal input eContentBytes[eContentBytesLength]; - - // pubkey that signed the passport - signal input dsc_modulus[k]; - - // signature of the passport - signal input signature[k]; - - // compute sha1 of formatted mrz - signal mrzSha[160] <== Sha1BytesStatic(93)(mrz); - - // mrzSha_bytes: list of 32 Bits2Num - component mrzSha_bytes[hashLen]; - - // cast the 160 bits from mrzSha into a list of 20 bytes - for (var i = 0; i < hashLen; i++) { - mrzSha_bytes[i] = Bits2Num(8); - - for (var j = 0; j < 8; j++) { - mrzSha_bytes[i].in[7 - j] <== mrzSha[i * 8 + j]; - } - } - - // assert mrz_hash equals the one extracted from dataHashes input (bytes dg1_hash_offset to dg1_hash_offset + hashLen) - signal dg1Hash[hashLen] <== SelectSubArray(max_datahashes_bytes, hashLen)(dataHashes, dg1_hash_offset, hashLen); - for(var i = 0; i < hashLen; i++) { - dg1Hash[i] === mrzSha_bytes[i].out; - } - - // hash dataHashes dynamically - signal dataHashesSha[160] <== Sha1Bytes(max_datahashes_bytes)(dataHashes, datahashes_padded_length); - - // get output of dataHashes into bytes to check against eContent - component dataHashesSha_bytes[hashLen]; - for (var i = 0; i < hashLen; i++) { - dataHashesSha_bytes[i] = Bits2Num(8); - for (var j = 0; j < 8; j++) { - dataHashesSha_bytes[i].in[7 - j] <== dataHashesSha[i * 8 + j]; - } - } - - // assert dataHashesSha is in eContentBytes in range bytes 72 to 92 - for(var i = 0; i < hashLen; i++) { - eContentBytes[eContentBytesLength - hashLen + i] === dataHashesSha_bytes[i].out; - } - - // hash eContentBytes - signal eContentSha[160] <== Sha1BytesStatic(eContentBytesLength)(eContentBytes); - - // get output of eContentBytes sha1 into k chunks of n bits each - var msg_len = (160 + n) \ n; - - //eContentHash: list of length 160/n +1 of components of n bits - component eContentHash[msg_len]; - for (var i = 0; i < msg_len; i++) { - eContentHash[i] = Bits2Num(n); - } - - for (var i = 0; i < 160; i++) { - eContentHash[i \ n].in[i % n] <== eContentSha[159 - i]; - } - - for (var i = 160; i < n * msg_len; i++) { - eContentHash[i \ n].in[i % n] <== 0; - } - - // verify eContentHash signature - component rsa = RSAVerify65537(n, k); - - for (var i = 0; i < msg_len; i++) { - rsa.base_message[i] <== eContentHash[i].out; - } - - for (var i = msg_len; i < k; i++) { - rsa.base_message[i] <== 0; - } - - rsa.modulus <== dsc_modulus; - rsa.signature <== signature; -} \ No newline at end of file diff --git a/circuits/circuits/verifier/passport_verifier_rsa_65537_sha256.circom b/circuits/circuits/verifier/passport_verifier_rsa_65537_sha256.circom deleted file mode 100644 index 6eb4d10c..00000000 --- a/circuits/circuits/verifier/passport_verifier_rsa_65537_sha256.circom +++ /dev/null @@ -1,96 +0,0 @@ -pragma circom 2.1.5; - -include "@zk-email/circuits/lib/rsa.circom"; -include "@zk-email/circuits/utils/bytes.circom"; -include "@zk-email/circuits/lib/sha.circom"; -include "@zk-email/circuits/utils/array.circom"; -include "../utils/Sha256BytesStatic.circom"; - -template PASSPORT_VERIFIER_RSA_65537_SHA256(n, k, max_datahashes_bytes) { - var hashLen = 32; - var eContentBytesLength = 72 + hashLen; // 104 - - signal input mrz[93]; // formatted mrz (5 + 88) chars - signal input dg1_hash_offset; - signal input dataHashes[max_datahashes_bytes]; - signal input datahashes_padded_length; - signal input eContentBytes[eContentBytesLength]; - - // dsc_modulus that signed the passport - signal input dsc_modulus[k]; - - // signature of the passport - signal input signature[k]; - - // compute sha256 of formatted mrz - signal mrzSha[256] <== Sha256BytesStatic(93)(mrz); - - // mrzSha_bytes: list of 32 Bits2Num - component mrzSha_bytes[hashLen]; - - // cast the 256 bits from mrzSha into a list of 32 bytes - for (var i = 0; i < hashLen; i++) { - mrzSha_bytes[i] = Bits2Num(8); - - for (var j = 0; j < 8; j++) { - mrzSha_bytes[i].in[7 - j] <== mrzSha[i * 8 + j]; - } - } - - // assert mrz_hash equals the one extracted from dataHashes input (bytes dg1_hash_offset to dg1_hash_offset + hashLen) - signal dg1Hash[hashLen] <== SelectSubArray(max_datahashes_bytes, hashLen)(dataHashes, dg1_hash_offset, hashLen); - for(var i = 0; i < hashLen; i++) { - dg1Hash[i] === mrzSha_bytes[i].out; - } - - // hash dataHashes dynamically - signal dataHashesSha[256] <== Sha256Bytes(max_datahashes_bytes)(dataHashes, datahashes_padded_length); - - // get output of dataHashes sha256 into bytes to check against eContent - component dataHashesSha_bytes[hashLen]; - for (var i = 0; i < hashLen; i++) { - dataHashesSha_bytes[i] = Bits2Num(8); - for (var j = 0; j < 8; j++) { - dataHashesSha_bytes[i].in[7 - j] <== dataHashesSha[i * 8 + j]; - } - } - - // assert dataHashesSha is in eContentBytes in range bytes 72 to 104 - for(var i = 0; i < hashLen; i++) { - eContentBytes[eContentBytesLength - hashLen + i] === dataHashesSha_bytes[i].out; - } - - // hash eContentBytes - signal eContentSha[256] <== Sha256BytesStatic(104)(eContentBytes); - - // get output of eContentBytes sha256 into k chunks of n bits each - var msg_len = (256 + n) \ n; - - //eContentHash: list of length 256/n +1 of components of n bits - component eContentHash[msg_len]; - for (var i = 0; i < msg_len; i++) { - eContentHash[i] = Bits2Num(n); - } - - for (var i = 0; i < 256; i++) { - eContentHash[i \ n].in[i % n] <== eContentSha[255 - i]; - } - - for (var i = 256; i < n * msg_len; i++) { - eContentHash[i \ n].in[i % n] <== 0; - } - - // verify eContentHash signature - component rsa = RSAVerifier65537(n, k); - - for (var i = 0; i < msg_len; i++) { - rsa.message[i] <== eContentHash[i].out; - } - - for (var i = msg_len; i < k; i++) { - rsa.message[i] <== 0; - } - - rsa.modulus <== dsc_modulus; - rsa.signature <== signature; -} \ No newline at end of file diff --git a/circuits/circuits/verifier/passport_verifier_rsapss_65537_sha256.circom b/circuits/circuits/verifier/passport_verifier_rsapss_65537_sha256.circom deleted file mode 100644 index 29436f98..00000000 --- a/circuits/circuits/verifier/passport_verifier_rsapss_65537_sha256.circom +++ /dev/null @@ -1,76 +0,0 @@ -pragma circom 2.1.5; - -// include "@zk-email/circuits/lib/rsa.circom"; -include "@zk-email/circuits/utils/bytes.circom"; -include "@zk-email/circuits/lib/sha.circom"; -include "@zk-email/circuits/utils/array.circom"; -include "../utils/Sha256BytesStatic.circom"; -include "../utils/RSASSAPSS.circom"; -include "@zk-email/circuits/lib/fp.circom"; - -template PASSPORT_VERIFIER_RSAPSS_65537_SHA256(n, k, max_datahashes_bytes) { - var hashLen = 32; - var eContentBytesLength = 72 + hashLen; // 104 - - signal input mrz[93]; // formatted mrz (5 + 88) chars - signal input dg1_hash_offset; - signal input dataHashes[max_datahashes_bytes]; - signal input datahashes_padded_length; - signal input eContentBytes[eContentBytesLength]; - - // dsc_modulus that signed the passport - signal input dsc_modulus[k]; - - // signature of the passport - signal input signature[k]; - - // compute sha256 of formatted mrz - signal mrzSha[256] <== Sha256BytesStatic(93)(mrz); - - // mrzSha_bytes: list of 32 Bits2Num - component mrzSha_bytes[hashLen]; - - // cast the 256 bits from mrzSha into a list of 32 bytes - for (var i = 0; i < hashLen; i++) { - mrzSha_bytes[i] = Bits2Num(8); - - for (var j = 0; j < 8; j++) { - mrzSha_bytes[i].in[7 - j] <== mrzSha[i * 8 + j]; - } - } - - // assert mrz_hash equals the one extracted from dataHashes input (bytes dg1_hash_offset to dg1_hash_offset + hashLen) - signal dg1Hash[hashLen] <== SelectSubArray(max_datahashes_bytes, hashLen)(dataHashes, dg1_hash_offset, hashLen); - for(var i = 0; i < hashLen; i++) { - dg1Hash[i] === mrzSha_bytes[i].out; - } - - // hash dataHashes dynamically - signal dataHashesSha[256] <== Sha256Bytes(max_datahashes_bytes)(dataHashes, datahashes_padded_length); - - // get output of dataHashes sha256 into bytes to check against eContent - component dataHashesSha_bytes[hashLen]; - for (var i = 0; i < hashLen; i++) { - dataHashesSha_bytes[i] = Bits2Num(8); - for (var j = 0; j < 8; j++) { - dataHashesSha_bytes[i].in[7 - j] <== dataHashesSha[i * 8 + j]; - } - } - - // assert dataHashesSha is in eContentBytes in range bytes 72 to 104 - for(var i = 0; i < hashLen; i++) { - eContentBytes[eContentBytesLength - hashLen + i] === dataHashesSha_bytes[i].out; - } - - // decode signature to get encoded message - component rsaDecode = RSASSAPSS_Decode(n, k); - rsaDecode.signature <== signature; - rsaDecode.modulus <== dsc_modulus; - var emLen = div_ceil(n * k, 8); - signal encodedMessage[emLen] <== rsaDecode.eM; - - // verify eContent signature - component rsaVerify = RSASSAPSSVerify_SHA256(n * k, eContentBytesLength); - rsaVerify.eM <== encodedMessage; - rsaVerify.message <== eContentBytes; -} \ No newline at end of file From 07a5b09426a9cd738f0822318a56bc5c8bd30ad6 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Thu, 19 Sep 2024 13:30:58 +0200 Subject: [PATCH 40/60] clean circuits repo --- .../circuits/dsc/dsc_rsa_65537_sha1.circom | 3 +- .../circuits/dsc/dsc_rsa_65537_sha256.circom | 3 +- .../dsc/dsc_rsapss_65537_sha256.circom | 3 +- circuits/circuits/ofac/ofac_name.circom | 2 +- circuits/circuits/ofac/ofac_name_dob.circom | 2 +- .../circuits/ofac/ofac_passport_number.circom | 2 +- .../Mgf1Sha256_1ByteMask_tester.circom | 31 --- .../Mgf1Sha256_32Bytes_tester.circom | 29 --- .../tests/mgf1Sha256/Mgf1Sha256_tester.circom | 33 --- .../circuits/tests/utils/rsa_verifier.circom | 3 - .../tests/utils/rsapss_verifier.circom | 20 -- circuits/circuits/utils/Mgf1Sha256.circom | 50 ----- circuits/circuits/utils/RSASSAPSS.circom | 193 ----------------- .../circuits/utils/RSASSAPSS_padded.circom | 201 ------------------ circuits/circuits/utils/other/bytes.circom | 104 +++++++++ .../utils/{ => other}/chunk_data.circom | 0 .../utils/{ => other}/getCommonLength.circom | 0 .../circuits/utils/{ => other}/smt.circom | 0 circuits/circuits/utils/rsapss/rsapss.circom | 2 +- .../circuits/utils/splitBytesToWords.circom | 36 ---- .../circuits/utils/splitSignalsToWords.circom | 72 ------- circuits/circuits/utils/xor.circom | 11 - .../tests/other_circuits/Mgf1_sha256.test.ts | 149 ------------- .../tests/other_circuits/rsa_verifier.test.ts | 97 --------- .../other_circuits/rsapss_verifier.test.ts | 72 ------- 25 files changed, 111 insertions(+), 1007 deletions(-) delete mode 100644 circuits/circuits/tests/mgf1Sha256/Mgf1Sha256_1ByteMask_tester.circom delete mode 100644 circuits/circuits/tests/mgf1Sha256/Mgf1Sha256_32Bytes_tester.circom delete mode 100644 circuits/circuits/tests/mgf1Sha256/Mgf1Sha256_tester.circom delete mode 100644 circuits/circuits/tests/utils/rsa_verifier.circom delete mode 100644 circuits/circuits/tests/utils/rsapss_verifier.circom delete mode 100644 circuits/circuits/utils/Mgf1Sha256.circom delete mode 100644 circuits/circuits/utils/RSASSAPSS.circom delete mode 100644 circuits/circuits/utils/RSASSAPSS_padded.circom rename circuits/circuits/utils/{ => other}/chunk_data.circom (100%) rename circuits/circuits/utils/{ => other}/getCommonLength.circom (100%) rename circuits/circuits/utils/{ => other}/smt.circom (100%) delete mode 100644 circuits/circuits/utils/splitBytesToWords.circom delete mode 100644 circuits/circuits/utils/splitSignalsToWords.circom delete mode 100644 circuits/circuits/utils/xor.circom delete mode 100644 circuits/tests/other_circuits/Mgf1_sha256.test.ts delete mode 100644 circuits/tests/other_circuits/rsa_verifier.test.ts delete mode 100644 circuits/tests/other_circuits/rsapss_verifier.test.ts diff --git a/circuits/circuits/dsc/dsc_rsa_65537_sha1.circom b/circuits/circuits/dsc/dsc_rsa_65537_sha1.circom index 900108a7..cf696558 100644 --- a/circuits/circuits/dsc/dsc_rsa_65537_sha1.circom +++ b/circuits/circuits/dsc/dsc_rsa_65537_sha1.circom @@ -3,8 +3,7 @@ include "circomlib/circuits/bitify.circom"; include "circomlib/circuits/poseidon.circom"; include "circomlib/circuits/comparators.circom"; include "binary-merkle-root.circom"; -include "../utils/splitBytesToWords.circom"; -include "../utils/splitSignalsToWords.circom"; +include "../utils/other/bytes.circom"; include "../utils/Sha1Bytes.circom"; include "../utils/leafHasherLight.circom"; include "../utils/rsaPkcs1.circom"; diff --git a/circuits/circuits/dsc/dsc_rsa_65537_sha256.circom b/circuits/circuits/dsc/dsc_rsa_65537_sha256.circom index a4239eeb..a1845ec3 100644 --- a/circuits/circuits/dsc/dsc_rsa_65537_sha256.circom +++ b/circuits/circuits/dsc/dsc_rsa_65537_sha256.circom @@ -6,8 +6,7 @@ include "circomlib/circuits/comparators.circom"; include "@zk-email/circuits/lib/sha.circom"; include "@zk-email/circuits/lib/rsa.circom"; include "binary-merkle-root.circom"; -include "../utils/splitBytesToWords.circom"; -include "../utils/splitSignalsToWords.circom"; +include "../utils/other/bytes.circom"; include "../utils/leafHasherLight.circom"; template DSC_RSA_65537_SHA256(max_cert_bytes, n_dsc, k_dsc, n_csca, k_csca, dsc_mod_len, nLevels, signatureAlgorithm) { diff --git a/circuits/circuits/dsc/dsc_rsapss_65537_sha256.circom b/circuits/circuits/dsc/dsc_rsapss_65537_sha256.circom index 4d4e62ef..7ce6623e 100644 --- a/circuits/circuits/dsc/dsc_rsapss_65537_sha256.circom +++ b/circuits/circuits/dsc/dsc_rsapss_65537_sha256.circom @@ -5,8 +5,7 @@ include "circomlib/circuits/poseidon.circom"; include "circomlib/circuits/comparators.circom"; include "@zk-email/circuits/lib/sha.circom"; include "binary-merkle-root.circom"; -include "../utils/splitBytesToWords.circom"; -include "../utils/splitSignalsToWords.circom"; +include "../utils/other/bytes.circom"; include "../utils/leafHasherLight.circom"; include "../utils/rsapss/rsapss.circom"; diff --git a/circuits/circuits/ofac/ofac_name.circom b/circuits/circuits/ofac/ofac_name.circom index a92e6666..1d6547fd 100644 --- a/circuits/circuits/ofac/ofac_name.circom +++ b/circuits/circuits/ofac/ofac_name.circom @@ -5,7 +5,7 @@ include "circomlib/circuits/comparators.circom"; include "binary-merkle-root.circom"; include "../utils/getCommonLength.circom"; include "../disclose/verify_commitment.circom"; -include "../utils/smt.circom"; +include "../utils/other/smt.circom"; template OFAC_NAME(nLevels) { signal input secret; diff --git a/circuits/circuits/ofac/ofac_name_dob.circom b/circuits/circuits/ofac/ofac_name_dob.circom index 32b7925e..96cbef30 100644 --- a/circuits/circuits/ofac/ofac_name_dob.circom +++ b/circuits/circuits/ofac/ofac_name_dob.circom @@ -6,7 +6,7 @@ include "circomlib/circuits/bitify.circom"; include "binary-merkle-root.circom"; include "../utils/getCommonLength.circom"; include "../disclose/verify_commitment.circom"; -include "../utils/smt.circom"; +include "../utils/other/smt.circom"; template OFAC_NAME_DOB(nLevels) { signal input secret; diff --git a/circuits/circuits/ofac/ofac_passport_number.circom b/circuits/circuits/ofac/ofac_passport_number.circom index bbc414ee..d9c63e62 100644 --- a/circuits/circuits/ofac/ofac_passport_number.circom +++ b/circuits/circuits/ofac/ofac_passport_number.circom @@ -7,7 +7,7 @@ include "../utils/other/array.circom"; include "binary-merkle-root.circom"; include "../utils/getCommonLength.circom"; include "../disclose/verify_commitment.circom"; -include "../utils/smt.circom"; +include "../utils/other/smt.circom"; template OFAC_PASSPORT_NUMBER(nLevels) { signal input secret; diff --git a/circuits/circuits/tests/mgf1Sha256/Mgf1Sha256_1ByteMask_tester.circom b/circuits/circuits/tests/mgf1Sha256/Mgf1Sha256_1ByteMask_tester.circom deleted file mode 100644 index 5c433942..00000000 --- a/circuits/circuits/tests/mgf1Sha256/Mgf1Sha256_1ByteMask_tester.circom +++ /dev/null @@ -1,31 +0,0 @@ -pragma circom 2.1.5; - -include "../../utils/Mgf1Sha256.circom"; -include "../../../node_modules/circomlib/circuits/bitify.circom"; - - -template Mgf1Sha256_1ByteMask_tester(seed_len_bytes, mask_len_bytes) { - - signal input seed; - signal input expected_mask_output[mask_len_bytes * 8]; - signal output mask[mask_len_bytes * 8]; - - component mgf1_sha256 = Mgf1Sha256(seed_len_bytes, mask_len_bytes); - component num2Bits = Num2Bits(seed_len_bytes * 8); - num2Bits.in <== seed; - - for (var i=0; i < seed_len_bytes * 8; i++) { - mgf1_sha256.seed[i] <== num2Bits.out[i]; - } - - for (var i=0; i < mask_len_bytes * 8; i++) { - mask[i] <== mgf1_sha256.out[i]; - } - - for (var i=0; i < mask_len_bytes * 8; i++) { - mgf1_sha256.out[i] === expected_mask_output[i]; - } - -} - -component main = Mgf1Sha256_1ByteMask_tester(4, 1); diff --git a/circuits/circuits/tests/mgf1Sha256/Mgf1Sha256_32Bytes_tester.circom b/circuits/circuits/tests/mgf1Sha256/Mgf1Sha256_32Bytes_tester.circom deleted file mode 100644 index dfb5b033..00000000 --- a/circuits/circuits/tests/mgf1Sha256/Mgf1Sha256_32Bytes_tester.circom +++ /dev/null @@ -1,29 +0,0 @@ -pragma circom 2.1.5; - -include "../../utils/Mgf1Sha256.circom"; -include "../../../node_modules/circomlib/circuits/bitify.circom"; - - -template Mgf1Sha256_32Bytes_tester(seed_len_bytes, mask_len_bytes) { - - signal input seed[seed_len_bytes * 8]; - signal input expected_mask_output[mask_len_bytes * 8]; - signal output mask[mask_len_bytes * 8]; - - component mgf1_sha256 = Mgf1Sha256(seed_len_bytes, mask_len_bytes); - - for (var i=0; i < seed_len_bytes * 8; i++) { - mgf1_sha256.seed[i] <== seed[i]; - } - - for (var i=0; i < mask_len_bytes * 8; i++) { - mask[i] <== mgf1_sha256.out[i]; - } - - for (var i=0; i < mask_len_bytes * 8; i++) { - mgf1_sha256.out[i] === expected_mask_output[i]; - } - -} - -component main = Mgf1Sha256_32Bytes_tester(32, 32); diff --git a/circuits/circuits/tests/mgf1Sha256/Mgf1Sha256_tester.circom b/circuits/circuits/tests/mgf1Sha256/Mgf1Sha256_tester.circom deleted file mode 100644 index 851b5630..00000000 --- a/circuits/circuits/tests/mgf1Sha256/Mgf1Sha256_tester.circom +++ /dev/null @@ -1,33 +0,0 @@ -pragma circom 2.1.5; - -include "../../utils/Mgf1Sha256.circom"; -include "../../../node_modules/circomlib/circuits/bitify.circom"; - - -template Mgf1Sha256_tester(seed_len_bytes, mask_len_bytes) { - - signal input seed; - signal input expected_mask_output[mask_len_bytes * 8]; - signal output mask[mask_len_bytes * 8]; - - component mgf1_sha256 = Mgf1Sha256(seed_len_bytes, mask_len_bytes); - component num2Bits = Num2Bits(seed_len_bytes * 8); - num2Bits.in <== seed; - - for (var i=0; i < seed_len_bytes * 8; i++) { - mgf1_sha256.seed[i] <== num2Bits.out[i]; - } - - for (var i=0; i < mask_len_bytes * 8; i++) { - mask[i] <== mgf1_sha256.out[i]; - } - - for (var i=0; i < mask_len_bytes * 8; i++) { - mgf1_sha256.out[i] === expected_mask_output[i]; - } - -} - -// component main { public [ seed ] } = Mgf1_sha256(4,32); - -component main = Mgf1Sha256_tester(4, 32); diff --git a/circuits/circuits/tests/utils/rsa_verifier.circom b/circuits/circuits/tests/utils/rsa_verifier.circom deleted file mode 100644 index 75039636..00000000 --- a/circuits/circuits/tests/utils/rsa_verifier.circom +++ /dev/null @@ -1,3 +0,0 @@ -include "@zk-email/circuits/lib/rsa.circom"; - -component main = RSAVerifier65537(121, 17); \ No newline at end of file diff --git a/circuits/circuits/tests/utils/rsapss_verifier.circom b/circuits/circuits/tests/utils/rsapss_verifier.circom deleted file mode 100644 index f89b8cf4..00000000 --- a/circuits/circuits/tests/utils/rsapss_verifier.circom +++ /dev/null @@ -1,20 +0,0 @@ -include "../../utils/RSASSAPSS_padded.circom"; - -template RSAPSSVerifier(n,k,max_bytes) { - signal input signature[k]; - signal input modulus[k]; - signal input raw_message[max_bytes]; - signal input raw_message_padded_bytes; - - component rsaDecode = RSASSAPSS_Decode(n, k); - rsaDecode.signature <== signature; - rsaDecode.modulus <== modulus; - var emLen = div_ceil(n * k, 8); - signal encodedMessage[emLen] <== rsaDecode.eM; - - component rsaVerify = RSASSAPSSVerify_SHA256(n * k, max_bytes); - rsaVerify.eM <== encodedMessage; - rsaVerify.message <== raw_message; - rsaVerify.messagePaddedLen <== raw_message_padded_bytes; -} -component main = RSAPSSVerifier(64, 32, 960); \ No newline at end of file diff --git a/circuits/circuits/utils/Mgf1Sha256.circom b/circuits/circuits/utils/Mgf1Sha256.circom deleted file mode 100644 index 19a71d6a..00000000 --- a/circuits/circuits/utils/Mgf1Sha256.circom +++ /dev/null @@ -1,50 +0,0 @@ -pragma circom 2.1.5; -include "circomlib/circuits/sha256/sha256.circom"; -include "circomlib/circuits/bitify.circom"; - -template Mgf1Sha256(seedLen, maskLen) { //in bytes - var seedLenBits = seedLen * 8; - var maskLenBits = maskLen * 8; - var hashLen = 32; //output len of sha function in bytes - var hashLenBits = hashLen * 8;//output len of sha function in bits - - signal input seed[seedLenBits]; //each represents a bit - signal output out[maskLenBits]; - - assert(maskLen <= 0xffffffff * hashLen ); - var iterations = (maskLen \ hashLen) + 1; //adding 1, in-case maskLen \ hashLen is 0 - - component sha256[iterations]; - component num2Bits[iterations]; - - for (var i = 0; i < iterations; i++) { - sha256[i] = Sha256(seedLenBits + 32); //32 bits for counter - num2Bits[i] = Num2Bits(32); - } - - var concated[seedLenBits + 32]; //seed + 32 bits(4 Bytes) for counter - signal hashed[hashLenBits * (iterations)]; - - for (var i = 0; i < seedLenBits; i++) { - concated[i] = seed[i]; - } - - for (var i = 0; i < iterations; i++) { - num2Bits[i].in <== i; //convert counter to bits - - for (var j = 0; j < 32; j++) { - //concat seed and counter - concated[seedLenBits + j] = num2Bits[i].out[31-j]; - } - - sha256[i].in <== concated; - - for (var j = 0; j < hashLenBits; j++) { - hashed[i * hashLenBits + j] <== sha256[i].out[j]; - } - } - - for (var i = 0; i < maskLenBits; i++) { - out[i] <== hashed[i]; - } -} diff --git a/circuits/circuits/utils/RSASSAPSS.circom b/circuits/circuits/utils/RSASSAPSS.circom deleted file mode 100644 index 5e7a4c53..00000000 --- a/circuits/circuits/utils/RSASSAPSS.circom +++ /dev/null @@ -1,193 +0,0 @@ -pragma circom 2.1.5; - -include "@zk-email/circuits/lib/rsa.circom"; -include "@zk-email/circuits/lib/fp.circom"; -include "@zk-email/circuits/lib/bigint-func.circom"; -include "circomlib/circuits/bitify.circom"; -include "circomlib/circuits/sha256/sha256.circom"; -include "./Mgf1Sha256.circom"; -include "./xor.circom"; - -/// @notice Returns the encoded message in 8bit chunks. -/// @param n Number of bits per chunk the modulus is split into. -/// @param k Number of chunks the modulus is split into. -template RSASSAPSS_Decode(n, k) { - signal input signature[k]; - signal input modulus[k]; - // signal output eM[k]; - signal encoded[k]; - signal eMsgInBits[n*k]; - var emLen = div_ceil(n*k, 8); - signal output eM[emLen]; //8 bit words - - component bigPow = FpPow65537Mod(n, k); - for (var i = 0; i < k; i++) { - bigPow.base[i] <== signature[i]; - bigPow.modulus[i] <== modulus[i]; - } - - encoded <== bigPow.out; - - component num2Bits[k]; - for (var i = 0; i < k; i++) { - num2Bits[i] = Num2Bits(n); - num2Bits[i].in <== encoded[k-1-i]; - - for (var j = 0; j < n; j++) { - eMsgInBits[i * n + j] <== num2Bits[i].out[n-j-1]; - } - } - - component bits2Num[(n*k)\8]; - for (var i = 0; i < (n*k)\8; i++) { - bits2Num[i] = Bits2Num(8); - for (var j = 0; j < 8; j++) { - bits2Num[i].in[7-j] <== eMsgInBits[i*8 + j]; - } - eM[(n*k)\8 - i -1] <== bits2Num[i].out; - } -} - -/// @param emBits Length of the encoded message in bits. -/// @param messageLen Length of the message in bytes. -/// @param n Number of bits per chunk the modulus is split into. -/// @param k Number of chunks the modulus is split into. -template RSASSAPSSVerify_SHA256(emBits, messageLen) { - var emLen = div_ceil(emBits, 8); - signal input eM[emLen]; - signal input message[messageLen]; - signal mHash[256]; - var hLen = 32; - var sLen = 32; - var hLenBits = 256; //sha256 - var sLenBits = 256; //sha256 - var emLenBits = emLen * 8; - - signal messageBits[messageLen*8]; - component num2BitsMessage[messageLen]; - for (var i = 0; i < messageLen; i++) { - num2BitsMessage[i] = Num2Bits(8); - num2BitsMessage[i].in <== message[i]; - for (var j = 0; j < 8; j++) { - messageBits[i*8 +j] <== num2BitsMessage[i].out[7-j]; - } - } - - //mHash - component sha256 = Sha256( messageLen* 8); - sha256.in <== messageBits; - for (var i = 0; i < 256; i++) { - mHash[i] <== sha256.out[i]; - } - - //If emLen < hLen + sLen + 2, output "inconsistent" and stop. - assert(emLen >= 32 + 32 +2); - - //should end with 0xBC (188 in decimal) - assert(eM[0] == 188); //inconsistent - - signal eMsgInBits[emLen * 8]; - signal maskedDB[(emLen - hLen - 1) * 8]; - signal hash[hLen * 8]; - var dbMaskLen = emLen - hLen - 1; - signal dbMask[dbMaskLen * 8]; - signal DB[dbMaskLen * 8]; - signal salt[hLen * 8]; - - //split eM into bits - component num2Bits[emLen]; - for (var i = 0; i < emLen; i++) { - num2Bits[i] = Num2Bits(8); - num2Bits[i].in <== eM[emLen-1-i]; - - for (var j = 0; j < 8; j++) { - eMsgInBits[i * 8 + j] <== num2Bits[i].out[8-j-1]; - } - } - - //extract maskedDB. leftmost emLen - hLen - 1 octets of EM - for (var i=0; i< (emLen - hLen -1) * 8; i++) { - maskedDB[i] <== eMsgInBits[i]; - } - - //Ref: https://github.com/directdemocracy-vote/app/blob/d0590b5515e749fa72fc50f05062273eb2465da1/httpdocs/app/js/rsa-blind.js#L183 - signal mask <== 0xff00 >> (emLenBits / 8 - emBits) & 0xff; - signal maskBits[8]; - component num2BitsMask = Num2Bits(8); - num2BitsMask.in <== mask; - for (var i = 0; i < 8; i++) { - maskBits[i] <== num2BitsMask.out[7-i]; - } - for (var i=0; i<8; i++) { - assert(maskBits[i] & maskedDB[i] == 0); - } - - //extract hash - for (var i=0; i= 32 + 32 +2); - - //should end with 0xBC (188 in decimal) - assert(eM[0] == 188); //inconsistent - - signal eMsgInBits[emLen * 8]; - signal maskedDB[(emLen - hLen - 1) * 8]; - signal hash[hLen * 8]; - var dbMaskLen = emLen - hLen - 1; - signal dbMask[dbMaskLen * 8]; - signal DB[dbMaskLen * 8]; - signal salt[hLen * 8]; - - //split eM into bits - component num2Bits[emLen]; - for (var i = 0; i < emLen; i++) { - num2Bits[i] = Num2Bits(8); - num2Bits[i].in <== eM[emLen-1-i]; - - for (var j = 0; j < 8; j++) { - eMsgInBits[i * 8 + j] <== num2Bits[i].out[8-j-1]; - } - } - - //extract maskedDB. leftmost emLen - hLen - 1 octets of EM - for (var i=0; i< (emLen - hLen -1) * 8; i++) { - maskedDB[i] <== eMsgInBits[i]; - } - - //Ref: https://github.com/directdemocracy-vote/app/blob/d0590b5515e749fa72fc50f05062273eb2465da1/httpdocs/app/js/rsa-blind.js#L183 - signal mask <== 0xff00 >> (emLenBits / 8 - emBits) & 0xff; - signal maskBits[8]; - component num2BitsMask = Num2Bits(8); - num2BitsMask.in <== mask; - for (var i = 0; i < 8; i++) { - maskBits[i] <== num2BitsMask.out[7-i]; - } - for (var i=0; i<8; i++) { - assert(maskBits[i] & maskedDB[i] == 0); - } - - //extract hash - for (var i=0; i= t*l); + + signal input in[l]; + signal output out[k]; + component num2bits[l]; + for (var i = 0 ; i < l ; i++){ + num2bits[i] = Num2Bits(t); + num2bits[i].in <== in[i]; + } + for (var i = 0 ; i < t ; i ++){ + } + component bits2num[k]; + for (var i = 0 ; i < k ; i++){ + bits2num[i] = Bits2Num(n); + + for(var j = 0 ; j < n ; j++){ + if(i*n + j >= l * t){ + bits2num[i].in[j] <== 0; + } + else{ + bits2num[i].in[j] <== num2bits[ (( i * n + j) \ t) ].out[ ((i * n + j) % t)]; + } + } + } + for( var i = 0 ; i< k ; i++){ + out[i] <== bits2num[i].out; + } + +} + +template SplitSignalsToWordsUnsafe (t,l,n,k) { + + signal input in[l]; + signal output out[k]; + component num2bits[l]; + for (var i = 0 ; i < l ; i++){ + num2bits[i] = Num2Bits(t); + num2bits[i].in <== in[i]; + } + for (var i = 0 ; i < t ; i ++){ + } + component bits2num[k]; + for (var i = 0 ; i < k ; i++){ + bits2num[i] = Bits2Num(n); + + for(var j = 0 ; j < n ; j++){ + if(i*n + j >= l * t){ + bits2num[i].in[j] <== 0; + } + else{ + bits2num[i].in[j] <== num2bits[ (( i * n + j) \ t) ].out[ ((i * n + j) % t)]; + } + } + } + for( var i = 0 ; i< k ; i++){ + out[i] <== bits2num[i].out; + } + +} + +/// NOTE: this circuit is unaudited and should not be used in production +/// @title SplitBytesToWords +/// @notice split an array of bytes into an array of words +/// @notice useful for casting a message or modulus before RSA verification +/// @param l: number of bytes in the input array +/// @param n: number of bits in a word +/// @param k: number of words +/// @input in: array of bytes +/// @output out: array of words +template SplitBytesToWords (l,n,k) { + signal input in[l]; + signal output out[k]; + component num2bits[l]; + for (var i = 0 ; i < l ; i++){ + num2bits[i] = Num2Bits(8); + num2bits[i].in <== in[i]; + } + component bits2num[k]; + for (var i = 0 ; i < k ; i++){ + bits2num[i] = Bits2Num(n); + for(var j = 0 ; j < n ; j++){ + if(i*n + j >= 8 * l){ + bits2num[i].in[j] <== 0; + } + else{ + bits2num[i].in[j] <== num2bits[l - (( i * n + j) \ 8) - 1].out[ ((i * n + j) % 8)]; + } + } + } + for( var i = 0 ; i< k ; i++){ + out[i] <== bits2num[i].out; + } +} \ No newline at end of file diff --git a/circuits/circuits/utils/chunk_data.circom b/circuits/circuits/utils/other/chunk_data.circom similarity index 100% rename from circuits/circuits/utils/chunk_data.circom rename to circuits/circuits/utils/other/chunk_data.circom diff --git a/circuits/circuits/utils/getCommonLength.circom b/circuits/circuits/utils/other/getCommonLength.circom similarity index 100% rename from circuits/circuits/utils/getCommonLength.circom rename to circuits/circuits/utils/other/getCommonLength.circom diff --git a/circuits/circuits/utils/smt.circom b/circuits/circuits/utils/other/smt.circom similarity index 100% rename from circuits/circuits/utils/smt.circom rename to circuits/circuits/utils/other/smt.circom diff --git a/circuits/circuits/utils/rsapss/rsapss.circom b/circuits/circuits/utils/rsapss/rsapss.circom index b982eda2..4ebe9717 100644 --- a/circuits/circuits/utils/rsapss/rsapss.circom +++ b/circuits/circuits/utils/rsapss/rsapss.circom @@ -5,7 +5,7 @@ include "./mgf1.circom"; include "./xor2.circom"; include "../sha2/sha256/sha256_hash_bits.circom"; include "../sha2/sha384/sha384_hash_bits.circom"; -include "../splitSignalsToWords.circom"; +include "../other/bytes.circom"; template VerifyRsaPssSig (n, k, e_bits, ALGO, modulus_bits_size){ diff --git a/circuits/circuits/utils/splitBytesToWords.circom b/circuits/circuits/utils/splitBytesToWords.circom deleted file mode 100644 index 16155dee..00000000 --- a/circuits/circuits/utils/splitBytesToWords.circom +++ /dev/null @@ -1,36 +0,0 @@ -pragma circom 2.1.5; -include "circomlib/circuits/bitify.circom"; - -/// NOTE: this circuit is unaudited and should not be used in production -/// @title SplitBytesToWords -/// @notice split an array of bytes into an array of words -/// @notice useful for casting a message or modulus before RSA verification -/// @param l: number of bytes in the input array -/// @param n: number of bits in a word -/// @param k: number of words -/// @input in: array of bytes -/// @output out: array of words -template SplitBytesToWords (l,n,k) { - signal input in[l]; - signal output out[k]; - component num2bits[l]; - for (var i = 0 ; i < l ; i++){ - num2bits[i] = Num2Bits(8); - num2bits[i].in <== in[i]; - } - component bits2num[k]; - for (var i = 0 ; i < k ; i++){ - bits2num[i] = Bits2Num(n); - for(var j = 0 ; j < n ; j++){ - if(i*n + j >= 8 * l){ - bits2num[i].in[j] <== 0; - } - else{ - bits2num[i].in[j] <== num2bits[l - (( i * n + j) \ 8) - 1].out[ ((i * n + j) % 8)]; - } - } - } - for( var i = 0 ; i< k ; i++){ - out[i] <== bits2num[i].out; - } -} \ No newline at end of file diff --git a/circuits/circuits/utils/splitSignalsToWords.circom b/circuits/circuits/utils/splitSignalsToWords.circom deleted file mode 100644 index 1d911f22..00000000 --- a/circuits/circuits/utils/splitSignalsToWords.circom +++ /dev/null @@ -1,72 +0,0 @@ -pragma circom 2.1.5; -include "circomlib/circuits/bitify.circom"; - -/// NOTE: this circuit is unaudited and should not be used in production -/// @title SplitBytesToWords -/// @notice split an array of bytes into an array of words -/// @notice useful for casting a message or modulus before RSA verification -/// @param l: number of bytes in the input array -/// @param n: number of bits in a word -/// @param k: number of words -/// @input in: array of bytes -/// @output out: array of words -template SplitSignalsToWords (t,l,n,k) { - assert(n*k >= t*l); - - signal input in[l]; - signal output out[k]; - component num2bits[l]; - for (var i = 0 ; i < l ; i++){ - num2bits[i] = Num2Bits(t); - num2bits[i].in <== in[i]; - } - for (var i = 0 ; i < t ; i ++){ - } - component bits2num[k]; - for (var i = 0 ; i < k ; i++){ - bits2num[i] = Bits2Num(n); - - for(var j = 0 ; j < n ; j++){ - if(i*n + j >= l * t){ - bits2num[i].in[j] <== 0; - } - else{ - bits2num[i].in[j] <== num2bits[ (( i * n + j) \ t) ].out[ ((i * n + j) % t)]; - } - } - } - for( var i = 0 ; i< k ; i++){ - out[i] <== bits2num[i].out; - } - -} - -template SplitSignalsToWordsUnsafe (t,l,n,k) { - - signal input in[l]; - signal output out[k]; - component num2bits[l]; - for (var i = 0 ; i < l ; i++){ - num2bits[i] = Num2Bits(t); - num2bits[i].in <== in[i]; - } - for (var i = 0 ; i < t ; i ++){ - } - component bits2num[k]; - for (var i = 0 ; i < k ; i++){ - bits2num[i] = Bits2Num(n); - - for(var j = 0 ; j < n ; j++){ - if(i*n + j >= l * t){ - bits2num[i].in[j] <== 0; - } - else{ - bits2num[i].in[j] <== num2bits[ (( i * n + j) \ t) ].out[ ((i * n + j) % t)]; - } - } - } - for( var i = 0 ; i< k ; i++){ - out[i] <== bits2num[i].out; - } - -} \ No newline at end of file diff --git a/circuits/circuits/utils/xor.circom b/circuits/circuits/utils/xor.circom deleted file mode 100644 index 21b2c308..00000000 --- a/circuits/circuits/utils/xor.circom +++ /dev/null @@ -1,11 +0,0 @@ -pragma circom 2.1.5; - -template Xor2(n) { - signal input a[n]; - signal input b[n]; - signal output out[n]; - - for (var k=0; k { - return await wasm_tester(path.join(circuitPath), { - include: ['node_modules'], - }); - }; - - function buffer2bitArray(b) { - const res = []; - for (let i = 0; i < b.length; i++) { - for (let j = 0; j < 8; j++) { - res.push((b[i] >> (7 - j)) & 1); - } - } - return res; - } - - function num2Bits(n, input) { - let out = []; - for (let i = 0; i < n; i++) { - out[i] = (input >> i) & 1; - } - return out; - } - - const bitArray2buffer = (a) => { - const len = Math.floor((a.length - 1) / 8) + 1; - const b = Buffer.alloc(len); - - for (let i = 0; i < a.length; i++) { - const p = Math.floor(i / 8); - b[p] = b[p] | (Number(a[i]) << (7 - (i % 8))); - } - return b; - }; - - const MGF1 = (mgfSeed: Buffer, maskLen: number) => { - const hLen = hashLen; - if (maskLen > 0xffffffff * hLen) { - throw new Error('mask too long'); - } - - var T = []; - for (var i = 0; i <= Math.ceil(maskLen / hLen) - 1; i++) { - var C = Buffer.alloc(4); - C.writeUInt32BE(i); - const hash3 = createHash('sha256'); - hash3.update(Buffer.concat([mgfSeed, C])); - T.push(hash3.digest()); - } - return Buffer.concat(T).slice(0, maskLen); - }; - - it('Should compile', async function () { - await compileCircuit('circuits/tests/mgf1Sha256/Mgf1Sha256_tester.circom'); - }); - - it('Should generate correct MGF1 output - 4 Byte Seed', async function () { - const seed = 12345678; - const maskLen = 32; - const seedLen = 4; // 4 bytes - set in the circuit - - const bitArray = num2Bits(seedLen * 8, seed); - const mgfSeed = bitArray2buffer(bitArray); - - const expected = MGF1(mgfSeed, maskLen); - - const circuit = await compileCircuit('circuits/tests/mgf1Sha256/Mgf1Sha256_tester.circom'); - const expected_mask_output = buffer2bitArray(expected); - const inputs = { - seed: seed, - expected_mask_output, - }; - - const witness = await circuit.calculateWitness(inputs); - await circuit.checkConstraints(witness); - }); - - it('Should generate correct MGF1 output - 32 Byte Seed', async function () { - const randBytes = randomBytes(32); - - const maskLen = 32; - const seedLen = 32; // set in circuit - const expected = MGF1(randBytes, maskLen); - - const circuit = await compileCircuit( - 'circuits/tests/mgf1Sha256/Mgf1Sha256_32Bytes_tester.circom' - ); - const expected_mask_output = buffer2bitArray(expected); - const inputs = { - seed: buffer2bitArray(randBytes), - expected_mask_output, - }; - - const witness = await circuit.calculateWitness(inputs); - await circuit.checkConstraints(witness); - }); - - it('Should generate correct MGF1 output - seedLen value > than actual seed length', async function () { - const seed = 1234; - const maskLen = 32; - const seedLen = 4; //set in circuit - - const bitArray = num2Bits(seedLen * 8, seed); - const mgfSeed = bitArray2buffer(bitArray); - - const expected = MGF1(mgfSeed, maskLen); - - const circuit = await compileCircuit('circuits/tests/mgf1Sha256/Mgf1Sha256_tester.circom'); - const expected_mask_output = buffer2bitArray(expected); - const inputs = { - seed: seed, - expected_mask_output, - }; - - const witness = await circuit.calculateWitness(inputs); - await circuit.checkConstraints(witness); - }); - - it('Should generate correct MGF1 output - maskLen == 1', async function () { - const seed = 12345678; - const maskLen = 1; - const seedLen = 4; - - const bitArray = num2Bits(seedLen * 8, seed); - const mgfSeed = bitArray2buffer(bitArray); - - const expected = MGF1(mgfSeed, maskLen); - - const circuit = await compileCircuit( - 'circuits/tests/mgf1Sha256/Mgf1Sha256_1ByteMask_tester.circom' - ); - const expected_mask_output = buffer2bitArray(expected); - const inputs = { - seed: seed, - expected_mask_output, - }; - - const witness = await circuit.calculateWitness(inputs); - await circuit.checkConstraints(witness); - }); -}); diff --git a/circuits/tests/other_circuits/rsa_verifier.test.ts b/circuits/tests/other_circuits/rsa_verifier.test.ts deleted file mode 100644 index a5733799..00000000 --- a/circuits/tests/other_circuits/rsa_verifier.test.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { expect } from 'chai'; -import { X509Certificate } from 'crypto'; -import path from 'path'; -import { getCSCAInputs, getTBSHash } from '../../../common/src/utils/csca'; -import { wasm as wasm_tester } from 'circom_tester'; -import forge from 'node-forge'; - -import { - mock_dsc_sha256_rsa_2048, - mock_csca_sha256_rsa_2048, - mock_dsc_sha1_rsa_2048, - mock_csca_sha1_rsa_2048, -} from '../../../common/src/constants/mockCertificates'; - -function loadCertificates(dscCertContent: string, cscaCertContent: string) { - const dscCert = new X509Certificate(dscCertContent); - const cscaCert = new X509Certificate(cscaCertContent); - const dscCert_forge = forge.pki.certificateFromPem(dscCertContent); - const cscaCert_forge = forge.pki.certificateFromPem(cscaCertContent); - - return { dscCert, cscaCert, dscCert_forge, cscaCert_forge }; -} - -describe('RSA Verifier', function () { - this.timeout(0); - let circuit; - - this.beforeAll(async () => { - const circuitPath = path.resolve(__dirname, '../../circuits/tests/utils/rsa_verifier.circom'); - circuit = await wasm_tester(circuitPath, { - include: [ - 'node_modules', - './node_modules/@zk-kit/binary-merkle-root.circom/src', - './node_modules/circomlib/circuits', - ], - }); - }); - describe('Circuit', () => { - it('should compile and load the circuit', () => { - expect(circuit).not.to.be.undefined; - }); - }); - - describe('SHA-256 certificates', async () => { - const { dscCert, cscaCert, dscCert_forge, cscaCert_forge } = loadCertificates( - mock_dsc_sha256_rsa_2048, - mock_csca_sha256_rsa_2048 - ); - const n = 121; - const k = 17; - - it('should verify DSC has been signed by the CSCA', () => { - const isVerified = dscCert.verify(cscaCert.publicKey); - console.log(`SHA-256 DSC certificate verification result: ${isVerified}`); - expect(isVerified).to.be.true; - }); - - // it('should extract and log certificate information', async () => { - // const csca_inputs = getCSCAInputs('0', dscCert_forge, cscaCert_forge, n, k, n, k, 2048, true); - // const tbsCertificateHashFormatted = getTBSHash(dscCert_forge, 'sha256', n, k); - - // const inputs = { - // message: tbsCertificateHashFormatted, - // signature: csca_inputs.inputs.dsc_signature, - // modulus: csca_inputs.inputs.dsc_modulus, - // }; - // const witness = await circuit.calculateWitness(inputs, true); - // }); - }); - - describe('SHA-1 certificates', () => { - const { dscCert, cscaCert, dscCert_forge, cscaCert_forge } = loadCertificates( - mock_dsc_sha1_rsa_2048, - mock_csca_sha1_rsa_2048 - ); - - it('should verify DSC has been signed by the CSCA', () => { - const isVerified = dscCert.verify(cscaCert.publicKey); - console.log(`SHA-1 DSC certificate verification result: ${isVerified}`); - expect(isVerified).to.be.true; - }); - /// TODO: Use SHA1RSA verifier circuit (won't work either case because of padding) - // it('should extract and log certificate information', async () => { - // const csca_inputs = getCSCAInputs("0", dscCert_forge, cscaCert_forge, 64, 32, 64, 32, 2048, true); - // const tbsCertificateHashFormatted = getTBSHash(dscCert_forge, 'sha1'); - - // const inputs = { - // "message": tbsCertificateHashFormatted, - // "signature": csca_inputs.dsc_signature, - // "modulus": csca_inputs.csca_modulus - // } - // console.log("final inputs: ", inputs); - // const witness = await circuit.calculateWitness(inputs, true); - // console.log(witness); - // }); - }); -}); diff --git a/circuits/tests/other_circuits/rsapss_verifier.test.ts b/circuits/tests/other_circuits/rsapss_verifier.test.ts deleted file mode 100644 index b6dd17f0..00000000 --- a/circuits/tests/other_circuits/rsapss_verifier.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { expect } from 'chai'; -import { X509Certificate } from 'crypto'; -import path from 'path'; -import { getCSCAInputs, getTBSHash } from '../../../common/src/utils/csca'; -import { wasm as wasm_tester } from 'circom_tester'; -import forge from 'node-forge'; - -import { - mock_dsc_sha256_rsapss_2048, - mock_csca_sha256_rsapss_2048, -} from '../../../common/src/constants/mockCertificates'; - -function loadCertificates(dscCertContent: string, cscaCertContent: string) { - const dscCert = new X509Certificate(dscCertContent); - const cscaCert = new X509Certificate(cscaCertContent); - const dscCert_forge = forge.pki.certificateFromPem(dscCertContent); - const cscaCert_forge = forge.pki.certificateFromPem(cscaCertContent); - - return { dscCert, cscaCert, dscCert_forge, cscaCert_forge }; -} - -describe('RSAPSS Verifier', function () { - this.timeout(0); - let circuit; - - this.beforeAll(async () => { - const circuitPath = path.resolve( - __dirname, - '../../circuits/tests/utils/rsapss_verifier.circom' - ); - circuit = await wasm_tester(circuitPath, { - include: [ - 'node_modules', - './node_modules/@zk-kit/binary-merkle-root.circom/src', - './node_modules/circomlib/circuits', - ], - }); - }); - describe('Circuit', () => { - it('should compile and load the circuit', () => { - expect(circuit).not.to.be.undefined; - }); - }); - - describe('SHA-256 certificates', async () => { - const { dscCert, cscaCert, dscCert_forge, cscaCert_forge } = loadCertificates( - mock_dsc_sha256_rsapss_2048, - mock_csca_sha256_rsapss_2048 - ); - const n = 64; - const k = 32; - - it('should verify DSC has been signed by the CSCA', () => { - const isVerified = dscCert.verify(cscaCert.publicKey); - console.log(`SHA-256 DSC certificate verification result: ${isVerified}`); - expect(isVerified).to.be.true; - }); - - // it('should extract and log certificate information', async () => { - // const csca_inputs = getCSCAInputs('0', dscCert_forge, cscaCert_forge, n, k, n, k, 960, true); - // // const tbsCertificateHashFormatted = getTBSHash(dscCert_forge, 'sha256', n, k); - - // const inputs = { - // raw_message: csca_inputs.inputs.raw_dsc_cert, - // raw_message_padded_bytes: csca_inputs.inputs.raw_dsc_cert_padded_bytes, - // signature: csca_inputs.inputs.dsc_signature, - // modulus: csca_inputs.inputs.dsc_modulus, - // }; - // /const witness = await circuit.calculateWitness(inputs, true); - // }); - }); -}); From c78a541b84cb6e2093c51f0336a4bcd6927f1356 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Thu, 19 Sep 2024 14:03:25 +0200 Subject: [PATCH 41/60] fix genMockPassportData.test.ts --- common/tests/genMockPassportData.test.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/common/tests/genMockPassportData.test.ts b/common/tests/genMockPassportData.test.ts index 8839b9c6..d929cc4f 100644 --- a/common/tests/genMockPassportData.test.ts +++ b/common/tests/genMockPassportData.test.ts @@ -31,20 +31,20 @@ describe('Mock Passport Data Generator', function () { }); function verify(passportData: PassportData): boolean { - const { mrz, dsc, dataGroupHashes, eContent, encryptedDigest } = passportData; + const { mrz, dsc, eContent, signedAttr, encryptedDigest } = passportData; const { signatureAlgorithm, hashFunction, hashLen, curve } = parseCertificate(dsc); const formattedMrz = formatMrz(mrz); const mrzHash = hash(hashFunction, formattedMrz); - const dg1HashOffset = findSubarrayIndex(dataGroupHashes, mrzHash) - assert(dg1HashOffset !== -1, 'MRZ hash index not found in dataGroupHashes'); - - const concatHash = hash(hashFunction, dataGroupHashes) + const dg1HashOffset = findSubarrayIndex(eContent, mrzHash) + assert(dg1HashOffset !== -1, 'MRZ hash index not found in eContent'); + console.error("\x1b[32m", "signatureAlgorithm", signatureAlgorithm, " hashFunction", hashFunction, "eContent size", eContent.length, "signedAttr size", signedAttr.length, "\x1b[0m"); + const concatHash = hash(hashFunction, eContent) assert( arraysAreEqual( concatHash, - eContent.slice(eContent.length - hashLen) + signedAttr.slice(signedAttr.length - hashLen) ), - 'concatHash is not at the right place in eContent' + 'concatHash is not at the right place in signedAttr' ); if (signatureAlgorithm === 'ecdsa') { @@ -58,7 +58,7 @@ function verify(passportData: PassportData): boolean { const key = ec.keyFromPublic(publicKeyBuffer); const md = hashFunction === 'sha1' ? forge.md.sha1.create() : forge.md.sha256.create(); - md.update(forge.util.binary.raw.encode(new Uint8Array(eContent))); + md.update(forge.util.binary.raw.encode(new Uint8Array(signedAttr))); const msgHash = md.digest().toHex() const signature_crypto = Buffer.from(encryptedDigest).toString('hex'); @@ -68,7 +68,7 @@ function verify(passportData: PassportData): boolean { const publicKey = cert.publicKey as forge.pki.rsa.PublicKey; const md = forge.md[hashFunction].create(); - md.update(forge.util.binary.raw.encode(new Uint8Array(eContent))); + md.update(forge.util.binary.raw.encode(new Uint8Array(signedAttr))); const signature = Buffer.from(encryptedDigest).toString('binary'); From a239169f80817a4689942f2beea55688f32cc0ca Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Thu, 19 Sep 2024 19:03:39 +0200 Subject: [PATCH 42/60] split bitmap into selector_dg1 and selector_older_than, fix nullifier generation in prove circuits --- circuits/README.md | 2 +- circuits/circuits/disclose/disclose.circom | 27 +-- .../circuits/disclose/vc_and_disclose.circom | 7 +- circuits/circuits/ofac/ofac_name.circom | 2 +- circuits/circuits/ofac/ofac_name_dob.circom | 2 +- .../circuits/ofac/ofac_passport_number.circom | 2 +- .../instances/prove_rsa_65537_sha256.circom | 2 +- .../circuits/prove/openpassport_prove.circom | 11 +- .../register_rsa_65537_sha256.circom | 2 +- circuits/circuits/utils/other/smt.circom | 2 +- .../utils/passport/signatureVerifier.circom | 23 ++- circuits/circuits/utils/rsa/rsa.circom | 181 ++++++++++++++++++ circuits/tests/disclose/disclose.test.ts | 39 ++-- circuits/tests/ofac/ofac.test.ts | 24 ++- circuits/tests/prove.test.ts | 14 +- .../utils/generateMockInputsInCircuits.ts | 8 +- common/src/constants/constants.ts | 4 +- common/src/utils/generateInputs.ts | 19 +- common/src/utils/utils.ts | 2 +- contracts/test/RegisterAndDisclose.ts | 10 +- sdk/tests/utils/generateInputsInSdk.ts | 4 +- 21 files changed, 300 insertions(+), 87 deletions(-) create mode 100644 circuits/circuits/utils/rsa/rsa.circom diff --git a/circuits/README.md b/circuits/README.md index 9a917ced..17fc242a 100644 --- a/circuits/README.md +++ b/circuits/README.md @@ -31,7 +31,7 @@ The `disclose` circuit is used for the following: 1. Verify that a user knows a secret e.g., he is able to reconstruct one leaf of the merkle tree (a check of the merkle roots will be performed on-chain) 2. Passport expiry is verified 3. A range check is performed over the age of the user -4. The output is multiplied by an input bitmap to allow the user to disclose only what they want to disclose. +4. The output is multiplied by an input selector_dg1 to allow the user to disclose only what they want to disclose. 5. Final output is packed. Any application that wants to use OpenPassport can actually build its own `disclose` circuit. diff --git a/circuits/circuits/disclose/disclose.circom b/circuits/circuits/disclose/disclose.circom index 2431c170..c6ebc816 100644 --- a/circuits/circuits/disclose/disclose.circom +++ b/circuits/circuits/disclose/disclose.circom @@ -8,10 +8,12 @@ include "binary-merkle-root.circom"; template DISCLOSE() { signal input dg1[93]; - signal input bitmap[90]; // 88 for MRZ + 2 for majority + signal input selector_dg1[88]; // 88 for MRZ + signal input selector_older_than; signal input current_date[6]; // YYMMDD - num signal input majority[2]; // YY - ASCII signal output revealedData_packed[3]; + signal output older_than[2]; signal output nullifier; // Verify validity of the passport @@ -31,20 +33,21 @@ template DISCLOSE() { isOlderThan.birthDateASCII[i] <== dg1[62 + i]; } - signal older_than[2]; - older_than[0] <== isOlderThan.out * majority[0]; - older_than[1] <== isOlderThan.out * majority[1]; + signal older_than_verified[2]; + older_than_verified[0] <== isOlderThan.out * majority[0]; + older_than_verified[1] <== isOlderThan.out * majority[1]; - // constrain bitmap to be 0s or 1s - for (var i = 0; i < 90; i++) { - bitmap[i] * (bitmap[i] - 1) === 0; + // constrain selector_dg1 to be 0s or 1s + for (var i = 0; i < 88; i++) { + selector_dg1[i] * (selector_dg1[i] - 1) === 0; } - signal revealedData[90]; + signal revealedData[88]; for (var i = 0; i < 88; i++) { - revealedData[i] <== dg1[5+i] * bitmap[i]; + revealedData[i] <== dg1[5+i] * selector_dg1[i]; } - revealedData[88] <== older_than[0] * bitmap[88]; - revealedData[89] <== older_than[1] * bitmap[89]; - revealedData_packed <== PackBytes(90)(revealedData); + older_than[0] <== older_than_verified[0] * selector_older_than; + older_than[1] <== older_than_verified[1] * selector_older_than; + + revealedData_packed <== PackBytes(88)(revealedData); } \ No newline at end of file diff --git a/circuits/circuits/disclose/vc_and_disclose.circom b/circuits/circuits/disclose/vc_and_disclose.circom index 005a06a4..edbe0477 100644 --- a/circuits/circuits/disclose/vc_and_disclose.circom +++ b/circuits/circuits/disclose/vc_and_disclose.circom @@ -16,7 +16,8 @@ template VC_AND_DISCLOSE( nLevels) { signal input path[nLevels]; signal input siblings[nLevels]; - signal input bitmap[90]; // 88 for MRZ + 2 for majority + signal input selector_dg1[88]; // 88 for MRZ + signal input selector_older_than; signal input scope; signal input current_date[6]; // YYMMDD - num signal input majority[2]; // YY - ASCII @@ -28,7 +29,8 @@ template VC_AND_DISCLOSE( nLevels) { // verify passport validity and disclose optional data component disclose = DISCLOSE(); disclose.dg1 <== dg1; - disclose.bitmap <== bitmap; + disclose.selector_dg1 <== selector_dg1; + disclose.selector_older_than <== selector_older_than; disclose.current_date <== current_date; disclose.majority <== majority; @@ -38,6 +40,7 @@ template VC_AND_DISCLOSE( nLevels) { poseidon_nullifier.inputs[1] <== scope; signal output nullifier <== poseidon_nullifier.out; signal output revealedData_packed[3] <== disclose.revealedData_packed; + signal output older_than[2] <== disclose.older_than; } component main { public [ merkle_root, scope, user_identifier, current_date, attestation_id] } = VC_AND_DISCLOSE(16); \ No newline at end of file diff --git a/circuits/circuits/ofac/ofac_name.circom b/circuits/circuits/ofac/ofac_name.circom index 1d6547fd..d19e1721 100644 --- a/circuits/circuits/ofac/ofac_name.circom +++ b/circuits/circuits/ofac/ofac_name.circom @@ -3,7 +3,7 @@ pragma circom 2.1.5; include "circomlib/circuits/poseidon.circom"; include "circomlib/circuits/comparators.circom"; include "binary-merkle-root.circom"; -include "../utils/getCommonLength.circom"; +include "../utils/other/getCommonLength.circom"; include "../disclose/verify_commitment.circom"; include "../utils/other/smt.circom"; diff --git a/circuits/circuits/ofac/ofac_name_dob.circom b/circuits/circuits/ofac/ofac_name_dob.circom index 96cbef30..62e34560 100644 --- a/circuits/circuits/ofac/ofac_name_dob.circom +++ b/circuits/circuits/ofac/ofac_name_dob.circom @@ -4,7 +4,7 @@ include "circomlib/circuits/poseidon.circom"; include "circomlib/circuits/comparators.circom"; include "circomlib/circuits/bitify.circom"; include "binary-merkle-root.circom"; -include "../utils/getCommonLength.circom"; +include "../utils/other/getCommonLength.circom"; include "../disclose/verify_commitment.circom"; include "../utils/other/smt.circom"; diff --git a/circuits/circuits/ofac/ofac_passport_number.circom b/circuits/circuits/ofac/ofac_passport_number.circom index d9c63e62..6bb31e4e 100644 --- a/circuits/circuits/ofac/ofac_passport_number.circom +++ b/circuits/circuits/ofac/ofac_passport_number.circom @@ -5,7 +5,7 @@ include "circomlib/circuits/comparators.circom"; include "circomlib/circuits/bitify.circom"; include "../utils/other/array.circom"; include "binary-merkle-root.circom"; -include "../utils/getCommonLength.circom"; +include "../utils/other/getCommonLength.circom"; include "../disclose/verify_commitment.circom"; include "../utils/other/smt.circom"; diff --git a/circuits/circuits/prove/instances/prove_rsa_65537_sha256.circom b/circuits/circuits/prove/instances/prove_rsa_65537_sha256.circom index b2d0e6c5..a2e056b8 100644 --- a/circuits/circuits/prove/instances/prove_rsa_65537_sha256.circom +++ b/circuits/circuits/prove/instances/prove_rsa_65537_sha256.circom @@ -2,4 +2,4 @@ pragma circom 2.1.6; include "../openpassport_prove.circom"; -component main { public [ user_identifier, scope ] } = OPENPASSPORT_PROVE(1, 64, 32, 640, 512); \ No newline at end of file +component main { public [ user_identifier, scope ] } = OPENPASSPORT_PROVE(1, 64, 32, 384, 320); \ No newline at end of file diff --git a/circuits/circuits/prove/openpassport_prove.circom b/circuits/circuits/prove/openpassport_prove.circom index 9d68322e..c94e0985 100644 --- a/circuits/circuits/prove/openpassport_prove.circom +++ b/circuits/circuits/prove/openpassport_prove.circom @@ -25,14 +25,16 @@ template OPENPASSPORT_PROVE(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, M signal input pubKey[kScaled]; // dislose related inputs - signal input bitmap[90]; + signal input selector_dg1[88]; + signal input selector_older_than; signal input current_date[6]; // YYMMDD - num signal input majority[2]; // YY - ASCII signal input user_identifier; signal input scope; - signal output nullifier <== CustomHasher(kScaled)(signature); // generate nullifier + signal signatureHashed <== CustomHasher(kScaled)(signature); // generate nullifier + signal output nullifier <== Poseidon(2)([signatureHashed, scope]); // verify passport signature PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset, dg2_hash, eContent,eContent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature); @@ -40,10 +42,11 @@ template OPENPASSPORT_PROVE(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, M // optionally disclose data component disclose = DISCLOSE(); disclose.dg1 <== dg1; - disclose.bitmap <== bitmap; + disclose.selector_dg1 <== selector_dg1; + disclose.selector_older_than <== selector_older_than; disclose.current_date <== current_date; disclose.majority <== majority; signal output revealedData_packed[3] <== disclose.revealedData_packed; - + signal output older_than[2] <== disclose.older_than; } \ No newline at end of file diff --git a/circuits/circuits/register/instances/register_rsa_65537_sha256.circom b/circuits/circuits/register/instances/register_rsa_65537_sha256.circom index bf7123c8..0dedbcfb 100644 --- a/circuits/circuits/register/instances/register_rsa_65537_sha256.circom +++ b/circuits/circuits/register/instances/register_rsa_65537_sha256.circom @@ -2,4 +2,4 @@ pragma circom 2.1.6; include "../openpassport_register.circom"; -component main = OPENPASSPORT_REGISTER(1, 64, 32, 640, 512); \ No newline at end of file +component main = OPENPASSPORT_REGISTER(1, 121, 17, 384, 320); \ No newline at end of file diff --git a/circuits/circuits/utils/other/smt.circom b/circuits/circuits/utils/other/smt.circom index 14bffa06..71656df5 100644 --- a/circuits/circuits/utils/other/smt.circom +++ b/circuits/circuits/utils/other/smt.circom @@ -3,7 +3,7 @@ pragma circom 2.1.5; include "circomlib/circuits/poseidon.circom"; include "circomlib/circuits/comparators.circom"; include "circomlib/circuits/bitify.circom"; -include "./other/array.circom"; +include "./array.circom"; include "binary-merkle-root.circom"; include "getCommonLength.circom"; diff --git a/circuits/circuits/utils/passport/signatureVerifier.circom b/circuits/circuits/utils/passport/signatureVerifier.circom index ed871327..7ca8c00e 100644 --- a/circuits/circuits/utils/passport/signatureVerifier.circom +++ b/circuits/circuits/utils/passport/signatureVerifier.circom @@ -1,11 +1,10 @@ pragma circom 2.1.6; -// include "@zk-email/circuits/lib/rsa.circom"; include "../rsa/rsaPkcs1.circom"; -include "../rsa/rsaPkcs1v15.circom"; -// include "../circom-ecdsa/ecdsa.circom"; +// include "../rsa/rsaPkcs1v15.circom"; include "secp256r1Verifier.circom"; include "../rsapss/rsapss.circom"; +include "../rsa/rsa.circom"; template SignatureVerifier(signatureAlgorithm, n, k) { var kLengthFactor = getKLengthFactor(signatureAlgorithm); @@ -22,11 +21,21 @@ template SignatureVerifier(signatureAlgorithm, n, k) { signal hashParsed[msg_len] <== HashParser(signatureAlgorithm, n, k)(hash); if (signatureAlgorithm == 1) { - var exponentBits = getExponentBits(signatureAlgorithm); - component rsa = RsaVerifierPkcs1v15(n, k, exponentBits, HASH_LEN_BITS); - rsa.hashed <== hash; - rsa.pubkey <== pubKey; + // var exponentBits = getExponentBits(signatureAlgorithm); + // component rsa = RsaVerifierPkcs1v15(n, k, exponentBits, HASH_LEN_BITS); + // rsa.hashed <== hash; + // rsa.pubkey <== pubKey; + // rsa.signature <== signature; + component rsa = RSAVerifier65537(n, k); + for (var i = 0; i < msg_len; i++) { + rsa.message[i] <== hashParsed[i]; + } + for (var i = msg_len; i < k; i++) { + rsa.message[i] <== 0; + } + rsa.modulus <== pubKey; rsa.signature <== signature; + } if (signatureAlgorithm == 3 ) { component rsa_pkcs1 = RSAVerifier65537Pkcs1(n, k); diff --git a/circuits/circuits/utils/rsa/rsa.circom b/circuits/circuits/utils/rsa/rsa.circom new file mode 100644 index 00000000..fe3dbc1d --- /dev/null +++ b/circuits/circuits/utils/rsa/rsa.circom @@ -0,0 +1,181 @@ +pragma circom 2.1.6; + +include "../other/fp.circom"; + + +/// @title RSAVerifier65537 +/// @notice Verifies an RSA signature with exponent 65537. +/// @param n Number of bits per chunk the modulus is split into. Recommended to be 121. +/// @param k Number of chunks the modulus is split into. Recommended to be 17. +/// @input message[k] The message that was signed; assumes to consist of `k` chunks that fit in `n` bits (also constrained implicitly). +/// @input signature[k] The signature to verify; assumes to consist of `k` chunks that fit in `n` bits (also constrained implicitly). +/// @input modulus[k] The modulus of the RSA key (pubkey); assumes to consist of `k` chunks that fit in `n` bits (also constrained implicitly). +template RSAVerifier65537(n, k) { + signal input message[k]; + signal input signature[k]; + signal input modulus[k]; + + component padder = RSAPad(n, k); + for (var i = 0; i < k; i++) { + padder.modulus[i] <== modulus[i]; + padder.message[i] <== message[i]; + } + + // Check that the signature is in proper form and reduced mod modulus. + component signatureRangeCheck[k]; + component bigLessThan = BigLessThan(n, k); + for (var i = 0; i < k; i++) { + signatureRangeCheck[i] = Num2Bits(n); + signatureRangeCheck[i].in <== signature[i]; + bigLessThan.a[i] <== signature[i]; + bigLessThan.b[i] <== modulus[i]; + } + bigLessThan.out === 1; + + component bigPow = FpPow65537Mod(n, k); + for (var i = 0; i < k; i++) { + bigPow.base[i] <== signature[i]; + bigPow.modulus[i] <== modulus[i]; + } + + // By construction of the padding, the padded message is necessarily + // smaller than the modulus. Thus, we don't have to check that bigPow is fully reduced. + for (var i = 0; i < k; i++) { + bigPow.out[i] === padder.out[i]; + } +} + + +/// @title FpPow65537Mod +/// @notice Computes base^65537 mod modulus +/// @dev Does not necessarily reduce fully mod modulus (the answer could be too big by a multiple of modulus) +/// @param n Number of bits per chunk the modulus is split into. +/// @param k Number of chunks the modulus is split into. +/// @input base The base to exponentiate; assumes to consist of `k` chunks, each of which must fit in `n` bits +/// @input modulus The modulus; assumes to consist of `k` chunks, each of which must fit in `n` bits +/// @output out The result of the exponentiation. +template FpPow65537Mod(n, k) { + signal input base[k]; + signal input modulus[k]; + + signal output out[k]; + + component doublers[16]; + component adder = FpMul(n, k); + for (var i = 0; i < 16; i++) { + doublers[i] = FpMul(n, k); + } + + for (var j = 0; j < k; j++) { + adder.p[j] <== modulus[j]; + for (var i = 0; i < 16; i++) { + doublers[i].p[j] <== modulus[j]; + } + } + for (var j = 0; j < k; j++) { + doublers[0].a[j] <== base[j]; + doublers[0].b[j] <== base[j]; + } + for (var i = 0; i + 1 < 16; i++) { + for (var j = 0; j < k; j++) { + doublers[i + 1].a[j] <== doublers[i].out[j]; + doublers[i + 1].b[j] <== doublers[i].out[j]; + } + } + for (var j = 0; j < k; j++) { + adder.a[j] <== base[j]; + adder.b[j] <== doublers[15].out[j]; + } + for (var j = 0; j < k; j++) { + out[j] <== adder.out[j]; + } +} + +/// @title RSAPad +/// @notice Pads a message for RSA signing. +/// @param n Number of bits per chunk the modulus is split into. +/// @param k Number of chunks the modulus is split into. +/// @input modulus The modulus of the RSA key (pubkey). +/// @input message The message to pad. +/// @output out The padded message. +template RSAPad(n, k) { + signal input modulus[k]; + signal input message[k]; + signal output out[k]; + + // The extra 152 bits comes from 0x3031300d060960864801650304020105000420 + // This is due to padding from the RSASSA-PKCS1-v1_5 standard + var baseLen = 408; + var msgLen = 256; + + signal paddedMessageBits[n*k]; + + component modulusN2B[k]; + component messageN2B[k]; + signal modulusBits[n*k]; + signal messageBits[n*k]; + for (var i = 0; i < k; i++) { + messageN2B[i] = Num2Bits(n); + messageN2B[i].in <== message[i]; + for (var j = 0; j < n; j++) { + messageBits[i*n+j] <== messageN2B[i].out[j]; + } + modulusN2B[i] = Num2Bits(n); + modulusN2B[i].in <== modulus[i]; + for (var j = 0; j < n; j++) { + modulusBits[i*n+j] <== modulusN2B[i].out[j]; + } + } + + for (var i = msgLen; i < n*k; i++) { + messageBits[i] === 0; + } + + for (var i = 0; i < msgLen; i++) { + paddedMessageBits[i] <== messageBits[i]; + } + + for (var i = baseLen; i < baseLen + 8; i++) { + paddedMessageBits[i] <== 0; + } + + for (var i = msgLen; i < baseLen; i++) { + paddedMessageBits[i] <== (0x3031300d060960864801650304020105000420 >> (i - msgLen)) & 1; + } + + component modulusZero[(n*k + 7 - (baseLen + 8))\8]; + { + var modulusPrefix = 0; + for (var i = n*k - 1; i >= baseLen + 8; i--) { + if (i+8 < n*k) { + modulusPrefix += modulusBits[i+8]; + if (i % 8 == 0) { + var idx = (i - (baseLen + 8)) \ 8; + modulusZero[idx] = IsZero(); + modulusZero[idx].in <== modulusPrefix; + paddedMessageBits[i] <== 1-modulusZero[idx].out; + } else { + paddedMessageBits[i] <== paddedMessageBits[i+1]; + } + } else { + paddedMessageBits[i] <== 0; + } + } + } + + // The RFC guarantees at least 8 octets of 0xff padding. + assert(baseLen + 8 + 65 <= n * k); + + for (var i = baseLen + 8; i < baseLen + 8 + 65; i++) { + paddedMessageBits[i] === 1; + } + + component passedMessageB2N[k]; + for (var i = 0; i < k; i++) { + passedMessageB2N[i] = Bits2Num(n); + for (var j = 0; j < n; j++) { + passedMessageB2N[i].in[j] <== paddedMessageBits[i*n+j]; + } + out[i] <== passedMessageB2N[i].out; + } +} diff --git a/circuits/tests/disclose/disclose.test.ts b/circuits/tests/disclose/disclose.test.ts index 63c03237..84d7bafd 100644 --- a/circuits/tests/disclose/disclose.test.ts +++ b/circuits/tests/disclose/disclose.test.ts @@ -38,7 +38,8 @@ describe('Disclose', function () { const majority = '18'; const user_identifier = crypto.randomUUID(); - const bitmap = Array(90).fill('1'); + const selector_dg1 = Array(88).fill('1'); + const selector_older_than = '1'; const scope = '@coboyApp'; // compute the commitment and insert it in the tree @@ -55,7 +56,8 @@ describe('Disclose', function () { passportData, tree, majority, - bitmap, + selector_dg1, + selector_older_than, scope, user_identifier, ); @@ -118,18 +120,18 @@ describe('Disclose', function () { return acc; }, {}); - const bitmap = Array(90).fill('0'); + const selector_dg1 = Array(88).fill('0'); Object.entries(attributeToReveal).forEach(([attribute, reveal]) => { if (reveal) { const [start, end] = attributeToPosition[attribute]; - bitmap.fill('1', start, end + 1); + selector_dg1.fill('1', start, end + 1); } }); inputs = { ...inputs, - bitmap: bitmap.map(String), + selector_dg1: selector_dg1.map(String), }; w = await circuit.calculateWitness(inputs); @@ -139,7 +141,7 @@ describe('Disclose', function () { const reveal_unpacked = formatAndUnpackReveal(revealedData_packed); for (let i = 0; i < reveal_unpacked.length; i++) { - if (bitmap[i] == '1') { + if (selector_dg1[i] == '1') { const char = String.fromCharCode(Number(inputs.dg1[i + 5])); assert(reveal_unpacked[i] == char, 'Should reveal the right character'); } else { @@ -151,33 +153,27 @@ describe('Disclose', function () { }); it('should allow disclosing majority', async function () { - const bitmap = Array(90).fill('0'); - bitmap[88] = '1'; - bitmap[89] = '1'; + const selector_dg1 = Array(88).fill('0'); w = await circuit.calculateWitness({ ...inputs, - bitmap: bitmap.map(String), + selector_dg1: selector_dg1.map(String), }); - const revealedData_packed = await circuit.getOutput(w, ['revealedData_packed[3]']); + const older_than = formatOlderThan(await circuit.getOutput(w, ['older_than[2]'])); - const reveal_unpacked = formatAndUnpackReveal(revealedData_packed); - //console.log("reveal_unpacked", reveal_unpacked) - expect(reveal_unpacked[88]).to.equal('1'); - expect(reveal_unpacked[89]).to.equal('8'); + expect(older_than[0]).to.equal(1); + expect(older_than[1]).to.equal(8); }); it("shouldn't allow disclosing wrong majority", async function () { - const bitmap = Array(90).fill('0'); - bitmap[88] = '1'; - bitmap[89] = '1'; + const selector_dg1 = Array(88).fill('0'); w = await circuit.calculateWitness({ ...inputs, majority: ['5', '0'].map((char) => BigInt(char.charCodeAt(0)).toString()), - bitmap: bitmap.map(String), + selector_dg1: selector_dg1.map(String), }); const revealedData_packed = await circuit.getOutput(w, ['revealedData_packed[3]']); @@ -189,3 +185,8 @@ describe('Disclose', function () { expect(reveal_unpacked[89]).to.equal('\x00'); }); }); + + +const formatOlderThan = (older_than: any) => { + return Object.values(older_than).map((value: any) => parseInt(value) - 48); +}; \ No newline at end of file diff --git a/circuits/tests/ofac/ofac.test.ts b/circuits/tests/ofac/ofac.test.ts index b0cdbbbb..4fed6e3b 100644 --- a/circuits/tests/ofac/ofac.test.ts +++ b/circuits/tests/ofac/ofac.test.ts @@ -35,7 +35,8 @@ function getPassportInputs(passportData: PassportData) { const majority = '18'; const user_identifier = crypto.randomUUID(); - const bitmap = Array(90).fill('1'); + const selector_dg1 = Array(88).fill('1'); + const selector_older_than = '1'; const scope = '@coboyApp'; const pubkey_leaf = getLeaf(passportData.dsc); @@ -48,7 +49,8 @@ function getPassportInputs(passportData: PassportData) { passportData: passportData, commitment: commitment, majority: majority, - bitmap: bitmap, + selector_dg1: selector_dg1, + selector_older_than: selector_older_than, scope: scope, user_identifier: user_identifier, }; @@ -95,7 +97,8 @@ describe('OFAC - Passport number match', function () { inputs.passportData, tree, inputs.majority, - inputs.bitmap, + inputs.selector_dg1, + inputs.selector_older_than, inputs.scope, inputs.user_identifier, passno_smt, @@ -109,7 +112,8 @@ describe('OFAC - Passport number match', function () { mockInputs.passportData, tree, mockInputs.majority, - mockInputs.bitmap, + mockInputs.selector_dg1, + mockInputs.selector_older_than, mockInputs.scope, mockInputs.user_identifier, passno_smt, @@ -182,7 +186,8 @@ describe('OFAC - Name and DOB match', function () { inputs.passportData, tree, inputs.majority, - inputs.bitmap, + inputs.selector_dg1, + inputs.selector_older_than, inputs.scope, inputs.user_identifier, namedob_smt, @@ -196,7 +201,8 @@ describe('OFAC - Name and DOB match', function () { mockInputs.passportData, tree, mockInputs.majority, - mockInputs.bitmap, + mockInputs.selector_dg1, + mockInputs.selector_older_than, mockInputs.scope, mockInputs.user_identifier, namedob_smt, @@ -269,7 +275,8 @@ describe('OFAC - Name match', function () { inputs.passportData, tree, inputs.majority, - inputs.bitmap, + inputs.selector_dg1, + inputs.selector_older_than, inputs.scope, inputs.user_identifier, name_smt, @@ -283,7 +290,8 @@ describe('OFAC - Name match', function () { mockInputs.passportData, tree, mockInputs.majority, - mockInputs.bitmap, + mockInputs.selector_dg1, + mockInputs.selector_older_than, mockInputs.scope, mockInputs.user_identifier, name_smt, diff --git a/circuits/tests/prove.test.ts b/circuits/tests/prove.test.ts index fb3e3465..52e0d3cf 100644 --- a/circuits/tests/prove.test.ts +++ b/circuits/tests/prove.test.ts @@ -9,11 +9,11 @@ import { SignatureAlgorithm } from '../../common/src/utils/types'; import crypto from 'crypto'; const sigAlgs = [ - { sigAlg: 'rsa', hashFunction: 'sha1' }, + // { sigAlg: 'rsa', hashFunction: 'sha1' }, { sigAlg: 'rsa', hashFunction: 'sha256' }, - { sigAlg: 'rsapss', hashFunction: 'sha256' }, - { sigAlg: 'ecdsa', hashFunction: 'sha256' }, - { sigAlg: 'ecdsa', hashFunction: 'sha1' }, + // { sigAlg: 'rsapss', hashFunction: 'sha256' }, + // { sigAlg: 'ecdsa', hashFunction: 'sha256' }, + // { sigAlg: 'ecdsa', hashFunction: 'sha1' }, ]; sigAlgs.forEach(({ sigAlg, hashFunction }) => { @@ -30,12 +30,14 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { const majority = '18'; const user_identifier = crypto.randomUUID(); const scope = '@coboyApp'; - const bitmap = Array(90).fill('1'); + const selector_dg1 = Array(88).fill('1'); + const selector_older_than = '1'; const inputs = generateCircuitInputsProve( passportData, scope, - bitmap, + selector_dg1, + selector_older_than, majority, user_identifier ); diff --git a/circuits/tests/utils/generateMockInputsInCircuits.ts b/circuits/tests/utils/generateMockInputsInCircuits.ts index c63a15a2..a5df1dcc 100644 --- a/circuits/tests/utils/generateMockInputsInCircuits.ts +++ b/circuits/tests/utils/generateMockInputsInCircuits.ts @@ -34,20 +34,18 @@ export const generateCircuitInputsInCircuits = ( secret, dscSecret, attestationId, - passportData, - signatureAlgorithm === 'ecdsa' ? n_dsc_ecdsa : n_dsc, - signatureAlgorithm === 'ecdsa' ? k_dsc_ecdsa : k_dsc + passportData ); } case 'prove': { - // const bitmap = Array(90).fill('1'); + // const selector_dg1 = Array(90).fill('1'); // const user_identifier = crypto.randomUUID(); // return generateCircuitInputsProve( // passportData, // n_dsc, // k_dsc, // scope, - // bitmap, + // selector_dg1, // majority, // user_identifier // ); diff --git a/common/src/constants/constants.ts b/common/src/constants/constants.ts index 244201f4..31123fab 100644 --- a/common/src/constants/constants.ts +++ b/common/src/constants/constants.ts @@ -23,7 +23,7 @@ export const DEVELOPMENT_MODE = true export const DEFAULT_MAJORITY = "18" export const MAX_PADDED_ECONTENT_LEN: Record = { - rsa_65537_sha256_2048: 640, + rsa_65537_sha256_2048: 384, rsa_65537_sha1_2048: 448, rsapss_65537_sha256_2048: 640, ecdsa_secp256r1_sha1_256: 448, @@ -32,7 +32,7 @@ export const MAX_PADDED_ECONTENT_LEN: Record = { - rsa_65537_sha256_2048: 512, + rsa_65537_sha256_2048: 320, rsa_65537_sha1_2048: 448, rsapss_65537_sha256_2048: 512, ecdsa_secp256r1_sha1_256: 448, diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index ed0df6af..66ad6b36 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -116,7 +116,8 @@ export function generateCircuitInputsDisclose( passportData: PassportData, merkletree: LeanIMT, majority: string, - bitmap: string[], + selector_dg1: string[], + selector_older_than: string, scope: string, user_identifier: string ) { @@ -146,7 +147,8 @@ export function generateCircuitInputsDisclose( merkletree_size: [BigInt(depthForThisOne).toString()], path: merkleProofIndices.map((index) => BigInt(index).toString()), siblings: merkleProofSiblings.map((index) => BigInt(index).toString()), - bitmap: bitmap, + selector_dg1: selector_dg1, + selector_older_than: [BigInt(selector_older_than).toString()], scope: [castFromScope(scope)], current_date: getCurrentDateYYMMDD().map(datePart => BigInt(datePart).toString()), majority: majority.split('').map(char => BigInt(char.charCodeAt(0)).toString()), @@ -160,15 +162,16 @@ export function generateCircuitInputsOfac( passportData: PassportData, merkletree: LeanIMT, majority: string, - bitmap: string[], + selector_dg1: string[], + selector_older_than: string, scope: string, user_identifier: string, sparsemerkletree: SMT, proofLevel: number, ) { - const result = generateCircuitInputsDisclose(secret, attestation_id, passportData, merkletree, majority, bitmap, scope, user_identifier); - const { majority: _, scope: __, bitmap: ___, user_identifier: ____, ...finalResult } = result; + const result = generateCircuitInputsDisclose(secret, attestation_id, passportData, merkletree, majority, selector_dg1, selector_older_than, scope, user_identifier); + const { majority: _, scope: __, selector_dg1: ___, selector_older_than: _____, user_identifier: ______, ...finalResult } = result; const mrz_bytes = formatMrz(passportData.mrz); const passport_leaf = getPassportNumberLeaf(mrz_bytes.slice(49, 58)) @@ -214,7 +217,8 @@ export function findIndexInTree(tree: LeanIMT, commitment: bigint): number { export function generateCircuitInputsProve( passportData: PassportData, scope: string, - bitmap: string[], + selector_dg1: string[], + selector_older_than: string, majority: string, user_identifier: string, user_identifier_type: 'uuid' | 'hex' | 'ascii' = DEFAULT_USER_ID_TYPE @@ -236,7 +240,8 @@ export function generateCircuitInputsProve( signature: register_inputs.signature, pubKey: register_inputs.pubKey, current_date: current_date, - bitmap: bitmap, + selector_dg1: selector_dg1, + selector_older_than: [BigInt(selector_older_than).toString()], majority: formattedMajority.split('').map(char => BigInt(char.charCodeAt(0)).toString()), user_identifier: [parseUIDToBigInt(user_identifier, user_identifier_type)], scope: [castFromScope(scope)] diff --git a/common/src/utils/utils.ts b/common/src/utils/utils.ts index 6f28e11c..b8493199 100644 --- a/common/src/utils/utils.ts +++ b/common/src/utils/utils.ts @@ -44,7 +44,7 @@ export function formatAndConcatenateDataHashes( () => Math.floor(Math.random() * 256) - 128 ); - // sha256 with rsa (index of mrzhash is 31) + // // sha256 with rsa (index of mrzhash is 31) // const startingSequence = [ // // SEQUENCE + long form indicator + length (293 bytes) // 48, -126, 1, 37, diff --git a/contracts/test/RegisterAndDisclose.ts b/contracts/test/RegisterAndDisclose.ts index 25de48a3..ee360192 100644 --- a/contracts/test/RegisterAndDisclose.ts +++ b/contracts/test/RegisterAndDisclose.ts @@ -84,7 +84,7 @@ describe("OpenPassport - Contracts - Register & Disclose flow", function () { let owner, otherAccount, thirdAccount: Signer; let imt: LeanIMT; - let bitmap, scope, user_address, majority, input_disclose: any; + let selector_dg1, scope, user_address, majority, input_disclose: any; let proof_disclose, publicSignals_disclose, proof_result_disclose, vkey_disclose, verified_disclose: any, rawCallData_disclose, parsedCallData_disclose: any[], formattedCallData_disclose: any; //let proof_csca, publicSignals_csca: any; let secret: string = BigInt(0).toString(); @@ -393,7 +393,7 @@ describe("OpenPassport - Contracts - Register & Disclose flow", function () { // // We only test with the sha256WithRSAEncryption_65537 commitment for now // // refactor in generate inputs function - // bitmap = Array(90).fill("1"); + // selector_dg1 = Array(90).fill("1"); // scope = BigInt(1).toString(); // majority = ["1", "8"]; @@ -403,7 +403,7 @@ describe("OpenPassport - Contracts - Register & Disclose flow", function () { // mockPassportData_sha256_rsa_65537, // imt as any, // majority, - // bitmap, + // selector_dg1, // scope, // BigInt(user_address.toString()).toString() // ); @@ -445,7 +445,7 @@ describe("OpenPassport - Contracts - Register & Disclose flow", function () { // // // refactor in generate inputs function - // // bitmap = Array(90).fill("1"); + // // selector_dg1 = Array(90).fill("1"); // // scope = BigInt(1).toString(); // // user_address = await thirdAccount.getAddress(); // // majority = ["1", "8"]; @@ -455,7 +455,7 @@ describe("OpenPassport - Contracts - Register & Disclose flow", function () { // // passportData, // // imt as any, // // majority, - // // bitmap, + // // selector_dg1, // // scope, // // BigInt(user_address.toString()).toString() // // ); diff --git a/sdk/tests/utils/generateInputsInSdk.ts b/sdk/tests/utils/generateInputsInSdk.ts index d7de8b63..6785fbcd 100644 --- a/sdk/tests/utils/generateInputsInSdk.ts +++ b/sdk/tests/utils/generateInputsInSdk.ts @@ -30,14 +30,14 @@ export const generateCircuitInputsInSdk = ( ); } case 'prove': { - const bitmap = Array(90).fill('1'); + const selector_dg1 = Array(90).fill('1'); const user_identifier = crypto.randomUUID(); return generateCircuitInputsProve( passportData, n_dsc, k_dsc, scope, - bitmap, + selector_dg1, majority, user_identifier ); From f8c6dc9e40968327bad89e245cae3567d13c1914 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Thu, 19 Sep 2024 19:05:47 +0200 Subject: [PATCH 43/60] yarn format --- circuits/package.json | 2 +- circuits/tests/disclose/disclose.test.ts | 20 +- circuits/tests/ofac/ofac.test.ts | 10 +- .../tests/other_circuits/leaf_hasher.test.ts | 10 +- circuits/tests/prove.test.ts | 6 +- circuits/tests/register.test.ts | 228 +++++++++--------- .../utils/generateMockInputsInCircuits.ts | 73 +++--- 7 files changed, 176 insertions(+), 173 deletions(-) diff --git a/circuits/package.json b/circuits/package.json index 114c57a3..47546b07 100644 --- a/circuits/package.json +++ b/circuits/package.json @@ -49,4 +49,4 @@ "ts-mocha": "^10.0.0", "ts-node": "^10.9.2" } -} \ No newline at end of file +} diff --git a/circuits/tests/disclose/disclose.test.ts b/circuits/tests/disclose/disclose.test.ts index 84d7bafd..2aa868b3 100644 --- a/circuits/tests/disclose/disclose.test.ts +++ b/circuits/tests/disclose/disclose.test.ts @@ -45,8 +45,14 @@ describe('Disclose', function () { // compute the commitment and insert it in the tree const pubkey_leaf = getLeaf(passportData.dsc).toString(); const mrz_bytes = packBytes(formatMrz(passportData.mrz)); - const commitment = generateCommitment(secret, PASSPORT_ATTESTATION_ID, pubkey_leaf, mrz_bytes, passportData.dg2Hash); - console.log("commitment in js ", commitment); + const commitment = generateCommitment( + secret, + PASSPORT_ATTESTATION_ID, + pubkey_leaf, + mrz_bytes, + passportData.dg2Hash + ); + console.log('commitment in js ', commitment); tree = new LeanIMT((a, b) => poseidon2([a, b]), []); tree.insert(BigInt(commitment)); @@ -59,7 +65,7 @@ describe('Disclose', function () { selector_dg1, selector_older_than, scope, - user_identifier, + user_identifier ); }); @@ -73,8 +79,8 @@ describe('Disclose', function () { const nullifier_js = poseidon2([inputs.secret, inputs.scope]).toString(); const nullifier_circom = (await circuit.getOutput(w, ['nullifier'])).nullifier; - console.log("nullifier_circom", nullifier_circom); - console.log("nullifier_js", nullifier_js); + console.log('nullifier_circom', nullifier_circom); + console.log('nullifier_js', nullifier_js); expect(nullifier_circom).to.equal(nullifier_js); }); @@ -162,7 +168,6 @@ describe('Disclose', function () { const older_than = formatOlderThan(await circuit.getOutput(w, ['older_than[2]'])); - expect(older_than[0]).to.equal(1); expect(older_than[1]).to.equal(8); }); @@ -186,7 +191,6 @@ describe('Disclose', function () { }); }); - const formatOlderThan = (older_than: any) => { return Object.values(older_than).map((value: any) => parseInt(value) - 48); -}; \ No newline at end of file +}; diff --git a/circuits/tests/ofac/ofac.test.ts b/circuits/tests/ofac/ofac.test.ts index 4fed6e3b..54abf2ff 100644 --- a/circuits/tests/ofac/ofac.test.ts +++ b/circuits/tests/ofac/ofac.test.ts @@ -41,7 +41,13 @@ function getPassportInputs(passportData: PassportData) { const pubkey_leaf = getLeaf(passportData.dsc); const mrz_bytes = packBytes(formatMrz(passportData.mrz)); - const commitment = generateCommitment(secret, PASSPORT_ATTESTATION_ID, pubkey_leaf, mrz_bytes, passportData.dg2Hash); + const commitment = generateCommitment( + secret, + PASSPORT_ATTESTATION_ID, + pubkey_leaf, + mrz_bytes, + passportData.dg2Hash + ); return { secret: secret, @@ -191,7 +197,7 @@ describe('OFAC - Name and DOB match', function () { inputs.scope, inputs.user_identifier, namedob_smt, - proofLevel, + proofLevel ); nonMemSmtInputs = generateCircuitInputsOfac( diff --git a/circuits/tests/other_circuits/leaf_hasher.test.ts b/circuits/tests/other_circuits/leaf_hasher.test.ts index 6fd74b58..75d16231 100644 --- a/circuits/tests/other_circuits/leaf_hasher.test.ts +++ b/circuits/tests/other_circuits/leaf_hasher.test.ts @@ -13,7 +13,13 @@ import { } from '../../../common/src/constants/mockCertificates'; import { hexToDecimal, splitToWords, toUnsignedByte } from '../../../common/src/utils/utils'; import { getLeaf, customHasher } from '../../../common/src/utils/pubkeyTree'; -import { k_dsc, k_dsc_ecdsa, n_dsc, n_dsc_ecdsa, SignatureAlgorithmIndex } from '../../../common/src/constants/constants'; +import { + k_dsc, + k_dsc_ecdsa, + n_dsc, + n_dsc_ecdsa, + SignatureAlgorithmIndex, +} from '../../../common/src/constants/constants'; import { parseCertificate, parseDSC, @@ -48,7 +54,6 @@ describe('LeafHasher Light', function () { }); }); - // describe('CustomHasher - getLeaf ECDSA', async () => { // const cert = mock_dsc_sha256_ecdsa; // const { signatureAlgorithm, hashFunction, x, y, bits, curve, exponent } = parseCertificate(cert); @@ -88,7 +93,6 @@ describe('LeafHasher Light', function () { }); }); - // describe('CustomHasher - getLeaf RSA', async () => { // const cert = mock_dsc_sha1_rsa_2048; // const { signatureAlgorithm, hashFunction, modulus, x, y, bits, curve, exponent } = diff --git a/circuits/tests/prove.test.ts b/circuits/tests/prove.test.ts index 52e0d3cf..74599e77 100644 --- a/circuits/tests/prove.test.ts +++ b/circuits/tests/prove.test.ts @@ -89,9 +89,7 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { try { const invalidInputs = { ...inputs, - eContent: inputs.eContent.map((byte: string) => - String((parseInt(byte, 10) + 1) % 256) - ), + eContent: inputs.eContent.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), }; await circuit.calculateWitness(invalidInputs); expect.fail('Expected an error but none was thrown.'); @@ -112,7 +110,5 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { expect(error.message).to.include('Assert Failed'); } }); - - }); }); diff --git a/circuits/tests/register.test.ts b/circuits/tests/register.test.ts index b3981673..c6cc8faf 100644 --- a/circuits/tests/register.test.ts +++ b/circuits/tests/register.test.ts @@ -2,135 +2,135 @@ import { describe } from 'mocha'; import { assert, expect } from 'chai'; import path from 'path'; import { wasm as wasm_tester } from 'circom_tester'; -import { } from 'poseidon-lite'; +import {} from 'poseidon-lite'; import { generateCircuitInputsRegister } from '../../common/src/utils/generateInputs'; import { packBytes } from '../../common/src/utils/utils'; -import { - PASSPORT_ATTESTATION_ID, -} from '../../common/src/constants/constants'; +import { PASSPORT_ATTESTATION_ID } from '../../common/src/constants/constants'; import { genMockPassportData } from '../../common/src/utils/genMockPassportData'; import { getCircuitName, parseDSC } from '../../common/src/utils/certificates/handleCertificate'; import { generateCommitment, getLeaf } from '../../common/src/utils/pubkeyTree'; import { SignatureAlgorithm } from '../../common/src/utils/types'; const sigAlgs = [ - { sigAlg: 'rsa', hashFunction: 'sha256' }, - { sigAlg: 'rsa', hashFunction: 'sha1' }, - { sigAlg: 'ecdsa', hashFunction: 'sha256' }, - { sigAlg: 'rsapss', hashFunction: 'sha256' }, - { sigAlg: 'ecdsa', hashFunction: 'sha1' }, + { sigAlg: 'rsa', hashFunction: 'sha256' }, + { sigAlg: 'rsa', hashFunction: 'sha1' }, + { sigAlg: 'ecdsa', hashFunction: 'sha256' }, + { sigAlg: 'rsapss', hashFunction: 'sha256' }, + { sigAlg: 'ecdsa', hashFunction: 'sha1' }, ]; sigAlgs.forEach(({ sigAlg, hashFunction }) => { - describe(`Register - ${hashFunction.toUpperCase()} ${sigAlg.toUpperCase()}`, function () { - this.timeout(0); - let circuit: any; - - const passportData = genMockPassportData( - `${sigAlg}_${hashFunction}` as SignatureAlgorithm, - 'FRA', - '000101', - '300101' - ); - const secret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); - const dscSecret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); - - const inputs = generateCircuitInputsRegister( - secret, - dscSecret, - PASSPORT_ATTESTATION_ID, - passportData - - ); - - before(async () => { - circuit = await wasm_tester( - path.join( - __dirname, - `../circuits/register/instances/${getCircuitName('register', sigAlg, hashFunction)}.circom` - ), - { - include: [ - 'node_modules', - './node_modules/@zk-kit/binary-merkle-root.circom/src', - './node_modules/circomlib/circuits', - ], - } - ); - }); - - it('should compile and load the circuit', async function () { - expect(circuit).to.not.be.undefined; - }); - - it('should calculate the witness with correct inputs', async function () { - // console.log('inputs', inputs); - const w = await circuit.calculateWitness(inputs); - // await circuit.checkConstraints(w); - - // const output = await circuit.getOutput(w); - - const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; - console.log('\x1b[34m%s\x1b[0m', 'nullifier', nullifier); - - const commitment_circom = (await circuit.getOutput(w, ['commitment'])).commitment; - console.log('\x1b[34m%s\x1b[0m', 'commitment', commitment_circom); - - const blinded_dsc_commitment = (await circuit.getOutput(w, ['blinded_dsc_commitment'])) - .blinded_dsc_commitment; - console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment', blinded_dsc_commitment); + describe(`Register - ${hashFunction.toUpperCase()} ${sigAlg.toUpperCase()}`, function () { + this.timeout(0); + let circuit: any; + + const passportData = genMockPassportData( + `${sigAlg}_${hashFunction}` as SignatureAlgorithm, + 'FRA', + '000101', + '300101' + ); + const secret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); + const dscSecret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); + + const inputs = generateCircuitInputsRegister( + secret, + dscSecret, + PASSPORT_ATTESTATION_ID, + passportData + ); + + before(async () => { + circuit = await wasm_tester( + path.join( + __dirname, + `../circuits/register/instances/${getCircuitName('register', sigAlg, hashFunction)}.circom` + ), + { + include: [ + 'node_modules', + './node_modules/@zk-kit/binary-merkle-root.circom/src', + './node_modules/circomlib/circuits', + ], + } + ); + }); - const mrz_bytes = packBytes(inputs.dg1); - const leaf = getLeaf(passportData.dsc).toString(); - const commitment_bytes = generateCommitment(secret, PASSPORT_ATTESTATION_ID, leaf, mrz_bytes, passportData.dg2Hash); - const commitment_js = commitment_bytes.toString(); - console.log('commitment_js', commitment_js); - console.log('commitment_circom', commitment_circom); - expect(commitment_circom).to.be.equal(commitment_js); - }); + it('should compile and load the circuit', async function () { + expect(circuit).to.not.be.undefined; + }); - it('should fail to calculate witness with invalid mrz', async function () { - try { - const invalidInputs = { - ...inputs, - dg1: Array(93) - .fill(0) - .map((byte) => BigInt(byte).toString()), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail(); - } catch (error) { - // expect(error.message).to.include('Assert Failed'); - } - }); + it('should calculate the witness with correct inputs', async function () { + // console.log('inputs', inputs); + const w = await circuit.calculateWitness(inputs); + // await circuit.checkConstraints(w); + + // const output = await circuit.getOutput(w); + + const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; + console.log('\x1b[34m%s\x1b[0m', 'nullifier', nullifier); + + const commitment_circom = (await circuit.getOutput(w, ['commitment'])).commitment; + console.log('\x1b[34m%s\x1b[0m', 'commitment', commitment_circom); + + const blinded_dsc_commitment = (await circuit.getOutput(w, ['blinded_dsc_commitment'])) + .blinded_dsc_commitment; + console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment', blinded_dsc_commitment); + + const mrz_bytes = packBytes(inputs.dg1); + const leaf = getLeaf(passportData.dsc).toString(); + const commitment_bytes = generateCommitment( + secret, + PASSPORT_ATTESTATION_ID, + leaf, + mrz_bytes, + passportData.dg2Hash + ); + const commitment_js = commitment_bytes.toString(); + console.log('commitment_js', commitment_js); + console.log('commitment_circom', commitment_circom); + expect(commitment_circom).to.be.equal(commitment_js); + }); - it('should fail to calculate witness with invalid eContent', async function () { - try { - const invalidInputs = { - ...inputs, - eContent: inputs.eContent.map((byte: string) => - String((parseInt(byte, 10) + 1) % 256) - ), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - // expect(error.message).to.include('Assert Failed'); - } - }); + it('should fail to calculate witness with invalid mrz', async function () { + try { + const invalidInputs = { + ...inputs, + dg1: Array(93) + .fill(0) + .map((byte) => BigInt(byte).toString()), + }; + await circuit.calculateWitness(invalidInputs); + expect.fail(); + } catch (error) { + // expect(error.message).to.include('Assert Failed'); + } + }); - it('should fail to calculate witness with invalid signature', async function () { - try { - const invalidInputs = { - ...inputs, - signature: inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - // expect(error.message).to.include('Assert Failed'); - } - }); + it('should fail to calculate witness with invalid eContent', async function () { + try { + const invalidInputs = { + ...inputs, + eContent: inputs.eContent.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), + }; + await circuit.calculateWitness(invalidInputs); + expect.fail('Expected an error but none was thrown.'); + } catch (error) { + // expect(error.message).to.include('Assert Failed'); + } + }); + it('should fail to calculate witness with invalid signature', async function () { + try { + const invalidInputs = { + ...inputs, + signature: inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), + }; + await circuit.calculateWitness(invalidInputs); + expect.fail('Expected an error but none was thrown.'); + } catch (error) { + // expect(error.message).to.include('Assert Failed'); + } }); + }); }); diff --git a/circuits/tests/utils/generateMockInputsInCircuits.ts b/circuits/tests/utils/generateMockInputsInCircuits.ts index a5df1dcc..af49775d 100644 --- a/circuits/tests/utils/generateMockInputsInCircuits.ts +++ b/circuits/tests/utils/generateMockInputsInCircuits.ts @@ -1,16 +1,16 @@ import { PassportData } from '../../../common/src/utils/types'; import { CircuitName } from '../../../common/src/utils/appType'; import { - DEFAULT_MAJORITY, - k_dsc, - k_dsc_ecdsa, - n_dsc, - n_dsc_ecdsa, - PASSPORT_ATTESTATION_ID, + DEFAULT_MAJORITY, + k_dsc, + k_dsc_ecdsa, + n_dsc, + n_dsc_ecdsa, + PASSPORT_ATTESTATION_ID, } from '../../../common/src/constants/constants'; import { - generateCircuitInputsProve, - generateCircuitInputsRegister, + generateCircuitInputsProve, + generateCircuitInputsRegister, } from '../../../common/src/utils/generateInputs'; import { parseCertificate } from '../../../common/src/utils/certificates/handleCertificate'; @@ -18,39 +18,32 @@ const majority = DEFAULT_MAJORITY; const scope = '@spaceShips'; export const generateCircuitInputsInCircuits = ( - passportData: PassportData, - circuit: CircuitName + passportData: PassportData, + circuit: CircuitName ): any => { + const { signatureAlgorithm } = parseCertificate(passportData.dsc); - const { signatureAlgorithm } = parseCertificate(passportData.dsc); - - - switch (circuit) { - case 'register': { - const secret = BigInt(0).toString(); - const dscSecret = BigInt(0).toString(); - const attestationId = PASSPORT_ATTESTATION_ID; - return generateCircuitInputsRegister( - secret, - dscSecret, - attestationId, - passportData - ); - } - case 'prove': { - // const selector_dg1 = Array(90).fill('1'); - // const user_identifier = crypto.randomUUID(); - // return generateCircuitInputsProve( - // passportData, - // n_dsc, - // k_dsc, - // scope, - // selector_dg1, - // majority, - // user_identifier - // ); - } - default: - throw new Error('Invalid circuit'); + switch (circuit) { + case 'register': { + const secret = BigInt(0).toString(); + const dscSecret = BigInt(0).toString(); + const attestationId = PASSPORT_ATTESTATION_ID; + return generateCircuitInputsRegister(secret, dscSecret, attestationId, passportData); + } + case 'prove': { + // const selector_dg1 = Array(90).fill('1'); + // const user_identifier = crypto.randomUUID(); + // return generateCircuitInputsProve( + // passportData, + // n_dsc, + // k_dsc, + // scope, + // selector_dg1, + // majority, + // user_identifier + // ); } + default: + throw new Error('Invalid circuit'); + } }; From b7f292e5b444ec633ce9d01d54365646e39521ee Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Thu, 19 Sep 2024 19:17:48 +0200 Subject: [PATCH 44/60] fix import issues --- circuits/circuits/tests/utils/isOlderThan_tester.circom | 2 +- circuits/circuits/tests/utils/isValid_tester.circom | 2 +- circuits/circuits/utils/passport/computeCommitment.circom | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/circuits/circuits/tests/utils/isOlderThan_tester.circom b/circuits/circuits/tests/utils/isOlderThan_tester.circom index 26629d22..f33b757b 100644 --- a/circuits/circuits/tests/utils/isOlderThan_tester.circom +++ b/circuits/circuits/tests/utils/isOlderThan_tester.circom @@ -1,6 +1,6 @@ pragma circom 2.1.6; -include "../../utils/isOlderThan.circom"; +include "../../utils/passport/date/isOlderThan.circom"; template isOlderThan_tester() { diff --git a/circuits/circuits/tests/utils/isValid_tester.circom b/circuits/circuits/tests/utils/isValid_tester.circom index cbed326b..e25d0a55 100644 --- a/circuits/circuits/tests/utils/isValid_tester.circom +++ b/circuits/circuits/tests/utils/isValid_tester.circom @@ -1,6 +1,6 @@ pragma circom 2.1.6; -include "../../utils/isValid.circom"; +include "../../utils/passport/date/isValid.circom"; template IsValid_tester() { diff --git a/circuits/circuits/utils/passport/computeCommitment.circom b/circuits/circuits/utils/passport/computeCommitment.circom index a622d26f..1d05cddb 100644 --- a/circuits/circuits/utils/passport/computeCommitment.circom +++ b/circuits/circuits/utils/passport/computeCommitment.circom @@ -2,7 +2,7 @@ pragma circom 2.1.9; include "circomlib/circuits/poseidon.circom"; include "../other/bytes.circom"; -include "./CustomHashers.circom"; +include "./customHashers.circom"; template ComputeCommitment() { From 7e888d9ede54fdaf20d6e8ca007faa980673ffdd Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Thu, 19 Sep 2024 21:28:12 +0200 Subject: [PATCH 45/60] use circom v2.1.9 compiler in github action --- .github/workflows/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/action.yml b/.github/workflows/action.yml index 36deda31..293ccb93 100644 --- a/.github/workflows/action.yml +++ b/.github/workflows/action.yml @@ -40,9 +40,9 @@ jobs: - name: Setup Rust uses: dtolnay/rust-toolchain@stable - - name: Download Circom Binary v2.1.8 + - name: Download Circom Binary v2.1.9 run: | - wget -qO /home/runner/work/circom https://github.com/iden3/circom/releases/download/v2.1.8/circom-linux-amd64 + wget -qO /home/runner/work/circom https://github.com/iden3/circom/releases/download/v2.1.9/circom-linux-amd64 chmod +x /home/runner/work/circom sudo mv /home/runner/work/circom /bin/circom From 11a2bc835631ba07dfed6bbd68580d1e224e637b Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Fri, 20 Sep 2024 13:43:35 +0200 Subject: [PATCH 46/60] refactor dsc circuits --- .../circuits/dsc/dsc_rsa_65537_sha1.circom | 75 ------------ .../circuits/dsc/dsc_rsa_65537_sha256.circom | 76 ------------ .../dsc/dsc_rsapss_65537_sha256.circom | 68 ----------- .../instances/dsc_rsa_65537_sha1_2048.circom | 3 + .../dsc_rsa_65537_sha256_2048.circom | 3 + .../dsc_rsapss_65537_sha256_2048.circom | 3 + circuits/circuits/dsc/openpassport_dsc.circom | 62 ++++++++++ .../tests/dsc/dsc_sha1_rsa_2048.circom | 5 - .../tests/dsc/dsc_sha1_rsa_4096.circom | 5 - .../tests/dsc/dsc_sha256_rsa_2048.circom | 5 - .../tests/dsc/dsc_sha256_rsa_4096.circom | 5 - .../tests/dsc/dsc_sha256_rsapss_2048.circom | 5 - .../tests/dsc/dsc_sha256_rsapss_4096.circom | 5 - .../utils/passport/signatureAlgorithm.circom | 27 ++++ circuits/tests/dsc.test.ts | 115 ++++++++++++++++++ circuits/tests/dsc/dsc_sha1_rsa_2048.test.ts | 66 ---------- .../tests/dsc/dsc_sha256_rsa_2048.test.ts | 65 ---------- .../tests/dsc/dsc_sha256_rsapss_2048.test.ts | 110 ----------------- 18 files changed, 213 insertions(+), 490 deletions(-) delete mode 100644 circuits/circuits/dsc/dsc_rsa_65537_sha1.circom delete mode 100644 circuits/circuits/dsc/dsc_rsa_65537_sha256.circom delete mode 100644 circuits/circuits/dsc/dsc_rsapss_65537_sha256.circom create mode 100644 circuits/circuits/dsc/instances/dsc_rsa_65537_sha1_2048.circom create mode 100644 circuits/circuits/dsc/instances/dsc_rsa_65537_sha256_2048.circom create mode 100644 circuits/circuits/dsc/instances/dsc_rsapss_65537_sha256_2048.circom create mode 100644 circuits/circuits/dsc/openpassport_dsc.circom delete mode 100644 circuits/circuits/tests/dsc/dsc_sha1_rsa_2048.circom delete mode 100644 circuits/circuits/tests/dsc/dsc_sha1_rsa_4096.circom delete mode 100644 circuits/circuits/tests/dsc/dsc_sha256_rsa_2048.circom delete mode 100644 circuits/circuits/tests/dsc/dsc_sha256_rsa_4096.circom delete mode 100644 circuits/circuits/tests/dsc/dsc_sha256_rsapss_2048.circom delete mode 100644 circuits/circuits/tests/dsc/dsc_sha256_rsapss_4096.circom create mode 100644 circuits/tests/dsc.test.ts delete mode 100644 circuits/tests/dsc/dsc_sha1_rsa_2048.test.ts delete mode 100644 circuits/tests/dsc/dsc_sha256_rsa_2048.test.ts delete mode 100644 circuits/tests/dsc/dsc_sha256_rsapss_2048.test.ts diff --git a/circuits/circuits/dsc/dsc_rsa_65537_sha1.circom b/circuits/circuits/dsc/dsc_rsa_65537_sha1.circom deleted file mode 100644 index cf696558..00000000 --- a/circuits/circuits/dsc/dsc_rsa_65537_sha1.circom +++ /dev/null @@ -1,75 +0,0 @@ -pragma circom 2.1.5; -include "circomlib/circuits/bitify.circom"; -include "circomlib/circuits/poseidon.circom"; -include "circomlib/circuits/comparators.circom"; -include "binary-merkle-root.circom"; -include "../utils/other/bytes.circom"; -include "../utils/Sha1Bytes.circom"; -include "../utils/leafHasherLight.circom"; -include "../utils/rsaPkcs1.circom"; - -template DSC_RSA_65537_SHA1(max_cert_bytes, n_dsc, k_dsc, n_csca, k_csca, dsc_mod_len, nLevels, signatureAlgorithm) { - signal input raw_dsc_cert[max_cert_bytes]; - signal input raw_dsc_cert_padded_bytes; - signal input csca_modulus[k_csca]; - signal input dsc_signature[k_csca]; - signal input dsc_modulus[k_dsc]; - signal input start_index; - signal input secret; - - signal input merkle_root; - signal input path[nLevels]; - signal input siblings[nLevels]; - - signal output blinded_dsc_commitment; - - //verify the leaf - component leafHasher = LeafHasher(k_csca); - leafHasher.sigAlg <== signatureAlgorithm; - leafHasher.in <== csca_modulus; - signal leaf <== leafHasher.out; - - - signal computed_merkle_root <== BinaryMerkleRoot(nLevels)(leaf, nLevels, path, siblings); - merkle_root === computed_merkle_root; - - // variables verification - assert(max_cert_bytes % 64 == 0); - assert(n_csca * k_csca > max_cert_bytes); - assert(n_csca <= (255 \ 2)); - - // hash raw TBS certificate - signal sha[160] <== Sha1Bytes(max_cert_bytes)(raw_dsc_cert, raw_dsc_cert_padded_bytes); - component sstw_1 = SplitSignalsToWords(1,160, n_csca, k_csca); - for (var i = 0; i < 160; i++) { - sstw_1.in[i] <== sha[159 - i]; - } - - //verify RSA dsc_signature - component rsa = RSAVerify65537(n_csca, k_csca); - for (var i = 0; i < k_csca; i++) { - rsa.base_message[i] <== sstw_1.out[i]; - rsa.modulus[i] <== csca_modulus[i]; - rsa.signature[i] <== dsc_signature[i]; - } - - // verify DSC csca_modulus - component shiftLeft = VarShiftLeft(max_cert_bytes, dsc_mod_len); - shiftLeft.in <== raw_dsc_cert; - shiftLeft.shift <== start_index; - component spbt_1 = SplitBytesToWords(dsc_mod_len, n_dsc, k_dsc); - spbt_1.in <== shiftLeft.out; - for (var i = 0; i < k_dsc; i++) { - dsc_modulus[i] === spbt_1.out[i]; - } - // generate blinded commitment - component sstw_2 = SplitSignalsToWords(n_dsc,k_dsc, 230, 9); - sstw_2.in <== dsc_modulus; - component poseidon = Poseidon(10); - poseidon.inputs[0] <== secret; - for (var i = 0; i < 9; i++) { - poseidon.inputs[i+1] <== sstw_2.out[i]; - } - blinded_dsc_commitment <== poseidon.out; -} - diff --git a/circuits/circuits/dsc/dsc_rsa_65537_sha256.circom b/circuits/circuits/dsc/dsc_rsa_65537_sha256.circom deleted file mode 100644 index a1845ec3..00000000 --- a/circuits/circuits/dsc/dsc_rsa_65537_sha256.circom +++ /dev/null @@ -1,76 +0,0 @@ -pragma circom 2.1.5; - -include "circomlib/circuits/bitify.circom"; -include "circomlib/circuits/poseidon.circom"; -include "circomlib/circuits/comparators.circom"; -include "@zk-email/circuits/lib/sha.circom"; -include "@zk-email/circuits/lib/rsa.circom"; -include "binary-merkle-root.circom"; -include "../utils/other/bytes.circom"; -include "../utils/leafHasherLight.circom"; - -template DSC_RSA_65537_SHA256(max_cert_bytes, n_dsc, k_dsc, n_csca, k_csca, dsc_mod_len, nLevels, signatureAlgorithm) { - signal input raw_dsc_cert[max_cert_bytes]; - signal input raw_dsc_cert_padded_bytes; - signal input csca_modulus[k_csca]; - signal input dsc_signature[k_csca]; - signal input dsc_modulus[k_dsc]; - signal input start_index; - signal input secret; - - signal input merkle_root; - signal input path[nLevels]; - signal input siblings[nLevels]; - - signal output blinded_dsc_commitment; - - //verify the leaf - component leafHasher = LeafHasher(k_csca); - leafHasher.sigAlg <== signatureAlgorithm; - leafHasher.in <== csca_modulus; - signal leaf <== leafHasher.out; - - - signal computed_merkle_root <== BinaryMerkleRoot(nLevels)(leaf, nLevels, path, siblings); - merkle_root === computed_merkle_root; - - // variables verification - assert(max_cert_bytes % 64 == 0); - assert(n_csca * k_csca > max_cert_bytes); - assert(n_csca <= (255 \ 2)); - - // hash raw TBS certificate - signal sha[256] <== Sha256Bytes(max_cert_bytes)(raw_dsc_cert, raw_dsc_cert_padded_bytes); - component sstw_1 = SplitSignalsToWords(1,256, n_csca, k_csca); - for (var i = 0; i < 256; i++) { - sstw_1.in[i] <== sha[255 - i]; - } - - // verify RSA dsc_signature - component rsa = RSAVerifier65537(n_csca, k_csca); - for (var i = 0; i < k_csca; i++) { - rsa.message[i] <== sstw_1.out[i]; - rsa.modulus[i] <== csca_modulus[i]; - rsa.signature[i] <== dsc_signature[i]; - } - - // verify DSC csca_modulus - component shiftLeft = VarShiftLeft(max_cert_bytes, dsc_mod_len); - shiftLeft.in <== raw_dsc_cert; - shiftLeft.shift <== start_index; - component spbt_1 = SplitBytesToWords(dsc_mod_len, n_dsc, k_dsc); - spbt_1.in <== shiftLeft.out; - for (var i = 0; i < k_dsc; i++) { - dsc_modulus[i] === spbt_1.out[i]; - } - // generate blinded commitment - component sstw_2 = SplitSignalsToWords(n_dsc,k_dsc, 230, 9); - sstw_2.in <== dsc_modulus; - component poseidon = Poseidon(10); - poseidon.inputs[0] <== secret; - for (var i = 0; i < 9; i++) { - poseidon.inputs[i+1] <== sstw_2.out[i]; - } - blinded_dsc_commitment <== poseidon.out; -} - diff --git a/circuits/circuits/dsc/dsc_rsapss_65537_sha256.circom b/circuits/circuits/dsc/dsc_rsapss_65537_sha256.circom deleted file mode 100644 index 7ce6623e..00000000 --- a/circuits/circuits/dsc/dsc_rsapss_65537_sha256.circom +++ /dev/null @@ -1,68 +0,0 @@ -pragma circom 2.1.5; - -include "circomlib/circuits/bitify.circom"; -include "circomlib/circuits/poseidon.circom"; -include "circomlib/circuits/comparators.circom"; -include "@zk-email/circuits/lib/sha.circom"; -include "binary-merkle-root.circom"; -include "../utils/other/bytes.circom"; -include "../utils/leafHasherLight.circom"; -include "../utils/rsapss/rsapss.circom"; - -template DSC_RSAPSS_65537_SHA256(max_cert_bytes, n_dsc, k_dsc, n_csca, k_csca, modulus_bits_size, dsc_mod_len, nLevels, signatureAlgorithm) { - signal input raw_dsc_cert[max_cert_bytes]; - signal input raw_dsc_cert_padded_bytes; - signal input csca_modulus[k_csca]; - signal input dsc_signature[k_csca]; - signal input dsc_modulus[k_dsc]; - signal input start_index; - signal input secret; - - signal input merkle_root; - signal input path[nLevels]; - signal input siblings[nLevels]; - - signal output blinded_dsc_commitment; - - //verify the leaf - component leafHasher = LeafHasher(k_csca); - leafHasher.sigAlg <== signatureAlgorithm; - leafHasher.in <== csca_modulus; - signal leaf <== leafHasher.out; - - signal computed_merkle_root <== BinaryMerkleRoot(nLevels)(leaf, nLevels, path, siblings); - merkle_root === computed_merkle_root; - - // variables verification - assert(max_cert_bytes % 64 == 0); - assert(n_csca * k_csca > max_cert_bytes); - assert(n_csca <= (255 \ 2)); - - // verify rsapss signature - signal dsc_cert_hash[256]; - dsc_cert_hash <== Sha256Bytes(max_cert_bytes)(raw_dsc_cert, raw_dsc_cert_padded_bytes); - component rsaPssSha256Verification = VerifyRsaPssSig(n_csca, k_csca, 17, 256, modulus_bits_size); - rsaPssSha256Verification.pubkey <== csca_modulus; - rsaPssSha256Verification.signature <== dsc_signature; - rsaPssSha256Verification.hashed <== dsc_cert_hash; - - // verify DSC csca_modulus - component shiftLeft = VarShiftLeft(max_cert_bytes, dsc_mod_len); - shiftLeft.in <== raw_dsc_cert; - shiftLeft.shift <== start_index; - component spbt_1 = SplitBytesToWords(dsc_mod_len, n_dsc, k_dsc); - spbt_1.in <== shiftLeft.out; - for (var i = 0; i < k_dsc; i++) { - dsc_modulus[i] === spbt_1.out[i]; - } - // generate blinded commitment - component sstw_1 = SplitSignalsToWords(n_dsc,k_dsc, 230, 9); - sstw_1.in <== dsc_modulus; - component poseidon = Poseidon(10); - poseidon.inputs[0] <== secret; - for (var i = 0; i < 9; i++) { - poseidon.inputs[i+1] <== sstw_1.out[i]; - } - blinded_dsc_commitment <== poseidon.out; -} - diff --git a/circuits/circuits/dsc/instances/dsc_rsa_65537_sha1_2048.circom b/circuits/circuits/dsc/instances/dsc_rsa_65537_sha1_2048.circom new file mode 100644 index 00000000..79afeede --- /dev/null +++ b/circuits/circuits/dsc/instances/dsc_rsa_65537_sha1_2048.circom @@ -0,0 +1,3 @@ +include "../openpassport_dsc.circom"; + +component main = OPENPASSPORT_DSC(3, 64, 32, 64, 32, 960, 256, 12); diff --git a/circuits/circuits/dsc/instances/dsc_rsa_65537_sha256_2048.circom b/circuits/circuits/dsc/instances/dsc_rsa_65537_sha256_2048.circom new file mode 100644 index 00000000..2e43c287 --- /dev/null +++ b/circuits/circuits/dsc/instances/dsc_rsa_65537_sha256_2048.circom @@ -0,0 +1,3 @@ +include "../openpassport_dsc.circom"; + +component main = OPENPASSPORT_DSC(1, 64, 32, 64, 32, 960, 256, 12); diff --git a/circuits/circuits/dsc/instances/dsc_rsapss_65537_sha256_2048.circom b/circuits/circuits/dsc/instances/dsc_rsapss_65537_sha256_2048.circom new file mode 100644 index 00000000..fdff4d73 --- /dev/null +++ b/circuits/circuits/dsc/instances/dsc_rsapss_65537_sha256_2048.circom @@ -0,0 +1,3 @@ +include "../openpassport_dsc.circom"; + +component main = OPENPASSPORT_DSC(4, 64, 32, 64, 32, 960, 256, 12); diff --git a/circuits/circuits/dsc/openpassport_dsc.circom b/circuits/circuits/dsc/openpassport_dsc.circom new file mode 100644 index 00000000..40917fb0 --- /dev/null +++ b/circuits/circuits/dsc/openpassport_dsc.circom @@ -0,0 +1,62 @@ +pragma circom 2.1.5; + +include "circomlib/circuits/bitify.circom"; +include "circomlib/circuits/poseidon.circom"; +include "circomlib/circuits/comparators.circom"; +include "binary-merkle-root.circom"; +include "../utils/passport/customHashers.circom"; +include "../utils/other/bytes.circom"; +include "../utils/passport/signatureAlgorithm.circom"; +include "../utils/passport/signatureVerifier.circom"; +include "../utils/shaBytes/shaBytesDynamic.circom"; +include "../utils/other/bytes.circom"; + + +template OPENPASSPORT_DSC(signatureAlgorithm, n_dsc, k_dsc, n_csca, k_csca, max_cert_bytes, dscPubkeyBytesLength, nLevels) { + + // variables verification + assert(max_cert_bytes % 64 == 0); + assert(n_csca * k_csca > max_cert_bytes); + assert(n_csca <= (255 \ 2)); + + var hashLength = getHashLength(signatureAlgorithm); + var kLengthFactor = getKLengthFactor(signatureAlgorithm); + var kScaled = k_csca * kLengthFactor; + + signal input raw_dsc_cert[max_cert_bytes]; + signal input raw_dsc_cert_padded_bytes; + signal input csca_pubKey[kScaled]; + signal input signature[kScaled]; + signal input dsc_pubKey[k_dsc]; + signal input dsc_pubKey_offset; + signal input secret; + + signal input merkle_root; + signal input path[nLevels]; + signal input siblings[nLevels]; + + // leaf + signal leaf <== LeafHasher(kScaled)(csca_pubKey, signatureAlgorithm); + + signal computed_merkle_root <== BinaryMerkleRoot(nLevels)(leaf, nLevels, path, siblings); + merkle_root === computed_merkle_root; + + // verify certificate signature + signal hashedCertificate[hashLength] <== ShaBytesDynamic(hashLength, max_cert_bytes)(raw_dsc_cert, raw_dsc_cert_padded_bytes); + SignatureVerifier(signatureAlgorithm, n_csca, k_csca)(hashedCertificate, csca_pubKey, signature); + + // verify DSC csca_pubKey + component shiftLeft = VarShiftLeft(max_cert_bytes, dscPubkeyBytesLength); // use select subarray for dscPubKey variable length + shiftLeft.in <== raw_dsc_cert; + shiftLeft.shift <== dsc_pubKey_offset; + component spbt_1 = SplitBytesToWords(dscPubkeyBytesLength, n_dsc, k_dsc); + spbt_1.in <== shiftLeft.out; + for (var i = 0; i < k_dsc; i++) { + dsc_pubKey[i] === spbt_1.out[i]; + } + + // blinded dsc commitment + signal pubkeyHash <== CustomHasher(k_dsc)(dsc_pubKey); + signal output blinded_dsc_commitment <== Poseidon(2)([secret, pubkeyHash]); +} + diff --git a/circuits/circuits/tests/dsc/dsc_sha1_rsa_2048.circom b/circuits/circuits/tests/dsc/dsc_sha1_rsa_2048.circom deleted file mode 100644 index c588f208..00000000 --- a/circuits/circuits/tests/dsc/dsc_sha1_rsa_2048.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.6; - -include "../../dsc/dsc_rsa_65537_sha1.circom"; - -component main { public [ merkle_root ] } = DSC_RSA_65537_SHA1(960, 64, 32, 64, 32, 256, 12, 3); \ No newline at end of file diff --git a/circuits/circuits/tests/dsc/dsc_sha1_rsa_4096.circom b/circuits/circuits/tests/dsc/dsc_sha1_rsa_4096.circom deleted file mode 100644 index 4686a551..00000000 --- a/circuits/circuits/tests/dsc/dsc_sha1_rsa_4096.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.6; - -include "../../dsc/dsc_rsa_65537_sha1.circom"; - -component main { public [ merkle_root ] } = DSC_RSA_65537_SHA1(1664, 64, 32, 120, 35, 256, 12); \ No newline at end of file diff --git a/circuits/circuits/tests/dsc/dsc_sha256_rsa_2048.circom b/circuits/circuits/tests/dsc/dsc_sha256_rsa_2048.circom deleted file mode 100644 index b914e90b..00000000 --- a/circuits/circuits/tests/dsc/dsc_sha256_rsa_2048.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.6; - -include "../../dsc/dsc_rsa_65537_sha256.circom"; - -component main { public [ merkle_root ] } = DSC_RSA_65537_SHA256(960, 64, 32, 64, 32, 256, 12,1); \ No newline at end of file diff --git a/circuits/circuits/tests/dsc/dsc_sha256_rsa_4096.circom b/circuits/circuits/tests/dsc/dsc_sha256_rsa_4096.circom deleted file mode 100644 index a092b77e..00000000 --- a/circuits/circuits/tests/dsc/dsc_sha256_rsa_4096.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.6; - -include "../../dsc/dsc_rsa_65537_sha256.circom"; - -component main { public [ merkle_root ] } = DSC_RSA_65537_SHA256(1664, 64, 32, 120, 35, 256, 12); \ No newline at end of file diff --git a/circuits/circuits/tests/dsc/dsc_sha256_rsapss_2048.circom b/circuits/circuits/tests/dsc/dsc_sha256_rsapss_2048.circom deleted file mode 100644 index e7b85cad..00000000 --- a/circuits/circuits/tests/dsc/dsc_sha256_rsapss_2048.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.6; - -include "../../dsc/dsc_rsapss_65537_sha256.circom"; - -component main { public [ merkle_root ] } = DSC_RSAPSS_65537_SHA256(960, 64, 32, 64, 32, 2048, 256, 12,4); \ No newline at end of file diff --git a/circuits/circuits/tests/dsc/dsc_sha256_rsapss_4096.circom b/circuits/circuits/tests/dsc/dsc_sha256_rsapss_4096.circom deleted file mode 100644 index f38a18d5..00000000 --- a/circuits/circuits/tests/dsc/dsc_sha256_rsapss_4096.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.6; - -include "../../dsc/dsc_rsapss_65537_sha256.circom"; - -component main { public [ merkle_root ] } = DSC_RSAPSS_65537_SHA256(1664, 64, 32, 120, 35, 4096, 256, 12); \ No newline at end of file diff --git a/circuits/circuits/utils/passport/signatureAlgorithm.circom b/circuits/circuits/utils/passport/signatureAlgorithm.circom index 45bc4d46..b7138279 100644 --- a/circuits/circuits/utils/passport/signatureAlgorithm.circom +++ b/circuits/circuits/utils/passport/signatureAlgorithm.circom @@ -19,6 +19,15 @@ function getHashLength(signatureAlgorithm) { if (signatureAlgorithm == 9) { return 384; } + if (signatureAlgorithm == 10) { + return 256; + } + if (signatureAlgorithm == 11) { + return 160; + } + if (signatureAlgorithm == 12) { + return 256; + } return 0; } @@ -41,6 +50,15 @@ function getKeyLength(signatureAlgorithm) { if (signatureAlgorithm == 9) { return 384; } + if (signatureAlgorithm == 10) { + return 4096; + } + if (signatureAlgorithm == 11) { + return 4096; + } + if (signatureAlgorithm == 12) { + return 4096; + } return 0; } @@ -64,6 +82,15 @@ function getKLengthFactor(signatureAlgorithm) { if (signatureAlgorithm == 9) { return 2; } + if (signatureAlgorithm == 10) { + return 1; + } + if (signatureAlgorithm == 11) { + return 1; + } + if (signatureAlgorithm == 12) { + return 1; + } return 0; } diff --git a/circuits/tests/dsc.test.ts b/circuits/tests/dsc.test.ts new file mode 100644 index 00000000..f4b1109f --- /dev/null +++ b/circuits/tests/dsc.test.ts @@ -0,0 +1,115 @@ +import { assert, expect } from 'chai'; +import fs from 'fs'; +const forge = require('node-forge'); +import path from 'path'; +import { wasm as wasm_tester } from 'circom_tester'; +import { getCSCAInputs } from '../../common/src/utils/csca'; +import { + mock_dsc_sha1_rsa_2048, + mock_dsc_sha256_rsa_2048, + mock_dsc_sha256_rsapss_2048, + mock_csca_sha1_rsa_2048, + mock_csca_sha256_rsa_2048, + mock_csca_sha256_rsapss_2048, +} from '../../common/src/constants/mockCertificates'; +import { k_dsc, n_dsc } from '../../common/src/constants/constants'; +import { getCircuitName } from '../../common/src/utils/certificates/handleCertificate'; +import { customHasher } from '../../common/src/utils/pubkeyTree'; +import { poseidon2 } from 'poseidon-lite'; + +const sigAlgs = [ + { sigAlg: 'rsa', hashFunction: 'sha256' }, + // { sigAlg: 'rsa', hashFunction: 'sha1' }, + // { sigAlg: 'rsapss', hashFunction: 'sha256' }, +]; + +sigAlgs.forEach(({ sigAlg, hashFunction }) => { + describe(`DSC chain certificate - ${hashFunction.toUpperCase()} ${sigAlg.toUpperCase()}`, function () { + this.timeout(0); // Disable timeout + let circuit; + const max_cert_bytes = 960; + + // Mock certificates based on signature algorithm and hash function + let dscCertPem; + let cscaCertPem; + + switch (`${sigAlg}_${hashFunction}`) { + case 'rsa_sha256': + dscCertPem = mock_dsc_sha256_rsa_2048; + cscaCertPem = mock_csca_sha256_rsa_2048; + break; + case 'rsa_sha1': + dscCertPem = mock_dsc_sha1_rsa_2048; + cscaCertPem = mock_csca_sha1_rsa_2048; + break; + case 'rsapss_sha256': + dscCertPem = mock_dsc_sha256_rsapss_2048; + cscaCertPem = mock_csca_sha256_rsapss_2048; + break; + default: + throw new Error('Unsupported signature algorithm and hash function combination'); + } + + const dscCert = forge.pki.certificateFromPem(dscCertPem); + const cscaCert = forge.pki.certificateFromPem(cscaCertPem); + + const inputs = getCSCAInputs( + BigInt(0).toString(), + dscCert, + cscaCert, + n_dsc, + k_dsc, + n_dsc, + k_dsc, + max_cert_bytes, + true + ); + + before(async () => { + const circuitPath = path.resolve( + __dirname, + `../circuits/dsc/instances/${getCircuitName('dsc', sigAlg, hashFunction)}_2048.circom` + ); + circuit = await wasm_tester(circuitPath, { + include: [ + 'node_modules', + './node_modules/@zk-kit/binary-merkle-root.circom/src', + './node_modules/circomlib/circuits', + ], + }); + }); + + // it('verify dsc has been signed by the csca', () => { + // const tbsCertAsn1 = forge.pki.getTBSCertificate(dscCert); + // const tbsCertDer = forge.asn1.toDer(tbsCertAsn1).getBytes(); + // let md; + // switch (hashFunction) { + // case 'sha256': + // md = forge.md.sha256.create(); + // break; + // case 'sha1': + // md = forge.md.sha1.create(); + // break; + // default: + // throw new Error('Unsupported hash function'); + // } + // md.update(tbsCertDer); + // const tbsHash = md.digest().getBytes(); + // const signature = dscCert.signature; + // const publicKey = cscaCert.publicKey; + // const verified = publicKey.verify(tbsHash, signature); + // expect(verified).to.be.true; + // }); + + it('should compile and load the circuit', () => { + expect(circuit).to.not.be.undefined; + }); + + it('should compute the correct output', async () => { + const witness = await circuit.calculateWitness(inputs.inputs, true); + const blinded_dsc_commitment = (await circuit.getOutput(witness, ['blinded_dsc_commitment'])).blinded_dsc_commitment; + console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment: ', blinded_dsc_commitment); + expect(blinded_dsc_commitment).to.be.not.null; + }); + }); +}); diff --git a/circuits/tests/dsc/dsc_sha1_rsa_2048.test.ts b/circuits/tests/dsc/dsc_sha1_rsa_2048.test.ts deleted file mode 100644 index f4111057..00000000 --- a/circuits/tests/dsc/dsc_sha1_rsa_2048.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { assert, expect } from 'chai'; -import fs from 'fs'; -const forge = require('node-forge'); -import path from 'path'; -import { wasm as wasm_tester } from 'circom_tester'; -import { getCSCAInputs } from '../../../common/src/utils/csca'; -import { - mock_dsc_sha1_rsa_2048, - mock_csca_sha1_rsa_2048, -} from '../../../common/src/constants/mockCertificates'; -import { k_dsc, n_dsc } from '../../../common/src/constants/constants'; - -describe('DSC chain certificate - SHA1 RSA', function () { - this.timeout(0); // Disable timeout - let circuit; - const max_cert_bytes = 960; - const dscCert = forge.pki.certificateFromPem(mock_dsc_sha1_rsa_2048); - const cscaCert = forge.pki.certificateFromPem(mock_csca_sha1_rsa_2048); - - const inputs = getCSCAInputs( - BigInt(0).toString(), - dscCert, - cscaCert, - n_dsc, - k_dsc, - n_dsc, - k_dsc, - max_cert_bytes, - true - ); - - before(async () => { - const circuitPath = path.resolve( - __dirname, - '../../circuits/tests/dsc/dsc_sha1_rsa_2048.circom' - ); - circuit = await wasm_tester(circuitPath, { - include: [ - 'node_modules', - './node_modules/@zk-kit/binary-merkle-root.circom/src', - './node_modules/circomlib/circuits', - ], - }); - }); - - it('verify dsc has been signed by the csca', () => { - const tbsCertAsn1 = forge.pki.getTBSCertificate(dscCert); - const tbsCertDer = forge.asn1.toDer(tbsCertAsn1).getBytes(); - const md = forge.md.sha1.create(); - md.update(tbsCertDer); - const tbsHash = md.digest().getBytes(); - const signature = dscCert.signature; - const cscaCert = forge.pki.certificateFromPem(mock_csca_sha1_rsa_2048); - const publicKey = cscaCert.publicKey; - const verified = publicKey.verify(tbsHash, signature); - expect(verified).to.be.true; - }); - - it('should compile and load the circuit', () => { - expect(circuit).to.not.be.undefined; - }); - - it('should compute the correct output', async () => { - const witness = await circuit.calculateWitness(inputs.inputs, true); - }); -}); diff --git a/circuits/tests/dsc/dsc_sha256_rsa_2048.test.ts b/circuits/tests/dsc/dsc_sha256_rsa_2048.test.ts deleted file mode 100644 index b411a88d..00000000 --- a/circuits/tests/dsc/dsc_sha256_rsa_2048.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { assert, expect } from 'chai'; -import fs from 'fs'; -const forge = require('node-forge'); -import path from 'path'; -import { wasm as wasm_tester } from 'circom_tester'; -import { getCSCAInputs } from '../../../common/src/utils/csca'; -import { - mock_dsc_sha256_rsa_2048, - mock_csca_sha256_rsa_2048, -} from '../../../common/src/constants/mockCertificates'; -import { k_dsc, n_dsc } from '../../../common/src/constants/constants'; - -describe('DSC chain certificate - SHA256 RSA', function () { - this.timeout(0); // Disable timeout - let circuit; - const max_cert_bytes = 960; - const dscCert = forge.pki.certificateFromPem(mock_dsc_sha256_rsa_2048); - const cscaCert = forge.pki.certificateFromPem(mock_csca_sha256_rsa_2048); - - const inputs = getCSCAInputs( - BigInt(0).toString(), - dscCert, - cscaCert, - n_dsc, - k_dsc, - n_dsc, - k_dsc, - max_cert_bytes, - true - ); - - before(async () => { - const circuitPath = path.resolve( - __dirname, - '../../circuits/tests/dsc/dsc_sha256_rsa_2048.circom' - ); - circuit = await wasm_tester(circuitPath, { - include: [ - 'node_modules', - './node_modules/@zk-kit/binary-merkle-root.circom/src', - './node_modules/circomlib/circuits', - ], - }); - }); - - it('verify dsc has been signed by the csca', () => { - const tbsCertAsn1 = forge.pki.getTBSCertificate(dscCert); - const tbsCertDer = forge.asn1.toDer(tbsCertAsn1).getBytes(); - const md = forge.md.sha256.create(); - md.update(tbsCertDer); - const tbsHash = md.digest().getBytes(); - const signature = dscCert.signature; - const publicKey = cscaCert.publicKey; - const verified = publicKey.verify(tbsHash, signature); - expect(verified).to.be.true; - }); - - it('should compile and load the circuit', () => { - expect(circuit).to.not.be.undefined; - }); - - it('should compute the correct output', async () => { - const witness = await circuit.calculateWitness(inputs.inputs, true); - }); -}); diff --git a/circuits/tests/dsc/dsc_sha256_rsapss_2048.test.ts b/circuits/tests/dsc/dsc_sha256_rsapss_2048.test.ts deleted file mode 100644 index 01665cd7..00000000 --- a/circuits/tests/dsc/dsc_sha256_rsapss_2048.test.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { assert, expect } from 'chai'; -import fs from 'fs'; -const forge = require('node-forge'); -import path from 'path'; -import { wasm as wasm_tester } from 'circom_tester'; -import { getCSCAInputs } from '../../../common/src/utils/csca'; -import crypto from 'crypto'; -import { - mock_dsc_sha256_rsapss_2048, - mock_csca_sha256_rsapss_2048, -} from '../../../common/src/constants/mockCertificates'; -import { k_dsc, n_dsc } from '../../../common/src/constants/constants'; - -describe('DSC chain certificate - SHA256 RSA-PSS', function () { - this.timeout(0); // Disable timeout - let circuit; - const max_cert_bytes = 960; - const dscCert = forge.pki.certificateFromPem(mock_dsc_sha256_rsapss_2048); - const cscaCert = forge.pki.certificateFromPem(mock_csca_sha256_rsapss_2048); - - const inputs = getCSCAInputs( - BigInt(0).toString(), - dscCert, - cscaCert, - n_dsc, - k_dsc, - n_dsc, - k_dsc, - max_cert_bytes, - true - ); - - before(async () => { - const circuitPath = path.resolve( - __dirname, - '../../circuits/tests/dsc/dsc_sha256_rsapss_2048.circom' - ); - circuit = await wasm_tester(circuitPath, { - include: [ - 'node_modules', - './node_modules/@zk-kit/binary-merkle-root.circom/src', - './node_modules/circomlib/circuits', - ], - }); - }); - // TODO: Verify the certificate chain in ts too. - // it('verify dsc has been signed by the csca using RSA-PSS', () => { - // // Extract TBS (To Be Signed) certificate - // const tbsCertAsn1 = forge.pki.getTBSCertificate(dscCert); - // const tbsCertDer = forge.asn1.toDer(tbsCertAsn1).getBytes(); - - // // Create SHA-256 hash of the TBS certificate - // const tbsHash = crypto.createHash('sha256').update(Buffer.from(tbsCertDer, 'binary')).digest(); - - // // Extract signature from DSC certificate - // const signature = Buffer.from(dscCert.signature, 'binary'); - - // // Get public key from CSCA certificate - // const publicKeyPem = forge.pki.publicKeyToPem(cscaCert.publicKey); - // const publicKey = crypto.createPublicKey(publicKeyPem); - - // // Verify signature - // const pssOptions = { - // saltLength: 32, - // mgf1Hash: 'sha256' - // }; - - // try { - // const verifier = crypto.createVerify('RSA-SHA256'); - // verifier.update(tbsHash); - // const isValid = verifier.verify({ - // key: publicKey, - // padding: crypto.constants.RSA_PKCS1_PSS_PADDING, - // saltLength: pssOptions.saltLength - // }, signature); - - // console.log('TBS Hash:', tbsHash.toString('hex')); - // console.log('Signature:', signature.toString('hex')); - // console.log('Public Key:', publicKeyPem); - // console.log('Verification result:', isValid); - - // expect(isValid).to.be.true; - // } catch (error) { - // console.error('Verification error:', error); - // throw error; - // } - // }) - - it('should compile and load the circuit', () => { - expect(circuit).to.not.be.undefined; - }); - - it('should compute the correct output', async () => { - const witness = await circuit.calculateWitness(inputs.inputs, true); - }); - it('should fail to calculate witness with invalid inputs', async function () { - try { - const invalidInputs = { - ...inputs.inputs, - dsc_signature: Array(k_dsc) - .fill(0) - .map((byte) => BigInt(byte).toString()), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - expect(error.message).to.include('Assert Failed'); - } - }); -}); From aad89dcd034e234d9ae6bccd35d23194329ca207 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Fri, 20 Sep 2024 13:43:47 +0200 Subject: [PATCH 47/60] fix import issue --- circuits/circuits/utils/shaBytes/shaBytesDynamic.circom | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circuits/circuits/utils/shaBytes/shaBytesDynamic.circom b/circuits/circuits/utils/shaBytes/shaBytesDynamic.circom index a6fdc987..82e6ef75 100644 --- a/circuits/circuits/utils/shaBytes/shaBytesDynamic.circom +++ b/circuits/circuits/utils/shaBytes/shaBytesDynamic.circom @@ -1,6 +1,6 @@ pragma circom 2.1.6; -include "./dynamic/Sha1Bytes.circom"; +include "./dynamic/sha1Bytes.circom"; //include "@zk-email/circuits/lib/sha.circom"; include "./dynamic/Sha256Bytes.circom"; From 0d988d22a229e2011dabb3ceeef91824f67a0e22 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Fri, 20 Sep 2024 13:44:24 +0200 Subject: [PATCH 48/60] use VarShiftLeft instead of SelectSubArray --- circuits/circuits/utils/passport/passportVerifier.circom | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/circuits/circuits/utils/passport/passportVerifier.circom b/circuits/circuits/utils/passport/passportVerifier.circom index af577c01..a61d25d3 100644 --- a/circuits/circuits/utils/passport/passportVerifier.circom +++ b/circuits/circuits/utils/passport/passportVerifier.circom @@ -37,7 +37,7 @@ template PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_LEN, MAX_SIGNED } // assert DG1 and DG2 hashes match the ones in eContent input - signal dg1AndDg2Hash[2 * HASH_LEN_BYTES] <== SelectSubArray(MAX_ECONTENT_LEN, 2 * HASH_LEN_BYTES)(eContent, dg1_hash_offset, 2 * HASH_LEN_BYTES); // TODO: use varShifLeft instead + signal dg1AndDg2Hash[2 * HASH_LEN_BYTES] <== VarShiftLeft(MAX_ECONTENT_LEN, 2 * HASH_LEN_BYTES)(eContent, dg1_hash_offset); for(var i = 0; i < HASH_LEN_BYTES; i++) { dg1AndDg2Hash[i] === dg1ShaBytes[i].out; dg1AndDg2Hash[i + HASH_LEN_BYTES] === dg2_hash[i]; @@ -54,7 +54,7 @@ template PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_LEN, MAX_SIGNED } // assert eContent hash matches the one in signedAttr - signal eContentHashInSignedAttr[HASH_LEN_BYTES] <== SelectSubArray(MAX_SIGNED_ATTR_LEN, HASH_LEN_BYTES)(signed_attr, signed_attr_econtent_hash_offset, HASH_LEN_BYTES); // TODO: use varShifLeft instead + signal eContentHashInSignedAttr[HASH_LEN_BYTES] <== VarShiftLeft(MAX_SIGNED_ATTR_LEN, HASH_LEN_BYTES)(signed_attr, signed_attr_econtent_hash_offset); for(var i = 0; i < HASH_LEN_BYTES; i++) { eContentHashInSignedAttr[i] === eContentShaBytes[i].out; } From 18764e94f7ecbbc0de14f6c29031b011001d0a12 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Fri, 20 Sep 2024 13:45:25 +0200 Subject: [PATCH 49/60] adapt common scipts to new dsc circuits --- common/src/constants/constants.ts | 13 +++++++++++-- common/src/utils/csca.ts | 11 +++++------ common/src/utils/pubkeyTree.ts | 1 - 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/common/src/constants/constants.ts b/common/src/constants/constants.ts index 31123fab..c20b0742 100644 --- a/common/src/constants/constants.ts +++ b/common/src/constants/constants.ts @@ -22,7 +22,7 @@ export const RPC_URL = "https://opt-mainnet.g.alchemy.com/v2/Mjj_SdklUaCdR6EPfVK export const DEVELOPMENT_MODE = true export const DEFAULT_MAJORITY = "18" -export const MAX_PADDED_ECONTENT_LEN: Record = { +export const MAX_PADDED_ECONTENT_LEN: Partial> = { rsa_65537_sha256_2048: 384, rsa_65537_sha1_2048: 448, rsapss_65537_sha256_2048: 640, @@ -31,7 +31,7 @@ export const MAX_PADDED_ECONTENT_LEN: Record = { +export const MAX_PADDED_SIGNED_ATTR_LEN: Partial> = { rsa_65537_sha256_2048: 320, rsa_65537_sha1_2048: 448, rsapss_65537_sha256_2048: 512, @@ -39,6 +39,12 @@ export const MAX_PADDED_SIGNED_ATTR_LEN: Record> = { + rsa_65537_sha256_4096: 512, + rsa_65537_sha1_4096: 640, + rsapss_65537_sha256_4096: 768, +} // possible values because of sha1 constaints: 448, 576, 640 export enum SignatureAlgorithmIndex { @@ -48,6 +54,9 @@ export enum SignatureAlgorithmIndex { ecdsa_secp256r1_sha1_256 = 7, ecdsa_secp256r1_sha256_256 = 8, ecdsa_secp384r1_sha384_384 = 9, + rsa_65537_sha256_4096 = 10, + rsa_65537_sha1_4096 = 11, + rsapss_65537_sha256_4096 = 12, } export const attributeToPosition = { diff --git a/common/src/utils/csca.ts b/common/src/utils/csca.ts index 2e3f0b7b..a03e8556 100644 --- a/common/src/utils/csca.ts +++ b/common/src/utils/csca.ts @@ -127,8 +127,7 @@ export function getCSCAInputs(dscSecret: string, dscCertificate: any, cscaCertif // merkle tree saga const pemContent = forge.pki.certificateToPem(cscaCertificate); - const leaf = getLeaf(pemContent, n_csca, k_csca); - console.log('leaf', leaf); + const leaf = getLeaf(pemContent); const [root, proof] = getCSCAModulusProof(leaf, n_csca, k_csca); const { signatureAlgorithm: signatureAlgorithmName, hashFunction } = getSignatureAlgorithmDetails(signatureAlgorithm); @@ -138,10 +137,10 @@ export function getCSCAInputs(dscSecret: string, dscCertificate: any, cscaCertif { "raw_dsc_cert": dsc_message_padded_formatted, "raw_dsc_cert_padded_bytes": [dsc_messagePaddedLen_formatted], - "csca_modulus": csca_modulus_formatted, - "dsc_signature": dsc_signature_formatted, - "dsc_modulus": dsc_modulus_formatted, - "start_index": [startIndex_formatted], + "csca_pubKey": csca_modulus_formatted, + "signature": dsc_signature_formatted, + "dsc_pubKey": dsc_modulus_formatted, + "dsc_pubKey_offset": [startIndex_formatted], "secret": [dscSecret], "merkle_root": [BigInt(root).toString()], "path": proof.pathIndices.map(index => index.toString()), diff --git a/common/src/utils/pubkeyTree.ts b/common/src/utils/pubkeyTree.ts index 1e4d59ef..9936f2c7 100644 --- a/common/src/utils/pubkeyTree.ts +++ b/common/src/utils/pubkeyTree.ts @@ -30,7 +30,6 @@ export function getLeaf(dsc: string): string { const sigAlgKey = `${signatureAlgorithm}_${curve || exponent}_${hashFunction}_${bits}`; const sigAlgIndex = SignatureAlgorithmIndex[sigAlgKey]; - console.log("sigAlgIndex", sigAlgIndex) if (sigAlgIndex == undefined) { console.error(`\x1b[31mInvalid signature algorithm: ${sigAlgKey}\x1b[0m`); throw new Error(`Invalid signature algorithm: ${sigAlgKey}`); From 3404f8b9083f57fcc38afacd5b58d99585cb648e Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Fri, 20 Sep 2024 13:46:41 +0200 Subject: [PATCH 50/60] update register circuit --- .../register/openpassport_register.circom | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/circuits/circuits/register/openpassport_register.circom b/circuits/circuits/register/openpassport_register.circom index 9e0dc7f9..e2b3e887 100644 --- a/circuits/circuits/register/openpassport_register.circom +++ b/circuits/circuits/register/openpassport_register.circom @@ -23,23 +23,24 @@ template OPENPASSPORT_REGISTER(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN signal input signed_attr_padded_length; signal input signed_attr_econtent_hash_offset; signal input signature[kScaled]; - signal input pubKey[kScaled]; - signal input attestation_id; + signal attestation_id = 1; - // passport verifier - PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset, dg2_hash, eContent,eContent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature); + // nullifier + signal output nullifier <== CustomHasher(kScaled)(signature); - // leaf - signal leaf <== LeafHasher(kScaled)(pubKey, signatureAlgorithm); + // verify passport signature + PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset, dg2_hash, eContent,eContent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature); // commitment + signal leaf <== LeafHasher(kScaled)(pubKey, signatureAlgorithm); signal output commitment <== ComputeCommitment()(secret, attestation_id, leaf, dg1, dg2_hash); + // blinded dsc commitment - signal output blinded_dsc_commitment <== Poseidon(2)([dsc_secret, leaf]); + signal pubkeyHash <== CustomHasher(kScaled)(pubKey); + signal output blinded_dsc_commitment <== Poseidon(2)([dsc_secret, pubkeyHash]); + - // nullifier - signal output nullifier <== CustomHasher(kScaled)(signature); } \ No newline at end of file From 715eee4f05ff4899594e3ad34c4d1c2908149df9 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Fri, 20 Sep 2024 13:47:11 +0200 Subject: [PATCH 51/60] update prove into register and/or disclose circuit --- .../circuits/prove/openpassport_prove.circom | 27 ++++-- circuits/tests/prove.test.ts | 10 +++ common/src/utils/generateInputs.ts | 88 ++++++++++++++++--- 3 files changed, 106 insertions(+), 19 deletions(-) diff --git a/circuits/circuits/prove/openpassport_prove.circom b/circuits/circuits/prove/openpassport_prove.circom index c94e0985..d5998075 100644 --- a/circuits/circuits/prove/openpassport_prove.circom +++ b/circuits/circuits/prove/openpassport_prove.circom @@ -21,24 +21,29 @@ template OPENPASSPORT_PROVE(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, M signal input signed_attr[MAX_SIGNED_ATTR_PADDED_LEN]; signal input signed_attr_padded_length; signal input signed_attr_econtent_hash_offset; - signal input signature[kScaled]; signal input pubKey[kScaled]; - - // dislose related inputs + signal input signature[kScaled]; + // diclose related inputs signal input selector_dg1[88]; signal input selector_older_than; signal input current_date[6]; // YYMMDD - num signal input majority[2]; // YY - ASCII signal input user_identifier; signal input scope; + // registration related inputs + signal input secret; + signal input dsc_secret; - - signal signatureHashed <== CustomHasher(kScaled)(signature); // generate nullifier - signal output nullifier <== Poseidon(2)([signatureHashed, scope]); + signal attestation_id <== 1; // verify passport signature PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset, dg2_hash, eContent,eContent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature); + // nulifier + signal signatureHashed <== CustomHasher(kScaled)(signature); // generate nullifier + signal output nullifier <== Poseidon(2)([signatureHashed, scope]); + + // DISCLOSE (optional) // optionally disclose data component disclose = DISCLOSE(); disclose.dg1 <== dg1; @@ -46,7 +51,15 @@ template OPENPASSPORT_PROVE(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, M disclose.selector_older_than <== selector_older_than; disclose.current_date <== current_date; disclose.majority <== majority; - signal output revealedData_packed[3] <== disclose.revealedData_packed; signal output older_than[2] <== disclose.older_than; + + // REGISTRATION (optional) + // generate the commitment + signal leaf <== LeafHasher(kScaled)(pubKey, signatureAlgorithm); + signal output commitment <== ComputeCommitment()(secret, attestation_id, leaf, dg1, dg2_hash); + // blinded dsc commitment + signal pubkeyHash <== CustomHasher(kScaled)(pubKey); + signal output blinded_dsc_commitment <== Poseidon(2)([dsc_secret, pubkeyHash]); + } \ No newline at end of file diff --git a/circuits/tests/prove.test.ts b/circuits/tests/prove.test.ts index 74599e77..f219d195 100644 --- a/circuits/tests/prove.test.ts +++ b/circuits/tests/prove.test.ts @@ -7,6 +7,8 @@ import { genMockPassportData } from '../../common/src/utils/genMockPassportData' import { getCircuitName } from '../../common/src/utils/certificates/handleCertificate'; import { SignatureAlgorithm } from '../../common/src/utils/types'; import crypto from 'crypto'; +import { customHasher } from '../../common/src/utils/pubkeyTree'; +import { poseidon2 } from 'poseidon-lite'; const sigAlgs = [ // { sigAlg: 'rsa', hashFunction: 'sha1' }, @@ -34,6 +36,8 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { const selector_older_than = '1'; const inputs = generateCircuitInputsProve( + BigInt(0).toString(), + BigInt(0).toString(), passportData, scope, selector_dg1, @@ -67,6 +71,12 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { await circuit.checkConstraints(w); const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; console.log('\x1b[34m%s\x1b[0m', 'nullifier', nullifier); + const commitment = (await circuit.getOutput(w, ['commitment'])).commitment; + console.log('\x1b[34m%s\x1b[0m', 'commitment', commitment); + const blinded_dsc_commitment = (await circuit.getOutput(w, ['blinded_dsc_commitment'])).blinded_dsc_commitment; + console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment', blinded_dsc_commitment); + + expect(blinded_dsc_commitment).to.be.not.null; expect(nullifier).to.be.not.null; }); diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index 66ad6b36..c423c7a5 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -215,6 +215,8 @@ export function findIndexInTree(tree: LeanIMT, commitment: bigint): number { export function generateCircuitInputsProve( + secret: string, + dsc_secret: string, passportData: PassportData, scope: string, selector_dg1: string[], @@ -224,27 +226,89 @@ export function generateCircuitInputsProve( user_identifier_type: 'uuid' | 'hex' | 'ascii' = DEFAULT_USER_ID_TYPE ) { - const register_inputs = generateCircuitInputsRegister('0', '0', '0', passportData); + const { mrz, eContent, signedAttr, encryptedDigest, dsc, dg2Hash } = passportData; + const { signatureAlgorithm, hashFunction, hashLen, x, y, modulus, curve, exponent, bits } = parseCertificate(passportData.dsc); + + const signatureAlgorithmFullName = `${signatureAlgorithm}_${curve || exponent}_${hashFunction}_${bits}`; + let pubKey: any; + let signature: any; + + const { n, k } = getNAndK(signatureAlgorithm); + + if (signatureAlgorithm === 'ecdsa') { + const { r, s } = extractRSFromSignature(encryptedDigest); + const signature_r = splitToWords(BigInt(hexToDecimal(r)), n, k) + const signature_s = splitToWords(BigInt(hexToDecimal(s)), n, k) + signature = [...signature_r, ...signature_s] + const dsc_modulus_x = splitToWords(BigInt(hexToDecimal(x)), n, k) + const dsc_modulus_y = splitToWords(BigInt(hexToDecimal(y)), n, k) + pubKey = [...dsc_modulus_x, ...dsc_modulus_y] + } else { + + signature = splitToWords( + BigInt(bytesToBigDecimal(encryptedDigest)), + n, + k + ) + + pubKey = splitToWords( + BigInt(hexToDecimal(modulus)), + n, + k + ) + } + + const dg1 = formatMrz(mrz); + const formattedMrz = formatMrz(mrz); + const dg1Hash = hash(hashFunction, formattedMrz); + + const dg1HashOffset = findSubarrayIndex(eContent, dg1Hash) + console.log('dg1HashOffset', dg1HashOffset); + assert(dg1HashOffset !== -1, `DG1 hash ${dg1Hash} not found in eContent`); + + const eContentHash = hash(hashFunction, eContent); + const eContentHashOffset = findSubarrayIndex(signedAttr, eContentHash) + console.log('eContentHashOffset', eContentHashOffset); + assert(eContentHashOffset !== -1, `eContent hash ${eContentHash} not found in signedAttr`); + + if (eContent.length > MAX_PADDED_ECONTENT_LEN[signatureAlgorithmFullName]) { + console.error(`Data hashes too long (${eContent.length} bytes). Max length is ${MAX_PADDED_ECONTENT_LEN[signatureAlgorithmFullName]} bytes.`); + throw new Error(`This length of datagroups (${eContent.length} bytes) is currently unsupported. Please contact us so we add support!`); + } + + const [eContentPadded, eContentLen] = shaPad( + signatureAlgorithm, + new Uint8Array(eContent), + MAX_PADDED_ECONTENT_LEN[signatureAlgorithmFullName] + ); + const [signedAttrPadded, signedAttrPaddedLen] = shaPad( + signatureAlgorithm, + new Uint8Array(signedAttr), + MAX_PADDED_SIGNED_ATTR_LEN[signatureAlgorithmFullName] + ); + const current_date = getCurrentDateYYMMDD().map(datePart => BigInt(datePart).toString()); // Ensure majority is at least two digits const formattedMajority = majority.length === 1 ? `0${majority}` : majority; return { - dg1: register_inputs.dg1, - dg1_hash_offset: register_inputs.dg1_hash_offset, // uncomment when adding new circuits - dg2_hash: register_inputs.dg2_hash, - eContent: register_inputs.eContent, - eContent_padded_length: register_inputs.eContent_padded_length, - signed_attr: register_inputs.signed_attr, - signed_attr_padded_length: register_inputs.signed_attr_padded_length, - signed_attr_econtent_hash_offset: register_inputs.signed_attr_econtent_hash_offset, - signature: register_inputs.signature, - pubKey: register_inputs.pubKey, + dg1: dg1.map(byte => String(byte)), + dg1_hash_offset: [dg1HashOffset.toString()], // uncomment when adding new circuits + dg2_hash: formatDg2Hash(dg2Hash), + eContent: Array.from(eContentPadded).map((x) => x.toString()), + eContent_padded_length: [eContentLen.toString()], + signed_attr: Array.from(signedAttrPadded).map((x) => x.toString()), + signed_attr_padded_length: [signedAttrPaddedLen.toString()], + signed_attr_econtent_hash_offset: [eContentHashOffset.toString()], + signature: signature, + pubKey: pubKey, current_date: current_date, selector_dg1: selector_dg1, selector_older_than: [BigInt(selector_older_than).toString()], majority: formattedMajority.split('').map(char => BigInt(char.charCodeAt(0)).toString()), user_identifier: [parseUIDToBigInt(user_identifier, user_identifier_type)], - scope: [castFromScope(scope)] + scope: [castFromScope(scope)], + secret: [secret], + dsc_secret: [dsc_secret], }; } \ No newline at end of file From a26e80649a702fb70c5fa5b9cc8371dbf1217709 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Fri, 20 Sep 2024 13:48:28 +0200 Subject: [PATCH 52/60] delete register circuits --- .../instances/register_ecdsa_sha1.circom | 5 - .../instances/register_ecdsa_sha256.circom | 5 - .../instances/register_rsa_65537_sha1.circom | 5 - .../register_rsa_65537_sha256.circom | 5 - .../register_rsapss_65537_sha256.circom | 5 - .../register/openpassport_register.circom | 46 ------ circuits/tests/register.test.ts | 136 ------------------ common/src/utils/generateInputs.ts | 85 ----------- 8 files changed, 292 deletions(-) delete mode 100644 circuits/circuits/register/instances/register_ecdsa_sha1.circom delete mode 100644 circuits/circuits/register/instances/register_ecdsa_sha256.circom delete mode 100644 circuits/circuits/register/instances/register_rsa_65537_sha1.circom delete mode 100644 circuits/circuits/register/instances/register_rsa_65537_sha256.circom delete mode 100644 circuits/circuits/register/instances/register_rsapss_65537_sha256.circom delete mode 100644 circuits/circuits/register/openpassport_register.circom delete mode 100644 circuits/tests/register.test.ts diff --git a/circuits/circuits/register/instances/register_ecdsa_sha1.circom b/circuits/circuits/register/instances/register_ecdsa_sha1.circom deleted file mode 100644 index 14452db7..00000000 --- a/circuits/circuits/register/instances/register_ecdsa_sha1.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.6; - -include "../openpassport_register.circom"; - -component main = OPENPASSPORT_REGISTER(7, 43, 6, 448, 448); \ No newline at end of file diff --git a/circuits/circuits/register/instances/register_ecdsa_sha256.circom b/circuits/circuits/register/instances/register_ecdsa_sha256.circom deleted file mode 100644 index 456304c6..00000000 --- a/circuits/circuits/register/instances/register_ecdsa_sha256.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.6; - -include "../openpassport_register.circom"; - -component main = OPENPASSPORT_REGISTER(8, 43, 6, 640, 512); \ No newline at end of file diff --git a/circuits/circuits/register/instances/register_rsa_65537_sha1.circom b/circuits/circuits/register/instances/register_rsa_65537_sha1.circom deleted file mode 100644 index 90ea381c..00000000 --- a/circuits/circuits/register/instances/register_rsa_65537_sha1.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.6; - -include "../openpassport_register.circom"; - -component main = OPENPASSPORT_REGISTER(3, 64, 32, 448, 448); \ No newline at end of file diff --git a/circuits/circuits/register/instances/register_rsa_65537_sha256.circom b/circuits/circuits/register/instances/register_rsa_65537_sha256.circom deleted file mode 100644 index 0dedbcfb..00000000 --- a/circuits/circuits/register/instances/register_rsa_65537_sha256.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.6; - -include "../openpassport_register.circom"; - -component main = OPENPASSPORT_REGISTER(1, 121, 17, 384, 320); \ No newline at end of file diff --git a/circuits/circuits/register/instances/register_rsapss_65537_sha256.circom b/circuits/circuits/register/instances/register_rsapss_65537_sha256.circom deleted file mode 100644 index d8343193..00000000 --- a/circuits/circuits/register/instances/register_rsapss_65537_sha256.circom +++ /dev/null @@ -1,5 +0,0 @@ -pragma circom 2.1.6; - -include "../openpassport_register.circom"; - -component main = OPENPASSPORT_REGISTER(4, 64, 32, 640, 512); \ No newline at end of file diff --git a/circuits/circuits/register/openpassport_register.circom b/circuits/circuits/register/openpassport_register.circom deleted file mode 100644 index e2b3e887..00000000 --- a/circuits/circuits/register/openpassport_register.circom +++ /dev/null @@ -1,46 +0,0 @@ -pragma circom 2.1.6; - -include "../utils/passport/customHashers.circom"; -include "../utils/passport/computeCommitment.circom"; -include "../utils/passport/signatureAlgorithm.circom"; -include "../utils/passport/passportVerifier.circom"; - -template OPENPASSPORT_REGISTER(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN) { - var kLengthFactor = getKLengthFactor(signatureAlgorithm); - var kScaled = k * kLengthFactor; - - var HASH_LEN_BITS = getHashLength(signatureAlgorithm); - var HASH_LEN_BYTES = HASH_LEN_BITS / 8; - - signal input secret; - signal input dsc_secret; - signal input dg1[93]; - signal input dg1_hash_offset; - signal input dg2_hash[64]; - signal input eContent[MAX_ECONTENT_PADDED_LEN]; - signal input eContent_padded_length; - signal input signed_attr[MAX_SIGNED_ATTR_PADDED_LEN]; - signal input signed_attr_padded_length; - signal input signed_attr_econtent_hash_offset; - signal input signature[kScaled]; - signal input pubKey[kScaled]; - - signal attestation_id = 1; - - // nullifier - signal output nullifier <== CustomHasher(kScaled)(signature); - - // verify passport signature - PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset, dg2_hash, eContent,eContent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature); - - // commitment - signal leaf <== LeafHasher(kScaled)(pubKey, signatureAlgorithm); - signal output commitment <== ComputeCommitment()(secret, attestation_id, leaf, dg1, dg2_hash); - - // blinded dsc commitment - signal pubkeyHash <== CustomHasher(kScaled)(pubKey); - signal output blinded_dsc_commitment <== Poseidon(2)([dsc_secret, pubkeyHash]); - - - -} \ No newline at end of file diff --git a/circuits/tests/register.test.ts b/circuits/tests/register.test.ts deleted file mode 100644 index c6cc8faf..00000000 --- a/circuits/tests/register.test.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { describe } from 'mocha'; -import { assert, expect } from 'chai'; -import path from 'path'; -import { wasm as wasm_tester } from 'circom_tester'; -import {} from 'poseidon-lite'; -import { generateCircuitInputsRegister } from '../../common/src/utils/generateInputs'; -import { packBytes } from '../../common/src/utils/utils'; -import { PASSPORT_ATTESTATION_ID } from '../../common/src/constants/constants'; -import { genMockPassportData } from '../../common/src/utils/genMockPassportData'; -import { getCircuitName, parseDSC } from '../../common/src/utils/certificates/handleCertificate'; -import { generateCommitment, getLeaf } from '../../common/src/utils/pubkeyTree'; -import { SignatureAlgorithm } from '../../common/src/utils/types'; - -const sigAlgs = [ - { sigAlg: 'rsa', hashFunction: 'sha256' }, - { sigAlg: 'rsa', hashFunction: 'sha1' }, - { sigAlg: 'ecdsa', hashFunction: 'sha256' }, - { sigAlg: 'rsapss', hashFunction: 'sha256' }, - { sigAlg: 'ecdsa', hashFunction: 'sha1' }, -]; - -sigAlgs.forEach(({ sigAlg, hashFunction }) => { - describe(`Register - ${hashFunction.toUpperCase()} ${sigAlg.toUpperCase()}`, function () { - this.timeout(0); - let circuit: any; - - const passportData = genMockPassportData( - `${sigAlg}_${hashFunction}` as SignatureAlgorithm, - 'FRA', - '000101', - '300101' - ); - const secret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); - const dscSecret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString(); - - const inputs = generateCircuitInputsRegister( - secret, - dscSecret, - PASSPORT_ATTESTATION_ID, - passportData - ); - - before(async () => { - circuit = await wasm_tester( - path.join( - __dirname, - `../circuits/register/instances/${getCircuitName('register', sigAlg, hashFunction)}.circom` - ), - { - include: [ - 'node_modules', - './node_modules/@zk-kit/binary-merkle-root.circom/src', - './node_modules/circomlib/circuits', - ], - } - ); - }); - - it('should compile and load the circuit', async function () { - expect(circuit).to.not.be.undefined; - }); - - it('should calculate the witness with correct inputs', async function () { - // console.log('inputs', inputs); - const w = await circuit.calculateWitness(inputs); - // await circuit.checkConstraints(w); - - // const output = await circuit.getOutput(w); - - const nullifier = (await circuit.getOutput(w, ['nullifier'])).nullifier; - console.log('\x1b[34m%s\x1b[0m', 'nullifier', nullifier); - - const commitment_circom = (await circuit.getOutput(w, ['commitment'])).commitment; - console.log('\x1b[34m%s\x1b[0m', 'commitment', commitment_circom); - - const blinded_dsc_commitment = (await circuit.getOutput(w, ['blinded_dsc_commitment'])) - .blinded_dsc_commitment; - console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment', blinded_dsc_commitment); - - const mrz_bytes = packBytes(inputs.dg1); - const leaf = getLeaf(passportData.dsc).toString(); - const commitment_bytes = generateCommitment( - secret, - PASSPORT_ATTESTATION_ID, - leaf, - mrz_bytes, - passportData.dg2Hash - ); - const commitment_js = commitment_bytes.toString(); - console.log('commitment_js', commitment_js); - console.log('commitment_circom', commitment_circom); - expect(commitment_circom).to.be.equal(commitment_js); - }); - - it('should fail to calculate witness with invalid mrz', async function () { - try { - const invalidInputs = { - ...inputs, - dg1: Array(93) - .fill(0) - .map((byte) => BigInt(byte).toString()), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail(); - } catch (error) { - // expect(error.message).to.include('Assert Failed'); - } - }); - - it('should fail to calculate witness with invalid eContent', async function () { - try { - const invalidInputs = { - ...inputs, - eContent: inputs.eContent.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - // expect(error.message).to.include('Assert Failed'); - } - }); - - it('should fail to calculate witness with invalid signature', async function () { - try { - const invalidInputs = { - ...inputs, - signature: inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)), - }; - await circuit.calculateWitness(invalidInputs); - expect.fail('Expected an error but none was thrown.'); - } catch (error) { - // expect(error.message).to.include('Assert Failed'); - } - }); - }); -}); diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index c423c7a5..4fc006ec 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -25,91 +25,6 @@ import { packBytes } from "../utils/utils"; import { SMT } from "@ashpect/smt" import { parseCertificate } from './certificates/handleCertificate'; - -export function generateCircuitInputsRegister( - secret: string, - dscSecret: string, - attestation_id: string, - passportData: PassportData -) { - const { mrz, eContent, signedAttr, encryptedDigest, dsc, dg2Hash } = passportData; - const { signatureAlgorithm, hashFunction, hashLen, x, y, modulus, curve, exponent, bits } = parseCertificate(passportData.dsc); - - const signatureAlgorithmFullName = `${signatureAlgorithm}_${curve || exponent}_${hashFunction}_${bits}`; - let pubKey: any; - let signature: any; - - const { n, k } = getNAndK(signatureAlgorithm); - - if (signatureAlgorithm === 'ecdsa') { - const { r, s } = extractRSFromSignature(encryptedDigest); - const signature_r = splitToWords(BigInt(hexToDecimal(r)), n, k) - const signature_s = splitToWords(BigInt(hexToDecimal(s)), n, k) - signature = [...signature_r, ...signature_s] - const dsc_modulus_x = splitToWords(BigInt(hexToDecimal(x)), n, k) - const dsc_modulus_y = splitToWords(BigInt(hexToDecimal(y)), n, k) - pubKey = [...dsc_modulus_x, ...dsc_modulus_y] - } else { - - signature = splitToWords( - BigInt(bytesToBigDecimal(encryptedDigest)), - n, - k - ) - - pubKey = splitToWords( - BigInt(hexToDecimal(modulus)), - n, - k - ) - } - - const dg1 = formatMrz(mrz); - const formattedMrz = formatMrz(mrz); - const dg1Hash = hash(hashFunction, formattedMrz); - - const dg1HashOffset = findSubarrayIndex(eContent, dg1Hash) - console.log('dg1HashOffset', dg1HashOffset); - assert(dg1HashOffset !== -1, `DG1 hash ${dg1Hash} not found in eContent`); - - const eContentHash = hash(hashFunction, eContent); - const eContentHashOffset = findSubarrayIndex(signedAttr, eContentHash) - console.log('eContentHashOffset', eContentHashOffset); - assert(eContentHashOffset !== -1, `eContent hash ${eContentHash} not found in signedAttr`); - - if (eContent.length > MAX_PADDED_ECONTENT_LEN[signatureAlgorithmFullName]) { - console.error(`Data hashes too long (${eContent.length} bytes). Max length is ${MAX_PADDED_ECONTENT_LEN[signatureAlgorithmFullName]} bytes.`); - throw new Error(`This length of datagroups (${eContent.length} bytes) is currently unsupported. Please contact us so we add support!`); - } - - const [eContentPadded, eContentLen] = shaPad( - signatureAlgorithm, - new Uint8Array(eContent), - MAX_PADDED_ECONTENT_LEN[signatureAlgorithmFullName] - ); - const [signedAttrPadded, signedAttrPaddedLen] = shaPad( - signatureAlgorithm, - new Uint8Array(signedAttr), - MAX_PADDED_SIGNED_ATTR_LEN[signatureAlgorithmFullName] - ); - - return { - secret: [secret], - dsc_secret: [dscSecret], - dg1: dg1.map(byte => String(byte)), - dg1_hash_offset: [dg1HashOffset.toString()], // uncomment when adding new circuits - dg2_hash: formatDg2Hash(dg2Hash), - eContent: Array.from(eContentPadded).map((x) => x.toString()), - eContent_padded_length: [eContentLen.toString()], - signed_attr: Array.from(signedAttrPadded).map((x) => x.toString()), - signed_attr_padded_length: [signedAttrPaddedLen.toString()], - signed_attr_econtent_hash_offset: [eContentHashOffset.toString()], - signature: signature, - pubKey: pubKey, - attestation_id: [attestation_id], - }; -} - export function generateCircuitInputsDisclose( secret: string, attestation_id: string, From 8c1baf4a9473a8ce2ba9e008f9e43231d4094f23 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Fri, 20 Sep 2024 13:48:59 +0200 Subject: [PATCH 53/60] uncomment tests --- circuits/tests/dsc.test.ts | 4 ++-- circuits/tests/prove.test.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/circuits/tests/dsc.test.ts b/circuits/tests/dsc.test.ts index f4b1109f..6c6f0517 100644 --- a/circuits/tests/dsc.test.ts +++ b/circuits/tests/dsc.test.ts @@ -19,8 +19,8 @@ import { poseidon2 } from 'poseidon-lite'; const sigAlgs = [ { sigAlg: 'rsa', hashFunction: 'sha256' }, - // { sigAlg: 'rsa', hashFunction: 'sha1' }, - // { sigAlg: 'rsapss', hashFunction: 'sha256' }, + { sigAlg: 'rsa', hashFunction: 'sha1' }, + { sigAlg: 'rsapss', hashFunction: 'sha256' }, ]; sigAlgs.forEach(({ sigAlg, hashFunction }) => { diff --git a/circuits/tests/prove.test.ts b/circuits/tests/prove.test.ts index f219d195..bce56efd 100644 --- a/circuits/tests/prove.test.ts +++ b/circuits/tests/prove.test.ts @@ -11,11 +11,11 @@ import { customHasher } from '../../common/src/utils/pubkeyTree'; import { poseidon2 } from 'poseidon-lite'; const sigAlgs = [ - // { sigAlg: 'rsa', hashFunction: 'sha1' }, + { sigAlg: 'rsa', hashFunction: 'sha1' }, { sigAlg: 'rsa', hashFunction: 'sha256' }, - // { sigAlg: 'rsapss', hashFunction: 'sha256' }, - // { sigAlg: 'ecdsa', hashFunction: 'sha256' }, - // { sigAlg: 'ecdsa', hashFunction: 'sha1' }, + { sigAlg: 'rsapss', hashFunction: 'sha256' }, + { sigAlg: 'ecdsa', hashFunction: 'sha256' }, + { sigAlg: 'ecdsa', hashFunction: 'sha1' }, ]; sigAlgs.forEach(({ sigAlg, hashFunction }) => { From a2e46523f3bd5ef66ea2e421f63087e8d8bb0175 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Fri, 20 Sep 2024 13:49:13 +0200 Subject: [PATCH 54/60] yarn format --- circuits/tests/dsc.test.ts | 3 ++- circuits/tests/prove.test.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/circuits/tests/dsc.test.ts b/circuits/tests/dsc.test.ts index 6c6f0517..34f1990f 100644 --- a/circuits/tests/dsc.test.ts +++ b/circuits/tests/dsc.test.ts @@ -107,7 +107,8 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { it('should compute the correct output', async () => { const witness = await circuit.calculateWitness(inputs.inputs, true); - const blinded_dsc_commitment = (await circuit.getOutput(witness, ['blinded_dsc_commitment'])).blinded_dsc_commitment; + const blinded_dsc_commitment = (await circuit.getOutput(witness, ['blinded_dsc_commitment'])) + .blinded_dsc_commitment; console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment: ', blinded_dsc_commitment); expect(blinded_dsc_commitment).to.be.not.null; }); diff --git a/circuits/tests/prove.test.ts b/circuits/tests/prove.test.ts index bce56efd..f9be38ea 100644 --- a/circuits/tests/prove.test.ts +++ b/circuits/tests/prove.test.ts @@ -73,7 +73,8 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { console.log('\x1b[34m%s\x1b[0m', 'nullifier', nullifier); const commitment = (await circuit.getOutput(w, ['commitment'])).commitment; console.log('\x1b[34m%s\x1b[0m', 'commitment', commitment); - const blinded_dsc_commitment = (await circuit.getOutput(w, ['blinded_dsc_commitment'])).blinded_dsc_commitment; + const blinded_dsc_commitment = (await circuit.getOutput(w, ['blinded_dsc_commitment'])) + .blinded_dsc_commitment; console.log('\x1b[34m%s\x1b[0m', 'blinded_dsc_commitment', blinded_dsc_commitment); expect(blinded_dsc_commitment).to.be.not.null; From a9f0322aa07cdcabddc15890309bd3469ab15e0e Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Fri, 20 Sep 2024 14:24:34 +0200 Subject: [PATCH 55/60] force git to rename --- .../shaBytes/dynamic/{Sha1Bytes.circom => SSha1Bytes.circom} | 0 .../dynamic/{Sha256Bytes.circom => SSha256Bytes.circom} | 0 circuits/circuits/utils/shaBytes/shaBytesDynamic.circom | 3 +-- 3 files changed, 1 insertion(+), 2 deletions(-) rename circuits/circuits/utils/shaBytes/dynamic/{Sha1Bytes.circom => SSha1Bytes.circom} (100%) rename circuits/circuits/utils/shaBytes/dynamic/{Sha256Bytes.circom => SSha256Bytes.circom} (100%) diff --git a/circuits/circuits/utils/shaBytes/dynamic/Sha1Bytes.circom b/circuits/circuits/utils/shaBytes/dynamic/SSha1Bytes.circom similarity index 100% rename from circuits/circuits/utils/shaBytes/dynamic/Sha1Bytes.circom rename to circuits/circuits/utils/shaBytes/dynamic/SSha1Bytes.circom diff --git a/circuits/circuits/utils/shaBytes/dynamic/Sha256Bytes.circom b/circuits/circuits/utils/shaBytes/dynamic/SSha256Bytes.circom similarity index 100% rename from circuits/circuits/utils/shaBytes/dynamic/Sha256Bytes.circom rename to circuits/circuits/utils/shaBytes/dynamic/SSha256Bytes.circom diff --git a/circuits/circuits/utils/shaBytes/shaBytesDynamic.circom b/circuits/circuits/utils/shaBytes/shaBytesDynamic.circom index 82e6ef75..5c666c7b 100644 --- a/circuits/circuits/utils/shaBytes/shaBytesDynamic.circom +++ b/circuits/circuits/utils/shaBytes/shaBytesDynamic.circom @@ -1,8 +1,7 @@ pragma circom 2.1.6; include "./dynamic/sha1Bytes.circom"; -//include "@zk-email/circuits/lib/sha.circom"; -include "./dynamic/Sha256Bytes.circom"; +include "./dynamic/sha256Bytes.circom"; template ShaBytesDynamic(hashLen, max_num_bytes) { signal input in_padded[max_num_bytes]; From 6e12d57ae549bb6c165eb3466b52558e1a9e289f Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Fri, 20 Sep 2024 14:25:00 +0200 Subject: [PATCH 56/60] force git to rename 2 --- .../shaBytes/dynamic/{SSha1Bytes.circom => sha1Bytes.circom} | 0 .../shaBytes/dynamic/{SSha256Bytes.circom => sha256Bytes.circom} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename circuits/circuits/utils/shaBytes/dynamic/{SSha1Bytes.circom => sha1Bytes.circom} (100%) rename circuits/circuits/utils/shaBytes/dynamic/{SSha256Bytes.circom => sha256Bytes.circom} (100%) diff --git a/circuits/circuits/utils/shaBytes/dynamic/SSha1Bytes.circom b/circuits/circuits/utils/shaBytes/dynamic/sha1Bytes.circom similarity index 100% rename from circuits/circuits/utils/shaBytes/dynamic/SSha1Bytes.circom rename to circuits/circuits/utils/shaBytes/dynamic/sha1Bytes.circom diff --git a/circuits/circuits/utils/shaBytes/dynamic/SSha256Bytes.circom b/circuits/circuits/utils/shaBytes/dynamic/sha256Bytes.circom similarity index 100% rename from circuits/circuits/utils/shaBytes/dynamic/SSha256Bytes.circom rename to circuits/circuits/utils/shaBytes/dynamic/sha256Bytes.circom From a79a46d9ffb276bec1c29a12f04b17862965bf69 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Fri, 20 Sep 2024 14:49:09 +0200 Subject: [PATCH 57/60] implement formatInput() in generateInputs --- .../circuits/prove/openpassport_prove.circom | 12 +++-- circuits/tests/prove.test.ts | 8 +++- common/src/utils/generateInputs.ts | 46 +++++++++++-------- 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/circuits/circuits/prove/openpassport_prove.circom b/circuits/circuits/prove/openpassport_prove.circom index d5998075..19874bba 100644 --- a/circuits/circuits/prove/openpassport_prove.circom +++ b/circuits/circuits/prove/openpassport_prove.circom @@ -23,7 +23,8 @@ template OPENPASSPORT_PROVE(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, M signal input signed_attr_econtent_hash_offset; signal input pubKey[kScaled]; signal input signature[kScaled]; - // diclose related inputs + signal input selector_mode; // 0 - disclose, 1 - registration + // disclose related inputs signal input selector_dg1[88]; signal input selector_older_than; signal input current_date[6]; // YYMMDD - num @@ -36,6 +37,9 @@ template OPENPASSPORT_PROVE(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, M signal attestation_id <== 1; + // assert selector_mode is 0 or 1 + selector_mode * (selector_mode - 1) === 0; + // verify passport signature PassportVerifier(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset, dg2_hash, eContent,eContent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature); @@ -57,9 +61,11 @@ template OPENPASSPORT_PROVE(signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, M // REGISTRATION (optional) // generate the commitment signal leaf <== LeafHasher(kScaled)(pubKey, signatureAlgorithm); - signal output commitment <== ComputeCommitment()(secret, attestation_id, leaf, dg1, dg2_hash); + signal commitmentPrivate <== ComputeCommitment()(secret, attestation_id, leaf, dg1, dg2_hash); + signal output commitment <== commitmentPrivate * selector_mode; // blinded dsc commitment signal pubkeyHash <== CustomHasher(kScaled)(pubKey); - signal output blinded_dsc_commitment <== Poseidon(2)([dsc_secret, pubkeyHash]); + signal blindedDscCommitmenPrivate <== Poseidon(2)([dsc_secret, pubkeyHash]); + signal output blinded_dsc_commitment <== blindedDscCommitmenPrivate * selector_mode; } \ No newline at end of file diff --git a/circuits/tests/prove.test.ts b/circuits/tests/prove.test.ts index f9be38ea..d9185acb 100644 --- a/circuits/tests/prove.test.ts +++ b/circuits/tests/prove.test.ts @@ -34,10 +34,14 @@ sigAlgs.forEach(({ sigAlg, hashFunction }) => { const scope = '@coboyApp'; const selector_dg1 = Array(88).fill('1'); const selector_older_than = '1'; + const secret = 0; + const dsc_secret = 0; + const selector_mode = 1; const inputs = generateCircuitInputsProve( - BigInt(0).toString(), - BigInt(0).toString(), + selector_mode, + secret, + dsc_secret, passportData, scope, selector_dg1, diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index 4fc006ec..18e81c1b 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -130,8 +130,9 @@ export function findIndexInTree(tree: LeanIMT, commitment: bigint): number { export function generateCircuitInputsProve( - secret: string, - dsc_secret: string, + selector_mode: number | string, + secret: number | string, + dsc_secret: number | string, passportData: PassportData, scope: string, selector_dg1: string[], @@ -173,7 +174,6 @@ export function generateCircuitInputsProve( ) } - const dg1 = formatMrz(mrz); const formattedMrz = formatMrz(mrz); const dg1Hash = hash(hashFunction, formattedMrz); @@ -202,28 +202,36 @@ export function generateCircuitInputsProve( MAX_PADDED_SIGNED_ATTR_LEN[signatureAlgorithmFullName] ); - const current_date = getCurrentDateYYMMDD().map(datePart => BigInt(datePart).toString()); - // Ensure majority is at least two digits const formattedMajority = majority.length === 1 ? `0${majority}` : majority; + const majority_ascii = formattedMajority.split('').map(char => char.charCodeAt(0)) return { - dg1: dg1.map(byte => String(byte)), - dg1_hash_offset: [dg1HashOffset.toString()], // uncomment when adding new circuits + selector_mode: formatInput(selector_mode), + dg1: formatInput(formattedMrz), + dg1_hash_offset: formatInput(dg1HashOffset), dg2_hash: formatDg2Hash(dg2Hash), eContent: Array.from(eContentPadded).map((x) => x.toString()), - eContent_padded_length: [eContentLen.toString()], + eContent_padded_length: formatInput(eContentLen), signed_attr: Array.from(signedAttrPadded).map((x) => x.toString()), - signed_attr_padded_length: [signedAttrPaddedLen.toString()], - signed_attr_econtent_hash_offset: [eContentHashOffset.toString()], + signed_attr_padded_length: formatInput(signedAttrPaddedLen), + signed_attr_econtent_hash_offset: formatInput(eContentHashOffset), signature: signature, pubKey: pubKey, - current_date: current_date, - selector_dg1: selector_dg1, - selector_older_than: [BigInt(selector_older_than).toString()], - majority: formattedMajority.split('').map(char => BigInt(char.charCodeAt(0)).toString()), - user_identifier: [parseUIDToBigInt(user_identifier, user_identifier_type)], - scope: [castFromScope(scope)], - secret: [secret], - dsc_secret: [dsc_secret], + current_date: formatInput(getCurrentDateYYMMDD()), + selector_dg1: formatInput(selector_dg1), + selector_older_than: formatInput(selector_older_than), + majority: formatInput(majority_ascii), + user_identifier: formatInput(parseUIDToBigInt(user_identifier, user_identifier_type)), + scope: formatInput(castFromScope(scope)), + secret: formatInput(secret), + dsc_secret: formatInput(dsc_secret), }; -} \ No newline at end of file +} + +function formatInput(input: any) { + if (Array.isArray(input)) { + return input.map(item => BigInt(item).toString()); + } else { + return [BigInt(input).toString()]; + } +} From 3329a6e1d2ebd8ff1a6a92939383c3556f0abead Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Fri, 20 Sep 2024 14:50:41 +0200 Subject: [PATCH 58/60] add --max-old-space-size=8192 flag to yarn test --- circuits/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/circuits/package.json b/circuits/package.json index 47546b07..40f1e3fa 100644 --- a/circuits/package.json +++ b/circuits/package.json @@ -4,7 +4,7 @@ "author": "", "license": "MIT", "scripts": { - "test": "yarn ts-mocha 'tests/**/*.test.ts' 'tests/*.test.ts' --exit", + "test": "yarn ts-mocha --max-old-space-size=8192 'tests/**/*.test.ts' 'tests/*.test.ts' --exit", "install-circuits": "cd ../common && yarn && cd ../circuits && yarn", "format": "prettier --write .", "lint": "prettier --check ." @@ -49,4 +49,4 @@ "ts-mocha": "^10.0.0", "ts-node": "^10.9.2" } -} +} \ No newline at end of file From bd41e578eb3e2479065110331c3f7c163971b33b Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Fri, 20 Sep 2024 14:55:23 +0200 Subject: [PATCH 59/60] uplgrade circom compiler version to 2.1.9 --- circuits/circuits/disclose/disclose.circom | 2 +- circuits/circuits/disclose/vc_and_disclose.circom | 2 +- circuits/circuits/disclose/verify_commitment.circom | 2 +- .../circuits/dsc/instances/dsc_rsa_65537_sha1_2048.circom | 1 + .../circuits/dsc/instances/dsc_rsa_65537_sha256_2048.circom | 4 +++- .../dsc/instances/dsc_rsapss_65537_sha256_2048.circom | 1 + circuits/circuits/dsc/openpassport_dsc.circom | 2 +- circuits/circuits/ofac/ofac_name.circom | 2 +- circuits/circuits/ofac/ofac_name_dob.circom | 2 +- circuits/circuits/ofac/ofac_passport_number.circom | 2 +- circuits/circuits/prove/instances/prove_ecdsa_sha1.circom | 2 +- circuits/circuits/prove/instances/prove_ecdsa_sha256.circom | 2 +- circuits/circuits/prove/instances/prove_rsa_65537_sha1.circom | 2 +- .../circuits/prove/instances/prove_rsa_65537_sha256.circom | 2 +- .../circuits/prove/instances/prove_rsapss_65537_sha256.circom | 2 +- circuits/circuits/prove/openpassport_prove.circom | 2 +- circuits/circuits/utils/circom-ecdsa/ecdsa.circom | 2 +- circuits/circuits/utils/circom-ecdsa/ecdsa_func.circom | 2 +- circuits/circuits/utils/circom-ecdsa/p256.circom | 2 +- circuits/circuits/utils/circom-ecdsa/p256_func.circom | 2 +- circuits/circuits/utils/circom-ecdsa/p256_utils.circom | 2 +- circuits/circuits/utils/other/array.circom | 2 +- circuits/circuits/utils/other/bytes.circom | 2 +- circuits/circuits/utils/other/chunk_data.circom | 2 +- circuits/circuits/utils/other/constants.circom | 2 +- circuits/circuits/utils/other/fp.circom | 2 +- circuits/circuits/utils/other/functions.circom | 2 +- circuits/circuits/utils/other/getCommonLength.circom | 2 +- circuits/circuits/utils/other/smt.circom | 2 +- circuits/circuits/utils/passport/customHashers.circom | 2 +- circuits/circuits/utils/passport/date/dateIsLess.circom | 2 +- circuits/circuits/utils/passport/date/isOlderThan.circom | 2 +- circuits/circuits/utils/passport/date/isValid.circom | 2 +- circuits/circuits/utils/passport/formatECDSAInputs.circom | 2 +- circuits/circuits/utils/passport/passportVerifier.circom | 2 +- circuits/circuits/utils/passport/secp256r1Verifier.circom | 2 +- circuits/circuits/utils/passport/signatureAlgorithm.circom | 2 +- circuits/circuits/utils/passport/signatureVerifier.circom | 2 +- circuits/circuits/utils/rsa/powMod.circom | 2 +- circuits/circuits/utils/rsa/rsa.circom | 2 +- circuits/circuits/utils/rsa/rsaPkcs1.circom | 2 +- circuits/circuits/utils/rsa/rsaPkcs1v15.circom | 2 +- circuits/circuits/utils/rsa/rsaVerify.circom | 2 +- circuits/circuits/utils/rsapss/mgf1.circom | 2 +- circuits/circuits/utils/rsapss/xor2.circom | 2 +- circuits/circuits/utils/sha1/constants.circom | 2 +- circuits/circuits/utils/sha1/f.circom | 2 +- circuits/circuits/utils/sha1/parity.circom | 2 +- circuits/circuits/utils/sha1/rotate.circom | 2 +- circuits/circuits/utils/sha1/sha1.circom | 2 +- circuits/circuits/utils/sha1/sha1compression.circom | 2 +- circuits/circuits/utils/sha1/t.circom | 2 +- circuits/circuits/utils/sha1/xor4.circom | 2 +- circuits/circuits/utils/shaBytes/dynamic/sha256Bytes.circom | 2 +- circuits/circuits/utils/shaBytes/shaBytesDynamic.circom | 2 +- circuits/circuits/utils/shaBytes/shaBytesStatic.circom | 2 +- .../circuits/utils/shaBytes/static/Sha1BytesStatic.circom | 2 +- .../circuits/utils/shaBytes/static/Sha256BytesStatic.circom | 2 +- 58 files changed, 60 insertions(+), 56 deletions(-) diff --git a/circuits/circuits/disclose/disclose.circom b/circuits/circuits/disclose/disclose.circom index c6ebc816..62aa77fb 100644 --- a/circuits/circuits/disclose/disclose.circom +++ b/circuits/circuits/disclose/disclose.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.5; +pragma circom 2.1.9; include "circomlib/circuits/poseidon.circom"; include "../utils/other/bytes.circom"; diff --git a/circuits/circuits/disclose/vc_and_disclose.circom b/circuits/circuits/disclose/vc_and_disclose.circom index edbe0477..4fc38514 100644 --- a/circuits/circuits/disclose/vc_and_disclose.circom +++ b/circuits/circuits/disclose/vc_and_disclose.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.5; +pragma circom 2.1.9; include "./verify_commitment.circom"; include "./disclose.circom"; diff --git a/circuits/circuits/disclose/verify_commitment.circom b/circuits/circuits/disclose/verify_commitment.circom index b0b55a34..6b8e3fff 100644 --- a/circuits/circuits/disclose/verify_commitment.circom +++ b/circuits/circuits/disclose/verify_commitment.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.5; +pragma circom 2.1.9; include "circomlib/circuits/poseidon.circom"; include "../utils/other/bytes.circom"; diff --git a/circuits/circuits/dsc/instances/dsc_rsa_65537_sha1_2048.circom b/circuits/circuits/dsc/instances/dsc_rsa_65537_sha1_2048.circom index 79afeede..16476e05 100644 --- a/circuits/circuits/dsc/instances/dsc_rsa_65537_sha1_2048.circom +++ b/circuits/circuits/dsc/instances/dsc_rsa_65537_sha1_2048.circom @@ -1,3 +1,4 @@ +pragma circom 2.1.9; include "../openpassport_dsc.circom"; component main = OPENPASSPORT_DSC(3, 64, 32, 64, 32, 960, 256, 12); diff --git a/circuits/circuits/dsc/instances/dsc_rsa_65537_sha256_2048.circom b/circuits/circuits/dsc/instances/dsc_rsa_65537_sha256_2048.circom index 2e43c287..21fe5ab5 100644 --- a/circuits/circuits/dsc/instances/dsc_rsa_65537_sha256_2048.circom +++ b/circuits/circuits/dsc/instances/dsc_rsa_65537_sha256_2048.circom @@ -1,3 +1,5 @@ +pragma circom 2.1.9; + include "../openpassport_dsc.circom"; -component main = OPENPASSPORT_DSC(1, 64, 32, 64, 32, 960, 256, 12); +component main = OPENPASSPORT_DSC(1, 64, 32, 64, 32, 960, 256, 12); \ No newline at end of file diff --git a/circuits/circuits/dsc/instances/dsc_rsapss_65537_sha256_2048.circom b/circuits/circuits/dsc/instances/dsc_rsapss_65537_sha256_2048.circom index fdff4d73..e906e77e 100644 --- a/circuits/circuits/dsc/instances/dsc_rsapss_65537_sha256_2048.circom +++ b/circuits/circuits/dsc/instances/dsc_rsapss_65537_sha256_2048.circom @@ -1,3 +1,4 @@ +pragma circom 2.1.9; include "../openpassport_dsc.circom"; component main = OPENPASSPORT_DSC(4, 64, 32, 64, 32, 960, 256, 12); diff --git a/circuits/circuits/dsc/openpassport_dsc.circom b/circuits/circuits/dsc/openpassport_dsc.circom index 40917fb0..8ed60e5c 100644 --- a/circuits/circuits/dsc/openpassport_dsc.circom +++ b/circuits/circuits/dsc/openpassport_dsc.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.5; +pragma circom 2.1.9; include "circomlib/circuits/bitify.circom"; include "circomlib/circuits/poseidon.circom"; diff --git a/circuits/circuits/ofac/ofac_name.circom b/circuits/circuits/ofac/ofac_name.circom index d19e1721..3ac0c108 100644 --- a/circuits/circuits/ofac/ofac_name.circom +++ b/circuits/circuits/ofac/ofac_name.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.5; +pragma circom 2.1.9; include "circomlib/circuits/poseidon.circom"; include "circomlib/circuits/comparators.circom"; diff --git a/circuits/circuits/ofac/ofac_name_dob.circom b/circuits/circuits/ofac/ofac_name_dob.circom index 62e34560..94f0fb4e 100644 --- a/circuits/circuits/ofac/ofac_name_dob.circom +++ b/circuits/circuits/ofac/ofac_name_dob.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.5; +pragma circom 2.1.9; include "circomlib/circuits/poseidon.circom"; include "circomlib/circuits/comparators.circom"; diff --git a/circuits/circuits/ofac/ofac_passport_number.circom b/circuits/circuits/ofac/ofac_passport_number.circom index 6bb31e4e..7c81f43f 100644 --- a/circuits/circuits/ofac/ofac_passport_number.circom +++ b/circuits/circuits/ofac/ofac_passport_number.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.5; +pragma circom 2.1.9; include "circomlib/circuits/poseidon.circom"; include "circomlib/circuits/comparators.circom"; diff --git a/circuits/circuits/prove/instances/prove_ecdsa_sha1.circom b/circuits/circuits/prove/instances/prove_ecdsa_sha1.circom index 7aaecd61..151bf5db 100644 --- a/circuits/circuits/prove/instances/prove_ecdsa_sha1.circom +++ b/circuits/circuits/prove/instances/prove_ecdsa_sha1.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "../openpassport_prove.circom"; diff --git a/circuits/circuits/prove/instances/prove_ecdsa_sha256.circom b/circuits/circuits/prove/instances/prove_ecdsa_sha256.circom index fd47f4b2..fb6adc81 100644 --- a/circuits/circuits/prove/instances/prove_ecdsa_sha256.circom +++ b/circuits/circuits/prove/instances/prove_ecdsa_sha256.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "../openpassport_prove.circom"; diff --git a/circuits/circuits/prove/instances/prove_rsa_65537_sha1.circom b/circuits/circuits/prove/instances/prove_rsa_65537_sha1.circom index f097057a..661e2327 100644 --- a/circuits/circuits/prove/instances/prove_rsa_65537_sha1.circom +++ b/circuits/circuits/prove/instances/prove_rsa_65537_sha1.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "../openpassport_prove.circom"; diff --git a/circuits/circuits/prove/instances/prove_rsa_65537_sha256.circom b/circuits/circuits/prove/instances/prove_rsa_65537_sha256.circom index a2e056b8..7718d0e0 100644 --- a/circuits/circuits/prove/instances/prove_rsa_65537_sha256.circom +++ b/circuits/circuits/prove/instances/prove_rsa_65537_sha256.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "../openpassport_prove.circom"; diff --git a/circuits/circuits/prove/instances/prove_rsapss_65537_sha256.circom b/circuits/circuits/prove/instances/prove_rsapss_65537_sha256.circom index 4c1832fa..2b3ffadc 100644 --- a/circuits/circuits/prove/instances/prove_rsapss_65537_sha256.circom +++ b/circuits/circuits/prove/instances/prove_rsapss_65537_sha256.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "../openpassport_prove.circom"; diff --git a/circuits/circuits/prove/openpassport_prove.circom b/circuits/circuits/prove/openpassport_prove.circom index 19874bba..0202cbae 100644 --- a/circuits/circuits/prove/openpassport_prove.circom +++ b/circuits/circuits/prove/openpassport_prove.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "../utils/passport/customHashers.circom"; include "../utils/passport/computeCommitment.circom"; diff --git a/circuits/circuits/utils/circom-ecdsa/ecdsa.circom b/circuits/circuits/utils/circom-ecdsa/ecdsa.circom index 7d31025e..4c01ac4e 100644 --- a/circuits/circuits/utils/circom-ecdsa/ecdsa.circom +++ b/circuits/circuits/utils/circom-ecdsa/ecdsa.circom @@ -1,6 +1,6 @@ /// This file implements the ECDSA verification algorithm along with public key generation (xG) -pragma circom 2.1.5; +pragma circom 2.1.9; include "../../../node_modules/circomlib/circuits/multiplexer.circom"; include "p256.circom"; diff --git a/circuits/circuits/utils/circom-ecdsa/ecdsa_func.circom b/circuits/circuits/utils/circom-ecdsa/ecdsa_func.circom index 03d4dbbd..69259b50 100644 --- a/circuits/circuits/utils/circom-ecdsa/ecdsa_func.circom +++ b/circuits/circuits/utils/circom-ecdsa/ecdsa_func.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.5; +pragma circom 2.1.9; function get_g_pow_stride8_table(n, k) { assert(n == 43 && k == 6); diff --git a/circuits/circuits/utils/circom-ecdsa/p256.circom b/circuits/circuits/utils/circom-ecdsa/p256.circom index a8f784b5..03eb7c53 100644 --- a/circuits/circuits/utils/circom-ecdsa/p256.circom +++ b/circuits/circuits/utils/circom-ecdsa/p256.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.5; +pragma circom 2.1.9; include "curve.circom"; include "p256_func.circom"; diff --git a/circuits/circuits/utils/circom-ecdsa/p256_func.circom b/circuits/circuits/utils/circom-ecdsa/p256_func.circom index 5a1a4dc6..36360490 100644 --- a/circuits/circuits/utils/circom-ecdsa/p256_func.circom +++ b/circuits/circuits/utils/circom-ecdsa/p256_func.circom @@ -1,6 +1,6 @@ /// This file provides methods to grab curve parameter based on various representations -pragma circom 2.1.5; +pragma circom 2.1.9; function get_A(n, k) { assert((n == 86 && k == 3) || (n == 64 && k == 4) || (n == 43 && k ==6)); diff --git a/circuits/circuits/utils/circom-ecdsa/p256_utils.circom b/circuits/circuits/utils/circom-ecdsa/p256_utils.circom index 2f6c08be..52febd6b 100644 --- a/circuits/circuits/utils/circom-ecdsa/p256_utils.circom +++ b/circuits/circuits/utils/circom-ecdsa/p256_utils.circom @@ -1,6 +1,6 @@ /// UNUSED FILE -pragma circom 2.1.5; +pragma circom 2.1.9; include "bigInt_func.circom"; include "p256_func.circom"; diff --git a/circuits/circuits/utils/other/array.circom b/circuits/circuits/utils/other/array.circom index d743aaa9..c33003fb 100644 --- a/circuits/circuits/utils/other/array.circom +++ b/circuits/circuits/utils/other/array.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "circomlib/circuits/comparators.circom"; include "circomlib/circuits/bitify.circom"; diff --git a/circuits/circuits/utils/other/bytes.circom b/circuits/circuits/utils/other/bytes.circom index f6c36f5f..2ac5249d 100644 --- a/circuits/circuits/utils/other/bytes.circom +++ b/circuits/circuits/utils/other/bytes.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "circomlib/circuits/bitify.circom"; include "circomlib/circuits/comparators.circom"; diff --git a/circuits/circuits/utils/other/chunk_data.circom b/circuits/circuits/utils/other/chunk_data.circom index 760aafb5..54f6907a 100644 --- a/circuits/circuits/utils/other/chunk_data.circom +++ b/circuits/circuits/utils/other/chunk_data.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.5; +pragma circom 2.1.9; // Converts data into chunk_size chunks of 192 bits, assuming original n, k are 64 and 32. // This is because Poseidon circuit only supports an array of 16 elements. diff --git a/circuits/circuits/utils/other/constants.circom b/circuits/circuits/utils/other/constants.circom index 69b0c993..29776904 100644 --- a/circuits/circuits/utils/other/constants.circom +++ b/circuits/circuits/utils/other/constants.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; function EMAIL_ADDR_MAX_BYTES() { diff --git a/circuits/circuits/utils/other/fp.circom b/circuits/circuits/utils/other/fp.circom index 63493091..602e5b7b 100644 --- a/circuits/circuits/utils/other/fp.circom +++ b/circuits/circuits/utils/other/fp.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "circomlib/circuits/bitify.circom"; include "circomlib/circuits/comparators.circom"; diff --git a/circuits/circuits/utils/other/functions.circom b/circuits/circuits/utils/other/functions.circom index 7c76024f..f9bb802e 100644 --- a/circuits/circuits/utils/other/functions.circom +++ b/circuits/circuits/utils/other/functions.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; /// @function log2Ceil /// @notice Calculate log2 of a number and round it up diff --git a/circuits/circuits/utils/other/getCommonLength.circom b/circuits/circuits/utils/other/getCommonLength.circom index 3be58107..8aacb1ad 100644 --- a/circuits/circuits/utils/other/getCommonLength.circom +++ b/circuits/circuits/utils/other/getCommonLength.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.5; +pragma circom 2.1.9; include "circomlib/circuits/comparators.circom"; include "circomlib/circuits/bitify.circom"; diff --git a/circuits/circuits/utils/other/smt.circom b/circuits/circuits/utils/other/smt.circom index 71656df5..7b102c44 100644 --- a/circuits/circuits/utils/other/smt.circom +++ b/circuits/circuits/utils/other/smt.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.5; +pragma circom 2.1.9; include "circomlib/circuits/poseidon.circom"; include "circomlib/circuits/comparators.circom"; diff --git a/circuits/circuits/utils/passport/customHashers.circom b/circuits/circuits/utils/passport/customHashers.circom index 56906fc3..752951b1 100644 --- a/circuits/circuits/utils/passport/customHashers.circom +++ b/circuits/circuits/utils/passport/customHashers.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "../other/fp.circom"; include "circomlib/circuits/poseidon.circom"; diff --git a/circuits/circuits/utils/passport/date/dateIsLess.circom b/circuits/circuits/utils/passport/date/dateIsLess.circom index 3dbf72b0..61b77e5d 100644 --- a/circuits/circuits/utils/passport/date/dateIsLess.circom +++ b/circuits/circuits/utils/passport/date/dateIsLess.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "../node_modules/circomlib/circuits/comparators.circom"; diff --git a/circuits/circuits/utils/passport/date/isOlderThan.circom b/circuits/circuits/utils/passport/date/isOlderThan.circom index 83b35e9c..0141ec1a 100644 --- a/circuits/circuits/utils/passport/date/isOlderThan.circom +++ b/circuits/circuits/utils/passport/date/isOlderThan.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "../node_modules/circomlib/circuits/comparators.circom"; include "../node_modules/circomlib/circuits/bitify.circom"; diff --git a/circuits/circuits/utils/passport/date/isValid.circom b/circuits/circuits/utils/passport/date/isValid.circom index 077f4c95..a772f87f 100644 --- a/circuits/circuits/utils/passport/date/isValid.circom +++ b/circuits/circuits/utils/passport/date/isValid.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "../node_modules/circomlib/circuits/comparators.circom"; include "../node_modules/circomlib/circuits/bitify.circom"; diff --git a/circuits/circuits/utils/passport/formatECDSAInputs.circom b/circuits/circuits/utils/passport/formatECDSAInputs.circom index 03ca51bb..e2caf70e 100644 --- a/circuits/circuits/utils/passport/formatECDSAInputs.circom +++ b/circuits/circuits/utils/passport/formatECDSAInputs.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; template FormatECDSAInputs(signatureAlgorithm, k) { diff --git a/circuits/circuits/utils/passport/passportVerifier.circom b/circuits/circuits/utils/passport/passportVerifier.circom index a61d25d3..6366b51d 100644 --- a/circuits/circuits/utils/passport/passportVerifier.circom +++ b/circuits/circuits/utils/passport/passportVerifier.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "../other/array.circom"; include "../other/bytes.circom"; diff --git a/circuits/circuits/utils/passport/secp256r1Verifier.circom b/circuits/circuits/utils/passport/secp256r1Verifier.circom index 8936aa19..ddc34f20 100644 --- a/circuits/circuits/utils/passport/secp256r1Verifier.circom +++ b/circuits/circuits/utils/passport/secp256r1Verifier.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "./signatureAlgorithm.circom"; include "../circom-ecdsa/ecdsa.circom"; diff --git a/circuits/circuits/utils/passport/signatureAlgorithm.circom b/circuits/circuits/utils/passport/signatureAlgorithm.circom index b7138279..2a87c205 100644 --- a/circuits/circuits/utils/passport/signatureAlgorithm.circom +++ b/circuits/circuits/utils/passport/signatureAlgorithm.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; function getHashLength(signatureAlgorithm) { if (signatureAlgorithm == 1 ) { diff --git a/circuits/circuits/utils/passport/signatureVerifier.circom b/circuits/circuits/utils/passport/signatureVerifier.circom index 7ca8c00e..f295a2cb 100644 --- a/circuits/circuits/utils/passport/signatureVerifier.circom +++ b/circuits/circuits/utils/passport/signatureVerifier.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "../rsa/rsaPkcs1.circom"; // include "../rsa/rsaPkcs1v15.circom"; diff --git a/circuits/circuits/utils/rsa/powMod.circom b/circuits/circuits/utils/rsa/powMod.circom index 8ac08e18..379d6326 100644 --- a/circuits/circuits/utils/rsa/powMod.circom +++ b/circuits/circuits/utils/rsa/powMod.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "../other/bigInt.circom"; diff --git a/circuits/circuits/utils/rsa/rsa.circom b/circuits/circuits/utils/rsa/rsa.circom index fe3dbc1d..28442503 100644 --- a/circuits/circuits/utils/rsa/rsa.circom +++ b/circuits/circuits/utils/rsa/rsa.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "../other/fp.circom"; diff --git a/circuits/circuits/utils/rsa/rsaPkcs1.circom b/circuits/circuits/utils/rsa/rsaPkcs1.circom index 8393cc0c..55e13859 100644 --- a/circuits/circuits/utils/rsa/rsaPkcs1.circom +++ b/circuits/circuits/utils/rsa/rsaPkcs1.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.5; +pragma circom 2.1.9; //include "@zk-email/circuits/lib/fp.circom"; include "../other/fp.circom"; diff --git a/circuits/circuits/utils/rsa/rsaPkcs1v15.circom b/circuits/circuits/utils/rsa/rsaPkcs1v15.circom index ca21d8f6..b604d0c8 100644 --- a/circuits/circuits/utils/rsa/rsaPkcs1v15.circom +++ b/circuits/circuits/utils/rsa/rsaPkcs1v15.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "./powMod.circom"; include "circomlib/circuits/bitify.circom"; diff --git a/circuits/circuits/utils/rsa/rsaVerify.circom b/circuits/circuits/utils/rsa/rsaVerify.circom index 3838fa18..accee93e 100644 --- a/circuits/circuits/utils/rsa/rsaVerify.circom +++ b/circuits/circuits/utils/rsa/rsaVerify.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "./rsa.circom"; diff --git a/circuits/circuits/utils/rsapss/mgf1.circom b/circuits/circuits/utils/rsapss/mgf1.circom index 8addf54c..1b4775f5 100644 --- a/circuits/circuits/utils/rsapss/mgf1.circom +++ b/circuits/circuits/utils/rsapss/mgf1.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "circomlib/circuits/bitify.circom"; include "../sha2/sha256/sha256_hash_bits.circom"; diff --git a/circuits/circuits/utils/rsapss/xor2.circom b/circuits/circuits/utils/rsapss/xor2.circom index 5e505f78..f63c1027 100644 --- a/circuits/circuits/utils/rsapss/xor2.circom +++ b/circuits/circuits/utils/rsapss/xor2.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; template Xor2(n) { signal input a[n]; diff --git a/circuits/circuits/utils/sha1/constants.circom b/circuits/circuits/utils/sha1/constants.circom index d3a85cca..ed6bfa41 100644 --- a/circuits/circuits/utils/sha1/constants.circom +++ b/circuits/circuits/utils/sha1/constants.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.3; +pragma circom 2.1.9; include "../node_modules/circomlib/circuits/bitify.circom"; diff --git a/circuits/circuits/utils/sha1/f.circom b/circuits/circuits/utils/sha1/f.circom index 628be9e6..8e62f554 100644 --- a/circuits/circuits/utils/sha1/f.circom +++ b/circuits/circuits/utils/sha1/f.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.3; +pragma circom 2.1.9; include "./parity.circom"; include "../node_modules/circomlib/circuits/sha256/maj.circom"; diff --git a/circuits/circuits/utils/sha1/parity.circom b/circuits/circuits/utils/sha1/parity.circom index 03524453..816452fd 100644 --- a/circuits/circuits/utils/sha1/parity.circom +++ b/circuits/circuits/utils/sha1/parity.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.3; +pragma circom 2.1.9; include "../node_modules/circomlib/circuits/sha256/xor3.circom"; diff --git a/circuits/circuits/utils/sha1/rotate.circom b/circuits/circuits/utils/sha1/rotate.circom index 7a7c8a9a..ac906d83 100644 --- a/circuits/circuits/utils/sha1/rotate.circom +++ b/circuits/circuits/utils/sha1/rotate.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.3; +pragma circom 2.1.9; template RotL(n, l) { signal input in[n]; diff --git a/circuits/circuits/utils/sha1/sha1.circom b/circuits/circuits/utils/sha1/sha1.circom index 5d6e972d..3ecbe2ec 100644 --- a/circuits/circuits/utils/sha1/sha1.circom +++ b/circuits/circuits/utils/sha1/sha1.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.3; +pragma circom 2.1.9; include "constants.circom"; include "sha1compression.circom"; diff --git a/circuits/circuits/utils/sha1/sha1compression.circom b/circuits/circuits/utils/sha1/sha1compression.circom index d37b5d3d..9f9d1751 100644 --- a/circuits/circuits/utils/sha1/sha1compression.circom +++ b/circuits/circuits/utils/sha1/sha1compression.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.3; +pragma circom 2.1.9; include "./rotate.circom"; include "./xor4.circom"; diff --git a/circuits/circuits/utils/sha1/t.circom b/circuits/circuits/utils/sha1/t.circom index e9e843c8..42e4b65a 100644 --- a/circuits/circuits/utils/sha1/t.circom +++ b/circuits/circuits/utils/sha1/t.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.3; +pragma circom 2.1.9; include "./rotate.circom"; include "circomlib/circuits/binsum.circom"; diff --git a/circuits/circuits/utils/sha1/xor4.circom b/circuits/circuits/utils/sha1/xor4.circom index dd04e094..3e97c3fe 100644 --- a/circuits/circuits/utils/sha1/xor4.circom +++ b/circuits/circuits/utils/sha1/xor4.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.3; +pragma circom 2.1.9; template Xor4(n) { signal input a[n]; diff --git a/circuits/circuits/utils/shaBytes/dynamic/sha256Bytes.circom b/circuits/circuits/utils/shaBytes/dynamic/sha256Bytes.circom index 003fd6ef..69289b49 100644 --- a/circuits/circuits/utils/shaBytes/dynamic/sha256Bytes.circom +++ b/circuits/circuits/utils/shaBytes/dynamic/sha256Bytes.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "circomlib/circuits/bitify.circom"; include "circomlib/circuits/sha256/constants.circom"; diff --git a/circuits/circuits/utils/shaBytes/shaBytesDynamic.circom b/circuits/circuits/utils/shaBytes/shaBytesDynamic.circom index 5c666c7b..06a7660f 100644 --- a/circuits/circuits/utils/shaBytes/shaBytesDynamic.circom +++ b/circuits/circuits/utils/shaBytes/shaBytesDynamic.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "./dynamic/sha1Bytes.circom"; include "./dynamic/sha256Bytes.circom"; diff --git a/circuits/circuits/utils/shaBytes/shaBytesStatic.circom b/circuits/circuits/utils/shaBytes/shaBytesStatic.circom index bec982d1..922ad9de 100644 --- a/circuits/circuits/utils/shaBytes/shaBytesStatic.circom +++ b/circuits/circuits/utils/shaBytes/shaBytesStatic.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.6; +pragma circom 2.1.9; include "./static/Sha256BytesStatic.circom"; include "./static/Sha1BytesStatic.circom"; diff --git a/circuits/circuits/utils/shaBytes/static/Sha1BytesStatic.circom b/circuits/circuits/utils/shaBytes/static/Sha1BytesStatic.circom index 150d09dd..0c76bdcc 100644 --- a/circuits/circuits/utils/shaBytes/static/Sha1BytesStatic.circom +++ b/circuits/circuits/utils/shaBytes/static/Sha1BytesStatic.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.5; +pragma circom 2.1.9; include "circomlib/circuits/bitify.circom"; include "../../sha1/sha1.circom"; diff --git a/circuits/circuits/utils/shaBytes/static/Sha256BytesStatic.circom b/circuits/circuits/utils/shaBytes/static/Sha256BytesStatic.circom index 9b9be67a..a0447243 100644 --- a/circuits/circuits/utils/shaBytes/static/Sha256BytesStatic.circom +++ b/circuits/circuits/utils/shaBytes/static/Sha256BytesStatic.circom @@ -1,4 +1,4 @@ -pragma circom 2.1.5; +pragma circom 2.1.9; include "circomlib/circuits/bitify.circom"; include "circomlib/circuits/sha256/sha256.circom"; From e031dfebad02fa44ee6aaef46e19b785517879d6 Mon Sep 17 00:00:00 2001 From: turnoffthiscomputer Date: Fri, 20 Sep 2024 14:57:09 +0200 Subject: [PATCH 60/60] yarn format --- circuits/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circuits/package.json b/circuits/package.json index 40f1e3fa..6d26be8e 100644 --- a/circuits/package.json +++ b/circuits/package.json @@ -49,4 +49,4 @@ "ts-mocha": "^10.0.0", "ts-node": "^10.9.2" } -} \ No newline at end of file +}