Merge branch 'dev' of https://github.com/zk-passport/openpassport into feat/register-disclose

This commit is contained in:
turnoffthiscomputer
2025-01-17 16:53:24 +01:00
167 changed files with 4800 additions and 102964 deletions

3
circuits/.gitignore vendored
View File

@@ -1,4 +1,5 @@
inputs
build
node_modules/
err.log
err.log
.env

View File

@@ -26,7 +26,7 @@ template VC_AND_DISCLOSE( nLevels,FORBIDDEN_COUNTRIES_LIST_LENGTH) {
signal input user_identifier;
// ofac check
signal input smt_leaf_value;
signal input smt_leaf_key;
signal input smt_root;
signal input smt_siblings[256];
signal input selector_ofac;
@@ -45,9 +45,9 @@ template VC_AND_DISCLOSE( nLevels,FORBIDDEN_COUNTRIES_LIST_LENGTH) {
disclose.majority <== majority;
// generate scope nullifier
component poseidon_nullifier = PoseidonHash(2);
poseidon_nullifier.in[0] <== secret;
poseidon_nullifier.in[1] <== scope;
component poseidon_nullifier = Poseidon(2);
poseidon_nullifier.inputs[0] <== secret;
poseidon_nullifier.inputs[1] <== scope;
signal output nullifier <== poseidon_nullifier.out;
signal output revealedData_packed[3] <== disclose.revealedData_packed;
signal output older_than[2] <== disclose.older_than;
@@ -56,7 +56,7 @@ template VC_AND_DISCLOSE( nLevels,FORBIDDEN_COUNTRIES_LIST_LENGTH) {
signal output forbidden_countries_list_packed_disclosed[2] <== ProveCountryIsNotInList(FORBIDDEN_COUNTRIES_LIST_LENGTH)(dg1, forbidden_countries_list);
// OFAC
signal ofacCheckResult <== OFAC_NAME()(dg1,smt_leaf_value,smt_root,smt_siblings);
signal ofacCheckResult <== OFAC_NAME()(dg1,smt_leaf_key,smt_root,smt_siblings);
signal ofacIntermediaryOutput <== ofacCheckResult * selector_ofac;
signal output ofac_result <== ofacIntermediaryOutput;
}

View File

@@ -1,10 +1,11 @@
pragma circom 2.1.9;
include "circomlib/circuits/bitify.circom";
include "../utils/circomlib/hasher/shaBytes/shaBytesDynamic.circom";
include "../utils/crypto/hasher/shaBytes/shaBytesDynamic.circom";
include "circomlib/circuits/comparators.circom";
include "../utils/circomlib/hasher/hash.circom";
include "../utils/circomlib/merkle-trees/binary-merkle-root.circom";
include "../utils/crypto/hasher/hash.circom";
include "circomlib/circuits/poseidon.circom";
include "@zk-kit/binary-merkle-root.circom/src/binary-merkle-root.circom";
include "../utils/passport/customHashers.circom";
include "../utils/passport/signatureAlgorithm.circom";
include "../utils/passport/signatureVerifier.circom";
@@ -58,6 +59,6 @@ template DSC(signatureAlgorithm, n_dsc, k_dsc, n_csca, k_csca, max_cert_bytes, d
// blinded dsc commitment
signal pubkeyHash <== CustomHasher(k_dsc)(dsc_pubKey);
signal output blinded_dsc_commitment <== PoseidonHash(2)([secret, pubkeyHash]);
signal output blinded_dsc_commitment <== Poseidon(2)([secret, pubkeyHash]);
}

View File

@@ -0,0 +1,5 @@
pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(160, 160 , 11, 120, 35, 320, 128, 20);

View File

@@ -0,0 +1,5 @@
pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(160, 256 , 10, 120, 35, 320, 128, 20);

View File

@@ -0,0 +1,5 @@
pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(256, 256, 13, 64, 32, 320, 128, 20);

View File

@@ -0,0 +1,5 @@
pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date ] } = OPENPASSPORT_PROVE(256, 256, 32, 120, 35, 448, 128, 20);

View File

@@ -0,0 +1,5 @@
pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(256, 256 , 1, 64, 32, 320, 128, 20);

View File

@@ -0,0 +1,5 @@
pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(256 ,256, 10, 120, 35, 448, 128, 20);

View File

@@ -0,0 +1,5 @@
pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(512, 512, 15, 64, 32, 768, 256, 20);

View File

@@ -0,0 +1,5 @@
pragma circom 2.1.9;
include "../openpassport_prove.circom";
component main { public [ scope, user_identifier, current_date] } = OPENPASSPORT_PROVE(512, 512, 31, 120, 35, 768, 256, 20);

View File

@@ -0,0 +1,164 @@
pragma circom 2.1.9;
include "../utils/passport/customHashers.circom";
include "../utils/passport/computeCommitment.circom";
include "../utils/passport/signatureAlgorithm.circom";
include "../utils/passport/date/isValid.circom";
include "circomlib/circuits/poseidon.circom";
include "../utils/passport/passportVerifier.circom";
include "../utils/passport/disclose/disclose.circom";
include "../utils/passport/disclose/proveCountryIsNotInList.circom";
include "../utils/passport/ofac/ofac_name.circom";
/// @title OPENPASSPORT_PROVE
/// @notice Main circuit to verify passport data and be used to several purposes to enable passport
/// @dev Handles passport verification, OFAC checks, selective disclosure, and commitment generation
/// @param DG_HASH_ALGO Hash algorithm used for DG (Document Group) hashing
/// @param ECONTENT_HASH_ALGO Hash algorithm used for eContent
/// @param signatureAlgorithm Algorithm used for passport signature verification
/// @param n Number of bits per chunk the key is split into.
/// @param k Number of chunks the key is split into.
/// @param MAX_ECONTENT_PADDED_LEN Maximum length of padded eContent
/// @param MAX_SIGNED_ATTR_PADDED_LEN Maximum length of padded signed attributes
/// @param FORBIDDEN_COUNTRIES_LIST_LENGTH Length of the forbidden countries list
/// @input dg1 Document Group 1 data (93 bytes)
/// @input dg1_hash_offset Offset for DG1 hash
/// @input dg2_hash Document Group 2 hash (64 bytes)
/// @input eContent eContent data
/// @input eContent_padded_length Padded length of eContent
/// @input signed_attr Signed attributes data
/// @input signed_attr_padded_length Padded length of signed attributes
/// @input signed_attr_econtent_hash_offset Offset for eContent hash in signed attributes
/// @input pubKey Public key for signature verification
/// @input signature Passport signature
/// @input selector_mode Mode selectors for different operations
/// @input smt_leaf_value SMT leaf value for OFAC check
/// @input smt_root SMT root for OFAC check
/// @input smt_siblings SMT siblings for OFAC check
/// @input selector_ofac Selector for OFAC check
/// @input forbidden_countries_list List of forbidden countries
/// @input selector_dg1 Selectors for DG1 disclosure
/// @input selector_older_than Selector for age verification
/// @input current_date Current date for age verification
/// @input majority Majority age threshold
/// @input user_identifier User identifier for commitment
/// @input scope Scope for nullifier
/// @input secret Secret for commitment generation. Supposed to be saved by the user to access this commitment.
/// @input dsc_secret One time secret data to generate the blinded commitment. This blinded dsc commitment is used to find the link between a proof from this circuit and a proof from the dsc circuit.
/// @output nullifier Generated nullifier
/// @output revealedData_packed Selectively disclosed data in the passport
/// @output older_than Age verification result
/// @output pubKey_disclosed Disclosed public key
/// @output forbidden_countries_list_packed_disclosed Packed forbidden countries list
/// @output ofac_result OFAC check result
/// @output commitment Unique commitment for the passport data and their secret
/// @output blinded_dsc_commitment To find the link between a proof from this circuit and a proof from the dsc circuit.
template OPENPASSPORT_PROVE(DG_HASH_ALGO, ECONTENT_HASH_ALGO, signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN, FORBIDDEN_COUNTRIES_LIST_LENGTH) {
var kLengthFactor = getKLengthFactor(signatureAlgorithm);
var kScaled = k * kLengthFactor;
var HASH_LEN_BITS = getHashLength(signatureAlgorithm);
var HASH_LEN_BYTES = HASH_LEN_BITS / 8;
signal input dg1[93];
signal input dg1_hash_offset;
signal input dg2_hash[64];
signal input eContent[MAX_ECONTENT_PADDED_LEN];
signal input eContent_padded_length;
signal input signed_attr[MAX_SIGNED_ATTR_PADDED_LEN];
signal input signed_attr_padded_length;
signal input signed_attr_econtent_hash_offset;
signal input pubKey[kScaled];
signal input signature[kScaled];
signal input selector_mode[2];
// ofac check
signal input smt_leaf_key;
signal input smt_root;
signal input smt_siblings[256];
signal input selector_ofac;
// forbidden countries list
signal input forbidden_countries_list[FORBIDDEN_COUNTRIES_LIST_LENGTH * 3];
// disclose related inputs
signal input selector_dg1[88];
signal input selector_older_than;
signal input current_date[6]; // YYMMDD - num
signal input majority[2]; // YY - ASCII
signal input user_identifier;
signal input scope;
// registration related inputs
signal input secret;
signal input dsc_secret;
signal attestation_id <== 1;
signal selectorModeDisclosure <== selector_mode[0];
signal selectorModePubKey <== selector_mode[1];
signal selectorModeBlindedDscCommitment <== 1 - selector_mode[1];
signal selectorModeCommitment <== (1- selector_mode[0]) * (1 - selector_mode[1]);
signal isWrongSelectorMode <== IsEqual()([2*selector_mode[0] + selector_mode[1], 1]);
isWrongSelectorMode === 0;
// verify passport signature
signal signedAttrShaBytes[HASH_LEN_BYTES] <== PassportVerifier(DG_HASH_ALGO, ECONTENT_HASH_ALGO, signatureAlgorithm, n, k, MAX_ECONTENT_PADDED_LEN, MAX_SIGNED_ATTR_PADDED_LEN)(dg1,dg1_hash_offset, dg2_hash, eContent,eContent_padded_length, signed_attr, signed_attr_padded_length, signed_attr_econtent_hash_offset, pubKey, signature);
// verify passport is not expired
component isValid = IsValid();
isValid.currDate <== current_date;
for (var i = 0; i < 6; i++) {
isValid.validityDateASCII[i] <== dg1[70 + i];
}
// nulifier
component passportDataHashed = CustomHasher(HASH_LEN_BYTES);
passportDataHashed.in <== signedAttrShaBytes;
component poseidon_hasher = Poseidon(2);
poseidon_hasher.inputs[0] <== passportDataHashed.out;
poseidon_hasher.inputs[1] <== scope;
signal output nullifier <== poseidon_hasher.out;
// DISCLOSE (optional)
// optionally disclose data
component disclose = DISCLOSE();
disclose.dg1 <== dg1;
disclose.selector_dg1 <== selector_dg1;
disclose.selector_older_than <== selector_older_than;
disclose.current_date <== current_date;
disclose.majority <== majority;
signal output revealedData_packed[3];
for (var i = 0; i < 3; i++) {
revealedData_packed[i] <== disclose.revealedData_packed[i] * selectorModeDisclosure;
}
signal output older_than[2];
for (var i = 0; i < 2; i++) {
older_than[i] <== disclose.older_than[i] * selectorModeDisclosure;
}
signal output pubKey_disclosed[kScaled];
for (var i = 0; i < kScaled; i++) {
pubKey_disclosed[i] <== pubKey[i] * selectorModePubKey;
}
// COUNTRY IS IN LIST
signal forbidden_countries_list_packed[2] <== ProveCountryIsNotInList(FORBIDDEN_COUNTRIES_LIST_LENGTH)(dg1, forbidden_countries_list);
signal output forbidden_countries_list_packed_disclosed[2];
for (var i = 0; i < 2; i++) {
forbidden_countries_list_packed_disclosed[i] <== forbidden_countries_list_packed[i] * selectorModeDisclosure;
}
// OFAC
signal ofacCheckResult <== OFAC_NAME()(dg1,smt_leaf_key,smt_root,smt_siblings);
signal ofacIntermediaryOutput <== ofacCheckResult * selector_ofac;
signal output ofac_result <== ofacIntermediaryOutput;
// // REGISTRATION (optional)
// // generate the commitment
signal leaf <== LeafHasher(kScaled)(pubKey, signatureAlgorithm);
signal commitmentPrivate <== ComputeCommitment()(secret, attestation_id, leaf, dg1, dg2_hash);
signal output commitment <== commitmentPrivate * selectorModeCommitment;
// // blinded dsc commitment
signal pubkeyHash <== CustomHasher(kScaled)(pubKey);
signal blindedDscCommitmenPrivate <== Poseidon(2)([dsc_secret, pubkeyHash]);
signal output blinded_dsc_commitment <== blindedDscCommitmenPrivate * selectorModeBlindedDscCommitment;
}

View File

@@ -0,0 +1,13 @@
pragma circom 2.1.9;
include "../../../utils/crypto/signature/ecdsa/ecdsaVerifier.circom";
template VerifyBrainpoolP224r1Sha160() {
signal input signature[2 * 7];
signal input pubKey[2 * 7];
signal input hashParsed[160];
EcdsaVerifier(27, 32, 7)(signature, pubKey, hashParsed);
}
component main = VerifyBrainpoolP224r1Sha160();

View File

@@ -0,0 +1,13 @@
pragma circom 2.1.9;
include "../../../utils/crypto/signature/ecdsa/ecdsaVerifier.circom";
template VerifyBrainpoolP256r1Sha512() {
signal input signature[2 * 4];
signal input pubKey[2 * 4];
signal input hashParsed[512];
EcdsaVerifier(25, 64, 4)(signature, pubKey, hashParsed);
}
component main = VerifyBrainpoolP256r1Sha512();

View File

@@ -0,0 +1,13 @@
pragma circom 2.1.9;
include "../../../utils/crypto/signature/ecdsa/ecdsaVerifier.circom";
template VerifyBrainpoolP384r1Sha384() {
signal input signature[2 * 6];
signal input pubKey[2 * 6];
signal input hashParsed[384];
EcdsaVerifier(22, 64, 6)(signature, pubKey, hashParsed);
}
component main = VerifyBrainpoolP384r1Sha384();

View File

@@ -1,6 +1,6 @@
pragma circom 2.1.9;
include "../../../utils/circomlib/signature/rsa/verifyRsa65537Pkcs1v1_5.circom";
include "../../../utils/crypto/signature/rsa/verifyRsa65537Pkcs1v1_5.circom";
template VerifyRsaPkcs1v1_5Tester() {
signal input signature[35];

View File

@@ -0,0 +1,13 @@
pragma circom 2.1.9;
include "../../../utils/crypto/signature/rsa/verifyRsa65537Pkcs1v1_5.circom";
template VerifyRsaPkcs1v1_5Tester() {
signal input signature[35];
signal input modulus[35];
signal input message[35];
VerifyRsa65537Pkcs1v1_5(120,35,224)(signature, modulus, message);
}
component main = VerifyRsaPkcs1v1_5Tester();

View File

@@ -1,6 +1,6 @@
pragma circom 2.1.9;
include "../../../utils/circomlib/signature/rsa/verifyRsa3Pkcs1v1_5.circom";
include "../../../utils/crypto/signature/rsa/verifyRsa3Pkcs1v1_5.circom";
template VerifyRsaPkcs1v1_5Tester() {
signal input signature[35];

View File

@@ -1,6 +1,6 @@
pragma circom 2.1.9;
include "../../../utils/circomlib/signature/rsa/verifyRsa65537Pkcs1v1_5.circom";
include "../../../utils/crypto/signature/rsa/verifyRsa65537Pkcs1v1_5.circom";
template VerifyRsaPkcs1v1_5Tester() {
signal input signature[35];

View File

@@ -1,6 +1,6 @@
pragma circom 2.1.9;
include "../../../utils/circomlib/signature/rsa/verifyRsa65537Pkcs1v1_5.circom";
include "../../../utils/crypto/signature/rsa/verifyRsa65537Pkcs1v1_5.circom";
template VerifyRsaPkcs1v1_5Tester() {
signal input signature[35];

View File

@@ -1,6 +1,6 @@
pragma circom 2.1.9;
include "../../../utils/circomlib/signature/rsa/verifyRsa65537Pkcs1v1_5.circom";
include "../../../utils/crypto/signature/rsa/verifyRsa65537Pkcs1v1_5.circom";
template VerifyRsaPkcs1v1_5Tester() {
signal input signature[35];

View File

@@ -1,6 +1,6 @@
pragma circom 2.1.9;
include "../../../utils/circomlib/signature/rsa/verifyRsa65537Pkcs1v1_5.circom";
include "../../../utils/crypto/signature/rsa/verifyRsa65537Pkcs1v1_5.circom";
template VerifyRsaPkcs1v1_5Tester() {
signal input signature[35];

View File

@@ -0,0 +1,12 @@
pragma circom 2.1.9;
include "../../../utils/crypto/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/crypto/signature/rsapss/rsapss3.circom";
template VerifyRsaPss3Sig_tester() {
signal input modulus[35];
signal input signature[35];
signal input message[256];
VerifyRsaPss3Sig(120, 35, 64, 256, 2048)(modulus,signature,message);
}
component main = VerifyRsaPss3Sig_tester();

View File

@@ -0,0 +1,12 @@
pragma circom 2.1.9;
include "../../../utils/crypto/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/crypto/signature/rsapss/rsapss3.circom";
template VerifyRsaPss3Sig_tester() {
signal input modulus[35];
signal input signature[35];
signal input message[256];
VerifyRsaPss3Sig(120, 35, 64, 256, 3072)(modulus,signature,message);
}
component main = VerifyRsaPss3Sig_tester();

View File

@@ -0,0 +1,12 @@
pragma circom 2.1.9;
include "../../../utils/crypto/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/crypto/signature/rsapss/rsapss3.circom";
template VerifyRsaPss3Sig_tester() {
signal input modulus[35];
signal input signature[35];
signal input message[256];
VerifyRsaPss3Sig(120, 35, 64, 256, 4096)(modulus,signature,message);
}
component main = VerifyRsaPss3Sig_tester();

View File

@@ -0,0 +1,12 @@
pragma circom 2.1.9;
include "../../../utils/crypto/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/crypto/signature/rsapss/rsapss65537.circom";
template VerifyRsaPss65537Sig_tester() {
signal input modulus[35];
signal input signature[35];
signal input message[256];
VerifyRsaPss65537Sig(120, 35, 64, 256, 2048)(modulus,signature,message);
}
component main = VerifyRsaPss65537Sig_tester();

View File

@@ -0,0 +1,12 @@
pragma circom 2.1.9;
include "../../../utils/crypto/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/crypto/signature/rsapss/rsapss65537.circom";
template VerifyRsaPss65537Sig_tester() {
signal input modulus[35];
signal input signature[35];
signal input message[256];
VerifyRsaPss65537Sig(120, 35, 64, 256, 3072)(modulus,signature,message);
}
component main = VerifyRsaPss65537Sig_tester();

View File

@@ -0,0 +1,12 @@
pragma circom 2.1.9;
include "../../../utils/crypto/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/crypto/signature/rsapss/rsapss65537.circom";
template VerifyRsaPss65537Sig_tester() {
signal input modulus[35];
signal input signature[35];
signal input message[256];
VerifyRsaPss65537Sig(120, 35, 64, 256, 4096)(modulus,signature,message);
}
component main = VerifyRsaPss65537Sig_tester();

View File

@@ -0,0 +1,12 @@
pragma circom 2.1.9;
include "../../../utils/crypto/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/crypto/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/crypto/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/crypto/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/crypto/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/crypto/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();

File diff suppressed because it is too large Load Diff

View File

@@ -1,49 +0,0 @@
pragma circom 2.1.6;
// Calculates 2 numbers with CHUNK_NUMBER multiplication using karatsuba method
// out is overflowed
// use only for 2 ** k CHUNK_NUMBER, othewise u will get error
// here is no check for CHUNK_SIZE <= 126, maybe will be added later
template KaratsubaNoCarry(CHUNK_NUMBER) {
signal input in[2][CHUNK_NUMBER];
signal output out[2 * CHUNK_NUMBER];
if (CHUNK_NUMBER == 1) {
out[0] <== in[0][0] * in[1][0];
} else {
component karatsubaA1B1 = KaratsubaNoCarry(CHUNK_NUMBER / 2);
component karatsubaA2B2 = KaratsubaNoCarry(CHUNK_NUMBER / 2);
component karatsubaA1A2B1B2 = KaratsubaNoCarry(CHUNK_NUMBER / 2);
for (var i = 0; i < CHUNK_NUMBER / 2; i++) {
karatsubaA1B1.in[0][i] <== in[0][i];
karatsubaA1B1.in[1][i] <== in[1][i];
karatsubaA2B2.in[0][i] <== in[0][i + CHUNK_NUMBER / 2];
karatsubaA2B2.in[1][i] <== in[1][i + CHUNK_NUMBER / 2];
karatsubaA1A2B1B2.in[0][i] <== in[0][i] + in[0][i + CHUNK_NUMBER / 2];
karatsubaA1A2B1B2.in[1][i] <== in[1][i] + in[1][i + CHUNK_NUMBER / 2];
}
for (var i = 0; i < 2 * CHUNK_NUMBER; i++) {
if (i < CHUNK_NUMBER) {
if (CHUNK_NUMBER / 2 <= i && i < 3 * (CHUNK_NUMBER / 2)) {
out[i] <== karatsubaA1B1.out[i]
+ karatsubaA1A2B1B2.out[i - CHUNK_NUMBER / 2]
- karatsubaA1B1.out[i - CHUNK_NUMBER / 2]
- karatsubaA2B2.out[i - CHUNK_NUMBER / 2];
} else {
out[i] <== karatsubaA1B1.out[i];
}
} else {
if (CHUNK_NUMBER / 2 <= i && i < 3 * (CHUNK_NUMBER / 2)) {
out[i] <== karatsubaA2B2.out[i - CHUNK_NUMBER]
+ karatsubaA1A2B1B2.out[i - CHUNK_NUMBER / 2]
- karatsubaA1B1.out[i - CHUNK_NUMBER / 2]
- karatsubaA2B2.out[i - CHUNK_NUMBER / 2];
} else {
out[i] <== karatsubaA2B2.out[i - CHUNK_NUMBER];
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,216 +0,0 @@
pragma circom 2.1.6;
include "./poseidonConstants.circom";
include "../../int/arithmetic.circom";
// Poseidon hash for less than 16 inputs
//--------------------------------------------------------------------------------------------------------------------------------------------------------
// Next templates are helpers, don`t use them not in poseidon hash without understanding what are u doing!
// Use Poseidon() below to get poseidon hash!
template Sigma() {
signal input in;
signal output out;
signal in2;
signal in4;
in2 <== in * in;
in4 <== in2 * in2;
out <== in4 * in;
}
template Ark(t, C, r) {
signal input in[t];
signal output out[t];
for (var i = 0; i < t; i++) {
out[i] <== in[i] + C[i + r];
}
}
template Mix(t, M) {
signal input in[t];
signal output out[t];
component sum[t];
for (var i = 0; i < t; i++) {
sum[i] = GetSumOfNElements(t);
for (var j = 0; j < t; j++) {
sum[i].in[j] <== M[j][i] * in[j];
}
out[i] <== sum[i].out;
}
}
template MixLast(t, M, s) {
signal input in[t];
signal output out;
component sum = GetSumOfNElements(t);
for (var j = 0; j < t; j++) {
sum.in[j] <== M[j][s] * in[j];
}
out <== sum.out;
}
template MixS(t, S, r) {
signal input in[t];
signal output out[t];
component sum = GetSumOfNElements(t);
for (var i = 0; i < t; i++) {
sum.in[i] <== S[(t * 2 - 1) * r + i] * in[i];
}
out[0] <== sum.out;
for (var i = 1; i < t; i++) {
out[i] <== in[i] + in[0] * S[(t * 2 - 1) * r + t + i - 1];
}
}
template PoseidonEx(nInputs, nOuts) {
signal input inputs[nInputs];
signal input initialState;
signal output out[nOuts];
var N_ROUNDS_P[16] = [56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68];
var t = nInputs + 1;
var nRoundsF = 8;
var nRoundsP = N_ROUNDS_P[t - 2];
var C[t * nRoundsF + nRoundsP] = POSEIDON_C(t);
var S[ N_ROUNDS_P[t - 2] * (t * 2 - 1) ] = POSEIDON_S(t);
var M[t][t] = POSEIDON_M(t);
var P[t][t] = POSEIDON_P(t);
component ark[nRoundsF];
component sigmaF[nRoundsF][t];
component sigmaP[nRoundsP];
component mix[nRoundsF - 1];
component mixS[nRoundsP];
component mixLast[nOuts];
ark[0] = Ark(t, C, 0);
for (var j = 0; j < t; j++) {
if (j > 0) {
ark[0].in[j] <== inputs[j - 1];
} else {
ark[0].in[j] <== initialState;
}
}
for (var r = 0; r < nRoundsF \ 2 - 1; r++) {
for (var j = 0; j < t; j++) {
sigmaF[r][j] = Sigma();
if (r == 0) {
sigmaF[r][j].in <== ark[0].out[j];
} else {
sigmaF[r][j].in <== mix[r - 1].out[j];
}
}
ark[r + 1] = Ark(t, C, (r + 1) * t);
for (var j = 0; j < t; j++) {
ark[r + 1].in[j] <== sigmaF[r][j].out;
}
mix[r] = Mix(t,M);
for (var j = 0; j < t; j++) {
mix[r].in[j] <== ark[r + 1].out[j];
}
}
for (var j = 0; j < t; j++) {
sigmaF[nRoundsF \ 2 - 1][j] = Sigma();
sigmaF[nRoundsF \ 2 - 1][j].in <== mix[nRoundsF \ 2 - 2].out[j];
}
ark[nRoundsF \ 2] = Ark(t, C, (nRoundsF \ 2) * t);
for (var j = 0; j < t; j++) {
ark[nRoundsF \ 2].in[j] <== sigmaF[nRoundsF \ 2 - 1][j].out;
}
mix[nRoundsF \ 2 - 1] = Mix(t,P);
for (var j = 0; j < t; j++) {
mix[nRoundsF \ 2 - 1].in[j] <== ark[nRoundsF \ 2].out[j];
}
for (var r = 0; r < nRoundsP; r++) {
sigmaP[r] = Sigma();
if (r == 0) {
sigmaP[r].in <== mix[nRoundsF \ 2 - 1].out[0];
} else {
sigmaP[r].in <== mixS[r - 1].out[0];
}
mixS[r] = MixS(t, S, r);
for (var j = 0; j < t; j++) {
if (j == 0) {
mixS[r].in[j] <== sigmaP[r].out + C[(nRoundsF \ 2 + 1) * t + r];
} else {
if (r == 0) {
mixS[r].in[j] <== mix[nRoundsF \ 2 - 1].out[j];
} else {
mixS[r].in[j] <== mixS[r - 1].out[j];
}
}
}
}
for (var r = 0; r < nRoundsF \ 2 - 1; r++) {
for (var j = 0; j < t; j++) {
sigmaF[nRoundsF \ 2 + r][j] = Sigma();
if (r == 0) {
sigmaF[nRoundsF \ 2 + r][j].in <== mixS[nRoundsP - 1].out[j];
} else {
sigmaF[nRoundsF \ 2 + r][j].in <== mix[nRoundsF \ 2 + r - 1].out[j];
}
}
ark[ nRoundsF \ 2 + r + 1] = Ark(t, C, (nRoundsF \ 2 + 1) * t + nRoundsP + r * t);
for (var j = 0; j < t; j++) {
ark[nRoundsF \ 2 + r + 1].in[j] <== sigmaF[nRoundsF \ 2 + r][j].out;
}
mix[nRoundsF \ 2 + r] = Mix(t,M);
for (var j = 0; j < t; j++) {
mix[nRoundsF \ 2 + r].in[j] <== ark[nRoundsF \ 2 + r + 1].out[j];
}
}
for (var j = 0; j < t; j++) {
sigmaF[nRoundsF - 1][j] = Sigma();
sigmaF[nRoundsF - 1][j].in <== mix[nRoundsF - 2].out[j];
}
for (var i = 0; i < nOuts; i++) {
mixLast[i] = MixLast(t,M,i);
for (var j = 0; j < t; j++) {
mixLast[i].in[j] <== sigmaF[nRoundsF - 1][j].out;
}
out[i] <== mixLast[i].out;
}
}
//--------------------------------------------------------------------------------------------------------------------------------------------------------
// Secured version of Poseidon hash circomlib implementation
// Use this template to calculate to calculate Poseidon hash of your vector (1 elememnt array for one num)
template Poseidon(nInputs) {
signal input in[nInputs];
signal output out;
component pEx = PoseidonEx(nInputs, 1);
pEx.initialState <== 0;
for (var i = 0; i < nInputs; i++) {
pEx.inputs[i] <== in[i];
}
out <== pEx.out[0];
}

View File

@@ -1,45 +0,0 @@
pragma circom 2.1.6;
include "../../circomlib/hasher/hash.circom";
include "circomlib/circuits/comparators.circom";
include "../../circomlib/mux/mux1.circom";
// This circuit is designed to calculate the root of a binary Merkle
// tree given a leaf, its depth, and the necessary sibling
// information (aka proof of membership).
// A circuit is designed without the capability to iterate through
// a dynamic array. To address this, a parameter with the static maximum
// tree depth is defined (i.e. 'MAX_DEPTH'). And additionally, the circuit
// receives a dynamic depth as an input, which is utilized in calculating the
// true root of the Merkle tree. The actual depth of the Merkle tree
// may be equal to or less than the static maximum depth.
// NOTE: This circuit will successfully verify `out = 0` for `depth > MAX_DEPTH`.
// Make sure to enforce `depth <= MAX_DEPTH` outside the circuit.
template BinaryMerkleRoot(MAX_DEPTH) {
signal input leaf, depth, indices[MAX_DEPTH], siblings[MAX_DEPTH];
signal output out;
signal nodes[MAX_DEPTH + 1];
nodes[0] <== leaf;
signal roots[MAX_DEPTH];
var root = 0;
for (var i = 0; i < MAX_DEPTH; i++) {
var isDepth = IsEqual()([depth, i]);
roots[i] <== isDepth * nodes[i];
root += roots[i];
var c[2][2] = [ [nodes[i], siblings[i]], [siblings[i], nodes[i]] ];
var childNodes[2] = MultiMux1(2)(c, indices[i]);
nodes[i + 1] <== PoseidonHash(2)(childNodes);
}
var isDepth = IsEqual()([depth, MAX_DEPTH]);
out <== root + isDepth * nodes[MAX_DEPTH];
}

View File

@@ -1,66 +0,0 @@
pragma circom 2.1.9;
include "circomlib/circuits/comparators.circom";
include "circomlib/circuits/bitify.circom";
// Computes the first n common bits of the hashes
template CommonBitsLengthFromEnd() {
signal input bits1[256];
signal input bits2[256];
signal output out;
component iseq[256];
signal pop[256];
pop[255] <== IsEqual()([bits1[255], bits2[255]]);
for (var i = 254; i >= 0; i--) {
var temp = bits2[i] - bits1[i];
iseq[i] = IsEqual();
bits1[i] ==> iseq[i].in[0];
bits2[i] ==> iseq[i].in[1];
pop[i] <== iseq[i].out*pop[i+1];
}
var added = 0;
for(var i = 0; i<256;i++){
added += pop[i];
}
added ==> out;
}
// Computes length of an array when array is padded with 0;s from end and the last element after which padding starts is not 0, 0's might come in between.
template SiblingsLength() {
signal input siblings[256];
signal output length;
// Siblings can be like (1,2,3,0,0,4,5,0,0...all 0 till 256[the padded 0 ones])
// We need to get the length , i.e 7 in this case
var foo[256];
for(var i = 0; i<256; i++){
foo[i] = 0;
}
foo[255] = siblings[255];
for(var i = 256-2; i>=0; i--){
foo[i] = siblings[i] + foo[i+1];
}
// convert to (15,14,12,9,9,9,5,0,0,0..), this takes out the middle 0's
var total = 0;
signal pop[256];
component iszero[256];
for(var i = 0; i<256; i++){
iszero[i] = IsZero();
foo[i] ==> iszero[i].in;
pop[i] <== iszero[i].out;
}
for(var i = 0; i<256; i++){
total += pop[i];
}
256-total ==> length;
}

View File

@@ -1,49 +0,0 @@
pragma circom 2.1.9;
include "../hasher/hash.circom";
include "circomlib/circuits/comparators.circom";
include "circomlib/circuits/bitify.circom";
include "@zk-email/circuits/utils/array.circom";
include "binary-merkle-root.circom";
include "getCommonLength.circom";
template SMTVerify(nLength) {
signal input virtualValue; // value from user's data
signal input value; // value included in the tree
signal input root;
signal input siblings[nLength];
signal input mode; // 0 for non inclusion, 1 for inclusion
signal depth <== SiblingsLength()(siblings);
// Calulate the path
signal path[nLength];
signal path_in_bits_reversed[nLength] <== Num2Bits(256)(virtualValue);
var path_in_bits[nLength];
for (var i = 0; i < nLength; i++) {
path_in_bits[i] = path_in_bits_reversed[nLength-1-i];
}
// Shift the path to the left by depth to make it compatible for BinaryMerkleRoot function
component ct1 = VarShiftLeft(nLength,nLength);
ct1.in <== path_in_bits;
ct1.shift <== (nLength-depth);
path <== ct1.out;
// Closest_key to leaf
signal leaf <== PoseidonHash(3)([value, 1, 1]); // compute the leaf from the value
signal isClosestZero <== IsEqual()([value,0]); // check if the inital value is 0, in that case the leaf will be 0 too, not Hash(0,1,1);
signal leafOrZero <== leaf * (1 - isClosestZero);
// Verification
signal computedRoot <== BinaryMerkleRoot(nLength)(leafOrZero, depth, path, siblings);
signal computedRootIsValid <== IsEqual()([computedRoot,root]);
// check is leaf equals virtual leaf
signal virtualLeaf <== PoseidonHash(3)([virtualValue, 1,1]);
signal areLeafAndVirtualLeafEquals <== IsEqual()([virtualLeaf, leaf]);
signal isInclusionOrNonInclusionValid <== IsEqual()([mode,areLeafAndVirtualLeafEquals]);
signal output out <== computedRootIsValid * isInclusionOrNonInclusionValid;
}

View File

@@ -1,48 +0,0 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
pragma circom 2.1.6;
template MultiMux1(n) {
signal input c[n][2]; // Constants
signal input s; // Selector
signal output out[n];
for (var i=0; i<n; i++) {
out[i] <== (c[i][1] - c[i][0])*s + c[i][0];
}
}
template Mux1() {
var i;
signal input c[2]; // Constants
signal input s; // Selector
signal output out;
component mux = MultiMux1(1);
for (i=0; i<2; i++) {
mux.c[0][i] <== c[i];
}
s ==> mux.s;
mux.out[0] ==> out;
}

View File

@@ -1,268 +0,0 @@
pragma circom 2.1.6;
include "circomlib/circuits/bitify.circom";
template Mgf1Sha384(SEED_LEN, MASK_LEN) { //in bytes
var SEED_LEN_BITS = SEED_LEN * 8;
var MASK_LEN_BITS = MASK_LEN * 8;
var HASH_LEN = 48; //output len of sha function in bytes
var HASH_LEN_BITS = HASH_LEN * 8;//output len of sha function in bits
signal input seed[SEED_LEN_BITS]; //each represents a bit
signal output out[MASK_LEN_BITS];
assert(MASK_LEN <= 0xffffffff * HASH_LEN );
var ITERATIONS = (MASK_LEN \ HASH_LEN) + 1; //adding 1, in-case MASK_LEN \ HASH_LEN is 0
component sha384[ITERATIONS];
component num2Bits[ITERATIONS];
for (var i = 0; i < ITERATIONS; i++) {
sha384[i] = ShaHashChunks(1 , 384); //32 bits for counter
num2Bits[i] = Num2Bits(32);
}
var concated[1024]; //seed + 32 bits(4 Bytes) for counter
signal hashed[HASH_LEN_BITS * (ITERATIONS)];
for (var i = 0; i < SEED_LEN_BITS; 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[SEED_LEN_BITS + j] = num2Bits[i].out[31-j];
}
//adding padding (len = 416 = 110100000)
for (var j = 417; j < 1015; j++) {
concated[j] = 0;
}
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];
}
}
for (var i = 0; i < MASK_LEN_BITS; i++) {
out[i] <== hashed[i];
}
}
template Mgf1Sha256(SEED_LEN, MASK_LEN) { //in bytes
var SEED_LEN_BITS = SEED_LEN * 8;
var MASK_LEN_BITS = MASK_LEN * 8;
var HASH_LEN = 32; //output len of sha function in bytes
var HASH_LEN_BITS = HASH_LEN * 8;//output len of sha function in bits
signal input seed[SEED_LEN_BITS]; //each represents a bit
signal output out[MASK_LEN_BITS];
assert(MASK_LEN <= 0xffffffff * HASH_LEN );
var ITERATIONS = (MASK_LEN \ HASH_LEN) + 1; //adding 1, in-case MASK_LEN \ HASH_LEN is 0
component sha256[ITERATIONS];
component num2Bits[ITERATIONS];
for (var i = 0; i < ITERATIONS; i++) {
sha256[i] = ShaHashChunks(1, 256); //32 bits for counter
num2Bits[i] = Num2Bits(32);
}
var concated[512]; //seed + 32 bits(4 Bytes) for counter
signal hashed[HASH_LEN_BITS * (ITERATIONS)];
for (var i = 0; i < SEED_LEN_BITS; 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[SEED_LEN_BITS + j] = num2Bits[i].out[31-j];
}
//adding padding (len = 288 = 100100000)
for (var j = 289; j < 503; j++) {
concated[j] = 0;
}
concated[288] = 1;
concated[511] = 0;
concated[510] = 0;
concated[509] = 0;
concated[508] = 0;
concated[507] = 0;
concated[506] = 1;
concated[505] = 0;
concated[504] = 0;
concated[503] = 1;
//hashing value
sha256[i].in <== concated;
for (var j = 0; j < HASH_LEN_BITS; j++) {
hashed[i * HASH_LEN_BITS + j] <== sha256[i].out[j];
}
}
for (var i = 0; i < MASK_LEN_BITS; i++) {
out[i] <== hashed[i];
}
}
// pragma circom 2.1.9;
// include "circom-dl/circuits/bitify/bitify.circom";
// include "../sha2/sha256/sha256_hash_bits.circom";
// include "../sha2/sha384/sha384_hash_bits.circom";
// template Mgf1Sha384(seedLen, maskLen) { //in bytes
// var seedLenBits = seedLen * 8;
// var maskLenBits = maskLen * 8;
// var hashLen = 48; //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 sha384[iterations];
// component num2Bits[iterations];
// for (var i = 0; i < iterations; i++) {
// sha384[i] = Sha384_hash_chunks(1); //32 bits for counter
// num2Bits[i] = Num2Bits(32);
// }
// var concated[1024]; //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];
// }
// //adding padding (len = 416 = 110100000)
// for (var j = 417; j < 1015; j++){
// concated[j] = 0;
// }
// 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 < hashLenBits; j++) {
// hashed[i * hashLenBits + j] <== sha384[i].out[j];
// }
// }
// for (var i = 0; i < maskLenBits; i++) {
// out[i] <== hashed[i];
// }
// }
// template Mgf1Sha256(seedLen, maskLen) { //in bytes
// var seedLenBits = seedLen * 8;
// var maskLenBits = maskLen * 8;
// var hashLen = 32; //output len of sha function in bytes
// var hashLenBits = hashLen * 8;//output len of sha function in bits
// signal input seed[seedLenBits]; //each represents a bit
// signal output out[maskLenBits];
// assert(maskLen <= 0xffffffff * hashLen );
// var iterations = (maskLen \ hashLen) + 1; //adding 1, in-case maskLen \ hashLen is 0
// component sha256[iterations];
// component num2Bits[iterations];
// for (var i = 0; i < iterations; i++) {
// sha256[i] = Sha256_hash_chunks(1);
// num2Bits[i] = Num2Bits(32);
// }
// var concated[512]; //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];
// }
// //adding padding (len = 288 = 100100000)
// for (var j = 289; j < 503; j++){
// concated[j] = 0;
// }
// concated[288] = 1;
// concated[511] = 0;
// concated[510] = 0;
// concated[509] = 0;
// concated[508] = 0;
// concated[507] = 0;
// concated[506] = 1;
// concated[505] = 0;
// concated[504] = 0;
// concated[503] = 1;
// //hashing value
// sha256[i].in <== concated;
// for (var j = 0; j < hashLenBits; j++) {
// hashed[i * hashLenBits + j] <== sha256[i].out[j];
// }
// }
// for (var i = 0; i < maskLenBits; i++) {
// out[i] <== hashed[i];
// }
// }

View File

@@ -1,446 +0,0 @@
pragma circom 2.1.6;
include "../../bigInt/bigInt.circom";
include "./mgf1.circom";
include "../../bitify/gates.circom";
include "../../hasher/hash.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 VerifyRsaPssSig(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 = PowerMod(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;
}
}
/*
* 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 VerifyRsaPssSigNonOptimised(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,74 +0,0 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
pragma circom 2.0.0;
include "circomlib/circuits/bitify.circom";
// Returns 1 if in (in binary) > ct
template CompConstant(ct) {
signal input in[254];
signal output out;
signal parts[127];
signal sout;
var clsb;
var cmsb;
var slsb;
var smsb;
var sum=0;
var b = (1 << 128) -1;
var a = 1;
var e = 1;
var i;
for (i=0;i<127; i++) {
clsb = (ct >> (i*2)) & 1;
cmsb = (ct >> (i*2+1)) & 1;
slsb = in[i*2];
smsb = in[i*2+1];
if ((cmsb==0)&&(clsb==0)) {
parts[i] <== -b*smsb*slsb + b*smsb + b*slsb;
} else if ((cmsb==0)&&(clsb==1)) {
parts[i] <== a*smsb*slsb - a*slsb + b*smsb - a*smsb + a;
} else if ((cmsb==1)&&(clsb==0)) {
parts[i] <== b*smsb*slsb - a*smsb + a;
} else {
parts[i] <== -a*smsb*slsb + a;
}
sum = sum + parts[i];
b = b -e;
a = a +e;
e = e*2;
}
sout <== sum;
component num2bits = Num2Bits(135);
num2bits.in <== sout;
out <== num2bits.out[127];
}

View File

@@ -1,36 +0,0 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
circom is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with circom. If not, see <https://www.gnu.org/licenses/>.
*/
pragma circom 2.0.0;
include "compconstant.circom";
template Sign() {
signal input in[254];
signal output sign;
component comp = CompConstant(10944121435919637611123202872628637544274182200208017171849102093287904247808);
var i;
for (i=0; i<254; i++) {
comp.in[i] <== in[i];
}
sign <== comp.out;
}

View File

@@ -0,0 +1,148 @@
pragma circom 2.1.6;
include "circomlib/circuits/comparators.circom";
include "circomlib/circuits/bitify.circom";
include "./bigIntFunc.circom";
include "./bigIntOverflow.circom";
include "../int/arithmetic.circom";
// What BigInt in this lib means
// We represent big number as array of chunks with some shunk_size (will be explained later)
// for this example we will use N for number, n for chunk size and k for chunk_number:
// N[k];
// Number can be calculated by this formula:
// N = N[0] * 2 ** (0 * n) + N[1] * 2 ** (1 * n) + ... + N[k - 1] * 2 ** ((k-1) * n)
// By overflow we mean situation where N[i] >= 2 ** n
// Without overflow every number has one and only one representation
// To reduce overflow we must leave N[i] % 2 ** n for N[i] and add N[i] // 2 ** n to N[i + 1]
// If u want to do many operation in a row, it is better to use overflow operations from "./bigIntOverflow" and then just reduce overflow from result
// -------------------------------------------------------------------------------------------------------------------------------------------------
// Get in1 * in2 % modulus and in1 * in2 // modulus
template BigMultModP(CHUNK_SIZE, CHUNK_NUMBER_GREATER, CHUNK_NUMBER_LESS, CHUNK_NUMBER_MODULUS){
signal input in1[CHUNK_NUMBER_GREATER];
signal input in2[CHUNK_NUMBER_LESS];
signal input modulus[CHUNK_NUMBER_MODULUS];
var CHUNK_NUMBER_BASE = CHUNK_NUMBER_GREATER + CHUNK_NUMBER_LESS;
var CHUNK_NUMBER_DIV = CHUNK_NUMBER_BASE - CHUNK_NUMBER_MODULUS + 1;
signal output div[CHUNK_NUMBER_DIV];
signal output mod[CHUNK_NUMBER_MODULUS];
component mult = BigMultOverflow(CHUNK_SIZE, CHUNK_NUMBER_GREATER, CHUNK_NUMBER_LESS);
mult.in1 <== in1;
mult.in2 <== in2;
var reduced[200] = reduce_overflow_dl(CHUNK_SIZE, CHUNK_NUMBER_BASE - 1, CHUNK_NUMBER_BASE, mult.out);
var long_division[2][200] = long_div_dl(CHUNK_SIZE, CHUNK_NUMBER_MODULUS, CHUNK_NUMBER_DIV - 1, reduced, modulus);
for (var i = 0; i < CHUNK_NUMBER_DIV; i++){
div[i] <-- long_division[0][i];
}
component modChecks[CHUNK_NUMBER_MODULUS];
for (var i = 0; i < CHUNK_NUMBER_MODULUS; i++){
mod[i] <-- long_division[1][i];
// Check to avoid negative numbers
modChecks[i] = Num2Bits(CHUNK_SIZE);
modChecks[i].in <== mod[i];
}
component greaterThan = BigGreaterThan(CHUNK_SIZE, CHUNK_NUMBER_MODULUS);
greaterThan.in[0] <== modulus;
greaterThan.in[1] <== mod;
greaterThan.out === 1;
component mult2;
if (CHUNK_NUMBER_DIV >= CHUNK_NUMBER_MODULUS){
mult2 = BigMultNonEqualOverflow(CHUNK_SIZE, CHUNK_NUMBER_DIV, CHUNK_NUMBER_MODULUS);
mult2.in1 <== div;
mult2.in2 <== modulus;
} else {
mult2 = BigMultNonEqualOverflow(CHUNK_SIZE, CHUNK_NUMBER_MODULUS, CHUNK_NUMBER_DIV);
mult2.in2 <== div;
mult2.in1 <== modulus;
}
component isZero = BigIntIsZero(CHUNK_SIZE, CHUNK_SIZE * 2 + log_ceil_dl(CHUNK_NUMBER_MODULUS + CHUNK_NUMBER_DIV - 1), CHUNK_NUMBER_BASE - 1);
for (var i = 0; i < CHUNK_NUMBER_MODULUS; i++) {
isZero.in[i] <== mult.out[i] - mult2.out[i] - mod[i];
}
for (var i = CHUNK_NUMBER_MODULUS; i < CHUNK_NUMBER_BASE - 1; i++) {
isZero.in[i] <== mult.out[i] - mult2.out[i];
}
}
// in[0] <= in[1]
template BigLessEqThan(CHUNK_SIZE, CHUNK_NUMBER){
signal input in[2][CHUNK_NUMBER];
signal output out;
component lessThan[CHUNK_NUMBER];
component isEqual[CHUNK_NUMBER];
signal result[CHUNK_NUMBER];
for (var i = 0; i < CHUNK_NUMBER; i++){
lessThan[i] = LessThan(CHUNK_SIZE);
lessThan[i].in[0] <== in[0][i];
lessThan[i].in[1] <== in[1][i];
isEqual[i] = IsEqual();
isEqual[i].in[0] <== in[0][i];
isEqual[i].in[1] <== in[1][i];
}
for (var i = 0; i < CHUNK_NUMBER; i++){
if (i == 0){
result[i] <== lessThan[i].out + isEqual[i].out;
} else {
result[i] <== lessThan[i].out + isEqual[i].out * result[i - 1];
}
}
out <== result[CHUNK_NUMBER - 1];
}
// in[0] > in[1]
template BigGreaterThan(CHUNK_SIZE, CHUNK_NUMBER){
signal input in[2][CHUNK_NUMBER];
signal output out;
component lessEqThan = BigLessEqThan(CHUNK_SIZE, CHUNK_NUMBER);
lessEqThan.in <== in;
out <== 1 - lessEqThan.out;
}
// calculates in ^ (-1) % modulus;
// in, modulus has CHUNK_NUMBER
template BigModInv(CHUNK_SIZE, CHUNK_NUMBER) {
assert(CHUNK_SIZE <= 252);
signal input in[CHUNK_NUMBER];
signal input modulus[CHUNK_NUMBER];
signal output out[CHUNK_NUMBER];
var inv[200] = mod_inv_dl(CHUNK_SIZE, CHUNK_NUMBER, in, modulus);
for (var i = 0; i < CHUNK_NUMBER; i++) {
out[i] <-- inv[i];
}
component mult = BigMultModP(CHUNK_SIZE, CHUNK_NUMBER, CHUNK_NUMBER, CHUNK_NUMBER);
mult.in1 <== in;
mult.in2 <== out;
mult.modulus <== modulus;
mult.mod[0] === 1;
for (var i = 1; i < CHUNK_NUMBER; i++) {
mult.mod[i] === 0;
}
}

View File

@@ -12,90 +12,6 @@ include "../utils/switcher.circom";
// there is no overflow allowed, so chunk are equal, otherwise this is no sense
// those are very "expensive" by constraints operations, try to reduse num of usage if these if u can
// in[0] < in[1]
template BigLessThanDl(CHUNK_SIZE, CHUNK_NUMBER){
signal input in[2][CHUNK_NUMBER];
signal output out;
component lessThan[CHUNK_NUMBER];
component isEqual[CHUNK_NUMBER - 1];
signal result[CHUNK_NUMBER - 1];
for (var i = 0; i < CHUNK_NUMBER; i++){
lessThan[i] = LessThan(CHUNK_SIZE);
lessThan[i].in[0] <== in[0][i];
lessThan[i].in[1] <== in[1][i];
if (i != 0){
isEqual[i - 1] = IsEqual();
isEqual[i - 1].in[0] <== in[0][i];
isEqual[i - 1].in[1] <== in[1][i];
}
}
for (var i = 1; i < CHUNK_NUMBER; i++){
if (i == 1){
result[i - 1] <== lessThan[i].out + isEqual[i - 1].out * lessThan[i - 1].out;
} else {
result[i - 1] <== lessThan[i].out + isEqual[i - 1].out * result[i - 2];
}
}
out <== result[CHUNK_NUMBER - 2];
}
// in[0] <= in[1]
template BigLessEqThanDl(CHUNK_SIZE, CHUNK_NUMBER){
signal input in[2][CHUNK_NUMBER];
signal output out;
component lessThan[CHUNK_NUMBER];
component isEqual[CHUNK_NUMBER];
signal result[CHUNK_NUMBER];
for (var i = 0; i < CHUNK_NUMBER; i++){
lessThan[i] = LessThan(CHUNK_SIZE);
lessThan[i].in[0] <== in[0][i];
lessThan[i].in[1] <== in[1][i];
isEqual[i] = IsEqual();
isEqual[i].in[0] <== in[0][i];
isEqual[i].in[1] <== in[1][i];
}
for (var i = 0; i < CHUNK_NUMBER; i++){
if (i == 0){
result[i] <== lessThan[i].out + isEqual[i].out;
} else {
result[i] <== lessThan[i].out + isEqual[i].out * result[i - 1];
}
}
out <== result[CHUNK_NUMBER - 1];
}
// in[0] > in[1]
template BigGreaterThanDl(CHUNK_SIZE, CHUNK_NUMBER){
signal input in[2][CHUNK_NUMBER];
signal output out;
component lessEqThan = BigLessEqThanDl(CHUNK_SIZE, CHUNK_NUMBER);
lessEqThan.in <== in;
out <== 1 - lessEqThan.out;
}
// in[0] >= in[1]
template BigGreaterEqThanDl(CHUNK_SIZE, CHUNK_NUMBER){
signal input in[2][CHUNK_NUMBER];
signal output out;
component lessThan = BigLessThanDl(CHUNK_SIZE, CHUNK_NUMBER);
lessThan.in <== in;
out <== 1 - lessThan.out;
}
// Check for BigInt is zero, fail if it isn`t
// Works with overflowed signed chunks
// Can check for 2 bigints equality if in is sub of each chunk of those numbers

View File

@@ -1,7 +1,6 @@
pragma circom 2.1.6;
include "./dontOpenPlease.circom";
include "./shouldUseKaratsuba.circom";
function is_negative_dl(x) {
return x > 10944121435919637611123202872628637544274182200208017171849102093287904247808 ? 1 : 0;

View File

@@ -68,29 +68,6 @@ template BigMultOverflow(CHUNK_SIZE, CHUNK_NUMBER_GREATER, CHUNK_NUMBER_LESS){
}
}
// computes modulus + in1 - in2 (WITHOUT % modulus!!!) with overflows, in1 and in2 shouldn`t have overflows and in1 < modulus, in2 < modulus!
// use only if you undestand what are you doing!!!
// Use case if (a * b - c) % p, here u can use (a * b + (p + p - c) % p)
template BigSubModOverflow(CHUNK_SIZE, CHUNK_NUMBER){
signal input in1[CHUNK_NUMBER];
signal input in2[CHUNK_NUMBER];
signal input modulus[CHUNK_NUMBER];
signal output out[CHUNK_NUMBER];
for (var i = 0; i < CHUNK_NUMBER; i++){
if (i == 0){
out[i] <== 2 ** CHUNK_SIZE + modulus[i] + in1[i] - in2[i];
} else {
if (i == CHUNK_NUMBER - 1){
out[i] <== modulus[i] + in1[i] - in2[i] - 1;
} else {
out[i] <== 2 ** CHUNK_SIZE + modulus[i] + in1[i] - in2[i] - 1;
}
}
}
}
// multiplying number with CHUNK_NUMBER by scalar, ignoring overflow
template ScalarMultOverflow(CHUNK_NUMBER){
signal input in[CHUNK_NUMBER];
@@ -123,28 +100,4 @@ template BigSubModP(CHUNK_SIZE, CHUNK_NUMBER){
}
}
}
}
// USE ONLY if u sure it will not affect your security, because it is possible to get 1 in out with non-equal inputs, be carefull with it!!!
// this compares one chunk representation of nums, and if they are bigger than circom curve prime (~2**254), it will compare modulus by it
// it always uses 4 constraints and allows to always get 1 for equal inputs
// there is a way to get "collision" and get 1 for non equal chunks, however
// it almost impossible to get it randomly (almost the same as hash sha-256 collision), but it can be calculated
// it still doesn`t allowed to put anything that u want at witness and get valid proof, so it shouldn`t affect on security if it is one of many cheks in your circuit
template SmartEqual(CHUNK_SIZE, CHUNK_NUMBER){
signal input in[2][CHUNK_NUMBER];
signal output out;
component isEqual = IsEqual();
component sumLeft = GetSumOfNElements(CHUNK_NUMBER);
component sumRight = GetSumOfNElements(CHUNK_NUMBER);
for (var i = 0; i < CHUNK_NUMBER; i++){
sumLeft.in[i] <== 2 ** (i * CHUNK_SIZE) * in[0][i];
sumRight.in[i] <== 2 ** (i * CHUNK_SIZE) * in[1][i];
}
isEqual.in[0] <== sumLeft.out;
isEqual.in[1] <== sumRight.out;
out <== isEqual.out;
}

View File

@@ -5,11 +5,10 @@ include "../bigInt/bigInt.circom";
include "../bigInt/bigIntOverflow.circom";
include "../bigInt/bigIntHelpers.circom";
include "./get.circom";
include "./powers/p224pows.circom";
include "./powers/p256pows.circom";
include "./powers/p384pows.circom";
include "./powers/secp224r1pows.circom";
include "./powers/secp256k1pows.circom";
include "./powers/secp521r1pows.circom";
include "./powers/p521pows.circom";
include "./powers/brainpoolP224r1pows.circom";
include "./powers/brainpoolP256r1pows.circom";
include "./powers/brainpoolP384r1pows.circom";
@@ -19,63 +18,39 @@ include "circomlib/circuits/bitify.circom";
include "circomlib/circuits/comparators.circom";
include "../int/arithmetic.circom";
// Operation for any Weierstrass prime-field eliptic curve (for now 256-bit)
// A, B, P in every function - params of needed curve, chunked the same as every other chunking (64 4 for now)
// Example usage of operation (those are params for secp256k1 ec):
// EllipticCurveDoubleOptimised(64, 4, [0,0,0,0], [7,0,0,0], [18446744069414583343, 18446744073709551615, 18446744073709551615, 18446744073709551615]);
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------
// To add a new curve u should do next steps:
// Get curve params(A, B, P) in chunked representation
// Add order, dummyPoint (G * 2**256), and generator to "./get.circom" for chunking:
// if (CHUNK_NUMBER == 4){
// if (P[0] == 18446744069414583343 && P[1] == 18446744073709551615 && P[2] == 18446744073709551615 && P[3] == 18446744073709551615){
// gen[0] <== [6481385041966929816, 188021827762530521, 6170039885052185351, 8772561819708210092];
// gen[1] <== [11261198710074299576, 18237243440184513561, 6747795201694173352, 5204712524664259685];
// }
// }
// This is example for generator for 64 4 chunked secp256r1 curve
// This steps can be simplified by "../../helpers/generate_get_for_new_curve.py", but it can be broken in some cases, make a copy of "./get.circom" before it
// But for new curve with already existing chunks should work fine
// Won`t work fine for new chunking, or already existing curve, will be fixed later
// Use "../../helpers/get.py" to get str to paste, this one works fine, but it isn`t pasting, u should do it by yourself
// Change first 8 lines with your parameters and get your code lines.
// Change params at 4..8 lines in "../../helpers/generate_pow_table_for_curve.py" for your curve params, then execute script from root, this will create file in ./powers
// Also change chunking in 140 line and curve name at 145
// execute script from root, it will create new file in "./powers", import it here
// include "./powers/p256pows.circom"; for example
// add same case for EllipicCurveScalarGeneratorMult template:
// var powers[parts][2 ** STRIDE][2][CHUNK_NUMBER];
// if (CHUNK_NUMBER == 4){
// if (P[0] == 18446744069414583343 && P[1] == 18446744073709551615 && P[2] == 18446744073709551615 && P[3] == 18446744073709551615){
// powers = get_g_pow_stride8_table_secp256k1(CHUNK_SIZE, CHUNK_NUMBER);
// }
// ...
// }
// add here your chunking and get generated pow table
//
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// Those are helpers template, don`t use them outside without knowing what are u doing!!!
// Check is input is point on curve
// (x^3 + a * x + b - y * 2 % p) === 0
/// @title PointOnCurve
/// @notice Verifies if a given point lies on an elliptic curve defined by the equation `y^2 = x^3 + ax + b mod p`
/// @param CHUNK_SIZE The size of each chunk in bits, used for representing large integers
/// @param CHUNK_NUMBER The number of chunks used to represent each large integer
/// @param A The coefficient `a` of the elliptic curve equation
/// @param B The coefficient `b` of the elliptic curve equation
/// @param P The prime number defining the finite field for the elliptic curve
/// @input in The point to verify, represented as a 2D array of chunks [x, y]
template PointOnCurve(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
signal input in[2][CHUNK_NUMBER];
// Compute x^2
component squareX = BigMultOverflow(CHUNK_SIZE, CHUNK_NUMBER, CHUNK_NUMBER);
squareX.in1 <== in[0];
squareX.in2 <== in[0];
// Compute x^3
component cubeX = BigMultOverflow(CHUNK_SIZE, CHUNK_NUMBER * 2 - 1, CHUNK_NUMBER);
cubeX.in1 <== squareX.out;
cubeX.in2 <== in[0];
// Compute y^2
component squareY = BigMultOverflow(CHUNK_SIZE, CHUNK_NUMBER, CHUNK_NUMBER);
squareY.in1 <== in[1];
squareY.in2 <== in[1];
// Compute a * x
component coefMult = BigMultOverflow(CHUNK_SIZE, CHUNK_NUMBER, CHUNK_NUMBER);
coefMult.in1 <== in[0];
coefMult.in2 <== A;
// Verify if y^2 - (x^3 + a * x + b) mod p == 0
component isZeroModP = BigIntIsZeroModP(CHUNK_SIZE, CHUNK_SIZE * 3 + 2 * CHUNK_NUMBER, CHUNK_NUMBER * 3 - 2, CHUNK_NUMBER * 3, CHUNK_NUMBER);
for (var i = 0; i < CHUNK_NUMBER; i++){
isZeroModP.in[i] <== cubeX.out[i] + coefMult.out[i] - squareY.out[i] + B[i];
@@ -89,48 +64,64 @@ template PointOnCurve(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
isZeroModP.modulus <== P;
}
// Check is point on tangent (for doubling check)
// (x, y), point that was doubled, (x3, y3) - result
// λ = (3 * x ** 2 + a) / (2 * y)
// y3 = λ * (x - x3) - y
// 2 * y * (y3 + y) = (3 * x ** 2 + a) * (x - x3)
/// @title PointOnTangent
/// @notice Verifies if the given point lies on the tangent line used during elliptic curve point doubling.
/// λ = (3 * x ** 2 + a) / (2 * y)
/// y3 = λ * (x - x3) - y
/// 2 * y * (y3 + y) = (3 * x ** 2 + a) * (x - x3)
/// @param CHUNK_SIZE The size of each chunk in bits, used for representing large integers.
/// @param CHUNK_NUMBER The number of chunks used to represent each large integer.
/// @param A The coefficient `a` of the elliptic curve equation.
/// @param B The coefficient `b` of the elliptic curve equation (not used explicitly here).
/// @param P The prime number defining the finite field for the elliptic curve.
/// @input in1 The point being doubled, represented as a 2D array of chunks [x, y].
/// @input in2 The resulting point from doubling, represented as a 2D array of chunks [x3, y3].
template PointOnTangent(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
signal input in1[2][CHUNK_NUMBER];
signal input in2[2][CHUNK_NUMBER];
// Compute x^2
component squareX = BigMultOverflow(CHUNK_SIZE, CHUNK_NUMBER, CHUNK_NUMBER);
squareX.in1 <== in1[0];
squareX.in2 <== in1[0];
// Compute 3 * x^2
component scalarMult = ScalarMultOverflow(CHUNK_NUMBER * 2 - 1);
scalarMult.in <== squareX.out;
scalarMult.scalar <== 3;
// Compute 3 * x^2 + a
component bigAdd = BigAddOverflow(CHUNK_SIZE, CHUNK_NUMBER * 2 - 1, CHUNK_NUMBER);
bigAdd.in1 <== scalarMult.out;
bigAdd.in2 <== A;
// Compute x - x3
component bigSub = BigSubModP(CHUNK_SIZE, CHUNK_NUMBER);
bigSub.in1 <== in1[0];
bigSub.in2 <== in2[0];
bigSub.modulus <== P;
// Compute (3 * x^2 + a) * (x - x3)
component rightMult = BigMultOverflow(CHUNK_SIZE, CHUNK_NUMBER * 2 - 1, CHUNK_NUMBER);
rightMult.in1 <== bigAdd.out;
rightMult.in2 <== bigSub.out;
// Compute 2 * y
component scalarMult2 = ScalarMultOverflow(CHUNK_NUMBER);
scalarMult2.in <== in1[1];
scalarMult2.scalar <== 2;
// Compute y3 + y
component bigAdd2 = BigAddOverflow(CHUNK_SIZE, CHUNK_NUMBER, CHUNK_NUMBER);
bigAdd2.in1 <== in1[1];
bigAdd2.in2 <== in2[1];
// Compute 2 * y * (y3 + y)
component leftMult = BigMultOverflow(CHUNK_SIZE, CHUNK_NUMBER, CHUNK_NUMBER);
leftMult.in1 <== bigAdd2.out;
leftMult.in2 <== scalarMult2.out;
// Verify if 2 * y * (y3 + y) == (3 * x^2 + a) * (x - x3) mod p
component isZeroModP = BigIntIsZeroModP(CHUNK_SIZE, CHUNK_SIZE * 3 + 2 * CHUNK_NUMBER, CHUNK_NUMBER * 3 - 2, CHUNK_NUMBER * 3 + 1, CHUNK_NUMBER);
for (var i = 0; i < CHUNK_NUMBER * 2 - 1; i++){
isZeroModP.in[i] <== rightMult.out[i] - leftMult.out[i];
@@ -143,44 +134,57 @@ template PointOnTangent(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
}
// in1 = (x1, y1)
// in2 = (x2, y2)
// in3 = (x3, y3) (sum of (x1, y1), (x2, y2))
// Implements constraint: (y1 + y3) * (x2 - x1) - (y2 - y1) * (x1 - x3) = 0 mod P
// used to show (x1, y1), (x2, y2), (x3, -y3) are co-linear
/// @title PointOnLine
/// @notice Verifies if three points are co-linear on the elliptic curve, implementing the constraint:
/// (y1 + y3) * (x2 - x1) = (y2 - y1) * (x1 - x3) mod P.
/// Used to confirm that (x1, y1), (x2, y2), and (x3, -y3) are co-linear.
/// @param CHUNK_SIZE The size of each chunk in bits, used for representing large integers.
/// @param CHUNK_NUMBER The number of chunks used to represent each large integer.
/// @param A The coefficient `a` of the elliptic curve equation (not used explicitly here).
/// @param B The coefficient `b` of the elliptic curve equation (not used explicitly here).
/// @param P The prime number defining the finite field for the elliptic curve.
/// @input in1 The first point (x1, y1), represented as a 2D array of chunks.
/// @input in2 The second point (x2, y2), represented as a 2D array of chunks.
/// @input in3 The third point (x3, y3), where y3 represents -y3 for co-linearity, represented as a 2D array of chunks.
template PointOnLine(CHUNK_SIZE, CHUNK_NUMBER, A, B, P) {
signal input in1[2][CHUNK_NUMBER];
signal input in2[2][CHUNK_NUMBER];
signal input in3[2][CHUNK_NUMBER];
// Compute y1 + y3
component bigAdd = BigAddOverflow(CHUNK_SIZE, CHUNK_NUMBER, CHUNK_NUMBER);
bigAdd.in1 <== in1[1];
bigAdd.in2 <== in3[1];
// Compute x2 - x1
component bigSub = BigSubModP(CHUNK_SIZE, CHUNK_NUMBER);
bigSub.in1 <== in2[0];
bigSub.in2 <== in1[0];
bigSub.modulus <== P;
// Compute y2 - y1
component bigSub2 = BigSubModP(CHUNK_SIZE, CHUNK_NUMBER);
bigSub2.in1 <== in2[1];
bigSub2.in2 <== in1[1];
bigSub2.modulus <== P;
// Compute x1 - x3
component bigSub3 = BigSubModP(CHUNK_SIZE, CHUNK_NUMBER);
bigSub3.in1 <== in1[0];
bigSub3.in2 <== in3[0];
bigSub3.modulus <== P;
// Compute (y1 + y3) * (x2 - x1)
component leftMult = BigMultOverflow(CHUNK_SIZE, CHUNK_NUMBER, CHUNK_NUMBER);
leftMult.in1 <== bigAdd.out;
leftMult.in2 <== bigSub.out;
// Compute (y2 - y1) * (x1 - x3)
component rightMult = BigMultOverflow(CHUNK_SIZE, CHUNK_NUMBER, CHUNK_NUMBER);
rightMult.in1 <== bigSub2.out;
rightMult.in2 <== bigSub3.out;
// Verify if (y1 + y3) * (x2 - x1) == (y2 - y1) * (x1 - x3) mod P
component isZeroModP = BigIntIsZeroModP(CHUNK_SIZE, CHUNK_SIZE * 2 + 2 * CHUNK_NUMBER, CHUNK_NUMBER * 2 - 1, CHUNK_NUMBER * 2 + 1, CHUNK_NUMBER);
for (var i = 0; i < CHUNK_NUMBER * 2 - 1; i++){
isZeroModP.in[i] <== leftMult.out[i] - rightMult.out[i];
@@ -189,8 +193,17 @@ template PointOnLine(CHUNK_SIZE, CHUNK_NUMBER, A, B, P) {
isZeroModP.modulus <== P;
}
// Precomputes for pipinger optimised multiplication
// Computes 0 * G, 1 * G, 2 * G, ... (2 ** WINDOW_SIZE - 1) * G
/// @title EllipticCurvePrecomputePipinger
/// @notice Precomputes points for Pippenger's optimized scalar multiplication algorithm.
/// Computes 0 * G, 1 * G, 2 * G, ..., (2^WINDOW_SIZE - 1) * G, where G is the base point.
/// @param CHUNK_SIZE The size of each chunk in bits, used for representing large integers.
/// @param CHUNK_NUMBER The number of chunks used to represent each large integer.
/// @param A The coefficient `a` of the elliptic curve equation.
/// @param B The coefficient `b` of the elliptic curve equation.
/// @param P The prime number defining the finite field for the elliptic curve.
/// @param WINDOW_SIZE The size of the window in bits for the Pippenger algorithm.
/// @input in The base point G, represented as a 2D array of chunks.
/// @output out Precomputed points, where out[i] = i * G for i in [0, 2^WINDOW_SIZE - 1].
template EllipticCurvePrecomputePipinger(CHUNK_SIZE, CHUNK_NUMBER, A, B, P, WINDOW_SIZE){
signal input in[2][CHUNK_NUMBER];
@@ -198,11 +211,14 @@ template EllipticCurvePrecomputePipinger(CHUNK_SIZE, CHUNK_NUMBER, A, B, P, WIND
signal output out[PRECOMPUTE_NUMBER][2][CHUNK_NUMBER];
// Initialize the point for 0 * G (dummy point)
component getDummy = EllipticCurveGetDummy(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
out[0] <== getDummy.dummyPoint;
// Initialize the point for 1 * G (base point)
out[1] <== in;
// Precompute the remaining points using doubling and addition
component doublers[PRECOMPUTE_NUMBER \ 2 - 1];
component adders [PRECOMPUTE_NUMBER \ 2 - 1];
@@ -225,20 +241,34 @@ template EllipticCurvePrecomputePipinger(CHUNK_SIZE, CHUNK_NUMBER, A, B, P, WIND
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// Use next templates for elliptic curve oprations
// λ = (3 * x ** 2 + a) / (2 * y)
// x3 = λ * λ - 2 * x
// y3 = λ * (x - x3) - y
// We check is point is lies both on tangent and curve to assume that point is result of doubling
/// @title EllipticCurveDouble
/// @notice Computes the doubling of a point on an elliptic curve using the formula:
/// λ = (3 * x^2 + a) / (2 * y)
/// x3 = λ^2 - 2 * x
/// y3 = λ * (x - x3) - y
/// Additionally checks if the resulting point lies on both the tangent and the curve.
/// @param CHUNK_SIZE The size of each chunk in bits, used for representing large integers.
/// @param CHUNK_NUMBER The number of chunks used to represent each large integer.
/// @param A The coefficient `a` of the elliptic curve equation.
/// @param B The coefficient `b` of the elliptic curve equation.
/// @param P The prime number defining the finite field for the elliptic curve.
/// @input in The input point to be doubled, represented as a 2D array of chunks.
/// @output out The resulting doubled point, represented as a 2D array of chunks.
template EllipticCurveDouble(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
signal input in[2][CHUNK_NUMBER];
signal output out[2][CHUNK_NUMBER];
var long_3[CHUNK_NUMBER];
long_3[0] = 3;
// Precompute λ numerator: (3 * x^2 + a)
var lamb_num[200] = long_add_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, A, prod_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, long_3, prod_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, in[0], in[0], P), P), P);
// Compute λ denominator: (2 * y)
var lamb_denom[200] = long_add_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, in[1], in[1], P);
// Compute λ: (lamb_num / lamb_denom) mod P
var lamb[200] = prod_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, lamb_num, mod_inv_dl(CHUNK_SIZE, CHUNK_NUMBER, lamb_denom, P), P);
// Compute x3 = λ^2 - 2 * x
var x3[200] = long_sub_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, prod_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, lamb, lamb, P), long_add_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, in[0], in[0], P), P);
// Compute y3 = λ * (x - x3) - y
var y3[200] = long_sub_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, prod_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, lamb, long_sub_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, in[0], x3, P), P), in[1], P);
for (var i = 0; i < CHUNK_NUMBER; i++){
@@ -246,11 +276,11 @@ template EllipticCurveDouble(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
out[1][i] <-- y3[i];
}
// We check for result point be both on tangent and curve
// Check if the resulting point lies on the tangent
component onTangentCheck = PointOnTangent(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
onTangentCheck.in1 <== in;
onTangentCheck.in2 <== out;
// Check if the resulting point lies on the curve
component onCurveCheck = PointOnCurve(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
onCurveCheck.in <== out;
@@ -263,19 +293,35 @@ template EllipticCurveDouble(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
// cause we work with overflowed values.
}
// We check is point both on curve and line ((x1, y1), (x2, y2), (x3, -y3) are co-linear) to assume that this is result of addition
/// @title EllipticCurveAdd
/// @notice Computes the addition of two points on an elliptic curve using the formula:
/// λ = (y2 - y1) / (x2 - x1)
/// x3 = λ^2 - x1 - x2
/// y3 = λ * (x1 - x3) - y1
/// Additionally checks if the resulting point lies on both the curve and the line formed by the input points.
/// @param CHUNK_SIZE The size of each chunk in bits, used for representing large integers.
/// @param CHUNK_NUMBER The number of chunks used to represent each large integer.
/// @param A The coefficient `a` of the elliptic curve equation.
/// @param B The coefficient `b` of the elliptic curve equation.
/// @param P The prime number defining the finite field for the elliptic curve.
/// @input in1 The first input point, represented as a 2D array of chunks.
/// @input in2 The second input point, represented as a 2D array of chunks.
/// @output out The resulting point after addition, represented as a 2D array of chunks.
template EllipticCurveAdd(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
signal input in1[2][CHUNK_NUMBER];
signal input in2[2][CHUNK_NUMBER];
signal output out[2][CHUNK_NUMBER];
// Compute the slope λ = (y2 - y1) / (x2 - x1)
var dy[200] = long_sub_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, in2[1], in1[1], P);
var dx[200] = long_sub_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, in2[0], in1[0], P);
var dx_inv[200] = mod_inv_dl(CHUNK_SIZE, CHUNK_NUMBER, dx, P);
var lambda[200] = prod_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, dy, dx_inv, P);
var lambda_sq[200] = prod_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, lambda, lambda, P);
// Compute x3 = λ^2 - x1 - x2
var x3[200] = long_sub_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, long_sub_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, lambda_sq, in1[0], P), in2[0], P);
// Compute y3 = λ * (x1 - x3) - y1
var y3[200] = long_sub_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, prod_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, lambda, long_sub_mod_dl(CHUNK_SIZE, CHUNK_NUMBER, in1[0], x3, P), P), in1[1], P);
for (var i = 0; i < CHUNK_NUMBER; i++){
@@ -283,10 +329,11 @@ template EllipticCurveAdd(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
out[1][i] <-- y3[i];
}
// Check if the resulting point lies on the elliptic curve
component onCurveCheck = PointOnCurve(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
onCurveCheck.in <== out;
// Check if the points (x1, y1), (x2, y2), and (x3, -y3) are collinear
component onLineCheck = PointOnLine(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
onLineCheck.in1 <== in1;
onLineCheck.in2 <== in2;
@@ -295,15 +342,24 @@ template EllipticCurveAdd(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
// same as previous, this checks should be enought, no need in range checks
}
// Optimised scalar point multiplication, use it if u can`t add precompute table
// Algo:
// Precompute (see "PrecomputePipinger" template)
// Convert each WINDOW_SIZE bits into num IDX, double WINDOW_SIZE times, add to result IDX * G (from precomputes), repeat
// Double add and algo complexity:
// 255 doubles + 255 adds
// Our algo complexity:
// 256 - WINDOW_SIZE doubles, (256 - WINDOW_SIZE) / WINDOW_SIZE adds, 2 ** WINDOW_SIZE - 2 adds and doubles for precompute
// for 256 curve best WINDOW_SIZE = 4 with 252 + 63 + 14 = 329 operations with points
/// @title EllipticCurveScalarMult
/// @notice Optimized scalar multiplication for elliptic curve points. (to be used if you can`t use precomputation table)
/// Precompute (see "PrecomputePipinger" template)
// Convert each WINDOW_SIZE bits into num IDX, double WINDOW_SIZE times, add to result IDX * G (from precomputes), repeat
// Double add and algo complexity:
// 255 doubles + 255 adds
// Algo complexity:
// 256 - WINDOW_SIZE doubles, (256 - WINDOW_SIZE) / WINDOW_SIZE adds, 2 ** WINDOW_SIZE - 2 adds and doubles for precompute
// for 256 curve best WINDOW_SIZE = 4 with 252 + 63 + 14 = 329 operations with points
/// @param CHUNK_SIZE The size of each chunk in bits, used for representing large integers.
/// @param CHUNK_NUMBER The number of chunks used to represent each large integer.
/// @param A The coefficient `a` of the elliptic curve equation.
/// @param B The coefficient `b` of the elliptic curve equation.
/// @param P The prime number defining the finite field for the elliptic curve.
/// @param WINDOW_SIZE The size of each window in bits for precomputation and scalar conversion.
/// @input in The input point on the elliptic curve, represented as a 2D array of chunks.
/// @input scalar The scalar value for multiplication, represented as an array of chunks.
/// @output out The resulting point after scalar multiplication, represented as a 2D array of chunks.
template EllipticCurveScalarMult(CHUNK_SIZE, CHUNK_NUMBER, A, B, P, WINDOW_SIZE){
signal input in[2][CHUNK_NUMBER];
@@ -457,15 +513,15 @@ template EllipticCurveScalarMult(CHUNK_SIZE, CHUNK_NUMBER, A, B, P, WINDOW_SIZE)
out <== resultingPoints[ADDERS_NUMBER];
}
// calculate G * scalar
// To make it work for other curve u should generate generator pow table
// Other curves will be added by ourself soon
// Will fail if scalar == 0, don`t do it
// Use chunking that CHUNK_NUMBER * CHUNK_SIZE % 8 != 0
// And don`t use for 43 * 6 % 8 == 2, for example
// This chunking will be added late
// Complexity is field \ 8 - 1 additions
// For 256 field is 31 additions
/// @title EllipicCurveScalarGeneratorMult
/// @notice Calculates the elliptic curve scalar multiplication: G * scalar
/// @dev This function works for multiple elliptic curve types. The generator power tables for each curve are pre-generated. It performs the scalar multiplication in chunks using the specified chunk size and number of chunks.
/// @param CHUNK_SIZE The size of each chunk used for scalar multiplication.
/// @param CHUNK_NUMBER The number of chunks used for scalar multiplication.
/// @param A The curve parameter A (used for curve equation: y^2 = x^3 + Ax + B).
/// @param B The curve parameter B (used for curve equation: y^2 = x^3 + Ax + B).
/// @param P The elliptic curve parameters [P0, P1, P2, P3] defining the curve.
/// @return out The resulting elliptic curve point after multiplying the generator G with the scalar.
template EllipicCurveScalarGeneratorMult(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
signal input scalar[CHUNK_NUMBER];
@@ -477,9 +533,6 @@ template EllipicCurveScalarGeneratorMult(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
var powers[parts][2 ** STRIDE][2][CHUNK_NUMBER];
if (CHUNK_NUMBER == 4){
if (P[0] == 18446744069414583343 && P[1] == 18446744073709551615 && P[2] == 18446744073709551615 && P[3] == 18446744073709551615){
powers = get_g_pow_stride8_table_secp256k1(CHUNK_SIZE, CHUNK_NUMBER);
}
if (P[0] == 2311270323689771895 && P[1] == 7943213001558335528 && P[2] == 4496292894210231666 && P[3] == 12248480212390422972){
powers = get_g_pow_stride8_table_brainpoolP256r1(CHUNK_SIZE, CHUNK_NUMBER);
}
@@ -489,7 +542,7 @@ template EllipicCurveScalarGeneratorMult(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
}
if (CHUNK_NUMBER == 8 && CHUNK_SIZE == 66){
if (P[0] == 73786976294838206463 && P[1] == 73786976294838206463 && P[2] == 73786976294838206463 && P[3] == 73786976294838206463 && P[4] == 73786976294838206463 && P[5] == 73786976294838206463 && P[6] == 73786976294838206463 && P[7] == 576460752303423487){
powers = get_g_pow_stride8_table_secp521r1(CHUNK_SIZE, CHUNK_NUMBER);
powers = get_g_pow_stride8_table_p521(CHUNK_SIZE, CHUNK_NUMBER);
}
}
if (CHUNK_NUMBER == 8 && CHUNK_SIZE == 64){
@@ -510,7 +563,7 @@ template EllipicCurveScalarGeneratorMult(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
powers = get_g_pow_stride8_table_brainpoolP224r1(CHUNK_SIZE, CHUNK_NUMBER);
}
if (P[0] == 1 && P[1] == 0 && P[2] == 0 && P[3] == 4294967295 && P[4] == 4294967295 && P[5] == 4294967295 && P[6] == 4294967295){
powers = get_g_pow_stride8_table_secp224r1(CHUNK_SIZE, CHUNK_NUMBER);
powers = get_g_pow_stride8_table_p224(CHUNK_SIZE, CHUNK_NUMBER);
}
}
// if (CHUNK_NUMBER == 5 && CHUNK_SIZE == 64){

View File

@@ -1,84 +1,19 @@
pragma circom 2.1.6;
// Get generator by curve params
// Now there is only secp256k1 \ brainpoolP256r1 generator (64 4 chunking) and brainpoolP384r1
// Other curves / chunking will be added later
template EllipticCurveGetGenerator(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
signal output gen[2][CHUNK_NUMBER];
if (CHUNK_NUMBER == 4){
if (P[0] == 18446744069414583343 && P[1] == 18446744073709551615 && P[2] == 18446744073709551615 && P[3] == 18446744073709551615){
gen[0] <== [6481385041966929816, 188021827762530521, 6170039885052185351, 8772561819708210092];
gen[1] <== [11261198710074299576, 18237243440184513561, 6747795201694173352, 5204712524664259685];
}
if (P[0] == 2311270323689771895 && P[1] == 7943213001558335528 && P[2] == 4496292894210231666 && P[3] == 12248480212390422972){
gen[0] <== [4198572826427273826, 13393186192988382146, 3191724131859150767, 10075307429387458507];
gen[1] <== [6637554640278022551, 14012744714263826004, 10950579571776363977, 6088576656054338813];
}
if (P[0] == 18446744073709551615 && P[1] == 4294967295 && P[2] == 0 && P[3] == 18446744069414584321) {
gen[0] <== [17627433388654248598, 8575836109218198432, 17923454489921339634, 7716867327612699207];
gen[1] <== [14678990851816772085, 3156516839386865358, 10297457778147434006, 5756518291402817435];
}
}
if (CHUNK_NUMBER == 6){
if (P[0] == 4294967295 && P[1] == 18446744069414584320 && P[2] == 18446744073709551614 && P[3] == 18446744073709551615 && P[4] == 18446744073709551615 && P[5] == 18446744073709551615){
gen[0] <== [4203087948775033527, 6125724927633205612, 6482722621138151992, 7934563412932533144, 10282218360005504372, 12288012358878168375];
gen[1] <== [8809917716911230559, 747793036959711645, 16850834916486723776, 17938995913990739068, 6745997240412855337, 3897828414440483951];
}
if (P[0] == 9747760000893709395 && P[1] == 12453481191562877553 && P[2] == 1347097566612230435 && P[3] == 1526563086152259252 && P[4] == 1107163671716839903 && P[5] == 10140169582434348328){
gen[0] <== [17259960781858189086, 16728304380777219754, 15816583608832692456, 9819997727167172579, 11720119409086381931, 2097662510161151487];
gen[1] <== [4792396531824874261, 1028586674454626577, 16256874595948243240, 7113166411453454436, 6679378719998465362, 9997460611710698148];
}
}
if (CHUNK_NUMBER == 8 && CHUNK_SIZE == 64){
if (P[0] == 2930260431521597683 && P[1] == 2918894611604883077 && P[2] == 12595900938455318758 && P[3] == 9029043254863489090 && P[4] == 15448363540090652785 && P[5] == 14641358191536493070 && P[6] == 4599554755319692295 && P[7] == 12312170373589877899){
gen[0] <== [10030961170254002210, 8965910700118138472, 5823550673135435103, 18391328107359425677, 12987082728901970318, 9650544882960897729, 6494527313417104019, 9344657780867258724];
gen[1] <== [8704646705537616018, 15116942582920270854, 6614182396149851054, 12888420639989254238, 11529432042984931601, 17440742611955841818, 13901133935883592445, 9069748673103213292];
}
}
if (CHUNK_NUMBER == 8 && CHUNK_SIZE == 66){
if (P[0] == 73786976294838206463 && P[1] == 73786976294838206463 && P[2] == 73786976294838206463 && P[3] == 73786976294838206463 && P[4] == 73786976294838206463 && P[5] == 73786976294838206463 && P[6] == 73786976294838206463 && P[7] == 576460752303423487){
gen[0] <== [73318177735826586982, 65487454542484902054, 47261297936520182413, 53792451325664927076, 20894495204887448893, 19646699525969629165, 48195803493093751131, 223515561732870163];
gen[1] <== [9853476271941576272, 5570702194968932496, 888629214913941622, 12853196140475830425, 7500656931080978022, 54648434146783127249, 19642388603652049, 315503374086858991];
}
}
if (CHUNK_NUMBER == 7 && CHUNK_SIZE == 32){
if (P[0] == 2127085823 && P[1] == 2547681781 && P[2] == 2963212119 && P[3] == 1976686471 && P[4] == 706228261 && P[5] == 641951366 && P[6] == 3619763370){
gen[0] <== [3994206333, 1277062909, 2655838999, 2826815116, 872948658, 746478836, 227551661];
gen[1] <== [1981022925, 3399743187, 894148249, 1322101796, 617003166, 1925214831, 1487558391];
}
if (P[0] == 1 && P[1] == 0 && P[2] == 0 && P[3] == 4294967295 && P[4] == 4294967295 && P[5] == 4294967295 && P[6] == 4294967295){
gen[0] <== [291249441, 875725014, 1455558946, 1241760211, 840143033, 1807007615, 3071151293];
gen[1] <== [2231402036, 1154843033, 1510426468, 3443750304, 1277353958, 3052872699, 3174523784];
}
}
if (CHUNK_NUMBER == 5 && CHUNK_SIZE == 64){
if (P[0] == 18218206948094062119 && P[1] == 5733849700882443304 && P[2] == 17982820153128390127 && P[3] == 16229979505782022245 && P[4] == 15230689193496432567){
gen[0] <== [1202334713476417041, 16683336510634039751, 17438280603111292598, 5947492335316484070, 4881196775246125240];
gen[1] <== [15227310055808208609, 12233879368135109319, 523543375370093290, 12340024763961780062, 1512594114530254024];
}
}
if (CHUNK_NUMBER == 3 && CHUNK_SIZE == 64){
if (P[0] == 18446744073709551615 && P[1] == 18446744073709551614 && P[2] == 18446744073709551615){
gen[0] <== [17653841148256391186, 8988939576078862336, 1769255009665454326];
gen[1] <== [8356842117447370769, 7138225120784731605, 511487955924736632];
}
}
}
/// @title EllipticCurveGetDummy
/// @notice Returns a "dummy" point on the elliptic curve. This dummy point is used to handle cases where operations are required but the result is not used.
/// The dummy point is defined as G * 2^256, where G is the generator point of the elliptic curve.
/// @param CHUNK_SIZE The size of each chunk for the scalar multiplication.
/// @param CHUNK_NUMBER The number of chunks used in the scalar multiplication.
/// @param A The parameter A of the elliptic curve equation.
/// @param B The parameter B of the elliptic curve equation.
/// @param P The curve's prime field parameter.
/// @return dummyPoint The dummy point, calculated as G * 2^256, represented in two arrays of CHUNK_NUMBER elements.
// Get "dummy" point
// We can`t "if" signal in circom, so we always need to do all opertions, even we won`t use results of them
// For example, in scalar mult we can have case where we shouln`t add anything (bits = [0,0, .. ,0])
// We will ignore result, but we still should get it, so we need to pout something anyway
// We use this dummy point for such purposes
// Dummy point = G * 2**256
template EllipticCurveGetDummy(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
signal output dummyPoint[2][CHUNK_NUMBER];
if (CHUNK_NUMBER == 4){
if (P[0] == 18446744069414583343 && P[1] == 18446744073709551615 && P[2] == 18446744073709551615 && P[3] == 18446744073709551615){
dummyPoint[0] <== [10590052641807177607, 9925333800925632128, 8387557479920400525, 15939969690812260448];
@@ -139,10 +74,18 @@ template EllipticCurveGetDummy(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
}
}
// Get order of eliptic curve
/// @title EllipticCurveGetOrder
/// @notice Returns the order of the elliptic curve, which is the number of points on the curve.
/// @dev The order of an elliptic curve is an important value used in cryptographic operations, particularly for elliptic curve discrete logarithm problems and key generation.
/// @param CHUNK_SIZE The size of each chunk for the scalar multiplication.
/// @param CHUNK_NUMBER The number of chunks used in the scalar multiplication.
/// @param A The parameter A of the elliptic curve equation.
/// @param B The parameter B of the elliptic curve equation.
/// @param P The curve's prime field parameter (the modulus of the finite field).
/// @return order The order of the elliptic curve, represented as a signal array of CHUNK_NUMBER elements. This is the number of points on the curve.
template EllipicCurveGetOrder(CHUNK_SIZE, CHUNK_NUMBER, A, B, P){
signal output order[CHUNK_NUMBER];
if (CHUNK_NUMBER == 4){
if (P[0] == 18446744069414583343 && P[1] == 18446744073709551615 && P[2] == 18446744073709551615 && P[3] == 18446744073709551615){
order <== [13822214165235122497, 13451932020343611451, 18446744073709551614, 18446744073709551615];

View File

@@ -1,6 +1,6 @@
pragma circom 2.1.6;
function get_g_pow_stride8_table_secp224r1(n, k) {
function get_g_pow_stride8_table_p224(n, k) {
assert(n == 32 && k == 7);
var powers[28][256][2][7];

View File

@@ -1,6 +1,6 @@
pragma circom 2.1.6;
function get_g_pow_stride8_table_secp521r1(n, k) {
function get_g_pow_stride8_table_p521(n, k) {
assert(n == 66 && k == 8);
var powers[66][256][2][8];

View File

@@ -9,7 +9,6 @@ include "./sha2/sha224/sha224HashBits.circom";
include "./sha2/sha256/sha256HashBits.circom";
include "./sha2/sha384/sha384HashBits.circom";
include "./sha2/sha512/sha512HashBits.circom";
include "./poseidon/poseidon.circom";
//------------------------------------------------------------------------------------------------------------------------------------------------------------
// Here is secure implementation of sha-1 and sha-2 hash algoritms.
@@ -97,21 +96,4 @@ template ShaHashBits(LEN, ALGO){
hash512.in <== in;
hash512.out ==> out;
}
}
//------------------------------------------------------------------------------------------------------------------------------------------------------------
// Here is secure implementation of Poseidon hash algoritm.
// LEN in lenght of input vector
// Poseidon works with vectors, not just nums or bits, so use 1 element arr in case of one number
// Max LEN is 16, but if u want to connect this to solidity smart contracts, remember that they have only Poseidon(6)
// U can use this for verification: https://poseidon-hash.online/
template PoseidonHash(LEN){
assert (LEN <= 16);
assert (LEN > 0);
signal input in[LEN];
signal output out;
component poseidon = Poseidon(LEN);
poseidon.in <== in;
out <== poseidon.out;
}
}

Some files were not shown because too many files have changed in this diff Show More