Merge pull request #301 from zk-passport/feat/rsapss-zkemail-tests

Feat/rsapss zkemail tests
This commit is contained in:
turnoffthiscomputer
2025-01-11 12:03:15 +01:00
committed by GitHub
26 changed files with 1430 additions and 144 deletions

View File

@@ -2,4 +2,4 @@ pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(256, 256, 8, 64, 4, 448, 128, 20);
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(256, 256, 8, 64, 4, 448, 128, 20);

View File

@@ -2,4 +2,4 @@ pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(384, 384, 9, 64, 6, 640, 256, 20);
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(384, 384, 9, 64, 6, 640, 256, 20);

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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];
}
}

View File

@@ -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];
}
}

View File

@@ -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];
}
}

View File

@@ -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;
@@ -21,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);
}
@@ -41,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];
}

View File

@@ -0,0 +1,470 @@
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, KEY_LENGTH) {
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];
signal input hashed[HASH_TYPE];
var EM_LEN = KEY_LENGTH \ 8;
var HASH_LEN = HASH_TYPE \ 8;
var SALT_LEN_BITS = SALT_LEN * 8;
var EM_LEN_BITS = KEY_LENGTH;
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++) {
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];
}
}
}
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)
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];
}
}
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);
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[2048];
//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;
signal mDash256[1024];
for (var i = 0; i < 1024; i++){
mDash256[i] <== mDash[i];
}
//hashing
component hDash256 = ShaHashChunks(2, HASH_TYPE);
hDash256.in <== mDash256;
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;
signal mDash256[1024];
for (var i = 0; i < 1024; i++){
mDash256[i] <== mDash[i];
}
component hDash256 = ShaHashChunks(2, HASH_TYPE);
hDash256.in <== mDash256;
hDash256.out === hash;
}
if (HASH_TYPE == 384 && SALT_LEN == 48) {
//padding
//len = 64+(48*8)+384 = 832 = 1101000000
component hDash384 = ShaHashBits(64 + SALT_LEN_BITS + HASH_LEN * 8, 384);
for (var i = 0; i < 832; i++) {
hDash384.in[i] <== mDash[i];
}
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;
}
}
/*
* 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;
}
}

View File

@@ -0,0 +1,473 @@
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.
* 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, 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 = KEY_LENGTH \ 8;
var HASH_LEN = HASH_TYPE \ 8;
var SALT_LEN_BITS = SALT_LEN * 8;
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++) {
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++) {
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];
}
}
}
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];
}
}
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);
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[2048];
//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;
signal mDash256[1024];
for (var i = 0; i < 1024; i++){
mDash256[i] <== mDash[i];
}
//hashing
component hDash256 = ShaHashChunks(2, HASH_TYPE);
hDash256.in <== mDash256;
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;
signal mDash256[1024];
for (var i = 0; i < 1024; i++){
mDash256[i] <== mDash[i];
}
component hDash256 = ShaHashChunks(2, HASH_TYPE);
hDash256.in <== mDash256;
hDash256.out === hash;
}
if (HASH_TYPE == 384 && SALT_LEN == 48) {
//padding
//len = 64+(48*8)+384 = 832 = 1101000000
component hDash384 = ShaHashBits(64 + SALT_LEN_BITS + HASH_LEN * 8, 384);
for (var i = 0; i < 832; i++) {
hDash384.in[i] <== mDash[i];
}
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);
for (var i = 0; i < 1088; i++) {
hDash512.in[i] <== mDash[i];
}
hDash512.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;
}
}

View File

@@ -1,6 +1,7 @@
pragma circom 2.1.9;
include "../circomlib/signature/rsapss/rsapss.circom";
include "../circomlib/signature/rsapss/rsapss3.circom";
include "../circomlib/signature/rsapss/rsapss65537.circom";
include "ecdsaVerifier.circom";
include "../circomlib/signature/rsa/verifyRsa3Pkcs1v1_5.circom";
include "../circomlib/signature/rsa/verifyRsa65537Pkcs1v1_5.circom";
@@ -47,30 +48,35 @@ 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, pubKeyBitsLength);
rsaPss65537ShaVerification.pubkey <== pubKey;
rsaPss65537ShaVerification.signature <== signature;
rsaPss65537ShaVerification.hashed <== hash; // send the raw hash
}
if (
signatureAlgorithm == 7
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, pubKeyBitsLength);
rsaPss3ShaVerification.pubkey <== pubKey;
rsaPss3ShaVerification.signature <== signature;
rsaPss3ShaVerification.hashed <== hash; // send the raw hash
}
if (signatureAlgorithm == 9
|| signatureAlgorithm == 7
|| signatureAlgorithm == 8
|| signatureAlgorithm == 9
|| signatureAlgorithm == 21
@@ -107,6 +113,7 @@ template SignatureVerifier(signatureAlgorithm, n, k) {
}
rsa.modulus <== pubKey;
rsa.signature <== signature;
}
if (signatureAlgorithm == 12) {

View File

@@ -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 ."

View File

@@ -238,7 +238,6 @@ const fullSigAlgs = [
];
const testSuite = process.env.FULL_TEST_SUITE === 'true' ? fullSigAlgs : sigAlgs;
// const testSuite = fullSigAlgs;
testSuite.forEach(
({

View File

@@ -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,
};
};

View File

@@ -0,0 +1,54 @@
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);
});
});
});

View File

@@ -13,32 +13,37 @@ export type PassportData = {
// Define the signature algorithm in "algorithm_hashfunction_domainPapameter_keyLength"
export type SignatureAlgorithm =
| 'rsa_sha1_65537_2048'
| 'rsa_sha256_65537_2048'
| 'rsapss_sha256_65537_2048'
| 'rsapss_sha256_3_4096'
| 'rsapss_sha256_3_3072'
| 'rsapss_sha384_65537_3072'
| 'rsapss_sha384_65537_4096'
| 'ecdsa_sha256_secp256r1_256'
| 'ecdsa_sha1_secp256r1_256'
| 'ecdsa_sha384_secp384r1_384'
| 'ecdsa_sha256_secp384r1_384'
| 'ecdsa_sha384_brainpoolP256r1_256'
| 'ecdsa_sha512_brainpoolP256r1_256'
| 'ecdsa_sha256_brainpoolP256r1_256'
| 'rsa_sha256_3_2048'
| 'rsa_sha256_65537_3072'
| 'rsa_sha256_65537_4096'
| 'rsa_sha512_65537_4096'
| 'rsapss_sha256_65537_3072'
| 'ecdsa_sha384_brainpoolP384r1_384'
| 'ecdsa_sha512_brainpoolP384r1_384'
| 'ecdsa_sha1_brainpoolP224r1_224'
| 'ecdsa_sha224_brainpoolP224r1_224'
| 'ecdsa_sha256_brainpoolP224r1_224'
| 'ecdsa_sha512_brainpoolP512r1_512'
| 'rsapss_sha256_65537_4096';
| 'rsa_sha1_65537_2048'
| 'rsa_sha256_65537_2048'
| 'rsapss_sha256_65537_2048'
| 'rsapss_sha256_3_4096'
| 'rsapss_sha256_3_3072'
| 'rsapss_sha384_65537_3072'
| 'rsapss_sha384_65537_4096'
| 'ecdsa_sha256_secp256r1_256'
| 'ecdsa_sha1_secp256r1_256'
| 'ecdsa_sha384_secp384r1_384'
| 'ecdsa_sha256_brainpoolP256r1_256'
| 'rsa_sha256_3_2048'
| 'rsa_sha256_65537_3072'
| 'rsa_sha256_65537_4096'
| 'rsa_sha512_65537_4096'
| 'rsapss_sha256_65537_3072'
| 'rsapss_sha256_65537_4096'
| 'rsapss_sha256_3_2048'
| 'rsapss_sha512_3_4096'
| 'rsapss_sha512_3_2048'
| 'rsapss_sha384_3_4096'
| 'rsapss_sha384_3_3072'
| 'ecdsa_sha256_secp384r1_384'
| 'ecdsa_sha384_brainpoolP256r1_256'
| 'ecdsa_sha512_brainpoolP256r1_256'
| 'ecdsa_sha384_brainpoolP384r1_384'
| 'ecdsa_sha512_brainpoolP384r1_384'
| 'ecdsa_sha1_brainpoolP224r1_224'
| 'ecdsa_sha224_brainpoolP224r1_224'
| 'ecdsa_sha256_brainpoolP224r1_224'
| 'ecdsa_sha512_brainpoolP512r1_512'
export type Proof = {
proof: {