Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RSASSAPSS: fix RSASSAPSS_Decode #141

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,12 @@ template PassportVerifier_sha256WithRSASSAPSS_65537(n, k, max_datahashes_bytes)
// decode signature to get encoded message
component rsaDecode = RSASSAPSS_Decode(n, k);
rsaDecode.signature <== signature;
rsaDecode.modulus <== dsc_modulus;
var emLen = div_ceil(n*k, 8);
rsaDecode.modulus <== pubkey;
var emLen = div_ceil((n*k) -1, 8); //refer point 2.C of https://datatracker.ietf.org/doc/html/rfc8017#section-8.1.2
signal encodedMessage[emLen] <== rsaDecode.eM;

// verify eContent signature
component rsaVerify = RSASSAPSSVerify_SHA256(n*k, eContentBytesLength);
component rsaVerify = RSASSAPSSVerify_SHA256((n*k) -1 , eContentBytesLength); //point 3 from https://datatracker.ietf.org/doc/html/rfc8017#section-8.1.2
rsaVerify.eM <== encodedMessage;
rsaVerify.message <== eContentBytes;
}
24 changes: 24 additions & 0 deletions circuits/circuits/tests/RSASSAPSS/rsassapss_2048.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
pragma circom 2.1.5;

include "../../utils/RSASSAPSS.circom";
include "../../../node_modules/circomlib/circuits/bitify.circom";

template RSASSAPSS_tester_2048(n, k) {
var eContentBytesLength = 104;

signal input signature[k];
signal input pubkey[k];
signal input eContentBytes[eContentBytesLength];

component rsaDecode = RSASSAPSS_Decode(n, k);
rsaDecode.signature <== signature;
rsaDecode.modulus <== pubkey;
var encoded_message_len = div_ceil((n*k) -1, 8);
signal encodedMessage[encoded_message_len] <== rsaDecode.eM;

component rsaVerify = RSASSAPSSVerify_SHA256((n*k) -1, eContentBytesLength);
rsaVerify.eM <== encodedMessage;
rsaVerify.message <== eContentBytes;
}

component main = RSASSAPSS_tester_2048(64, 32);
24 changes: 24 additions & 0 deletions circuits/circuits/tests/RSASSAPSS/rsassapss_2057.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
pragma circom 2.1.5;

include "../../utils/RSASSAPSS.circom";
include "../../../node_modules/circomlib/circuits/bitify.circom";

template RSASSAPSS_tester_2057(n, k) {
var eContentBytesLength = 104;

signal input signature[k];
signal input pubkey[k];
signal input eContentBytes[eContentBytesLength];

component rsaDecode = RSASSAPSS_Decode(n, k);
rsaDecode.signature <== signature;
rsaDecode.modulus <== pubkey;
var encoded_message_len = div_ceil((n*k) -1, 8);
signal encodedMessage[encoded_message_len] <== rsaDecode.eM;

component rsaVerify = RSASSAPSSVerify_SHA256((n*k) -1, eContentBytesLength);
rsaVerify.eM <== encodedMessage;
rsaVerify.message <== eContentBytes;
}

component main = RSASSAPSS_tester_2057(121, 17);
27 changes: 12 additions & 15 deletions circuits/circuits/utils/RSASSAPSS.circom
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ include "./xor.circom";
template RSASSAPSS_Decode(n, k) {
signal input signature[k];
signal input modulus[k];
// signal output eM[k];
signal encoded[k];
signal eMsgInBits[n*k];
var emLen = div_ceil(n*k, 8);
var emLen = div_ceil((n*k) -1, 8); //refer point 2.C of https://datatracker.ietf.org/doc/html/rfc8017#section-8.1.2
signal eMsgInBits[emLen * 8];
signal output eM[emLen]; //8 bit words

component bigPow = FpPow65537Mod(n, k);
Expand All @@ -31,27 +30,26 @@ template RSASSAPSS_Decode(n, k) {
component num2Bits[k];
for (var i = 0; i < k; i++) {
num2Bits[i] = Num2Bits(n);
num2Bits[i].in <== encoded[k-1-i];
num2Bits[i].in <== encoded[i];

for (var j = 0; j < n; j++) {
eMsgInBits[i * n + j] <== num2Bits[i].out[n-j-1];
if (i * n + j < emLen * 8)
eMsgInBits[i * n + j] <== num2Bits[i].out[j];
}
}

component bits2Num[(n*k)\8];
for (var i = 0; i < (n*k)\8; i++) {
component bits2Num[emLen];
for (var i = 0; i < emLen; i++) {
bits2Num[i] = Bits2Num(8);
for (var j = 0; j < 8; j++) {
bits2Num[i].in[7-j] <== eMsgInBits[i*8 + j];
bits2Num[i].in[7-j] <== eMsgInBits[i*8 + (7-j)];
}
eM[(n*k)\8 - i -1] <== bits2Num[i].out;
eM[i] <== bits2Num[i].out;
}
}

/// @param emBits Length of the encoded message in bits.
/// @param messageLen Length of the message in bytes.
/// @param n Number of bits per chunk the modulus is split into.
/// @param k Number of chunks the modulus is split into.
template RSASSAPSSVerify_SHA256(emBits, messageLen) {
var emLen = div_ceil(emBits, 8);
signal input eM[emLen];
Expand All @@ -74,7 +72,7 @@ template RSASSAPSSVerify_SHA256(emBits, messageLen) {
}

//mHash
component sha256 = Sha256( messageLen* 8);
component sha256 = Sha256(messageLen*8);
sha256.in <== messageBits;
for (var i = 0; i < 256; i++) {
mHash[i] <== sha256.out[i];
Expand All @@ -99,9 +97,8 @@ template RSASSAPSSVerify_SHA256(emBits, messageLen) {
for (var i = 0; i < emLen; i++) {
num2Bits[i] = Num2Bits(8);
num2Bits[i].in <== eM[emLen-1-i];

for (var j = 0; j < 8; j++) {
eMsgInBits[i * 8 + j] <== num2Bits[i].out[8-j-1];
eMsgInBits[(i * 8) + j] <== num2Bits[i].out[8-j-1];
}
}

Expand Down
66 changes: 66 additions & 0 deletions circuits/tests/rsassapss/rsassapss_2048.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { describe } from 'mocha';
import { assert, expect } from 'chai';
import path from 'path';
const wasm_tester = require('circom_tester').wasm;
import { poseidon1 } from 'poseidon-lite';
import { generateCircuitInputsRegister } from '../../../common/src/utils/generateInputs';
import { mockPassportData_sha256_rsapss_65537 } from '../../../common/src/constants/mockPassportData';

describe('Proof of Passport - Circuits - RSASSAPSS - 2048', function () {
this.timeout(0);
let inputs: any;
let circuit: any;
let circuit_inputs: any;
let attestation_id: string;
const n_dsc = 64;
const k_dsc = 32;


let passportData = mockPassportData_sha256_rsapss_65537;

before(async () => {
circuit = await wasm_tester(
path.join(__dirname, '../../circuits/tests/rsassapss/rsassapss_2048.circom'),
{
include: [
'node_modules',
'node_modules/@zk-email/circuits/helpers/sha.circom',
'./node_modules/circomlib/circuits',
],
}
);

const secret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString();
const attestation_name = 'E-PASSPORT';
attestation_id = poseidon1([BigInt(Buffer.from(attestation_name).readUIntBE(0, 6))]).toString();
inputs = generateCircuitInputsRegister(secret, secret, attestation_id, passportData, n_dsc, k_dsc);
circuit_inputs = {
signature: inputs.signature,
pubkey: inputs.dsc_modulus,
eContentBytes: inputs.signed_attributes,
};
});

it('should compile and load the circuit', async function () {
expect(circuit).to.not.be.undefined;
});

it('should calculate the witness with correct inputs', async function () {
const w = await circuit.calculateWitness(circuit_inputs);
await circuit.checkConstraints(w);
});

it('should fail to calculate witness with invalid signature', async function () {
try {
const invalidInputs = {
pubkey: inputs.dsc_modulus,
eContentBytes: inputs.signed_attributes,
signature: inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)),
};
await circuit.calculateWitness(invalidInputs);
expect.fail('Expected an error but none was thrown.');
} catch (error) {
expect(error.message).to.include('Assert Failed');
}
});
});
64 changes: 64 additions & 0 deletions circuits/tests/rsassapss/rsassapss_2057.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { describe } from 'mocha';
import { assert, expect } from 'chai';
import path from 'path';
const wasm_tester = require('circom_tester').wasm;
import { poseidon1, poseidon6 } from 'poseidon-lite';
import { generateCircuitInputsRegister } from '../../../common/src/utils/generateInputs';
import { mockPassportData_sha256_rsapss_65537 } from '../../../common/src/constants/mockPassportData';

describe('Proof of Passport - Circuits - RSASSAPSS - 2057', function () {
this.timeout(0);
let inputs: any;
let circuit: any;
let attestation_id: string;
const n_dsc = 121;
const k_dsc = 17;

let passportData = mockPassportData_sha256_rsapss_65537;

before(async () => {
circuit = await wasm_tester(
path.join(__dirname, '../../circuits/tests/rsassapss/rsassapss_2057.circom'),
{
include: [
'node_modules',
'node_modules/@zk-email/circuits/helpers/sha.circom',
'./node_modules/circomlib/circuits',
],
}
);

const secret = BigInt(Math.floor(Math.random() * Math.pow(2, 254))).toString();
const attestation_name = 'E-PASSPORT';
attestation_id = poseidon1([BigInt(Buffer.from(attestation_name).readUIntBE(0, 6))]).toString();
inputs = generateCircuitInputsRegister(secret, secret, attestation_id, passportData, n_dsc, k_dsc);

});

it('should compile and load the circuit', async function () {
expect(circuit).to.not.be.undefined;
});

it('should calculate the witness with correct inputs', async function () {
const w = await circuit.calculateWitness({
signature: inputs.signature,
pubkey: inputs.dsc_modulus,
eContentBytes: inputs.signed_attributes,
});
await circuit.checkConstraints(w);
});

it('should fail to calculate witness with invalid signature', async function () {
try {
const invalidInputs = {
pubkey: inputs.dsc_modulus,
eContentBytes: inputs.signed_attributes,
signature: inputs.signature.map((byte: string) => String((parseInt(byte, 10) + 1) % 256)),
};
await circuit.calculateWitness(invalidInputs);
expect.fail('Expected an error but none was thrown.');
} catch (error) {
expect(error.message).to.include('Assert Failed');
}
});
});
Loading