From 824d174a730237d700983f2b7cffc1506948e373 Mon Sep 17 00:00:00 2001 From: motemotech Date: Sun, 5 Jan 2025 20:16:18 +0900 Subject: [PATCH 1/5] fixed except for 4096 bits --- .../prove_rsapss_sha256_3_4096.circom | 2 +- .../prove_rsapss_sha256_65537_4096.circom | 2 +- .../utils/circomlib/signature/FpPowMod.circom | 83 ++++ .../signature/rsa/verifyRsa3Pkcs1v1_5.circom | 36 +- .../rsa/verifyRsa65537Pkcs1v1_5.circom | 47 +- .../circomlib/signature/rsapss/rsapss3.circom | 448 ++++++++++++++++++ .../signature/rsapss/rsapss65537.circom | 448 ++++++++++++++++++ .../utils/passport/signatureVerifier.circom | 39 +- circuits/tests/prove.test.ts | 12 +- 9 files changed, 1015 insertions(+), 102 deletions(-) create mode 100644 circuits/circuits/utils/circomlib/signature/FpPowMod.circom create mode 100644 circuits/circuits/utils/circomlib/signature/rsapss/rsapss3.circom create mode 100644 circuits/circuits/utils/circomlib/signature/rsapss/rsapss65537.circom diff --git a/circuits/circuits/prove/instances/prove_rsapss_sha256_3_4096.circom b/circuits/circuits/prove/instances/prove_rsapss_sha256_3_4096.circom index e7b384750..bb6924084 100644 --- a/circuits/circuits/prove/instances/prove_rsapss_sha256_3_4096.circom +++ b/circuits/circuits/prove/instances/prove_rsapss_sha256_3_4096.circom @@ -2,4 +2,4 @@ pragma circom 2.1.9; include "../openpassport_prove.circom"; -component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(17, 64, 64, 384, 192, 20); \ No newline at end of file +component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(17, 120, 35, 384, 192, 20); \ No newline at end of file diff --git a/circuits/circuits/prove/instances/prove_rsapss_sha256_65537_4096.circom b/circuits/circuits/prove/instances/prove_rsapss_sha256_65537_4096.circom index 3e1834183..08d217446 100644 --- a/circuits/circuits/prove/instances/prove_rsapss_sha256_65537_4096.circom +++ b/circuits/circuits/prove/instances/prove_rsapss_sha256_65537_4096.circom @@ -2,4 +2,4 @@ pragma circom 2.1.9; include "../openpassport_prove.circom"; -component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(12, 64, 64, 384, 192, 20); \ No newline at end of file +component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(12, 120, 35, 384, 192, 20); \ No newline at end of file diff --git a/circuits/circuits/utils/circomlib/signature/FpPowMod.circom b/circuits/circuits/utils/circomlib/signature/FpPowMod.circom new file mode 100644 index 000000000..af3af64a1 --- /dev/null +++ b/circuits/circuits/utils/circomlib/signature/FpPowMod.circom @@ -0,0 +1,83 @@ +pragma circom 2.1.9; + +include "@zk-email/circuits/lib/fp.circom"; +include "circomlib/circuits/bitify.circom"; + +/// @title FpPow3Mod +/// @notice Computes base^3 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 FpPow3Mod(n, k) { + signal input base[k]; + signal input modulus[k]; + + signal output out[k]; + + component doublers = FpMul(n, k); + component adder = FpMul(n, k); + + for (var j = 0; j < k; j++) { + adder.p[j] <== modulus[j]; + doublers.p[j] <== modulus[j]; + } + for (var j = 0; j < k; j++) { + doublers.a[j] <== base[j]; + doublers.b[j] <== base[j]; + } + for (var j = 0; j < k; j++) { + adder.a[j] <== base[j]; + adder.b[j] <== doublers.out[j]; + } + for (var j = 0; j < k; j++) { + out[j] <== adder.out[j]; + } +} + +/// @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]; + } +} \ No newline at end of file diff --git a/circuits/circuits/utils/circomlib/signature/rsa/verifyRsa3Pkcs1v1_5.circom b/circuits/circuits/utils/circomlib/signature/rsa/verifyRsa3Pkcs1v1_5.circom index 2ed14499f..138999c05 100644 --- a/circuits/circuits/utils/circomlib/signature/rsa/verifyRsa3Pkcs1v1_5.circom +++ b/circuits/circuits/utils/circomlib/signature/rsa/verifyRsa3Pkcs1v1_5.circom @@ -2,7 +2,7 @@ pragma circom 2.1.9; include "@zk-email/circuits/lib/fp.circom"; include "./pkcs1v1_5Padding.circom"; -include "circomlib/circuits/bitify.circom"; +include "../FpPowMod.circom"; // For 2048bits RSA, CHUNK_SIZE = 64, CHUNK_NUMBER = 32 // For 3072bits RSA, CHUNK_SIZE = 64, CHUNK_NUMBER = 48 @@ -46,37 +46,3 @@ template VerifyRsa3Pkcs1v1_5(CHUNK_SIZE, CHUNK_NUMBER, HASH_SIZE) { bigPow.out[i] === padder.out[i]; } } - -/// @title FpPow3Mod -/// @notice Computes base^3 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 FpPow3Mod(n, k) { - signal input base[k]; - signal input modulus[k]; - - signal output out[k]; - - component doublers = FpMul(n, k); - component adder = FpMul(n, k); - - for (var j = 0; j < k; j++) { - adder.p[j] <== modulus[j]; - doublers.p[j] <== modulus[j]; - } - for (var j = 0; j < k; j++) { - doublers.a[j] <== base[j]; - doublers.b[j] <== base[j]; - } - for (var j = 0; j < k; j++) { - adder.a[j] <== base[j]; - adder.b[j] <== doublers.out[j]; - } - for (var j = 0; j < k; j++) { - out[j] <== adder.out[j]; - } -} diff --git a/circuits/circuits/utils/circomlib/signature/rsa/verifyRsa65537Pkcs1v1_5.circom b/circuits/circuits/utils/circomlib/signature/rsa/verifyRsa65537Pkcs1v1_5.circom index b56e1e5d5..80e7067ab 100644 --- a/circuits/circuits/utils/circomlib/signature/rsa/verifyRsa65537Pkcs1v1_5.circom +++ b/circuits/circuits/utils/circomlib/signature/rsa/verifyRsa65537Pkcs1v1_5.circom @@ -2,7 +2,7 @@ pragma circom 2.1.9; include "@zk-email/circuits/lib/fp.circom"; include "./pkcs1v1_5Padding.circom"; -include "circomlib/circuits/bitify.circom"; +include "../FpPowMod.circom"; // For 2048bits RSA, CHUNK_SIZE = 64, CHUNK_NUMBER = 32 // For 3072bits RSA, CHUNK_SIZE = 64, CHUNK_NUMBER = 48 @@ -46,48 +46,3 @@ template VerifyRsa65537Pkcs1v1_5(CHUNK_SIZE, CHUNK_NUMBER, HASH_SIZE) { 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]; - } -} diff --git a/circuits/circuits/utils/circomlib/signature/rsapss/rsapss3.circom b/circuits/circuits/utils/circomlib/signature/rsapss/rsapss3.circom new file mode 100644 index 000000000..9e9607bea --- /dev/null +++ b/circuits/circuits/utils/circomlib/signature/rsapss/rsapss3.circom @@ -0,0 +1,448 @@ +pragma circom 2.1.6; + +include "../../bigInt/bigInt.circom"; +include "./mgf1.circom"; +include "../../bitify/gates.circom"; +include "../../hasher/hash.circom"; +include "../FpPowMod.circom"; + +/* +* Verification for RSAPSS signature. +* hashed is hashed message of hash_type algo, hash_type is algo hash algo for mgf1 mask generation. +* There is no assert for CHUNK_SIZE == 64 and it may work with other chunking, but this one wasn`t tested, +* so better use 64 signature and pubkey - chunked numbers (CHUNK_SIZE, CHUNK_NUMBER). +* default exp = 65537 +* SALT_LEN is salt lenght in bytes! (NOT IN BITES LIKE HASH_TYPE!). +* This is because salt len can`t be % 8 != 0 so we use bytes len (8 bites). +* For now, only HASH_TYPE == 384 && SALT_LEN == 48, HASH_TYPE == 256 && SALT_LEN == 64, HASH_TYPE == 256 && SALT_LEN == 32 cases supported. +* Use this for CHUNK_NUMBER == 2**n, otherwise error will occur. +*/ +template VerifyRsaPss3Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE) { + assert((HASH_TYPE == 384 && SALT_LEN == 48) || (HASH_TYPE == 256 && SALT_LEN == 64) || (HASH_TYPE == 256 && SALT_LEN == 32)); + + signal input pubkey[CHUNK_NUMBER]; + signal input signature[CHUNK_NUMBER]; + signal input hashed[HASH_TYPE]; + + + var EM_LEN = (CHUNK_SIZE * CHUNK_NUMBER) \ 8; + var HASH_LEN = HASH_TYPE \ 8; + var SALT_LEN_BITS = SALT_LEN * 8; + var EM_LEN_BITS = CHUNK_SIZE * CHUNK_NUMBER; + + signal eM[EM_LEN]; + signal eMsgInBits[EM_LEN_BITS]; + + //computing encoded message + component bigPow = FpPow3Mod(CHUNK_SIZE, CHUNK_NUMBER); + for (var i = 0; i < CHUNK_NUMBER; i++) { + bigPow.base[i] <== signature[i]; + bigPow.modulus[i] <== pubkey[i]; + } + + signal encoded[CHUNK_NUMBER]; + encoded <== bigPow.out; + + component num2Bits[CHUNK_NUMBER]; + + for (var i = 0; i < CHUNK_NUMBER; i++) { + num2Bits[i] = Num2Bits(CHUNK_SIZE); + num2Bits[i].in <== encoded[CHUNK_NUMBER - 1 - i]; + + for (var j = 0; j < CHUNK_SIZE; j++) { + eMsgInBits[i * CHUNK_SIZE + j] <== num2Bits[i].out[CHUNK_SIZE - j - 1]; + } + } + + component bits2Num[EM_LEN]; + + for (var i = 0; i < EM_LEN; i++) { + bits2Num[i] = Bits2Num(8); + + for (var j = 0; j < 8; j++) { + bits2Num[i].in[7 - j] <== eMsgInBits[i * 8 + j]; + } + + eM[EM_LEN - i - 1] <== bits2Num[i].out; + } + + //should be more than HLEN + SLEN + 2 + assert(EM_LEN >= HASH_LEN + SALT_LEN + 2); + + //should end with 0xBC (188 in decimal) + assert(eM[0] == 188); + + var DB_MASK_LEN = EM_LEN - HASH_LEN - 1; + + signal dbMask[DB_MASK_LEN * 8]; + signal db[DB_MASK_LEN * 8]; + signal salt[SALT_LEN * 8]; + signal maskedDB[(EM_LEN - HASH_LEN - 1) * 8]; + + for (var i = 0; i < (EM_LEN - HASH_LEN - 1) * 8; i++) { + maskedDB[i] <== eMsgInBits[i]; + } + + signal hash[HASH_LEN * 8]; + + //inserting hash + for (var i = 0; i < HASH_TYPE; i++) { + hash[i] <== eMsgInBits[(EM_LEN_BITS) - HASH_TYPE - 8 + i]; + } + + //getting mask + if (HASH_TYPE == 256) { + component MGF1_256 = Mgf1Sha256(HASH_LEN, DB_MASK_LEN); + + for (var i = 0; i < (HASH_TYPE); i++) { + MGF1_256.seed[i] <== hash[i]; + } + + for (var i = 0; i < DB_MASK_LEN * 8; i++) { + dbMask[i] <== MGF1_256.out[i]; + } + } + if (HASH_TYPE == 384) { + component MGF1_384 = Mgf1Sha384(HASH_LEN, DB_MASK_LEN); + + for (var i = 0; i < (HASH_TYPE); i++) { + MGF1_384.seed[i] <== hash[i]; + } + + for (var i = 0; i < DB_MASK_LEN * 8; i++) { + dbMask[i] <== MGF1_384.out[i]; + } + } + + component xor = Xor2(DB_MASK_LEN * 8); + + for (var i = 0; i < DB_MASK_LEN * 8; i++) { + xor.in1[i] <== maskedDB[i]; + xor.in2[i] <== dbMask[i]; + } + + for (var i = 0; i < DB_MASK_LEN * 8; i++) { + //setting the first leftmost byte to 0 + if (i == 0) { + db[i] <== 0; + } else { + db[i] <== xor.out[i]; + } + } + + //inserting salt + for (var i = 0; i < SALT_LEN_BITS; i++) { + salt[SALT_LEN_BITS - 1 - i] <== db[(DB_MASK_LEN * 8) - 1 - i]; + } + + signal mDash[1024]; + //adding 0s + for (var i = 0; i < 64; i++) { + mDash[i] <== 0; + } + + //adding message hash + for (var i = 0; i < HASH_LEN * 8; i++) { + mDash[64 + i] <== hashed[i]; + } + + //adding salt + for (var i = 0; i < SALT_LEN * 8; i++) { + mDash[64 + HASH_LEN * 8 + i] <== salt[i]; + } + + if (HASH_TYPE == 256 && SALT_LEN == 32) { + //adding padding + //len = 64+512 = 576 = 1001000000 + for (var i = 577; i < 1014; i++) { + mDash[i] <== 0; + } + + mDash[576] <== 1; + mDash[1023] <== 0; + mDash[1022] <== 0; + mDash[1021] <== 0; + mDash[1020] <== 0; + mDash[1019] <== 0; + mDash[1018] <== 0; + mDash[1017] <== 1; + mDash[1016] <== 0; + mDash[1015] <== 0; + mDash[1014] <== 1; + + //hashing + component hDash256 = ShaHashChunks(2, HASH_TYPE); + hDash256.in <== mDash; + + hDash256.out === hash; + } + + if (HASH_TYPE == 256 && SALT_LEN == 64) { + for (var i = 833; i < 1014; i++) { + mDash[i] <== 0; + } + + mDash[832] <== 1; + mDash[1023] <== 0; + mDash[1022] <== 0; + mDash[1021] <== 0; + mDash[1020] <== 0; + mDash[1019] <== 0; + mDash[1018] <== 0; + mDash[1017] <== 1; + mDash[1016] <== 0; + mDash[1015] <== 1; + mDash[1014] <== 1; + + component hDash256 = ShaHashChunks(2, HASH_TYPE); + hDash256.in <== mDash; + + hDash256.out === hash; + } + + if (HASH_TYPE == 384 && SALT_LEN == 48) { + //padding + //len = 64+48*16 = 832 = 1101000000 + for (var i = 833; i < 1014; i++) { + mDash[i] <== 0; + } + + mDash[832] <== 1; + mDash[1023] <== 0; + mDash[1022] <== 0; + mDash[1021] <== 0; + mDash[1020] <== 0; + mDash[1019] <== 0; + mDash[1018] <== 0; + mDash[1017] <== 1; + mDash[1016] <== 0; + mDash[1015] <== 1; + mDash[1014] <== 1; + + //hashing mDash + component hDash384 = ShaHashChunks(1, HASH_TYPE); + hDash384.in <== mDash; + + hDash384.out === hash; + } +} + +/* +* Verification for RSAPSS signature. +* hashed is hashed message of hash_type algo, hash_type is algo hash algo for mgf1 mask generation. +* There is no assert for CHUNK_SIZE == 64 and it may work with other chunking, but this one wasn`t tested, +* so better use 64 signature and pubkey - chunked numbers (CHUNK_SIZE, CHUNK_NUMBER). +* e_bits - Len of bit representation of exponent with 1 highest and lowest bits, other are 0 (2^(e_bits - 1) + 1). +* default exp = 65537 (e_bits = 17) +* SALT_LEN is salt lenght in bytes! (NOT IN BITES LIKE HASH_TYPE!) +* This is because salt len can`t be % 8 != 0 so we use bytes len (8 bites). +* For now, only HASH_TYPE == 384 && SALT_LEN == 48, HASH_TYPE == 256 && SALT_LEN == 64, HASH_TYPE == 256 && SALT_LEN == 32 cases supported. +* Use this for CHUNK_NUMBER != 2**n, otherwise use previous template. +*/ +template VerifyRsaPss3SigNonOptimised(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, EXP, HASH_TYPE) { + assert((HASH_TYPE == 384 && SALT_LEN == 48) || (HASH_TYPE == 256 && SALT_LEN == 64) || (HASH_TYPE == 256 && SALT_LEN == 32)); + + signal input pubkey[CHUNK_NUMBER]; + signal input signature[CHUNK_NUMBER]; + signal input hashed[HASH_TYPE]; + + + var EM_LEN = (CHUNK_SIZE * CHUNK_NUMBER) \ 8; + var HASH_LEN = HASH_TYPE \ 8; + var SALT_LEN_BITS = SALT_LEN * 8; + var EM_LEN_BITS = CHUNK_SIZE * CHUNK_NUMBER; + + signal eM[EM_LEN]; + signal eMsgInBits[EM_LEN_BITS]; + + //computing encoded message + component powerMod; + powerMod = PowerModNonOptimised(CHUNK_SIZE, CHUNK_NUMBER, EXP); + powerMod.base <== signature; + powerMod.modulus <== pubkey; + + signal encoded[CHUNK_NUMBER]; + encoded <== powerMod.out; + + component num2Bits[CHUNK_NUMBER]; + + for (var i = 0; i < CHUNK_NUMBER; i++) { + num2Bits[i] = Num2Bits(CHUNK_SIZE); + num2Bits[i].in <== encoded[CHUNK_NUMBER - 1 - i]; + + for (var j = 0; j < CHUNK_SIZE; j++) { + eMsgInBits[i * CHUNK_SIZE + j] <== num2Bits[i].out[CHUNK_SIZE - j - 1]; + } + } + + component bits2Num[EM_LEN]; + + for (var i = 0; i < EM_LEN; i++) { + bits2Num[i] = Bits2Num(8); + + for (var j = 0; j < 8; j++) { + bits2Num[i].in[7 - j] <== eMsgInBits[i * 8 + j]; + } + + eM[EM_LEN - i - 1] <== bits2Num[i].out; + } + + //should be more than HLEN + SLEN + 2 + assert(EM_LEN >= HASH_LEN + SALT_LEN + 2); + + //should end with 0xBC (188 in decimal) + assert(eM[0] == 188); + + var DB_MASK_LEN = EM_LEN - HASH_LEN - 1; + signal dbMask[DB_MASK_LEN * 8]; + signal db[DB_MASK_LEN * 8]; + signal salt[SALT_LEN * 8]; + signal maskedDB[(EM_LEN - HASH_LEN - 1) * 8]; + + for (var i = 0; i < (EM_LEN - HASH_LEN - 1) * 8; i++) { + maskedDB[i] <== eMsgInBits[i]; + } + + signal hash[HASH_LEN * 8]; + + //inserting hash + for (var i = 0; i < HASH_TYPE; i++) { + hash[i] <== eMsgInBits[(EM_LEN_BITS) - HASH_TYPE - 8 + i]; + } + + //getting mask + if (HASH_TYPE == 256) { + component MGF1_256 = Mgf1Sha256(HASH_LEN, DB_MASK_LEN); + + for (var i = 0; i < (HASH_TYPE); i++) { + MGF1_256.seed[i] <== hash[i]; + } + + for (var i = 0; i < DB_MASK_LEN * 8; i++) { + dbMask[i] <== MGF1_256.out[i]; + } + } + if (HASH_TYPE == 384) { + component MGF1_384 = Mgf1Sha384(HASH_LEN, DB_MASK_LEN); + + for (var i = 0; i < (HASH_TYPE); i++) { + MGF1_384.seed[i] <== hash[i]; + } + + for (var i = 0; i < DB_MASK_LEN * 8; i++) { + dbMask[i] <== MGF1_384.out[i]; + } + } + + component xor = Xor2(DB_MASK_LEN * 8); + + for (var i = 0; i < DB_MASK_LEN * 8; i++) { + xor.in1[i] <== maskedDB[i]; + xor.in2[i] <== dbMask[i]; + } + + for (var i = 0; i < DB_MASK_LEN * 8; i++) { + //setting the first leftmost byte to 0 + if (i == 0) { + db[i] <== 0; + } else { + db[i] <== xor.out[i]; + } + } + + //inserting salt + for (var i = 0; i < SALT_LEN_BITS; i++) { + salt[SALT_LEN_BITS - 1 - i] <== db[(DB_MASK_LEN * 8) - 1 - i]; + } + + signal mDash[1024]; + //adding 0s + for (var i = 0; i < 64; i++) { + mDash[i] <== 0; + } + + //adding message hash + for (var i = 0; i < HASH_LEN * 8; i++) { + mDash[64 + i] <== hashed[i]; + + } + + //adding salt + for (var i = 0; i < SALT_LEN * 8; i++) { + mDash[64 + HASH_LEN * 8 + i] <== salt[i]; + } + + if (HASH_TYPE == 256 && SALT_LEN == 32) { + //adding padding + //len = 64+512 = 576 = 1001000000 + for (var i = 577; i < 1014; i++) { + mDash[i] <== 0; + } + + mDash[576] <== 1; + mDash[1023] <== 0; + mDash[1022] <== 0; + mDash[1021] <== 0; + mDash[1020] <== 0; + mDash[1019] <== 0; + mDash[1018] <== 0; + mDash[1017] <== 1; + mDash[1016] <== 0; + mDash[1015] <== 0; + mDash[1014] <== 1; + + //hashing + component hDash256 = ShaHashChunks(2, HASH_TYPE); + hDash256.in <== mDash; + + hDash256.out === hash; + } + if (HASH_TYPE == 256 && SALT_LEN == 64) { + for (var i = 833; i < 1014; i++) { + mDash[i] <== 0; + } + + mDash[832] <== 1; + mDash[1023] <== 0; + mDash[1022] <== 0; + mDash[1021] <== 0; + mDash[1020] <== 0; + mDash[1019] <== 0; + mDash[1018] <== 0; + mDash[1017] <== 1; + mDash[1016] <== 0; + mDash[1015] <== 1; + mDash[1014] <== 1; + + component hDash256 = ShaHashChunks(2, HASH_TYPE); + hDash256.in <== mDash; + + hDash256.out === hash; + } + + if (HASH_TYPE == 384 && SALT_LEN == 48) { + //padding + //len = 64+48*16 = 832 = 1101000000 + for (var i = 833; i < 1014; i++) { + mDash[i] <== 0; + } + + mDash[832] <== 1; + mDash[1023] <== 0; + mDash[1022] <== 0; + mDash[1021] <== 0; + mDash[1020] <== 0; + mDash[1019] <== 0; + mDash[1018] <== 0; + mDash[1017] <== 1; + mDash[1016] <== 0; + mDash[1015] <== 1; + mDash[1014] <== 1; + + //hashing mDash + component hDash384 = ShaHashChunks(1, HASH_TYPE); + hDash384.in <== mDash; + + hDash384.out === hash; + } +} diff --git a/circuits/circuits/utils/circomlib/signature/rsapss/rsapss65537.circom b/circuits/circuits/utils/circomlib/signature/rsapss/rsapss65537.circom new file mode 100644 index 000000000..4939f098c --- /dev/null +++ b/circuits/circuits/utils/circomlib/signature/rsapss/rsapss65537.circom @@ -0,0 +1,448 @@ +pragma circom 2.1.6; + +include "../../bigInt/bigInt.circom"; +include "./mgf1.circom"; +include "../../bitify/gates.circom"; +include "../../hasher/hash.circom"; +include "../FpPowMod.circom"; + +/* +* Verification for RSAPSS signature. +* hashed is hashed message of hash_type algo, hash_type is algo hash algo for mgf1 mask generation. +* There is no assert for CHUNK_SIZE == 64 and it may work with other chunking, but this one wasn`t tested, +* so better use 64 signature and pubkey - chunked numbers (CHUNK_SIZE, CHUNK_NUMBER). +* default exp = 65537 +* SALT_LEN is salt lenght in bytes! (NOT IN BITES LIKE HASH_TYPE!). +* This is because salt len can`t be % 8 != 0 so we use bytes len (8 bites). +* For now, only HASH_TYPE == 384 && SALT_LEN == 48, HASH_TYPE == 256 && SALT_LEN == 64, HASH_TYPE == 256 && SALT_LEN == 32 cases supported. +* Use this for CHUNK_NUMBER == 2**n, otherwise error will occur. +*/ +template VerifyRsaPss65537Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE) { + assert((HASH_TYPE == 384 && SALT_LEN == 48) || (HASH_TYPE == 256 && SALT_LEN == 64) || (HASH_TYPE == 256 && SALT_LEN == 32)); + + signal input pubkey[CHUNK_NUMBER]; + signal input signature[CHUNK_NUMBER]; + signal input hashed[HASH_TYPE]; + + + var EM_LEN = (CHUNK_SIZE * CHUNK_NUMBER) \ 8; + var HASH_LEN = HASH_TYPE \ 8; + var SALT_LEN_BITS = SALT_LEN * 8; + var EM_LEN_BITS = CHUNK_SIZE * CHUNK_NUMBER; + + signal eM[EM_LEN]; + signal eMsgInBits[EM_LEN_BITS]; + + //computing encoded message + component bigPow = FpPow65537Mod(CHUNK_SIZE, CHUNK_NUMBER); + for (var i = 0; i < CHUNK_NUMBER; i++) { + bigPow.base[i] <== signature[i]; + bigPow.modulus[i] <== pubkey[i]; + } + + signal encoded[CHUNK_NUMBER]; + encoded <== bigPow.out; + + component num2Bits[CHUNK_NUMBER]; + + for (var i = 0; i < CHUNK_NUMBER; i++) { + num2Bits[i] = Num2Bits(CHUNK_SIZE); + num2Bits[i].in <== encoded[CHUNK_NUMBER - 1 - i]; + + for (var j = 0; j < CHUNK_SIZE; j++) { + eMsgInBits[i * CHUNK_SIZE + j] <== num2Bits[i].out[CHUNK_SIZE - j - 1]; + } + } + + component bits2Num[EM_LEN]; + + for (var i = 0; i < EM_LEN; i++) { + bits2Num[i] = Bits2Num(8); + + for (var j = 0; j < 8; j++) { + bits2Num[i].in[7 - j] <== eMsgInBits[i * 8 + j]; + } + + eM[EM_LEN - i - 1] <== bits2Num[i].out; + } + + //should be more than HLEN + SLEN + 2 + assert(EM_LEN >= HASH_LEN + SALT_LEN + 2); + + //should end with 0xBC (188 in decimal) + assert(eM[0] == 188); + + var DB_MASK_LEN = EM_LEN - HASH_LEN - 1; + + signal dbMask[DB_MASK_LEN * 8]; + signal db[DB_MASK_LEN * 8]; + signal salt[SALT_LEN * 8]; + signal maskedDB[(EM_LEN - HASH_LEN - 1) * 8]; + + for (var i = 0; i < (EM_LEN - HASH_LEN - 1) * 8; i++) { + maskedDB[i] <== eMsgInBits[i]; + } + + signal hash[HASH_LEN * 8]; + + //inserting hash + for (var i = 0; i < HASH_TYPE; i++) { + hash[i] <== eMsgInBits[(EM_LEN_BITS) - HASH_TYPE - 8 + i]; + } + + //getting mask + if (HASH_TYPE == 256) { + component MGF1_256 = Mgf1Sha256(HASH_LEN, DB_MASK_LEN); + + for (var i = 0; i < (HASH_TYPE); i++) { + MGF1_256.seed[i] <== hash[i]; + } + + for (var i = 0; i < DB_MASK_LEN * 8; i++) { + dbMask[i] <== MGF1_256.out[i]; + } + } + if (HASH_TYPE == 384) { + component MGF1_384 = Mgf1Sha384(HASH_LEN, DB_MASK_LEN); + + for (var i = 0; i < (HASH_TYPE); i++) { + MGF1_384.seed[i] <== hash[i]; + } + + for (var i = 0; i < DB_MASK_LEN * 8; i++) { + dbMask[i] <== MGF1_384.out[i]; + } + } + + component xor = Xor2(DB_MASK_LEN * 8); + + for (var i = 0; i < DB_MASK_LEN * 8; i++) { + xor.in1[i] <== maskedDB[i]; + xor.in2[i] <== dbMask[i]; + } + + for (var i = 0; i < DB_MASK_LEN * 8; i++) { + //setting the first leftmost byte to 0 + if (i == 0) { + db[i] <== 0; + } else { + db[i] <== xor.out[i]; + } + } + + //inserting salt + for (var i = 0; i < SALT_LEN_BITS; i++) { + salt[SALT_LEN_BITS - 1 - i] <== db[(DB_MASK_LEN * 8) - 1 - i]; + } + + signal mDash[1024]; + //adding 0s + for (var i = 0; i < 64; i++) { + mDash[i] <== 0; + } + + //adding message hash + for (var i = 0; i < HASH_LEN * 8; i++) { + mDash[64 + i] <== hashed[i]; + } + + //adding salt + for (var i = 0; i < SALT_LEN * 8; i++) { + mDash[64 + HASH_LEN * 8 + i] <== salt[i]; + } + + if (HASH_TYPE == 256 && SALT_LEN == 32) { + //adding padding + //len = 64+512 = 576 = 1001000000 + for (var i = 577; i < 1014; i++) { + mDash[i] <== 0; + } + + mDash[576] <== 1; + mDash[1023] <== 0; + mDash[1022] <== 0; + mDash[1021] <== 0; + mDash[1020] <== 0; + mDash[1019] <== 0; + mDash[1018] <== 0; + mDash[1017] <== 1; + mDash[1016] <== 0; + mDash[1015] <== 0; + mDash[1014] <== 1; + + //hashing + component hDash256 = ShaHashChunks(2, HASH_TYPE); + hDash256.in <== mDash; + + hDash256.out === hash; + } + + if (HASH_TYPE == 256 && SALT_LEN == 64) { + for (var i = 833; i < 1014; i++) { + mDash[i] <== 0; + } + + mDash[832] <== 1; + mDash[1023] <== 0; + mDash[1022] <== 0; + mDash[1021] <== 0; + mDash[1020] <== 0; + mDash[1019] <== 0; + mDash[1018] <== 0; + mDash[1017] <== 1; + mDash[1016] <== 0; + mDash[1015] <== 1; + mDash[1014] <== 1; + + component hDash256 = ShaHashChunks(2, HASH_TYPE); + hDash256.in <== mDash; + + hDash256.out === hash; + } + + if (HASH_TYPE == 384 && SALT_LEN == 48) { + //padding + //len = 64+48*16 = 832 = 1101000000 + for (var i = 833; i < 1014; i++) { + mDash[i] <== 0; + } + + mDash[832] <== 1; + mDash[1023] <== 0; + mDash[1022] <== 0; + mDash[1021] <== 0; + mDash[1020] <== 0; + mDash[1019] <== 0; + mDash[1018] <== 0; + mDash[1017] <== 1; + mDash[1016] <== 0; + mDash[1015] <== 1; + mDash[1014] <== 1; + + //hashing mDash + component hDash384 = ShaHashChunks(1, HASH_TYPE); + hDash384.in <== mDash; + + hDash384.out === hash; + } +} + +/* +* Verification for RSAPSS signature. +* hashed is hashed message of hash_type algo, hash_type is algo hash algo for mgf1 mask generation. +* There is no assert for CHUNK_SIZE == 64 and it may work with other chunking, but this one wasn`t tested, +* so better use 64 signature and pubkey - chunked numbers (CHUNK_SIZE, CHUNK_NUMBER). +* e_bits - Len of bit representation of exponent with 1 highest and lowest bits, other are 0 (2^(e_bits - 1) + 1). +* default exp = 65537 (e_bits = 17) +* SALT_LEN is salt lenght in bytes! (NOT IN BITES LIKE HASH_TYPE!) +* This is because salt len can`t be % 8 != 0 so we use bytes len (8 bites). +* For now, only HASH_TYPE == 384 && SALT_LEN == 48, HASH_TYPE == 256 && SALT_LEN == 64, HASH_TYPE == 256 && SALT_LEN == 32 cases supported. +* Use this for CHUNK_NUMBER != 2**n, otherwise use previous template. +*/ +template VerifyRsaPss65537SigNonOptimised(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, EXP, HASH_TYPE) { + assert((HASH_TYPE == 384 && SALT_LEN == 48) || (HASH_TYPE == 256 && SALT_LEN == 64) || (HASH_TYPE == 256 && SALT_LEN == 32)); + + signal input pubkey[CHUNK_NUMBER]; + signal input signature[CHUNK_NUMBER]; + signal input hashed[HASH_TYPE]; + + + var EM_LEN = (CHUNK_SIZE * CHUNK_NUMBER) \ 8; + var HASH_LEN = HASH_TYPE \ 8; + var SALT_LEN_BITS = SALT_LEN * 8; + var EM_LEN_BITS = CHUNK_SIZE * CHUNK_NUMBER; + + signal eM[EM_LEN]; + signal eMsgInBits[EM_LEN_BITS]; + + //computing encoded message + component powerMod; + powerMod = PowerModNonOptimised(CHUNK_SIZE, CHUNK_NUMBER, EXP); + powerMod.base <== signature; + powerMod.modulus <== pubkey; + + signal encoded[CHUNK_NUMBER]; + encoded <== powerMod.out; + + component num2Bits[CHUNK_NUMBER]; + + for (var i = 0; i < CHUNK_NUMBER; i++) { + num2Bits[i] = Num2Bits(CHUNK_SIZE); + num2Bits[i].in <== encoded[CHUNK_NUMBER - 1 - i]; + + for (var j = 0; j < CHUNK_SIZE; j++) { + eMsgInBits[i * CHUNK_SIZE + j] <== num2Bits[i].out[CHUNK_SIZE - j - 1]; + } + } + + component bits2Num[EM_LEN]; + + for (var i = 0; i < EM_LEN; i++) { + bits2Num[i] = Bits2Num(8); + + for (var j = 0; j < 8; j++) { + bits2Num[i].in[7 - j] <== eMsgInBits[i * 8 + j]; + } + + eM[EM_LEN - i - 1] <== bits2Num[i].out; + } + + //should be more than HLEN + SLEN + 2 + assert(EM_LEN >= HASH_LEN + SALT_LEN + 2); + + //should end with 0xBC (188 in decimal) + assert(eM[0] == 188); + + var DB_MASK_LEN = EM_LEN - HASH_LEN - 1; + signal dbMask[DB_MASK_LEN * 8]; + signal db[DB_MASK_LEN * 8]; + signal salt[SALT_LEN * 8]; + signal maskedDB[(EM_LEN - HASH_LEN - 1) * 8]; + + for (var i = 0; i < (EM_LEN - HASH_LEN - 1) * 8; i++) { + maskedDB[i] <== eMsgInBits[i]; + } + + signal hash[HASH_LEN * 8]; + + //inserting hash + for (var i = 0; i < HASH_TYPE; i++) { + hash[i] <== eMsgInBits[(EM_LEN_BITS) - HASH_TYPE - 8 + i]; + } + + //getting mask + if (HASH_TYPE == 256) { + component MGF1_256 = Mgf1Sha256(HASH_LEN, DB_MASK_LEN); + + for (var i = 0; i < (HASH_TYPE); i++) { + MGF1_256.seed[i] <== hash[i]; + } + + for (var i = 0; i < DB_MASK_LEN * 8; i++) { + dbMask[i] <== MGF1_256.out[i]; + } + } + if (HASH_TYPE == 384) { + component MGF1_384 = Mgf1Sha384(HASH_LEN, DB_MASK_LEN); + + for (var i = 0; i < (HASH_TYPE); i++) { + MGF1_384.seed[i] <== hash[i]; + } + + for (var i = 0; i < DB_MASK_LEN * 8; i++) { + dbMask[i] <== MGF1_384.out[i]; + } + } + + component xor = Xor2(DB_MASK_LEN * 8); + + for (var i = 0; i < DB_MASK_LEN * 8; i++) { + xor.in1[i] <== maskedDB[i]; + xor.in2[i] <== dbMask[i]; + } + + for (var i = 0; i < DB_MASK_LEN * 8; i++) { + //setting the first leftmost byte to 0 + if (i == 0) { + db[i] <== 0; + } else { + db[i] <== xor.out[i]; + } + } + + //inserting salt + for (var i = 0; i < SALT_LEN_BITS; i++) { + salt[SALT_LEN_BITS - 1 - i] <== db[(DB_MASK_LEN * 8) - 1 - i]; + } + + signal mDash[1024]; + //adding 0s + for (var i = 0; i < 64; i++) { + mDash[i] <== 0; + } + + //adding message hash + for (var i = 0; i < HASH_LEN * 8; i++) { + mDash[64 + i] <== hashed[i]; + + } + + //adding salt + for (var i = 0; i < SALT_LEN * 8; i++) { + mDash[64 + HASH_LEN * 8 + i] <== salt[i]; + } + + if (HASH_TYPE == 256 && SALT_LEN == 32) { + //adding padding + //len = 64+512 = 576 = 1001000000 + for (var i = 577; i < 1014; i++) { + mDash[i] <== 0; + } + + mDash[576] <== 1; + mDash[1023] <== 0; + mDash[1022] <== 0; + mDash[1021] <== 0; + mDash[1020] <== 0; + mDash[1019] <== 0; + mDash[1018] <== 0; + mDash[1017] <== 1; + mDash[1016] <== 0; + mDash[1015] <== 0; + mDash[1014] <== 1; + + //hashing + component hDash256 = ShaHashChunks(2, HASH_TYPE); + hDash256.in <== mDash; + + hDash256.out === hash; + } + if (HASH_TYPE == 256 && SALT_LEN == 64) { + for (var i = 833; i < 1014; i++) { + mDash[i] <== 0; + } + + mDash[832] <== 1; + mDash[1023] <== 0; + mDash[1022] <== 0; + mDash[1021] <== 0; + mDash[1020] <== 0; + mDash[1019] <== 0; + mDash[1018] <== 0; + mDash[1017] <== 1; + mDash[1016] <== 0; + mDash[1015] <== 1; + mDash[1014] <== 1; + + component hDash256 = ShaHashChunks(2, HASH_TYPE); + hDash256.in <== mDash; + + hDash256.out === hash; + } + + if (HASH_TYPE == 384 && SALT_LEN == 48) { + //padding + //len = 64+48*16 = 832 = 1101000000 + for (var i = 833; i < 1014; i++) { + mDash[i] <== 0; + } + + mDash[832] <== 1; + mDash[1023] <== 0; + mDash[1022] <== 0; + mDash[1021] <== 0; + mDash[1020] <== 0; + mDash[1019] <== 0; + mDash[1018] <== 0; + mDash[1017] <== 1; + mDash[1016] <== 0; + mDash[1015] <== 1; + mDash[1014] <== 1; + + //hashing mDash + component hDash384 = ShaHashChunks(1, HASH_TYPE); + hDash384.in <== mDash; + + hDash384.out === hash; + } +} diff --git a/circuits/circuits/utils/passport/signatureVerifier.circom b/circuits/circuits/utils/passport/signatureVerifier.circom index 86095d123..e9400550c 100644 --- a/circuits/circuits/utils/passport/signatureVerifier.circom +++ b/circuits/circuits/utils/passport/signatureVerifier.circom @@ -2,7 +2,9 @@ pragma circom 2.1.9; // include "../rsa/rsaPkcs1.circom"; // include "secp256r1Verifier.circom"; -include "../circomlib/signature/rsapss/rsapss.circom"; +// include "../circomlib/signature/rsapss/rsapss.circom"; +include "../circomlib/signature/rsapss/rsapss3.circom"; +include "../circomlib/signature/rsapss/rsapss65537.circom"; include "secp256r1Verifier.circom"; // include "../rsapss/rsapss.circom"; // include "../rsa/rsa.circom"; @@ -52,28 +54,34 @@ template SignatureVerifier(signatureAlgorithm, n, k) { if ( signatureAlgorithm == 4 - || signatureAlgorithm == 12 - || signatureAlgorithm == 16 - || signatureAlgorithm == 17 + || signatureAlgorithm == 12 || signatureAlgorithm == 18 || signatureAlgorithm == 19 ) { var pubKeyBitsLength = getKeyLength(signatureAlgorithm); var SALT_LEN = HASH_LEN_BITS / 8; var E_BITS = getExponentBits(signatureAlgorithm); - var EXP; - if (E_BITS == 17) { - EXP = 65537; - } else { - EXP = 3; - } - - component rsaPssShaVerification = VerifyRsaPssSig(n, k, SALT_LEN, EXP, HASH_LEN_BITS); - rsaPssShaVerification.pubkey <== pubKey; - rsaPssShaVerification.signature <== signature; - rsaPssShaVerification.hashed <== hash; // send the raw hash + component rsaPss65537ShaVerification = VerifyRsaPss65537Sig(n, k, SALT_LEN, HASH_LEN_BITS); + rsaPss65537ShaVerification.pubkey <== pubKey; + rsaPss65537ShaVerification.signature <== signature; + rsaPss65537ShaVerification.hashed <== hash; // send the raw hash } + if ( + signatureAlgorithm == 16 + || signatureAlgorithm == 17 + ) { + var pubKeyBitsLength = getKeyLength(signatureAlgorithm); + var SALT_LEN = HASH_LEN_BITS / 8; + var E_BITS = getExponentBits(signatureAlgorithm); + + component rsaPss3ShaVerification = VerifyRsaPss3Sig(n, k, SALT_LEN, HASH_LEN_BITS); + rsaPss3ShaVerification.pubkey <== pubKey; + rsaPss3ShaVerification.signature <== signature; + rsaPss3ShaVerification.hashed <== hash; // send the raw hash + + } + if (signatureAlgorithm == 7) { Secp256r1Verifier (signatureAlgorithm, n, k)(signature, pubKey, hash); } @@ -103,6 +111,7 @@ template SignatureVerifier(signatureAlgorithm, n, k) { } rsa.modulus <== pubKey; rsa.signature <== signature; + } if (signatureAlgorithm == 12) { diff --git a/circuits/tests/prove.test.ts b/circuits/tests/prove.test.ts index 1900020a6..34ac56db7 100644 --- a/circuits/tests/prove.test.ts +++ b/circuits/tests/prove.test.ts @@ -11,9 +11,14 @@ import { SMT } from '@openpassport/zk-kit-smt'; import namejson from '../../common/ofacdata/outputs/nameSMT.json'; import { getCircuitName } from '../../common/src/utils/certificate_parsing/parseCertificateSimple'; const sigAlgs = [ - { sigAlg: 'rsapss', hashFunction: 'sha256', domainParameter: '3', keyLength: '3072' }, - { sigAlg: 'rsa', hashFunction: 'sha256', domainParameter: '65537', keyLength: '3072' }, - { sigAlg: 'ecdsa', hashFunction: 'sha1', domainParameter: 'secp256r1', keyLength: '256' }, + // { sigAlg: 'rsapss', hashFunction: 'sha256', domainParameter: '65537', keyLength: '2048' }, + // { sigAlg: 'rsapss', hashFunction: 'sha256', domainParameter: '65537', keyLength: '3072' }, + { sigAlg: 'rsapss', hashFunction: 'sha256', domainParameter: '65537', keyLength: '4096' }, + { sigAlg: 'rsapss', hashFunction: 'sha256', domainParameter: '3', keyLength: '4096' }, + // { sigAlg: 'rsapss', hashFunction: 'sha256', domainParameter: '3', keyLength: '3072' }, + // { sigAlg: 'rsapss', hashFunction: 'sha256', domainParameter: '3', keyLength: '3072' }, + // { sigAlg: 'rsa', hashFunction: 'sha256', domainParameter: '65537', keyLength: '3072' }, + // { sigAlg: 'ecdsa', hashFunction: 'sha1', domainParameter: 'secp256r1', keyLength: '256' }, ]; const fullSigAlgs = [ @@ -31,7 +36,6 @@ const fullSigAlgs = [ ]; const testSuite = process.env.FULL_TEST_SUITE === 'true' ? fullSigAlgs : sigAlgs; -// const testSuite = fullSigAlgs; testSuite.forEach(({ sigAlg, hashFunction, domainParameter, keyLength }) => { describe(`Prove - ${hashFunction.toUpperCase()} ${sigAlg.toUpperCase()} ${domainParameter} ${keyLength}`, function () { From cbd1446b2fd6d3f28292a71c062cf6121de5ff17 Mon Sep 17 00:00:00 2001 From: seshanthS Date: Tue, 7 Jan 2025 23:21:06 +0530 Subject: [PATCH 2/5] fix rsapss 4096 bits --- .../circomlib/signature/rsapss/rsapss3.circom | 12 +++++++---- .../signature/rsapss/rsapss65537.circom | 20 +++++++++++++------ .../utils/passport/signatureVerifier.circom | 4 ++-- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/circuits/circuits/utils/circomlib/signature/rsapss/rsapss3.circom b/circuits/circuits/utils/circomlib/signature/rsapss/rsapss3.circom index 9e9607bea..6548c8be2 100644 --- a/circuits/circuits/utils/circomlib/signature/rsapss/rsapss3.circom +++ b/circuits/circuits/utils/circomlib/signature/rsapss/rsapss3.circom @@ -17,7 +17,7 @@ include "../FpPowMod.circom"; * For now, only HASH_TYPE == 384 && SALT_LEN == 48, HASH_TYPE == 256 && SALT_LEN == 64, HASH_TYPE == 256 && SALT_LEN == 32 cases supported. * Use this for CHUNK_NUMBER == 2**n, otherwise error will occur. */ -template VerifyRsaPss3Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE) { +template VerifyRsaPss3Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY_LENGTH) { assert((HASH_TYPE == 384 && SALT_LEN == 48) || (HASH_TYPE == 256 && SALT_LEN == 64) || (HASH_TYPE == 256 && SALT_LEN == 32)); signal input pubkey[CHUNK_NUMBER]; @@ -25,10 +25,10 @@ template VerifyRsaPss3Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE) { signal input hashed[HASH_TYPE]; - var EM_LEN = (CHUNK_SIZE * CHUNK_NUMBER) \ 8; + var EM_LEN = KEY_LENGTH \ 8; var HASH_LEN = HASH_TYPE \ 8; var SALT_LEN_BITS = SALT_LEN * 8; - var EM_LEN_BITS = CHUNK_SIZE * CHUNK_NUMBER; + var EM_LEN_BITS = KEY_LENGTH; signal eM[EM_LEN]; signal eMsgInBits[EM_LEN_BITS]; @@ -50,7 +50,11 @@ template VerifyRsaPss3Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE) { num2Bits[i].in <== encoded[CHUNK_NUMBER - 1 - i]; for (var j = 0; j < CHUNK_SIZE; j++) { - eMsgInBits[i * CHUNK_SIZE + j] <== num2Bits[i].out[CHUNK_SIZE - j - 1]; + var sourcePos = i * CHUNK_SIZE + j; + var targetPos = sourcePos - (CHUNK_NUMBER * CHUNK_SIZE - EM_LEN_BITS); + if (targetPos >= 0 && targetPos < EM_LEN_BITS) { + eMsgInBits[targetPos] <== num2Bits[i].out[CHUNK_SIZE - j - 1]; + } } } diff --git a/circuits/circuits/utils/circomlib/signature/rsapss/rsapss65537.circom b/circuits/circuits/utils/circomlib/signature/rsapss/rsapss65537.circom index 4939f098c..7db49f72f 100644 --- a/circuits/circuits/utils/circomlib/signature/rsapss/rsapss65537.circom +++ b/circuits/circuits/utils/circomlib/signature/rsapss/rsapss65537.circom @@ -16,23 +16,27 @@ include "../FpPowMod.circom"; * This is because salt len can`t be % 8 != 0 so we use bytes len (8 bites). * For now, only HASH_TYPE == 384 && SALT_LEN == 48, HASH_TYPE == 256 && SALT_LEN == 64, HASH_TYPE == 256 && SALT_LEN == 32 cases supported. * Use this for CHUNK_NUMBER == 2**n, otherwise error will occur. + +* Singature length will not exceed the modulus length of the public key (which is the keylength), because the signature is +* calculated as mod Modulus_of_pubkey . */ -template VerifyRsaPss65537Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE) { +template VerifyRsaPss65537Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY_LENGTH) { assert((HASH_TYPE == 384 && SALT_LEN == 48) || (HASH_TYPE == 256 && SALT_LEN == 64) || (HASH_TYPE == 256 && SALT_LEN == 32)); - + signal input pubkey[CHUNK_NUMBER]; signal input signature[CHUNK_NUMBER]; signal input hashed[HASH_TYPE]; - var EM_LEN = (CHUNK_SIZE * CHUNK_NUMBER) \ 8; + var EM_LEN = KEY_LENGTH \ 8; + var HASH_LEN = HASH_TYPE \ 8; var SALT_LEN_BITS = SALT_LEN * 8; - var EM_LEN_BITS = CHUNK_SIZE * CHUNK_NUMBER; + var EM_LEN_BITS = KEY_LENGTH; signal eM[EM_LEN]; signal eMsgInBits[EM_LEN_BITS]; - + //computing encoded message component bigPow = FpPow65537Mod(CHUNK_SIZE, CHUNK_NUMBER); for (var i = 0; i < CHUNK_NUMBER; i++) { @@ -50,7 +54,11 @@ template VerifyRsaPss65537Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE) { num2Bits[i].in <== encoded[CHUNK_NUMBER - 1 - i]; for (var j = 0; j < CHUNK_SIZE; j++) { - eMsgInBits[i * CHUNK_SIZE + j] <== num2Bits[i].out[CHUNK_SIZE - j - 1]; + var sourcePos = i * CHUNK_SIZE + j; + var targetPos = sourcePos - (CHUNK_NUMBER * CHUNK_SIZE - EM_LEN_BITS); + if (targetPos >= 0 && targetPos < EM_LEN_BITS) { + eMsgInBits[targetPos] <== num2Bits[i].out[CHUNK_SIZE - j - 1]; + } } } diff --git a/circuits/circuits/utils/passport/signatureVerifier.circom b/circuits/circuits/utils/passport/signatureVerifier.circom index e9400550c..30219a764 100644 --- a/circuits/circuits/utils/passport/signatureVerifier.circom +++ b/circuits/circuits/utils/passport/signatureVerifier.circom @@ -61,7 +61,7 @@ template SignatureVerifier(signatureAlgorithm, n, k) { var pubKeyBitsLength = getKeyLength(signatureAlgorithm); var SALT_LEN = HASH_LEN_BITS / 8; var E_BITS = getExponentBits(signatureAlgorithm); - component rsaPss65537ShaVerification = VerifyRsaPss65537Sig(n, k, SALT_LEN, HASH_LEN_BITS); + component rsaPss65537ShaVerification = VerifyRsaPss65537Sig(n, k, SALT_LEN, HASH_LEN_BITS, pubKeyBitsLength); rsaPss65537ShaVerification.pubkey <== pubKey; rsaPss65537ShaVerification.signature <== signature; rsaPss65537ShaVerification.hashed <== hash; // send the raw hash @@ -75,7 +75,7 @@ template SignatureVerifier(signatureAlgorithm, n, k) { var SALT_LEN = HASH_LEN_BITS / 8; var E_BITS = getExponentBits(signatureAlgorithm); - component rsaPss3ShaVerification = VerifyRsaPss3Sig(n, k, SALT_LEN, HASH_LEN_BITS); + component rsaPss3ShaVerification = VerifyRsaPss3Sig(n, k, SALT_LEN, HASH_LEN_BITS, pubKeyBitsLength); rsaPss3ShaVerification.pubkey <== pubKey; rsaPss3ShaVerification.signature <== signature; rsaPss3ShaVerification.hashed <== hash; // send the raw hash From 27a0be44dbbbf5a9b82bb3543cff0418163ed22f Mon Sep 17 00:00:00 2001 From: seshanthS Date: Fri, 10 Jan 2025 23:30:13 +0530 Subject: [PATCH 3/5] add tests for rsapss primitives --- .../test_rsapss_sha256_3_2048_32.circom | 12 +++ .../test_rsapss_sha256_3_3072_32.circom | 12 +++ .../test_rsapss_sha256_3_4096_32.circom | 12 +++ .../test_rsapss_sha256_65537_2048_32.circom | 12 +++ .../test_rsapss_sha256_65537_3072_32.circom | 12 +++ .../test_rsapss_sha256_65537_4096_32.circom | 12 +++ .../test_rsapss_sha384_3_3072_48.circom | 12 +++ .../test_rsapss_sha384_3_4096_48.circom | 12 +++ .../test_rsapss_sha384_65537_3072_48.circom | 12 +++ .../test_rsapss_sha384_65537_4096_48.circom | 12 +++ .../test_rsapss_sha512_3_2048_64.circom | 12 +++ .../test_rsapss_sha512_3_4096_64.circom | 12 +++ .../circomlib/signature/rsapss/mgf1.circom | 49 ++++++++++ .../circomlib/signature/rsapss/rsapss3.circom | 49 ++++++++-- .../signature/rsapss/rsapss65537.circom | 45 ++++++++- .../tests/utils/generateMockInputsRsaPss.ts | 95 +++++++++++++++++++ circuits/tests/utils/rsapss.test.ts | 58 +++++++++++ common/src/constants/constants.ts | 8 +- common/src/utils/types.ts | 7 +- 19 files changed, 440 insertions(+), 15 deletions(-) create mode 100644 circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_3_2048_32.circom create mode 100644 circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_3_3072_32.circom create mode 100644 circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_3_4096_32.circom create mode 100644 circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_65537_2048_32.circom create mode 100644 circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_65537_3072_32.circom create mode 100644 circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_65537_4096_32.circom create mode 100644 circuits/circuits/tests/utils/rsapss/test_rsapss_sha384_3_3072_48.circom create mode 100644 circuits/circuits/tests/utils/rsapss/test_rsapss_sha384_3_4096_48.circom create mode 100644 circuits/circuits/tests/utils/rsapss/test_rsapss_sha384_65537_3072_48.circom create mode 100644 circuits/circuits/tests/utils/rsapss/test_rsapss_sha384_65537_4096_48.circom create mode 100644 circuits/circuits/tests/utils/rsapss/test_rsapss_sha512_3_2048_64.circom create mode 100644 circuits/circuits/tests/utils/rsapss/test_rsapss_sha512_3_4096_64.circom create mode 100644 circuits/tests/utils/generateMockInputsRsaPss.ts create mode 100644 circuits/tests/utils/rsapss.test.ts diff --git a/circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_3_2048_32.circom b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_3_2048_32.circom new file mode 100644 index 000000000..d5b136987 --- /dev/null +++ b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_3_2048_32.circom @@ -0,0 +1,12 @@ +pragma circom 2.1.9; +include "../../../utils/circomlib/signature/rsapss/rsapss3.circom"; + +template VerifyRsaPss3Sig_tester() { + signal input modulus[35]; + signal input signature[35]; + signal input message[256]; + + VerifyRsaPss3Sig(120, 35, 32, 256, 2048)(modulus,signature,message); +} + +component main = VerifyRsaPss3Sig_tester(); \ No newline at end of file diff --git a/circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_3_3072_32.circom b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_3_3072_32.circom new file mode 100644 index 000000000..fcd072b6b --- /dev/null +++ b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_3_3072_32.circom @@ -0,0 +1,12 @@ +pragma circom 2.1.9; +include "../../../utils/circomlib/signature/rsapss/rsapss3.circom"; + +template VerifyRsaPss3Sig_tester() { + signal input modulus[35]; + signal input signature[35]; + signal input message[256]; + + VerifyRsaPss3Sig(120, 35, 32, 256, 3072)(modulus,signature,message); +} + +component main = VerifyRsaPss3Sig_tester(); \ No newline at end of file diff --git a/circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_3_4096_32.circom b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_3_4096_32.circom new file mode 100644 index 000000000..0f61979a7 --- /dev/null +++ b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_3_4096_32.circom @@ -0,0 +1,12 @@ +pragma circom 2.1.9; +include "../../../utils/circomlib/signature/rsapss/rsapss3.circom"; + +template VerifyRsaPss3Sig_tester() { + signal input modulus[35]; + signal input signature[35]; + signal input message[256]; + + VerifyRsaPss3Sig(120, 35, 32, 256, 4096)(modulus,signature,message); +} + +component main = VerifyRsaPss3Sig_tester(); \ No newline at end of file diff --git a/circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_65537_2048_32.circom b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_65537_2048_32.circom new file mode 100644 index 000000000..1157d04b6 --- /dev/null +++ b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_65537_2048_32.circom @@ -0,0 +1,12 @@ +pragma circom 2.1.9; +include "../../../utils/circomlib/signature/rsapss/rsapss65537.circom"; + +template VerifyRsaPss65537Sig_tester() { + signal input modulus[35]; + signal input signature[35]; + signal input message[256]; + + VerifyRsaPss65537Sig(120, 35, 32, 256, 2048)(modulus,signature,message); +} + +component main = VerifyRsaPss65537Sig_tester(); \ No newline at end of file diff --git a/circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_65537_3072_32.circom b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_65537_3072_32.circom new file mode 100644 index 000000000..6e0a5f8b4 --- /dev/null +++ b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_65537_3072_32.circom @@ -0,0 +1,12 @@ +pragma circom 2.1.9; +include "../../../utils/circomlib/signature/rsapss/rsapss65537.circom"; + +template VerifyRsaPss65537Sig_tester() { + signal input modulus[35]; + signal input signature[35]; + signal input message[256]; + + VerifyRsaPss65537Sig(120, 35, 32, 256, 3072)(modulus,signature,message); +} + +component main = VerifyRsaPss65537Sig_tester(); \ No newline at end of file diff --git a/circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_65537_4096_32.circom b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_65537_4096_32.circom new file mode 100644 index 000000000..9521e4999 --- /dev/null +++ b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha256_65537_4096_32.circom @@ -0,0 +1,12 @@ +pragma circom 2.1.9; +include "../../../utils/circomlib/signature/rsapss/rsapss65537.circom"; + +template VerifyRsaPss65537Sig_tester() { + signal input modulus[35]; + signal input signature[35]; + signal input message[256]; + + VerifyRsaPss65537Sig(120, 35, 32, 256, 4096)(modulus,signature,message); +} + +component main = VerifyRsaPss65537Sig_tester(); \ No newline at end of file diff --git a/circuits/circuits/tests/utils/rsapss/test_rsapss_sha384_3_3072_48.circom b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha384_3_3072_48.circom new file mode 100644 index 000000000..b526b6f39 --- /dev/null +++ b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha384_3_3072_48.circom @@ -0,0 +1,12 @@ +pragma circom 2.1.9; +include "../../../utils/circomlib/signature/rsapss/rsapss3.circom"; + +template VerifyRsaPss3Sig_tester() { + signal input modulus[35]; + signal input signature[35]; + signal input message[384]; + + VerifyRsaPss3Sig(120, 35, 48, 384, 3072)(modulus,signature,message); +} + +component main = VerifyRsaPss3Sig_tester(); \ No newline at end of file diff --git a/circuits/circuits/tests/utils/rsapss/test_rsapss_sha384_3_4096_48.circom b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha384_3_4096_48.circom new file mode 100644 index 000000000..b3e7234fd --- /dev/null +++ b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha384_3_4096_48.circom @@ -0,0 +1,12 @@ +pragma circom 2.1.9; +include "../../../utils/circomlib/signature/rsapss/rsapss3.circom"; + +template VerifyRsaPss3Sig_tester() { + signal input modulus[35]; + signal input signature[35]; + signal input message[384]; + + VerifyRsaPss3Sig(120, 35, 48, 384, 4096)(modulus,signature,message); +} + +component main = VerifyRsaPss3Sig_tester(); \ No newline at end of file diff --git a/circuits/circuits/tests/utils/rsapss/test_rsapss_sha384_65537_3072_48.circom b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha384_65537_3072_48.circom new file mode 100644 index 000000000..a325a283a --- /dev/null +++ b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha384_65537_3072_48.circom @@ -0,0 +1,12 @@ +pragma circom 2.1.9; +include "../../../utils/circomlib/signature/rsapss/rsapss65537.circom"; + +template VerifyRsaPss65537Sig_tester() { + signal input modulus[35]; + signal input signature[35]; + signal input message[384]; + + VerifyRsaPss65537Sig(120, 35, 48, 384, 3072)(modulus,signature,message); +} + +component main = VerifyRsaPss65537Sig_tester(); \ No newline at end of file diff --git a/circuits/circuits/tests/utils/rsapss/test_rsapss_sha384_65537_4096_48.circom b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha384_65537_4096_48.circom new file mode 100644 index 000000000..dcfa0b5ab --- /dev/null +++ b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha384_65537_4096_48.circom @@ -0,0 +1,12 @@ +pragma circom 2.1.9; +include "../../../utils/circomlib/signature/rsapss/rsapss65537.circom"; + +template VerifyRsaPss65537Sig_tester() { + signal input modulus[35]; + signal input signature[35]; + signal input message[384]; + + VerifyRsaPss65537Sig(120, 35, 48, 384, 4096)(modulus,signature,message); +} + +component main = VerifyRsaPss65537Sig_tester(); \ No newline at end of file diff --git a/circuits/circuits/tests/utils/rsapss/test_rsapss_sha512_3_2048_64.circom b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha512_3_2048_64.circom new file mode 100644 index 000000000..163aef72b --- /dev/null +++ b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha512_3_2048_64.circom @@ -0,0 +1,12 @@ +pragma circom 2.1.9; +include "../../../utils/circomlib/signature/rsapss/rsapss3.circom"; + +template VerifyRsaPss65537Sig_tester() { + signal input modulus[35]; + signal input signature[35]; + signal input message[512]; + + VerifyRsaPss3Sig(120, 35, 64, 512, 2048)(modulus,signature,message); +} + +component main = VerifyRsaPss65537Sig_tester(); \ No newline at end of file diff --git a/circuits/circuits/tests/utils/rsapss/test_rsapss_sha512_3_4096_64.circom b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha512_3_4096_64.circom new file mode 100644 index 000000000..d0495490e --- /dev/null +++ b/circuits/circuits/tests/utils/rsapss/test_rsapss_sha512_3_4096_64.circom @@ -0,0 +1,12 @@ +pragma circom 2.1.9; +include "../../../utils/circomlib/signature/rsapss/rsapss3.circom"; + +template VerifyRsaPss65537Sig_tester() { + signal input modulus[35]; + signal input signature[35]; + signal input message[512]; + + VerifyRsaPss3Sig(120, 35, 64, 512, 4096)(modulus,signature,message); +} + +component main = VerifyRsaPss65537Sig_tester(); \ No newline at end of file diff --git a/circuits/circuits/utils/circomlib/signature/rsapss/mgf1.circom b/circuits/circuits/utils/circomlib/signature/rsapss/mgf1.circom index 0b85f4a4d..3e75c4837 100644 --- a/circuits/circuits/utils/circomlib/signature/rsapss/mgf1.circom +++ b/circuits/circuits/utils/circomlib/signature/rsapss/mgf1.circom @@ -2,6 +2,55 @@ pragma circom 2.1.6; include "circomlib/circuits/bitify.circom"; +template Mgf1Sha512(seedLen, maskLen) { //in bytes + var seedLenBits = seedLen * 8; + var maskLenBits = maskLen * 8; + var hashLen = 64; //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 sha512[iterations]; + component num2Bits[iterations]; + + for (var i = 0; i < iterations; i++) { + //512 + 32 bits for counter + sha512[i] = ShaHashBits(544, 512); + + num2Bits[i] = Num2Bits(32); + } + + var concated[hashLenBits + 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]; + } + + //hashing value + sha512[i].in <== concated; + + for (var j = 0; j < hashLenBits; j++) { + hashed[i * hashLenBits + j] <== sha512[i].out[j]; + } + } + + for (var i = 0; i < maskLenBits; i++) { + out[i] <== hashed[i]; + } +} + template Mgf1Sha384(SEED_LEN, MASK_LEN) { //in bytes var SEED_LEN_BITS = SEED_LEN * 8; var MASK_LEN_BITS = MASK_LEN * 8; diff --git a/circuits/circuits/utils/circomlib/signature/rsapss/rsapss3.circom b/circuits/circuits/utils/circomlib/signature/rsapss/rsapss3.circom index 6548c8be2..0913d26c9 100644 --- a/circuits/circuits/utils/circomlib/signature/rsapss/rsapss3.circom +++ b/circuits/circuits/utils/circomlib/signature/rsapss/rsapss3.circom @@ -18,7 +18,7 @@ include "../FpPowMod.circom"; * Use this for CHUNK_NUMBER == 2**n, otherwise error will occur. */ template VerifyRsaPss3Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY_LENGTH) { - assert((HASH_TYPE == 384 && SALT_LEN == 48) || (HASH_TYPE == 256 && SALT_LEN == 64) || (HASH_TYPE == 256 && SALT_LEN == 32)); + assert((HASH_TYPE == 512 && SALT_LEN == 64) || (HASH_TYPE == 384 && SALT_LEN == 48) || (HASH_TYPE == 256 && SALT_LEN == 64) || (HASH_TYPE == 256 && SALT_LEN == 32)); signal input pubkey[CHUNK_NUMBER]; signal input signature[CHUNK_NUMBER]; @@ -74,7 +74,7 @@ template VerifyRsaPss3Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY_LEN assert(EM_LEN >= HASH_LEN + SALT_LEN + 2); //should end with 0xBC (188 in decimal) - assert(eM[0] == 188); + eM[0] === 188; var DB_MASK_LEN = EM_LEN - HASH_LEN - 1; @@ -117,6 +117,17 @@ template VerifyRsaPss3Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY_LEN dbMask[i] <== MGF1_384.out[i]; } } + if (HASH_TYPE == 512) { + component MGF1_512 = Mgf1Sha512(HASH_LEN, DB_MASK_LEN); + + for (var i = 0; i < (HASH_TYPE); i++) { + MGF1_512.seed[i] <== hash[i]; + } + + for (var i = 0; i < DB_MASK_LEN * 8; i++) { + dbMask[i] <== MGF1_512.out[i]; + } + } component xor = Xor2(DB_MASK_LEN * 8); @@ -139,7 +150,7 @@ template VerifyRsaPss3Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY_LEN salt[SALT_LEN_BITS - 1 - i] <== db[(DB_MASK_LEN * 8) - 1 - i]; } - signal mDash[1024]; + signal mDash[2048]; //adding 0s for (var i = 0; i < 64; i++) { mDash[i] <== 0; @@ -173,10 +184,15 @@ template VerifyRsaPss3Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY_LEN mDash[1016] <== 0; mDash[1015] <== 0; mDash[1014] <== 1; + + signal mDash256[1024]; + for (var i = 0; i < 1024; i++){ + mDash256[i] <== mDash[i]; + } //hashing component hDash256 = ShaHashChunks(2, HASH_TYPE); - hDash256.in <== mDash; + hDash256.in <== mDash256; hDash256.out === hash; } @@ -198,8 +214,13 @@ template VerifyRsaPss3Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY_LEN mDash[1015] <== 1; mDash[1014] <== 1; + signal mDash256[1024]; + for (var i = 0; i < 1024; i++){ + mDash256[i] <== mDash[i]; + } + component hDash256 = ShaHashChunks(2, HASH_TYPE); - hDash256.in <== mDash; + hDash256.in <== mDash256; hDash256.out === hash; } @@ -222,13 +243,29 @@ template VerifyRsaPss3Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY_LEN mDash[1016] <== 0; mDash[1015] <== 1; mDash[1014] <== 1; + + signal mDash384[1024]; + for (var i = 0; i < 1024; i++){ + mDash384[i] <== mDash[i]; + } //hashing mDash component hDash384 = ShaHashChunks(1, HASH_TYPE); - hDash384.in <== mDash; + hDash384.in <== mDash384; hDash384.out === hash; } + if (HASH_TYPE == 512 && SALT_LEN == 64) { + // 64 + 512 + 512 = 1088 + component hDash512 = ShaHashBits(64 + SALT_LEN_BITS + HASH_LEN * 8, 512); + // hDash512.dummy <== dummy; + + for (var i = 0; i < 1088; i++) { + hDash512.in[i] <== mDash[i]; + } + + hDash512.out === hash; + } } /* diff --git a/circuits/circuits/utils/circomlib/signature/rsapss/rsapss65537.circom b/circuits/circuits/utils/circomlib/signature/rsapss/rsapss65537.circom index 7db49f72f..6c642d32b 100644 --- a/circuits/circuits/utils/circomlib/signature/rsapss/rsapss65537.circom +++ b/circuits/circuits/utils/circomlib/signature/rsapss/rsapss65537.circom @@ -121,6 +121,17 @@ template VerifyRsaPss65537Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY dbMask[i] <== MGF1_384.out[i]; } } + if (HASH_TYPE == 512) { + component MGF1_512 = Mgf1Sha512(HASH_LEN, DB_MASK_LEN); + + for (var i = 0; i < (HASH_TYPE); i++) { + MGF1_512.seed[i] <== hash[i]; + } + + for (var i = 0; i < DB_MASK_LEN * 8; i++) { + dbMask[i] <== MGF1_512.out[i]; + } + } component xor = Xor2(DB_MASK_LEN * 8); @@ -143,7 +154,7 @@ template VerifyRsaPss65537Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY salt[SALT_LEN_BITS - 1 - i] <== db[(DB_MASK_LEN * 8) - 1 - i]; } - signal mDash[1024]; + signal mDash[2048]; //adding 0s for (var i = 0; i < 64; i++) { mDash[i] <== 0; @@ -177,10 +188,15 @@ template VerifyRsaPss65537Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY mDash[1016] <== 0; mDash[1015] <== 0; mDash[1014] <== 1; + + signal mDash256[1024]; + for (var i = 0; i < 1024; i++){ + mDash256[i] <== mDash[i]; + } //hashing component hDash256 = ShaHashChunks(2, HASH_TYPE); - hDash256.in <== mDash; + hDash256.in <== mDash256; hDash256.out === hash; } @@ -202,8 +218,13 @@ template VerifyRsaPss65537Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY mDash[1015] <== 1; mDash[1014] <== 1; + signal mDash256[1024]; + for (var i = 0; i < 1024; i++){ + mDash256[i] <== mDash[i]; + } + component hDash256 = ShaHashChunks(2, HASH_TYPE); - hDash256.in <== mDash; + hDash256.in <== mDash256; hDash256.out === hash; } @@ -226,13 +247,29 @@ template VerifyRsaPss65537Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY mDash[1016] <== 0; mDash[1015] <== 1; mDash[1014] <== 1; + + signal mDash384[1024]; + for (var i = 0; i < 1024; i++){ + mDash384[i] <== mDash[i]; + } //hashing mDash component hDash384 = ShaHashChunks(1, HASH_TYPE); - hDash384.in <== mDash; + hDash384.in <== mDash384; hDash384.out === hash; } + if (HASH_TYPE == 512 && SALT_LEN == 64) { + // 64 + 512 + 512 = 1088 + component hDash512 = ShaHashBits(64 + SALT_LEN_BITS + HASH_LEN * 8, 512); + // hDash512.dummy <== dummy; + + for (var i = 0; i < 1088; i++) { + hDash512.in[i] <== mDash[i]; + } + + hDash512.out === hash; + } } /* diff --git a/circuits/tests/utils/generateMockInputsRsaPss.ts b/circuits/tests/utils/generateMockInputsRsaPss.ts new file mode 100644 index 000000000..1f7b447c2 --- /dev/null +++ b/circuits/tests/utils/generateMockInputsRsaPss.ts @@ -0,0 +1,95 @@ +import * as forge from 'node-forge'; +import { + splitToWords, + hexToDecimal, + bytesToBigDecimal, + getNAndK, +} from '../../../common/src/utils/utils'; +import { SignatureAlgorithm } from '../../../common/src/utils/types'; + +export const generateMockRsaPssInputs = (signatureAlgorithm: SignatureAlgorithm) => { + let saltLength: number; + + const [sigAlg, hashAlgorithm, exponent, modulusLength] = signatureAlgorithm.split('_'); + + switch (signatureAlgorithm) { + case 'rsapss_sha256_65537_4096': + saltLength = 32; + break; + case 'rsapss_sha256_65537_3072': + saltLength = 32; + break; + case 'rsapss_sha256_65537_2048': + saltLength = 32; + break; + case 'rsapss_sha256_3_4096': + saltLength = 32; + break; + case 'rsapss_sha256_3_3072': + saltLength = 32; + break; + case 'rsapss_sha256_3_2048': + saltLength = 32; + break; + case 'rsapss_sha512_3_4096': + saltLength = 64; + break; + case 'rsapss_sha512_3_2048': + saltLength = 64; + break; + case 'rsapss_sha384_65537_4096': + saltLength = 48; + break; + case 'rsapss_sha384_65537_3072': + saltLength = 48; + break; + case 'rsapss_sha384_3_4096': + saltLength = 48; + break; + case 'rsapss_sha384_3_3072': + saltLength = 48; + break; + + default: + throw new Error(`Unsupported signature algorithm: ${signatureAlgorithm}`); + } + + // Generate RSA key pair + const keypair = forge.pki.rsa.generateKeyPair({ + bits: parseInt(modulusLength), + e: parseInt(exponent), + }); + const message = 'helloworld'; + + // Create message hash + const md = forge.md[hashAlgorithm].create(); + md.update(forge.util.binary.raw.encode(Buffer.from(message))); + const messageHash = md.digest().bytes(); + const messageBits = Array.from(messageHash) + .map((char: string) => { + const byte = char.charCodeAt(0); + return Array.from({ length: 8 }, (_, i) => (byte >> (7 - i)) & 1); + }) + .flat(); + + // Create PSS signature + const pss = forge.pss.create({ + md: forge.md[hashAlgorithm].create(), + mgf: forge.mgf.mgf1.create(forge.md[hashAlgorithm].create()), + saltLength, + }); + const signatureBytes = keypair.privateKey.sign(md, pss); + const signature = Array.from(signatureBytes, (c: string) => c.charCodeAt(0)); + + // Get modulus from public key + const modulus = keypair.publicKey.n.toString(16); + + const { n, k } = getNAndK(signatureAlgorithm); + + return { + signature: splitToWords(BigInt(bytesToBigDecimal(signature)), n, k), + modulus: splitToWords(BigInt(hexToDecimal(modulus)), n, k), + message: messageBits, + saltLength: saltLength, + }; +}; diff --git a/circuits/tests/utils/rsapss.test.ts b/circuits/tests/utils/rsapss.test.ts new file mode 100644 index 000000000..447250a77 --- /dev/null +++ b/circuits/tests/utils/rsapss.test.ts @@ -0,0 +1,58 @@ +import { wasm as wasmTester } from 'circom_tester'; +import { describe, it } from 'mocha'; +import path from 'path'; +import { SignatureAlgorithm } from '../../../common/src/utils/types'; +import { generateMockRsaPssInputs } from './generateMockInputsRsaPss'; + +describe('VerifyRsapss Circuit Test', function () { + this.timeout(0); + const rsaAlgorithms: SignatureAlgorithm[] = [ + 'rsapss_sha256_65537_4096', + 'rsapss_sha256_65537_3072', + 'rsapss_sha256_65537_2048', + + 'rsapss_sha256_3_4096', + 'rsapss_sha256_3_3072', + 'rsapss_sha256_3_2048', + + 'rsapss_sha512_3_4096', + 'rsapss_sha512_3_2048', + + 'rsapss_sha384_65537_4096', + 'rsapss_sha384_65537_3072', + + 'rsapss_sha384_3_4096', + 'rsapss_sha384_3_3072', + ]; + + rsaAlgorithms.forEach((algorithm) => { + it(`should verify RSA signature using the circuit for ${algorithm}`, async function () { + this.timeout(0); + // Generate inputs using the utility function + const { signature, modulus, message, saltLength } = generateMockRsaPssInputs(algorithm); + + // Run circuit with inputs + const circuit = await wasmTester( + path.join( + __dirname, + `../../circuits/tests/utils/rsapss/test_${algorithm}_${saltLength}.circom` + ), + { + include: ['node_modules', './node_modules/@zk-kit/binary-merkle-root.circom/src'], + } + ); + + // Log the inputs for debugging + console.log(`Testing algorithm: ${algorithm}`); + + const witness = await circuit.calculateWitness({ + signature, + modulus, + message, + }); + + // Check constraints + await circuit.checkConstraints(witness); + }); + }); +}); diff --git a/common/src/constants/constants.ts b/common/src/constants/constants.ts index b419eca06..0c0d458a9 100644 --- a/common/src/constants/constants.ts +++ b/common/src/constants/constants.ts @@ -119,11 +119,11 @@ export const circuitToSelectorMode = { }; export const MAX_DATAHASHES_LEN = 320; // max formatted and concatenated datagroup hashes length in bytes -export const n_dsc = 64; -export const n_dsc_3072 = 96; +export const n_dsc = 120; +export const n_dsc_3072 = 120; export const n_dsc_4096 = 120; -export const k_dsc = 32; -export const k_dsc_3072 = 32; //48; +export const k_dsc = 35; +export const k_dsc_3072 = 35; //48; export const k_dsc_4096 = 35; export const n_csca = 120; export const k_csca = 35; diff --git a/common/src/utils/types.ts b/common/src/utils/types.ts index 1901a58e5..921cecd94 100644 --- a/common/src/utils/types.ts +++ b/common/src/utils/types.ts @@ -29,7 +29,12 @@ export type SignatureAlgorithm = | 'rsa_sha256_65537_4096' | 'rsa_sha512_65537_4096' | 'rsapss_sha256_65537_3072' -| 'rsapss_sha256_65537_4096'; +| 'rsapss_sha256_65537_4096' +| 'rsapss_sha256_3_2048' +| 'rsapss_sha512_3_4096' +| 'rsapss_sha512_3_2048' +| 'rsapss_sha384_3_4096' +| 'rsapss_sha384_3_3072' ; export type Proof = { proof: { From a3aabfb39260cfb6c3b8ca712ea9666771ba6b16 Mon Sep 17 00:00:00 2001 From: seshanthS Date: Sat, 11 Jan 2025 00:33:18 +0530 Subject: [PATCH 4/5] fix rsapss-sha384 --- .../circomlib/signature/rsapss/mgf1.circom | 21 ++------------ .../circomlib/signature/rsapss/rsapss3.circom | 27 +++--------------- .../signature/rsapss/rsapss65537.circom | 28 +++---------------- circuits/tests/utils/rsapss.test.ts | 4 --- 4 files changed, 11 insertions(+), 69 deletions(-) diff --git a/circuits/circuits/utils/circomlib/signature/rsapss/mgf1.circom b/circuits/circuits/utils/circomlib/signature/rsapss/mgf1.circom index 3e75c4837..d7aedf12e 100644 --- a/circuits/circuits/utils/circomlib/signature/rsapss/mgf1.circom +++ b/circuits/circuits/utils/circomlib/signature/rsapss/mgf1.circom @@ -70,7 +70,7 @@ template Mgf1Sha384(SEED_LEN, MASK_LEN) { //in bytes component num2Bits[ITERATIONS]; for (var i = 0; i < ITERATIONS; i++) { - sha384[i] = ShaHashChunks(1 , 384); //32 bits for counter + sha384[i] = ShaHashBits(416, 384); //32 bits for counter num2Bits[i] = Num2Bits(32); } @@ -90,25 +90,10 @@ template Mgf1Sha384(SEED_LEN, MASK_LEN) { //in bytes concated[SEED_LEN_BITS + j] = num2Bits[i].out[31-j]; } - //adding padding (len = 416 = 110100000) - for (var j = 417; j < 1015; j++) { - concated[j] = 0; + for (var k =0; k < 416; k++) { + sha384[i].in[k] <== concated[k]; } - concated[416] = 1; - concated[1023] = 0; - concated[1022] = 0; - concated[1021] = 0; - concated[1020] = 0; - concated[1019] = 0; - concated[1018] = 1; - concated[1017] = 0; - concated[1016] = 1; - concated[1015] = 1; - - //hashing value - sha384[i].in <== concated; - for (var j = 0; j < HASH_LEN_BITS; j++) { hashed[i * HASH_LEN_BITS + j] <== sha384[i].out[j]; } diff --git a/circuits/circuits/utils/circomlib/signature/rsapss/rsapss3.circom b/circuits/circuits/utils/circomlib/signature/rsapss/rsapss3.circom index 0913d26c9..05c073106 100644 --- a/circuits/circuits/utils/circomlib/signature/rsapss/rsapss3.circom +++ b/circuits/circuits/utils/circomlib/signature/rsapss/rsapss3.circom @@ -227,31 +227,12 @@ template VerifyRsaPss3Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY_LEN if (HASH_TYPE == 384 && SALT_LEN == 48) { //padding - //len = 64+48*16 = 832 = 1101000000 - for (var i = 833; i < 1014; i++) { - mDash[i] <== 0; - } + //len = 64+(48*8)+384 = 832 = 1101000000 - mDash[832] <== 1; - mDash[1023] <== 0; - mDash[1022] <== 0; - mDash[1021] <== 0; - mDash[1020] <== 0; - mDash[1019] <== 0; - mDash[1018] <== 0; - mDash[1017] <== 1; - mDash[1016] <== 0; - mDash[1015] <== 1; - mDash[1014] <== 1; - - signal mDash384[1024]; - for (var i = 0; i < 1024; i++){ - mDash384[i] <== mDash[i]; + component hDash384 = ShaHashBits(64 + SALT_LEN_BITS + HASH_LEN * 8, 384); + for (var i = 0; i < 832; i++) { + hDash384.in[i] <== mDash[i]; } - - //hashing mDash - component hDash384 = ShaHashChunks(1, HASH_TYPE); - hDash384.in <== mDash384; hDash384.out === hash; } diff --git a/circuits/circuits/utils/circomlib/signature/rsapss/rsapss65537.circom b/circuits/circuits/utils/circomlib/signature/rsapss/rsapss65537.circom index 6c642d32b..4cd38f821 100644 --- a/circuits/circuits/utils/circomlib/signature/rsapss/rsapss65537.circom +++ b/circuits/circuits/utils/circomlib/signature/rsapss/rsapss65537.circom @@ -231,38 +231,18 @@ template VerifyRsaPss65537Sig(CHUNK_SIZE, CHUNK_NUMBER, SALT_LEN, HASH_TYPE, KEY if (HASH_TYPE == 384 && SALT_LEN == 48) { //padding - //len = 64+48*16 = 832 = 1101000000 - for (var i = 833; i < 1014; i++) { - mDash[i] <== 0; - } + //len = 64+(48*8)+384 = 832 = 1101000000 - mDash[832] <== 1; - mDash[1023] <== 0; - mDash[1022] <== 0; - mDash[1021] <== 0; - mDash[1020] <== 0; - mDash[1019] <== 0; - mDash[1018] <== 0; - mDash[1017] <== 1; - mDash[1016] <== 0; - mDash[1015] <== 1; - mDash[1014] <== 1; - - signal mDash384[1024]; - for (var i = 0; i < 1024; i++){ - mDash384[i] <== mDash[i]; + component hDash384 = ShaHashBits(64 + SALT_LEN_BITS + HASH_LEN * 8, 384); + for (var i = 0; i < 832; i++) { + hDash384.in[i] <== mDash[i]; } - - //hashing mDash - component hDash384 = ShaHashChunks(1, HASH_TYPE); - hDash384.in <== mDash384; hDash384.out === hash; } if (HASH_TYPE == 512 && SALT_LEN == 64) { // 64 + 512 + 512 = 1088 component hDash512 = ShaHashBits(64 + SALT_LEN_BITS + HASH_LEN * 8, 512); - // hDash512.dummy <== dummy; for (var i = 0; i < 1088; i++) { hDash512.in[i] <== mDash[i]; diff --git a/circuits/tests/utils/rsapss.test.ts b/circuits/tests/utils/rsapss.test.ts index 447250a77..65d9312c5 100644 --- a/circuits/tests/utils/rsapss.test.ts +++ b/circuits/tests/utils/rsapss.test.ts @@ -10,17 +10,13 @@ describe('VerifyRsapss Circuit Test', function () { 'rsapss_sha256_65537_4096', 'rsapss_sha256_65537_3072', 'rsapss_sha256_65537_2048', - 'rsapss_sha256_3_4096', 'rsapss_sha256_3_3072', 'rsapss_sha256_3_2048', - 'rsapss_sha512_3_4096', 'rsapss_sha512_3_2048', - 'rsapss_sha384_65537_4096', 'rsapss_sha384_65537_3072', - 'rsapss_sha384_3_4096', 'rsapss_sha384_3_3072', ]; From 8592a895a28b4e890318115b4b6465eb7c315a58 Mon Sep 17 00:00:00 2001 From: seshanthS Date: Sat, 11 Jan 2025 00:37:22 +0530 Subject: [PATCH 5/5] add test command to package.json --- circuits/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/circuits/package.json b/circuits/package.json index e52289cae..ba057df08 100644 --- a/circuits/package.json +++ b/circuits/package.json @@ -8,6 +8,7 @@ "test-dsc": "yarn ts-mocha --max-old-space-size=8192 'tests/dsc.test.ts' --exit", "test-prove": "yarn ts-mocha --max-old-space-size=40960 'tests/prove.test.ts' --exit", "test-rsa": "yarn ts-mocha --max-old-space-size=8192 'tests/utils/rsaPkcs1v1_5.test.ts' --exit", + "test-rsa-pss": "yarn ts-mocha --max-old-space-size=8192 'tests/utils/rsapss.test.ts' --exit", "install-circuits": "cd ../common && yarn && cd ../circuits && yarn", "format": "prettier --write .", "lint": "prettier --check ."