mirror of
https://github.com/selfxyz/self.git
synced 2026-01-09 14:48:06 -05:00
Merge branch 'dev' of https://github.com/zk-passport/openpassport into feat/register-disclose
This commit is contained in:
3
circuits/.gitignore
vendored
3
circuits/.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
inputs
|
||||
build
|
||||
node_modules/
|
||||
err.log
|
||||
err.log
|
||||
.env
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
164
circuits/circuits/prove/openpassport_prove.circom
Normal file
164
circuits/circuits/prove/openpassport_prove.circom
Normal 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;
|
||||
}
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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];
|
||||
|
||||
@@ -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();
|
||||
@@ -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];
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
@@ -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
@@ -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
@@ -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];
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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];
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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];
|
||||
// }
|
||||
// }
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
148
circuits/circuits/utils/crypto/bigInt/bigInt.circom
Normal file
148
circuits/circuits/utils/crypto/bigInt/bigInt.circom
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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){
|
||||
@@ -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];
|
||||
@@ -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];
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user