mirror of
https://github.com/selfxyz/self.git
synced 2026-04-05 03:00:53 -04:00
refactor some code, generate dsc verification inputs in app, update dsc.circom and tests
This commit is contained in:
@@ -7,61 +7,69 @@ include "@zk-email/circuits/helpers/extract.circom";
|
||||
include "@zk-email/circuits/helpers/sha.circom";
|
||||
include "../utils/splitBytesToWords.circom";
|
||||
|
||||
template DSC(max_cert_bytes, csca_mod_n, csca_mod_k, dsc_mod_len, dsc_mod_n , dsc_mod_k) {
|
||||
template DSC(max_cert_bytes, n_dsc, k_dsc, n_csca, k_csca, dsc_mod_len ) {
|
||||
signal input raw_dsc_cert[max_cert_bytes];
|
||||
signal input message_padded_bytes;
|
||||
signal input modulus[csca_mod_k];
|
||||
signal input signature[csca_mod_k];
|
||||
signal input dsc_modulus[dsc_mod_k];
|
||||
signal input raw_dsc_cert_padded_bytes;
|
||||
signal input csca_modulus[k_csca];
|
||||
signal input dsc_signature[k_csca];
|
||||
signal input dsc_modulus[k_dsc];
|
||||
signal input start_index;
|
||||
signal input secret;
|
||||
|
||||
signal output blinded_csca_commitment;
|
||||
|
||||
// variables verification
|
||||
assert(max_cert_bytes % 64 == 0);
|
||||
assert(csca_mod_n * csca_mod_k > max_cert_bytes);
|
||||
assert(csca_mod_n < (255 \ 2));
|
||||
assert(n_csca * k_csca > max_cert_bytes);
|
||||
assert(n_csca < (255 \ 2));
|
||||
|
||||
// hash raw TBS certificate
|
||||
signal sha[256] <== Sha256Bytes(max_cert_bytes)(raw_dsc_cert, message_padded_bytes);
|
||||
signal sha[256] <== Sha256Bytes(max_cert_bytes)(raw_dsc_cert, raw_dsc_cert_padded_bytes);
|
||||
|
||||
var msg_len = (256+csca_mod_n)\csca_mod_n;
|
||||
var msg_len = (256+n_csca)\n_csca;
|
||||
component base_msg[msg_len];
|
||||
for (var i = 0; i < msg_len; i++) {
|
||||
base_msg[i] = Bits2Num(csca_mod_n);
|
||||
base_msg[i] = Bits2Num(n_csca);
|
||||
}
|
||||
for (var i = 0; i < 256; i++) {
|
||||
base_msg[i\csca_mod_n].in[i%csca_mod_n] <== sha[255 - i];
|
||||
base_msg[i\n_csca].in[i%n_csca] <== sha[255 - i];
|
||||
}
|
||||
for (var i = 256; i < csca_mod_n*msg_len; i++) {
|
||||
base_msg[i\csca_mod_n].in[i%csca_mod_n] <== 0;
|
||||
for (var i = 256; i < n_csca*msg_len; i++) {
|
||||
base_msg[i\n_csca].in[i%n_csca] <== 0;
|
||||
}
|
||||
|
||||
// verify RSA signature
|
||||
component rsa = RSAVerify65537(csca_mod_n, csca_mod_k);
|
||||
// verify RSA dsc_signature
|
||||
component rsa = RSAVerify65537(n_csca, k_csca);
|
||||
for (var i = 0; i < msg_len; i++) {
|
||||
rsa.base_message[i] <== base_msg[i].out;
|
||||
}
|
||||
for (var i = msg_len; i < csca_mod_k; i++) {
|
||||
for (var i = msg_len; i < k_csca; i++) {
|
||||
rsa.base_message[i] <== 0;
|
||||
}
|
||||
for (var i = 0; i < csca_mod_k; i++) {
|
||||
rsa.modulus[i] <== modulus[i];
|
||||
for (var i = 0; i < k_csca; i++) {
|
||||
rsa.modulus[i] <== csca_modulus[i];
|
||||
}
|
||||
for (var i = 0; i < csca_mod_k; i++) {
|
||||
rsa.signature[i] <== signature[i];
|
||||
for (var i = 0; i < k_csca; i++) {
|
||||
rsa.signature[i] <== dsc_signature[i];
|
||||
}
|
||||
|
||||
// verify DSC modulus
|
||||
// verify DSC csca_modulus
|
||||
component shiftLeft = VarShiftLeft(max_cert_bytes, dsc_mod_len);
|
||||
shiftLeft.in <== raw_dsc_cert;
|
||||
shiftLeft.shift <== start_index;
|
||||
|
||||
component splitBytesToWords = SplitBytesToWords(dsc_mod_len, dsc_mod_n, dsc_mod_k);
|
||||
splitBytesToWords.in <== shiftLeft.out;
|
||||
for (var i = 0; i < dsc_mod_k; i++) {
|
||||
dsc_modulus[i] === splitBytesToWords.out[i];
|
||||
component spbt_1 = SplitBytesToWords(dsc_mod_len, n_dsc, k_dsc);
|
||||
spbt_1.in <== shiftLeft.out;
|
||||
for (var i = 0; i < k_dsc; i++) {
|
||||
dsc_modulus[i] === spbt_1.out[i];
|
||||
}
|
||||
|
||||
|
||||
// generate blinded commitment
|
||||
component spbt_2 = SplitBytesToWords(dsc_mod_len, 192, 15);
|
||||
spbt_2.in <== shiftLeft.out;
|
||||
component poseidon = Poseidon(16);
|
||||
poseidon.inputs[0] <== secret;
|
||||
for (var i = 0; i < 15; i++) {
|
||||
poseidon.inputs[i+1] <== spbt_2.out[i];
|
||||
}
|
||||
blinded_csca_commitment <== poseidon.out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,20 +2,5 @@ pragma circom 2.1.6;
|
||||
|
||||
include "../../certificates/dsc.circom";
|
||||
|
||||
template dsc_2048_tester() {
|
||||
signal input raw_dsc_cert[2048];
|
||||
signal input message_padded_bytes;
|
||||
signal input modulus[17];
|
||||
signal input signature[17];
|
||||
signal input dsc_modulus[17];
|
||||
signal input start_index;
|
||||
|
||||
component dsc = DSC(2048, 121, 17, 256, 121, 17);
|
||||
dsc.raw_dsc_cert <== raw_dsc_cert;
|
||||
dsc.message_padded_bytes <== message_padded_bytes;
|
||||
dsc.modulus <== modulus;
|
||||
dsc.signature <== signature;
|
||||
dsc.dsc_modulus <== dsc_modulus;
|
||||
dsc.start_index <== start_index;
|
||||
}
|
||||
component main = dsc_2048_tester();
|
||||
component main = DSC(1664,121 ,17 ,121, 34, 256);
|
||||
|
||||
@@ -2,20 +2,4 @@ pragma circom 2.1.6;
|
||||
|
||||
include "../../certificates/dsc.circom";
|
||||
|
||||
template dsc_4096_tester() {
|
||||
signal input raw_dsc_cert[4096];
|
||||
signal input message_padded_bytes;
|
||||
signal input modulus[34];
|
||||
signal input signature[34];
|
||||
signal input dsc_modulus[17];
|
||||
signal input start_index;
|
||||
|
||||
component dsc = DSC(4096, 121, 34, 256, 121, 17);
|
||||
dsc.raw_dsc_cert <== raw_dsc_cert;
|
||||
dsc.message_padded_bytes <== message_padded_bytes;
|
||||
dsc.modulus <== modulus;
|
||||
dsc.signature <== signature;
|
||||
dsc.dsc_modulus <== dsc_modulus;
|
||||
dsc.start_index <== start_index;
|
||||
}
|
||||
component main = dsc_4096_tester();
|
||||
component main = DSC(1664,121 ,17 ,121, 34, 256);
|
||||
36
circuits/circuits/utils/splitSignalsToWords.circom
Normal file
36
circuits/circuits/utils/splitSignalsToWords.circom
Normal file
@@ -0,0 +1,36 @@
|
||||
pragma circom 2.1.5;
|
||||
include "circomlib/circuits/bitify.circom";
|
||||
|
||||
/// NOTE: this circuit is unaudited and should not be used in production
|
||||
/// @title SplitBytesToWords
|
||||
/// @notice split an array of bytes into an array of words
|
||||
/// @notice useful for casting a message or modulus before RSA verification
|
||||
/// @param l: number of bytes in the input array
|
||||
/// @param n: number of bits in a word
|
||||
/// @param k: number of words
|
||||
/// @input in: array of bytes
|
||||
/// @output out: array of words
|
||||
template SplitSignalsToWords (l,t,n,k) {
|
||||
signal input in[l];
|
||||
signal output out[k];
|
||||
component num2bits[l];
|
||||
for (var i = 0 ; i < l ; i++){
|
||||
num2bits[i] = Num2Bits(t);
|
||||
num2bits[i].in <== in[i];
|
||||
}
|
||||
component bits2num[k];
|
||||
for (var i = 0 ; i < k ; i++){
|
||||
bits2num[i] = Bits2Num(n);
|
||||
for(var j = 0 ; j < n ; j++){
|
||||
if(i*n + j >= t * l){
|
||||
bits2num[i].in[j] <== 0;
|
||||
}
|
||||
else{
|
||||
bits2num[i].in[j] <== num2bits[l - (( i * n + j) \ t) - 1].out[ ((i * n + j) % t)];
|
||||
}
|
||||
}
|
||||
}
|
||||
for( var i = 0 ; i< k ; i++){
|
||||
out[i] <== bits2num[i].out;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,9 @@ import assert from "assert";
|
||||
import { PassportData } from "../../../common/src/utils/types";
|
||||
import { hash, assembleEContent, formatAndConcatenateDataHashes, formatMrz, hexToDecimal, arraysAreEqual } from "../../../common/src/utils/utils";
|
||||
import * as forge from 'node-forge';
|
||||
import { writeFileSync } from "fs";
|
||||
import { writeFileSync, readFileSync } from "fs";
|
||||
|
||||
const dsc_key = readFileSync('../common/src/mock_certificates/sha256_rsa_4096/mock_dsc.key', 'utf8');
|
||||
|
||||
const sampleMRZ = "P<FRADUPONT<<ALPHONSE<HUGUES<ALBERT<<<<<<<<<24HB818324FRA0402111M3111115<<<<<<<<<<<<<<02"
|
||||
const sampleDataHashes = [
|
||||
@@ -43,8 +45,9 @@ export function genMockPassportData_sha256WithRSAEncryption_65537(): PassportDat
|
||||
|
||||
const eContent = assembleEContent(hash(signatureAlgorithm, concatenatedDataHashes));
|
||||
|
||||
const rsa = forge.pki.rsa;
|
||||
const privKey = rsa.generateKeyPair({ bits: 2048 }).privateKey;
|
||||
//const rsa = forge.pki.rsa;
|
||||
//const privKey = rsa.generateKeyPair({ bits: 2048 }).privateKey;
|
||||
const privKey = forge.pki.privateKeyFromPem(dsc_key);
|
||||
const modulus = privKey.n.toString(16);
|
||||
|
||||
const md = forge.md.sha256.create();
|
||||
|
||||
@@ -5,50 +5,23 @@ import path from 'path';
|
||||
const wasm_tester = require("circom_tester").wasm;
|
||||
import { splitToWords } from '../../common/src/utils/utils';
|
||||
import { sha256Pad } from '../../common/src/utils/shaPad';
|
||||
import { findStartIndex } from '../../common/src/utils/csca';
|
||||
import { findStartIndex, getCSCAInputs } from '../../common/src/utils/csca';
|
||||
|
||||
describe('DSC chain certificate', function () {
|
||||
this.timeout(0); // Disable timeout
|
||||
let circuit;
|
||||
const n = 121;
|
||||
const k = 17;
|
||||
const max_cert_bytes = 2048;
|
||||
const n_dsc = 121;
|
||||
const k_dsc = 17;
|
||||
const n_csca = 121;
|
||||
const k_csca = 34;
|
||||
const max_cert_bytes = 1664;
|
||||
const dsc = fs.readFileSync('../common/src/mock_certificates/sha256_rsa_2048/mock_dsc.crt', 'utf8');
|
||||
const csca = fs.readFileSync('../common/src/mock_certificates/sha256_rsa_2048/mock_csca.crt', 'utf8');
|
||||
const dscCert = forge.pki.certificateFromPem(dsc);
|
||||
const cscaCert = forge.pki.certificateFromPem(csca);
|
||||
|
||||
const dsc_modulus = dscCert.publicKey.n.toString(16).toLowerCase();
|
||||
|
||||
const csca_modulus = cscaCert.publicKey.n.toString(16).toLowerCase();
|
||||
const csca_modulus_number = BigInt(`0x${csca_modulus}`);
|
||||
const dsc_modulus_number = BigInt(`0x${dsc_modulus}`);
|
||||
|
||||
const dsc_signature = dscCert.signature;
|
||||
const dsc_signature_hex = forge.util.bytesToHex(dsc_signature);
|
||||
const dsc_signature_number = BigInt(`0x${dsc_signature_hex}`);
|
||||
|
||||
const csca_modulus_formatted = splitToWords(csca_modulus_number, BigInt(n), BigInt(k));
|
||||
const dsc_modulus_formatted = splitToWords(dsc_modulus_number, BigInt(n), BigInt(k));
|
||||
const dsc_signature_formatted = splitToWords(dsc_signature_number, BigInt(n), BigInt(k));
|
||||
|
||||
const dsc_tbsCertificateDer = forge.asn1.toDer(dscCert.tbsCertificate).getBytes();
|
||||
const dsc_tbsCertificateBuffer = Buffer.from(dsc_tbsCertificateDer, 'binary')
|
||||
const dsc_tbsCertificateListOfBytes = Array.from(dsc_tbsCertificateBuffer).map(byte => BigInt(byte).toString());
|
||||
const dsc_tbsCertificateUint8Array = Uint8Array.from(dsc_tbsCertificateListOfBytes.map(byte => parseInt(byte)));
|
||||
const [dsc_message_padded, dsc_messagePaddedLen] = sha256Pad(dsc_tbsCertificateUint8Array, max_cert_bytes);
|
||||
const startIndex = findStartIndex(dsc_modulus, dsc_message_padded);
|
||||
|
||||
assert(startIndex != -1, "Modulus not found in message padded");
|
||||
|
||||
const inputs = {
|
||||
raw_dsc_cert: Array.from(dsc_message_padded).map((x) => x.toString()),
|
||||
message_padded_bytes: BigInt(dsc_messagePaddedLen).toString(),
|
||||
modulus: csca_modulus_formatted,
|
||||
signature: dsc_signature_formatted,
|
||||
start_index: startIndex.toString(),
|
||||
dsc_modulus: dsc_modulus_formatted,
|
||||
}
|
||||
const inputs = getCSCAInputs(dscCert, cscaCert, n_dsc, k_dsc, n_csca, k_csca, max_cert_bytes, true);
|
||||
console.log("inputs:", inputs);
|
||||
|
||||
before(async () => {
|
||||
@@ -62,22 +35,6 @@ describe('DSC chain certificate', function () {
|
||||
);
|
||||
});
|
||||
|
||||
it('check inputs', () => {
|
||||
expect(inputs.raw_dsc_cert.length).to.equal(max_cert_bytes);
|
||||
expect(inputs.modulus.length).to.equal(k);
|
||||
expect(inputs.signature.length).to.equal(k);
|
||||
it('check modulus slices size', () => {
|
||||
inputs.modulus.forEach(slice => {
|
||||
expect(slice.length).to.equal(n);
|
||||
});
|
||||
});
|
||||
it('check signature slices size', () => {
|
||||
inputs.signature.forEach(slice => {
|
||||
expect(slice.length).to.equal(n);
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
it('should compile and load the circuit', () => {
|
||||
expect(circuit).to.not.be.undefined;
|
||||
})
|
||||
|
||||
@@ -5,50 +5,23 @@ import path from 'path';
|
||||
const wasm_tester = require("circom_tester").wasm;
|
||||
import { splitToWords } from '../../common/src/utils/utils';
|
||||
import { sha256Pad } from '../../common/src/utils/shaPad';
|
||||
import { findStartIndex } from '../../common/src/utils/csca';
|
||||
import { findStartIndex, getCSCAInputs } from '../../common/src/utils/csca';
|
||||
|
||||
describe('DSC chain certificate', function () {
|
||||
this.timeout(0); // Disable timeout
|
||||
let circuit;
|
||||
const n = 121;
|
||||
const k = 17;
|
||||
const max_cert_bytes = 4096;
|
||||
const n_dsc = 121;
|
||||
const k_dsc = 17;
|
||||
const n_csca = 121;
|
||||
const k_csca = 34;
|
||||
const max_cert_bytes = 1664;
|
||||
const dsc = fs.readFileSync('../common/src/mock_certificates/sha256_rsa_4096/mock_dsc.crt', 'utf8');
|
||||
const csca = fs.readFileSync('../common/src/mock_certificates/sha256_rsa_4096/mock_csca.crt', 'utf8');
|
||||
const dscCert = forge.pki.certificateFromPem(dsc);
|
||||
const cscaCert = forge.pki.certificateFromPem(csca);
|
||||
|
||||
const dsc_modulus = dscCert.publicKey.n.toString(16).toLowerCase();
|
||||
|
||||
const csca_modulus = cscaCert.publicKey.n.toString(16).toLowerCase();
|
||||
const csca_modulus_number = BigInt(`0x${csca_modulus}`);
|
||||
const dsc_modulus_number = BigInt(`0x${dsc_modulus}`);
|
||||
|
||||
const dsc_signature = dscCert.signature;
|
||||
const dsc_signature_hex = forge.util.bytesToHex(dsc_signature);
|
||||
const dsc_signature_number = BigInt(`0x${dsc_signature_hex}`);
|
||||
|
||||
const csca_modulus_formatted = splitToWords(csca_modulus_number, BigInt(n), BigInt(2 * k));
|
||||
const dsc_modulus_formatted = splitToWords(dsc_modulus_number, BigInt(n), BigInt(k));
|
||||
const dsc_signature_formatted = splitToWords(dsc_signature_number, BigInt(n), BigInt(2 * k));
|
||||
|
||||
const dsc_tbsCertificateDer = forge.asn1.toDer(dscCert.tbsCertificate).getBytes();
|
||||
const dsc_tbsCertificateBuffer = Buffer.from(dsc_tbsCertificateDer, 'binary')
|
||||
const dsc_tbsCertificateListOfBytes = Array.from(dsc_tbsCertificateBuffer).map(byte => BigInt(byte).toString());
|
||||
const dsc_tbsCertificateUint8Array = Uint8Array.from(dsc_tbsCertificateListOfBytes.map(byte => parseInt(byte)));
|
||||
const [dsc_message_padded, dsc_messagePaddedLen] = sha256Pad(dsc_tbsCertificateUint8Array, max_cert_bytes);
|
||||
const startIndex = findStartIndex(dsc_modulus, dsc_message_padded);
|
||||
|
||||
assert(startIndex != -1, "Modulus not found in message padded");
|
||||
|
||||
const inputs = {
|
||||
raw_dsc_cert: Array.from(dsc_message_padded).map((x) => x.toString()),
|
||||
message_padded_bytes: BigInt(dsc_messagePaddedLen).toString(),
|
||||
modulus: csca_modulus_formatted,
|
||||
signature: dsc_signature_formatted,
|
||||
start_index: startIndex.toString(),
|
||||
dsc_modulus: dsc_modulus_formatted,
|
||||
}
|
||||
const inputs = getCSCAInputs(dscCert, cscaCert, n_dsc, k_dsc, n_csca, k_csca, max_cert_bytes, true);
|
||||
console.log("inputs:", inputs);
|
||||
|
||||
before(async () => {
|
||||
@@ -62,22 +35,6 @@ describe('DSC chain certificate', function () {
|
||||
);
|
||||
});
|
||||
|
||||
it('check inputs', () => {
|
||||
expect(inputs.raw_dsc_cert.length).to.equal(max_cert_bytes);
|
||||
expect(inputs.modulus.length).to.equal(2 * k);
|
||||
expect(inputs.signature.length).to.equal(2 * k);
|
||||
it('check modulus slices size', () => {
|
||||
inputs.modulus.forEach(slice => {
|
||||
expect(slice.length).to.equal(n);
|
||||
});
|
||||
});
|
||||
it('check signature slices size', () => {
|
||||
inputs.signature.forEach(slice => {
|
||||
expect(slice.length).to.equal(n);
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
it('should compile and load the circuit', () => {
|
||||
expect(circuit).to.not.be.undefined;
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user