Skip to content

Commit

Permalink
audit fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
richardliang committed Sep 18, 2024
1 parent e3c9b01 commit cd17f70
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 19 deletions.
Binary file not shown.
25 changes: 18 additions & 7 deletions circuits-circom/circuits/namecheap/namecheap_push.circom
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,10 @@ pragma circom 2.1.9;

include "circomlib/circuits/poseidon.circom";
include "@zk-email/circuits/utils/regex.circom";
include "@zk-email/circuits/helpers/email-nullifier.circom";
include "@zk-email/circuits/email-verifier.circom";
include "@zk-email/zk-regex-circom/circuits/common/from_addr_regex.circom";

include "../utils/ceil.circom";
include "../utils/email_nullifier.circom";
include "../utils/hash_sign_gen_rand.circom";

include "./regexes/namecheap_subject.circom";
include "./regexes/namecheap_transfer_details.circom";

Expand Down Expand Up @@ -99,14 +96,29 @@ template NamecheapPushDomainVerifier(maxHeadersLength, maxBodyLength, n, k) {

// Output packed email from
signal input fromEmailIndex;

// Assert fromEmailIndex < emailHeaderLength
signal isFromIndexValid <== LessThan(log2Ceil(maxHeadersLength))([fromEmailIndex, emailHeaderLength]);
isFromIndexValid === 1;

signal output fromEmailAddrPacked[maxEmailPackedChunks] <== PackRegexReveal(maxHeadersLength, maxEmailFromLen)(fromEmailReveal, fromEmailIndex);

// Packed buyer id (Hashed before making public output)
signal input namecheapBuyerIdIndex;

// Assert namecheapBuyerIdIndex < emailBodyLength
signal namecheapBuyerIdIndexValid <== LessThan(log2Ceil(maxBodyLength))([namecheapBuyerIdIndex, emailBodyLength]);
namecheapBuyerIdIndexValid === 1;

signal buyerIdPacked[maxBuyerIdPackedChunks] <== PackRegexReveal(maxBodyLength, maxBuyerIdLen)(buyerIdReveal, namecheapBuyerIdIndex);

// Output packed domain name
signal input namecheapDomainNameIndex;

// Assert namecheapDomainNameIndex < emailBodyLength
signal namecheapDomainNameIndexValid <== LessThan(log2Ceil(maxBodyLength))([namecheapDomainNameIndex, emailBodyLength]);
namecheapDomainNameIndexValid === 1;

signal output domainNamePacked[maxDomainNamePackedChunks] <== PackRegexReveal(maxBodyLength, maxDomainNameLen)(domainNameReveal, namecheapDomainNameIndex);

//---------------POSEIDON HASHING------------------//
Expand All @@ -116,16 +128,15 @@ template NamecheapPushDomainVerifier(maxHeadersLength, maxBodyLength, n, k) {

// NULLIFIER
signal output emailNullifier;
signal cmRand <== HashSignGenRand(n, k)(signature);
emailNullifier <== EmailNullifier()(headerHash, cmRand);
emailNullifier <== EmailNullifier(n, k)(signature);

// The following signals do not take part in any computation, but tie the proof to a specific intentHash to prevent replay attacks and frontrunning.
// https://geometry.xyz/notebook/groth16-malleability
signal input bidId;
signal bidIdSquared;
bidIdSquared <== bidId * bidId;

// TOTAL CONSTRAINTS: 2980073
// TOTAL CONSTRAINTS: 2980076
}


Expand Down
70 changes: 58 additions & 12 deletions circuits-circom/circuits/namecheap/test/namecheap_push.spec.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import chai from "chai";
import path from "path";
import { F1Field, Scalar } from "ffjavascript";
import { buildPoseidonOpt as buildPoseidon, buildMimcSponge, poseidonContract } from "circomlibjs";
import { chunkArray, bytesToPacked, chunkedBytesToBigInt, packNullifier, hashSignatureGenRand } from "../../utils/test-utils";
import { partialSha } from "@zk-email/helpers/src/sha-utils";

import { buildPoseidonOpt as buildPoseidon, buildMimcSponge } from "circomlibjs";
import { chunkArray, bytesToPacked, chunkedBytesToBigInt } from "../../utils/test-utils";
import { bigIntToChunkedBytes } from "@zk-email/helpers/dist/binary-format";
import { ethers } from "ethers";
import ganache from "ganache";

const { createCode, generateABI } = poseidonContract;
export const p = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617");
const Fr = new F1Field(p);

Expand Down Expand Up @@ -182,11 +177,14 @@ describe("Namecheap Push Domain Circuit", function () {
// Get returned nullifier
const nullifier = witness[9];

// Get expected nullifier
const sha_out = await partialSha(input["emailHeader"], input["emailHeaderLength"]);
const packed_nullifier = packNullifier(sha_out);
const cm_rand = hashSignatureGenRand(input["signature"], N, K, poseidon);
const expected_nullifier = poseidon([cm_rand, packed_nullifier])
// Calculate expected output
const bigIntSignature = chunkedBytesToBigInt(input["signature"], 121);
const signatureChunked = bigIntToChunkedBytes(bigIntSignature, 242, 9);

// Calculate expected nullifier
const signatureHash = poseidon(signatureChunked);
const expected_nullifier = poseidon([signatureHash]);

assert.equal(JSON.stringify(poseidon.F.e(nullifier)), JSON.stringify(expected_nullifier), true);
});

Expand All @@ -208,4 +206,52 @@ describe("Namecheap Push Domain Circuit", function () {

assert.equal(JSON.stringify(bid_id), JSON.stringify(expected_bid_id), true);
});

it("Should not generate witnesses when fromEmailIndex is invalid", async () => {
const input_path = path.join(__dirname, "../inputs/input_namecheap_push.json");
const jsonString = fs.readFileSync(input_path, "utf8");
const input = JSON.parse(jsonString);
input["fromEmailIndex"] = 100000;
try {
await cir.calculateWitness(input, true);
assert.fail('Expected calculateWitness to throw an error');
} catch (error) {
assert.instanceOf(error, Error);
assert.equal(
error.message,
'Error: Assert Failed.\nError in template Num2Bits_1 line: 38\nError in template LessThan_252 line: 96\nError in template NamecheapPushDomainVerifier_337 line: 101\n');
}
});

it("Should not generate witnesses when namecheapBuyerIdIndex is invalid", async () => {
const input_path = path.join(__dirname, "../inputs/input_namecheap_push.json");
const jsonString = fs.readFileSync(input_path, "utf8");
const input = JSON.parse(jsonString);
input["namecheapBuyerIdIndex"] = 100000;
try {
await cir.calculateWitness(input, true);
assert.fail('Expected calculateWitness to throw an error');
} catch (error) {
assert.instanceOf(error, Error);
assert.equal(
error.message,
'Error: Assert Failed.\nError in template Num2Bits_1 line: 38\nError in template LessThan_252 line: 96\nError in template NamecheapPushDomainVerifier_337 line: 101\nError in template Num2Bits_1 line: 38\nError in template LessThan_252 line: 96\nError in template NamecheapPushDomainVerifier_337 line: 110\n');
}
});

it("Should not generate witnesses when namecheapDomainNameIndex is invalid", async () => {
const input_path = path.join(__dirname, "../inputs/input_namecheap_push.json");
const jsonString = fs.readFileSync(input_path, "utf8");
const input = JSON.parse(jsonString);
input["namecheapDomainNameIndex"] = 100000;
try {
await cir.calculateWitness(input, true);
assert.fail('Expected calculateWitness to throw an error');
} catch (error) {
assert.instanceOf(error, Error);
assert.equal(
error.message,
'Error: Assert Failed.\nError in template Num2Bits_1 line: 38\nError in template LessThan_252 line: 96\nError in template NamecheapPushDomainVerifier_337 line: 101\nError in template Num2Bits_1 line: 38\nError in template LessThan_252 line: 96\nError in template NamecheapPushDomainVerifier_337 line: 110\nError in template Num2Bits_1 line: 38\nError in template LessThan_252 line: 96\nError in template NamecheapPushDomainVerifier_337 line: 119\n');
}
});
});

0 comments on commit cd17f70

Please sign in to comment.