Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Audit/ecdsa #354

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions circuits/circuits/tests/utils/utils/isNBitsEqual.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pragma circom 2.1.6;

include "../../../utils/crypto/utils/isNBits.circom";

component main = isNBits(64);
5 changes: 5 additions & 0 deletions circuits/circuits/tests/utils/utils/isNBitsGreater.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pragma circom 2.1.6;

include "../../../utils/crypto/utils/isNBits.circom";

component main = isNBits(65);
5 changes: 5 additions & 0 deletions circuits/circuits/tests/utils/utils/isNBitsLesser.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pragma circom 2.1.6;

include "../../../utils/crypto/utils/isNBits.circom";

component main = isNBits(64);
54 changes: 51 additions & 3 deletions circuits/circuits/utils/crypto/bigInt/bigInt.circom
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ template BigMultModP(CHUNK_SIZE, CHUNK_NUMBER_GREATER, CHUNK_NUMBER_LESS, CHUNK_

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];
Expand Down Expand Up @@ -79,6 +79,36 @@ template BigMultModP(CHUNK_SIZE, CHUNK_NUMBER_GREATER, CHUNK_NUMBER_LESS, CHUNK_
}
}

// in[0] < in[1]
template BigLessThan(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 BigLessEqThan(CHUNK_SIZE, CHUNK_NUMBER){
Expand All @@ -100,15 +130,14 @@ template BigLessEqThan(CHUNK_SIZE, CHUNK_NUMBER){
}

for (var i = 0; i < CHUNK_NUMBER; i++){
if (i == 0){
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]
Expand All @@ -122,6 +151,25 @@ template BigGreaterThan(CHUNK_SIZE, CHUNK_NUMBER){
out <== 1 - lessEqThan.out;
}

// lowerbound <= value < upperbound
template BigRangeCheck(CHUNK_SIZE, CHUNK_NUMBER) {
signal input value[CHUNK_NUMBER];
signal input lowerBound[CHUNK_NUMBER];
signal input upperBound[CHUNK_NUMBER];

signal output out;

component greaterThanLower = BigLessThan(CHUNK_SIZE, CHUNK_NUMBER);
greaterThanLower.in[0] <== value;
greaterThanLower.in[1] <== lowerBound;

component lessThanUpper = BigLessThan(CHUNK_SIZE, CHUNK_NUMBER);
lessThanUpper.in[0] <== value;
lessThanUpper.in[1] <== upperBound;

out <== (1 - greaterThanLower.out) * lessThanUpper.out;
}

// calculates in ^ (-1) % modulus;
// in, modulus has CHUNK_NUMBER
template BigModInv(CHUNK_SIZE, CHUNK_NUMBER) {
Expand Down
28 changes: 27 additions & 1 deletion circuits/circuits/utils/crypto/signature/ecdsa/ecdsa.circom
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,31 @@ template verifyECDSABits(CHUNK_SIZE, CHUNK_NUMBER, A, B, P, ALGO){
}
hashedChunked[CHUNK_NUMBER - 1 - i] <== bits2Num[i].out;
}

signal one[CHUNK_NUMBER];
one[0] <== 1;
for (var i = 1; i < CHUNK_NUMBER; i++){
one[i] <== 0;
}

component getOrder = EllipicCurveGetOrder(CHUNK_SIZE,CHUNK_NUMBER, A, B, P);
signal order[CHUNK_NUMBER];
order <== getOrder.order;

// check if 1 <= r < order
component rangeChecks[2];
rangeChecks[0] = BigRangeCheck(CHUNK_SIZE, CHUNK_NUMBER);
rangeChecks[0].value <== signature[0];
rangeChecks[0].lowerBound <== one;
rangeChecks[0].upperBound <== order;
rangeChecks[0].out === 1;

//check if 1 <= s < order
rangeChecks[1] = BigRangeCheck(CHUNK_SIZE, CHUNK_NUMBER);
rangeChecks[1].value <== signature[1];
rangeChecks[1].lowerBound <== one;
rangeChecks[1].upperBound <== order;
rangeChecks[1].out === 1;

// s_inv = s ^ -1 mod n
signal sinv[CHUNK_NUMBER];
Expand Down Expand Up @@ -69,9 +90,14 @@ template verifyECDSABits(CHUNK_SIZE, CHUNK_NUMBER, A, B, P, ALGO){
component add = EllipticCurveAdd(CHUNK_SIZE, CHUNK_NUMBER, A, B, P);
add.in1 <== scalarMult1.out;
add.in2 <== scalarMult2.out;

component addModN = BigMultModP(CHUNK_SIZE, CHUNK_NUMBER, CHUNK_NUMBER, CHUNK_NUMBER);
addModN.in1 <== add.out[0];
addModN.in2 <== one;
addModN.modulus <== order;

// x1 === r
for (var i = 0; i < CHUNK_NUMBER; i++){
add.out[0][i] === signature[0][i];
addModN.mod[i] === signature[0][i];
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
pragma circom 2.1.9;

include "../../../passport/signatureAlgorithm.circom";
include "../../utils/isNBits.circom";
include "ecdsa.circom";

/// @title EcdsaVerifier
/// @notice Verifies an ECDSA signature for a given signature algorithm, public key, and message hash
/// @param signatureAlgorithm The hashing/signature algorithm as defined in `signatureAlgorithm.circom`
/// @param n The number of chunks used to represent integers (e.g., public key components and signature)
/// @param k The base chunk size, scaled based on the signature algorithm
/// @param n The base chunk size, scaled based on the signature algorithm
/// @param k The number of chunks used to represent integers (e.g., public key components and signature)
/// @input signature The [R, S] component in an array
/// @input pubKey The public key to verify the signature
/// @input hashParsed The hash of the message to be verified
Expand Down Expand Up @@ -53,6 +54,19 @@ template EcdsaVerifier(signatureAlgorithm, n, k) {
}
signal pubkey_xy[2][k] <== [pubKey_x, pubKey_y];

component rangeCheck[4 * k];
for (var i = 0; i < k; i++) {
rangeCheck[4 * i + 0] = isNBits(n);
rangeCheck[4 * i + 1] = isNBits(n);
rangeCheck[4 * i + 2] = isNBits(n);
rangeCheck[4 * i + 3] = isNBits(n);

rangeCheck[4 * i + 0].in <== signature_r[i];
rangeCheck[4 * i + 1].in <== signature_s[i];
rangeCheck[4 * i + 2].in <== pubKey_x[i];
rangeCheck[4 * i + 3].in <== pubKey_y[i];
}

var a[k] = get_a(signatureAlgorithm);
var b[k] = get_b(signatureAlgorithm);
var p[k] = get_p(signatureAlgorithm);
Expand Down
23 changes: 23 additions & 0 deletions circuits/circuits/utils/crypto/utils/isNBits.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
pragma circom 2.1.6;

include "circomlib/circuits/bitify.circom";

/// @title isNBits
/// @notice Checks whether an input number can be represented using at most `n` bits.
/// @param n The maximum number of bits allowed for the input value.
/// @input in The integer input to be checked.
template isNBits(n) {
signal input in;

component n2b = Num2Bits(254);
n2b.in <== in;

signal check[254 - n];
check[0] <== n2b.out[n];

for (var i = n + 1; i < 254; i++) {
check[i - n] <== check[i - n - 1] + n2b.out[i];
}

check[254 - n - 1] === 0;
}
Loading