diff --git a/circuits/bigint.circom b/circuits/bigint.circom index 72c31c0..94c032b 100644 --- a/circuits/bigint.circom +++ b/circuits/bigint.circom @@ -559,7 +559,7 @@ template CheckCarryToZero(n, m, k) { carry[i] <-- (in[i]+carry[i-1]) / (1< -Q = (x, -y) + // So we can check the x coordinate with [(n-1)*Q].x = Q.x, + + // Because -y === p - y mod p, + // we can check the y coordinate with [(n-1)*Q].y = p - Q.y + var prime[100] = get_secp256k1_prime(n, k); + component negative_y = BigSub(n, k); + for (var i = 0; i < k; i++) { + negative_y.a[i] <== prime[i]; + negative_y.b[i] <== pubkey[1][i]; + } + negative_y.underflow === 0; + + component rhs = Secp256k1Double(n, k); + for (var i = 0; i < k; i++) { + rhs.in[0][i] <== pubkey[0][i]; + rhs.in[1][i] <== negative_y.out[i]; + } + + for (var i = 0; i < k; i++) { + lhs.out[0][i] === rhs.out[0][i]; + lhs.out[1][i] === rhs.out[1][i]; + } +} + // TODO: implement ECDSA extended verify // r, s, and msghash have coordinates // encoded with k registers of n bits each diff --git a/test/circuits/test_ecdsa_check_pub_key.circom b/test/circuits/test_ecdsa_check_pub_key.circom new file mode 100644 index 0000000..c079767 --- /dev/null +++ b/test/circuits/test_ecdsa_check_pub_key.circom @@ -0,0 +1,5 @@ +pragma circom 2.0.2; + +include "../../circuits/ecdsa.circom"; + +component main {public [pubkey]} = ECDSACheckPubKey(64, 4); diff --git a/test/ecdsa.test.ts b/test/ecdsa.test.ts index a696b7d..40c9dc2 100644 --- a/test/ecdsa.test.ts +++ b/test/ecdsa.test.ts @@ -210,3 +210,41 @@ describe("ECDSAVerifyNoPubkeyCheck", function () { test_cases.forEach(test_ecdsa_verify); }); + + +describe("ECDSACheckPubKey", function () { + this.timeout(1000 * 1000); + + var test_cases: Array<[bigint, bigint]> = []; + var privkeys: Array = [ + 88549154299169935420064281163296845505587953610183896504176354567359434168161n, + 37706893564732085918706190942542566344879680306879183356840008504374628845468n, + 90388020393783788847120091912026443124559466591761394939671630294477859800601n, + 110977009687373213104962226057480551605828725303063265716157300460694423838923n + ]; + + for (var idx = 0; idx < privkeys.length; idx++) { + var pubkey: Point = Point.fromPrivateKey(privkeys[idx]); + test_cases.push([pubkey.x, pubkey.y]); + } + + let circuit: any; + before(async function () { + circuit = await wasm_tester(path.join(__dirname, "circuits", "test_ecdsa_check_pub_key.circom")); + }); + + var test_ecdsa_verify = function (test_case: [bigint, bigint]) { + let pub0 = test_case[0]; + let pub1 = test_case[1]; + + + var pub0_array: bigint[] = bigint_to_array(64, 4, pub0); + var pub1_array: bigint[] = bigint_to_array(64, 4, pub1); + it('Testing valid pub key: pub0: ' + pub0 + ' pub1: ' + pub1, async function() { + let witness = await circuit.calculateWitness({"pubkey": [pub0_array, pub1_array]}); + await circuit.checkConstraints(witness); + }); + } + + test_cases.forEach(test_ecdsa_verify); +});