mirror of
https://github.com/selfxyz/self.git
synced 2026-01-09 22:58:20 -05:00
* save import sorting work * remove dupe headers and fix type errors * sort imports and exports * fix errors from export sorting * fix tests * codex feedback * fix exports * fix exports and tweak test build * fix export and format * fix license headers * fix app building and clean up test errors * fix android local e2e test * improve caching * final fixes * remove invalid option * fix sorting and get random values loading * fix import sorting
411 lines
18 KiB
TypeScript
411 lines
18 KiB
TypeScript
import { expect } from "chai";
|
|
import { TransactionReceipt, ZeroAddress } from "ethers";
|
|
import { ethers } from "hardhat";
|
|
import { poseidon2 } from "poseidon-lite";
|
|
import { CIRCUIT_CONSTANTS, DscVerifierId, RegisterVerifierId } from "@selfxyz/common/constants";
|
|
import { ATTESTATION_ID } from "../utils/constants";
|
|
import { deploySystemFixtures } from "../utils/deployment";
|
|
import { generateDscProof, generateRegisterProof } from "../utils/generateProof";
|
|
import serialized_dsc_tree from "../../../common/pubkeys/serialized_dsc_tree.json";
|
|
import { DeployedActors } from "../utils/types";
|
|
import { generateRandomFieldElement } from "../utils/utils";
|
|
|
|
describe("Commitment Registration Tests", function () {
|
|
this.timeout(0);
|
|
|
|
let deployedActors: DeployedActors;
|
|
let snapshotId: string;
|
|
let baseDscProof: any;
|
|
let baseRegisterProof: any;
|
|
let dscProof: any;
|
|
let registerProof: any;
|
|
let registerSecret: any;
|
|
|
|
before(async () => {
|
|
deployedActors = await deploySystemFixtures();
|
|
registerSecret = generateRandomFieldElement();
|
|
baseDscProof = await generateDscProof(deployedActors.mockPassport);
|
|
baseRegisterProof = await generateRegisterProof(registerSecret, deployedActors.mockPassport);
|
|
snapshotId = await ethers.provider.send("evm_snapshot", []);
|
|
});
|
|
|
|
beforeEach(async () => {
|
|
dscProof = structuredClone(baseDscProof);
|
|
registerProof = structuredClone(baseRegisterProof);
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await ethers.provider.send("evm_revert", [snapshotId]);
|
|
snapshotId = await ethers.provider.send("evm_snapshot", []);
|
|
});
|
|
|
|
describe("Register Commitment", () => {
|
|
describe("Initialization", () => {
|
|
it("should have consistent addresses between registry and hub", async () => {
|
|
const { hub, registry } = deployedActors;
|
|
|
|
expect(await registry.hub()).to.equal(hub.target);
|
|
expect(await hub.registry()).to.equal(registry.target);
|
|
});
|
|
});
|
|
|
|
describe("Register DSC Pubkey", async () => {
|
|
it("Should register DSC key commitment successfully", async () => {
|
|
const { hub, registry } = deployedActors;
|
|
|
|
const previousRoot = await registry.getDscKeyCommitmentMerkleRoot();
|
|
const previousSize = await registry.getDscKeyCommitmentTreeSize();
|
|
const tx = await hub.registerDscKeyCommitment(DscVerifierId.dsc_sha256_rsa_65537_4096, dscProof);
|
|
|
|
const hashFunction = (a: bigint, b: bigint) => poseidon2([a, b]);
|
|
// must be imported dynamic since @openpassport/zk-kit-lean-imt is exclusively esm and hardhat does not support esm with typescript until verison 3
|
|
const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then((mod) => mod.LeanIMT);
|
|
const imt = new LeanIMT<bigint>(hashFunction);
|
|
await imt.insert(BigInt(dscProof.pubSignals[CIRCUIT_CONSTANTS.DSC_TREE_LEAF_INDEX]));
|
|
|
|
const receipt = (await tx.wait()) as TransactionReceipt;
|
|
const event = receipt?.logs.find(
|
|
(log) => log.topics[0] === registry.interface.getEvent("DscKeyCommitmentRegistered").topicHash,
|
|
);
|
|
const eventArgs = event
|
|
? registry.interface.decodeEventLog("DscKeyCommitmentRegistered", event.data, event.topics)
|
|
: null;
|
|
|
|
const blockTimestamp = (await ethers.provider.getBlock(receipt.blockNumber))!.timestamp;
|
|
const currentRoot = await registry.getDscKeyCommitmentMerkleRoot();
|
|
const index = await registry.getDscKeyCommitmentIndex(
|
|
dscProof.pubSignals[CIRCUIT_CONSTANTS.DSC_TREE_LEAF_INDEX],
|
|
);
|
|
|
|
expect(eventArgs?.commitment).to.equal(dscProof.pubSignals[CIRCUIT_CONSTANTS.DSC_TREE_LEAF_INDEX]);
|
|
expect(eventArgs?.timestamp).to.equal(blockTimestamp);
|
|
expect(eventArgs?.imtRoot).to.equal(currentRoot);
|
|
expect(eventArgs?.imtIndex).to.equal(index);
|
|
|
|
// Check state
|
|
expect(currentRoot).to.not.equal(previousRoot);
|
|
expect(currentRoot).to.be.equal(imt.root);
|
|
expect(await registry.getDscKeyCommitmentTreeSize()).to.equal(previousSize + 1n);
|
|
expect(
|
|
await registry.getDscKeyCommitmentIndex(dscProof.pubSignals[CIRCUIT_CONSTANTS.DSC_TREE_LEAF_INDEX]),
|
|
).to.equal(index);
|
|
expect(
|
|
await registry.isRegisteredDscKeyCommitment(dscProof.pubSignals[CIRCUIT_CONSTANTS.DSC_TREE_LEAF_INDEX]),
|
|
).to.equal(true);
|
|
});
|
|
|
|
it("Should fail when called by proxy address", async () => {
|
|
const { hubImpl } = deployedActors;
|
|
await expect(
|
|
hubImpl.registerDscKeyCommitment(DscVerifierId.dsc_sha256_rsa_65537_4096, dscProof),
|
|
).to.be.revertedWithCustomError(hubImpl, "UUPSUnauthorizedCallContext");
|
|
});
|
|
|
|
it("Should fail when the verifier is not set", async () => {
|
|
const { hub } = deployedActors;
|
|
await expect(
|
|
hub.registerDscKeyCommitment(DscVerifierId.dsc_sha1_rsa_65537_4096, dscProof),
|
|
).to.be.revertedWithCustomError(hub, "NO_VERIFIER_SET");
|
|
});
|
|
|
|
it("Should fail when the csca root is invalid", async () => {
|
|
const { hub } = deployedActors;
|
|
dscProof.pubSignals[CIRCUIT_CONSTANTS.DSC_CSCA_ROOT_INDEX] = generateRandomFieldElement();
|
|
await expect(
|
|
hub.registerDscKeyCommitment(DscVerifierId.dsc_sha256_rsa_65537_4096, dscProof),
|
|
).to.be.revertedWithCustomError(hub, "INVALID_CSCA_ROOT");
|
|
});
|
|
|
|
it("Should fail when the proof is invalid", async () => {
|
|
const { hub } = deployedActors;
|
|
dscProof.a[0] = generateRandomFieldElement();
|
|
await expect(
|
|
hub.registerDscKeyCommitment(DscVerifierId.dsc_sha256_rsa_65537_4096, dscProof),
|
|
).to.be.revertedWithCustomError(hub, "INVALID_DSC_PROOF");
|
|
});
|
|
|
|
it("Should fail when registerDscKeyCommitment is called directly on implementation", async () => {
|
|
const { registryImpl } = deployedActors;
|
|
await expect(registryImpl.registerDscKeyCommitment(generateRandomFieldElement())).to.be.revertedWithCustomError(
|
|
registryImpl,
|
|
"UUPSUnauthorizedCallContext",
|
|
);
|
|
});
|
|
|
|
it("Should fail when the registerDscKeyCommitment is called by non-hub address", async () => {
|
|
const { registry, vcAndDisclose, register, dsc, owner } = deployedActors;
|
|
const IdentityVerificationHubImplFactory = await ethers.getContractFactory(
|
|
"IdentityVerificationHubImplV1",
|
|
owner,
|
|
);
|
|
const hubImpl2 = await IdentityVerificationHubImplFactory.deploy();
|
|
await hubImpl2.waitForDeployment();
|
|
|
|
const initializeData = hubImpl2.interface.encodeFunctionData("initialize", [
|
|
registry.target,
|
|
vcAndDisclose.target,
|
|
[RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096],
|
|
[register.target],
|
|
[DscVerifierId.dsc_sha256_rsa_65537_4096],
|
|
[dsc.target],
|
|
]);
|
|
const hubFactory = await ethers.getContractFactory("IdentityVerificationHub", owner);
|
|
const hub2Proxy = await hubFactory.deploy(hubImpl2.target, initializeData);
|
|
await hub2Proxy.waitForDeployment();
|
|
|
|
const hub2 = await ethers.getContractAt("IdentityVerificationHubImplV1", hub2Proxy.target);
|
|
|
|
await expect(
|
|
hub2.registerDscKeyCommitment(DscVerifierId.dsc_sha256_rsa_65537_4096, dscProof),
|
|
).to.be.revertedWithCustomError(registry, "ONLY_HUB_CAN_ACCESS");
|
|
});
|
|
|
|
it("should fail registerDscKeyCommitment when hub address is not set", async () => {
|
|
const { hub, registry } = deployedActors;
|
|
|
|
await registry.updateHub(ZeroAddress);
|
|
await expect(
|
|
hub.registerDscKeyCommitment(DscVerifierId.dsc_sha256_rsa_65537_4096, dscProof),
|
|
).to.be.revertedWithCustomError(registry, "HUB_NOT_SET");
|
|
});
|
|
|
|
it("should fail when the dsc key commitment is already registered", async () => {
|
|
const { hub, registry } = deployedActors;
|
|
await hub.registerDscKeyCommitment(DscVerifierId.dsc_sha256_rsa_65537_4096, dscProof);
|
|
await expect(
|
|
hub.registerDscKeyCommitment(DscVerifierId.dsc_sha256_rsa_65537_4096, dscProof),
|
|
).to.be.revertedWithCustomError(registry, "REGISTERED_COMMITMENT");
|
|
});
|
|
|
|
it("should fail when getDscKeyCommitmentMerkleRoot is called by non-proxy", async () => {
|
|
const { registryImpl } = deployedActors;
|
|
await expect(registryImpl.getDscKeyCommitmentMerkleRoot()).to.be.revertedWithCustomError(
|
|
registryImpl,
|
|
"UUPSUnauthorizedCallContext",
|
|
);
|
|
});
|
|
|
|
it("should fail when checkDscKeyCommitmentMerkleRoot is called by non-proxy", async () => {
|
|
const { registryImpl } = deployedActors;
|
|
const root = generateRandomFieldElement();
|
|
await expect(registryImpl.checkDscKeyCommitmentMerkleRoot(root)).to.be.revertedWithCustomError(
|
|
registryImpl,
|
|
"UUPSUnauthorizedCallContext",
|
|
);
|
|
});
|
|
|
|
it("should fail when getDscKeyCommitmentTreeSize is called by non-proxy", async () => {
|
|
const { registryImpl } = deployedActors;
|
|
await expect(registryImpl.getDscKeyCommitmentTreeSize()).to.be.revertedWithCustomError(
|
|
registryImpl,
|
|
"UUPSUnauthorizedCallContext",
|
|
);
|
|
});
|
|
|
|
it("should fail when getDscKeyCommitmentIndex is called by non-proxy", async () => {
|
|
const { registryImpl } = deployedActors;
|
|
const commitment = generateRandomFieldElement();
|
|
await expect(registryImpl.getDscKeyCommitmentIndex(commitment)).to.be.revertedWithCustomError(
|
|
registryImpl,
|
|
"UUPSUnauthorizedCallContext",
|
|
);
|
|
});
|
|
|
|
it("should fail when registerDscKeyCommitment is called by non-proxy address", async () => {
|
|
const { hubImpl } = deployedActors;
|
|
await expect(
|
|
hubImpl.registerDscKeyCommitment(DscVerifierId.dsc_sha256_rsa_65537_4096, dscProof),
|
|
).to.be.revertedWithCustomError(hubImpl, "UUPSUnauthorizedCallContext");
|
|
});
|
|
});
|
|
|
|
describe("Register Passport Commitment", () => {
|
|
before(async () => {
|
|
const { registry } = deployedActors;
|
|
const dscKeys = JSON.parse(serialized_dsc_tree);
|
|
for (let i = 0; i < dscKeys[0].length; i++) {
|
|
await registry.devAddDscKeyCommitment(BigInt(dscKeys[0][i]));
|
|
}
|
|
snapshotId = await ethers.provider.send("evm_snapshot", []);
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await ethers.provider.send("evm_revert", [snapshotId]);
|
|
snapshotId = await ethers.provider.send("evm_snapshot", []);
|
|
});
|
|
|
|
it("should register passport commitment successfully", async () => {
|
|
const { hub, registry, mockPassport } = deployedActors;
|
|
|
|
const registerProof = await generateRegisterProof(registerSecret, mockPassport);
|
|
|
|
const previousRoot = await registry.getIdentityCommitmentMerkleRoot();
|
|
|
|
const hashFunction = (a: bigint, b: bigint) => poseidon2([a, b]);
|
|
// must be imported dynamic since @openpassport/zk-kit-lean-imt is exclusively esm and hardhat does not support esm with typescript until verison 3
|
|
const LeanIMT = await import("@openpassport/zk-kit-lean-imt").then((mod) => mod.LeanIMT);
|
|
const imt = new LeanIMT<bigint>(hashFunction);
|
|
await imt.insert(BigInt(registerProof.pubSignals[CIRCUIT_CONSTANTS.REGISTER_COMMITMENT_INDEX]));
|
|
|
|
const tx = await hub.registerPassportCommitment(
|
|
RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096,
|
|
registerProof,
|
|
);
|
|
const receipt = (await tx.wait()) as TransactionReceipt;
|
|
const blockTimestamp = (await ethers.provider.getBlock(receipt.blockNumber))!.timestamp;
|
|
|
|
const currentRoot = await registry.getIdentityCommitmentMerkleRoot();
|
|
const size = await registry.getIdentityCommitmentMerkleTreeSize();
|
|
const rootTimestamp = await registry.rootTimestamps(currentRoot);
|
|
const index = await registry.getIdentityCommitmentIndex(
|
|
registerProof.pubSignals[CIRCUIT_CONSTANTS.REGISTER_COMMITMENT_INDEX],
|
|
);
|
|
const nullifier = await registry.nullifiers(
|
|
ATTESTATION_ID.E_PASSPORT,
|
|
registerProof.pubSignals[CIRCUIT_CONSTANTS.REGISTER_NULLIFIER_INDEX],
|
|
);
|
|
|
|
const event = receipt?.logs.find(
|
|
(log) => log.topics[0] === registry.interface.getEvent("CommitmentRegistered").topicHash,
|
|
);
|
|
const eventArgs = event
|
|
? registry.interface.decodeEventLog("CommitmentRegistered", event.data, event.topics)
|
|
: null;
|
|
|
|
expect(eventArgs?.attestationId).to.equal(ATTESTATION_ID.E_PASSPORT);
|
|
expect(eventArgs?.nullifier).to.equal(registerProof.pubSignals[CIRCUIT_CONSTANTS.REGISTER_NULLIFIER_INDEX]);
|
|
expect(eventArgs?.commitment).to.equal(registerProof.pubSignals[CIRCUIT_CONSTANTS.REGISTER_COMMITMENT_INDEX]);
|
|
expect(eventArgs?.timestamp).to.equal(blockTimestamp);
|
|
expect(eventArgs?.imtRoot).to.equal(currentRoot);
|
|
expect(eventArgs?.imtIndex).to.equal(0);
|
|
|
|
expect(currentRoot).to.not.equal(previousRoot);
|
|
expect(currentRoot).to.be.equal(imt.root);
|
|
expect(size).to.equal(1);
|
|
expect(rootTimestamp).to.equal(blockTimestamp);
|
|
expect(index).to.equal(0);
|
|
expect(nullifier).to.equal(true);
|
|
});
|
|
|
|
it("should fail when verifier is not set", async () => {
|
|
const { hub } = deployedActors;
|
|
|
|
registerProof.a[0] = generateRandomFieldElement();
|
|
|
|
await expect(
|
|
hub.registerPassportCommitment(RegisterVerifierId.register_sha256_sha256_sha256_rsa_3_4096, registerProof),
|
|
).to.be.revertedWithCustomError(hub, "NO_VERIFIER_SET");
|
|
});
|
|
|
|
it("should fail when commitment root is invalid", async () => {
|
|
const { hub } = deployedActors;
|
|
|
|
const invalidCommitmentRoot = generateRandomFieldElement();
|
|
|
|
registerProof.pubSignals[CIRCUIT_CONSTANTS.REGISTER_MERKLE_ROOT_INDEX] = invalidCommitmentRoot;
|
|
await expect(
|
|
hub.registerPassportCommitment(
|
|
RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096,
|
|
registerProof,
|
|
),
|
|
).to.be.revertedWithCustomError(hub, "INVALID_COMMITMENT_ROOT");
|
|
});
|
|
|
|
it("should fail when register proof verification fails", async () => {
|
|
const { hub } = deployedActors;
|
|
|
|
registerProof.a[0] = generateRandomFieldElement();
|
|
|
|
await expect(
|
|
hub.registerPassportCommitment(
|
|
RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096,
|
|
registerProof,
|
|
),
|
|
).to.be.revertedWithCustomError(hub, "INVALID_REGISTER_PROOF");
|
|
});
|
|
|
|
it("should fail when nullifier is already used", async () => {
|
|
const { hub, registry, mockPassport } = deployedActors;
|
|
|
|
const registerProof = await generateRegisterProof(registerSecret, mockPassport);
|
|
|
|
await hub.registerPassportCommitment(
|
|
RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096,
|
|
registerProof,
|
|
);
|
|
|
|
await expect(
|
|
hub.registerPassportCommitment(
|
|
RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096,
|
|
registerProof,
|
|
),
|
|
).to.be.revertedWithCustomError(registry, "REGISTERED_COMMITMENT");
|
|
});
|
|
|
|
it("should fail when registerPassportCommitment is called by non-proxy address", async () => {
|
|
const { hubImpl } = deployedActors;
|
|
await expect(
|
|
hubImpl.registerPassportCommitment(
|
|
RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096,
|
|
registerProof,
|
|
),
|
|
).to.be.revertedWithCustomError(hubImpl, "UUPSUnauthorizedCallContext");
|
|
});
|
|
|
|
it("should fail when registerCommitment is called by non-hub address", async () => {
|
|
const { registry, vcAndDisclose, register, dsc, owner } = deployedActors;
|
|
const IdentityVerificationHubImplFactory = await ethers.getContractFactory(
|
|
"IdentityVerificationHubImplV1",
|
|
owner,
|
|
);
|
|
const hubImpl2 = await IdentityVerificationHubImplFactory.deploy();
|
|
await hubImpl2.waitForDeployment();
|
|
|
|
const initializeData = hubImpl2.interface.encodeFunctionData("initialize", [
|
|
registry.target,
|
|
vcAndDisclose.target,
|
|
[RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096],
|
|
[register.target],
|
|
[DscVerifierId.dsc_sha256_rsa_65537_4096],
|
|
[dsc.target],
|
|
]);
|
|
const hubFactory = await ethers.getContractFactory("IdentityVerificationHub", owner);
|
|
const hub2Proxy = await hubFactory.deploy(hubImpl2.target, initializeData);
|
|
await hub2Proxy.waitForDeployment();
|
|
|
|
const hub2 = await ethers.getContractAt("IdentityVerificationHubImplV1", hub2Proxy.target);
|
|
|
|
await expect(
|
|
hub2.registerPassportCommitment(
|
|
RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096,
|
|
registerProof,
|
|
),
|
|
).to.be.revertedWithCustomError(registry, "ONLY_HUB_CAN_ACCESS");
|
|
});
|
|
|
|
it("should fail registerCommitment when hub address is not set", async () => {
|
|
const { hub, registry } = deployedActors;
|
|
|
|
await registry.updateHub(ZeroAddress);
|
|
await expect(
|
|
hub.registerPassportCommitment(
|
|
RegisterVerifierId.register_sha256_sha256_sha256_rsa_65537_4096,
|
|
registerProof,
|
|
),
|
|
).to.be.revertedWithCustomError(registry, "HUB_NOT_SET");
|
|
});
|
|
|
|
it("should fail when registerCommitment is called by non-proxy address", async () => {
|
|
const { registryImpl } = deployedActors;
|
|
|
|
const nullifier = generateRandomFieldElement();
|
|
const commitment = generateRandomFieldElement();
|
|
|
|
await expect(
|
|
registryImpl.registerCommitment(ATTESTATION_ID.E_PASSPORT, nullifier, commitment),
|
|
).to.be.revertedWithCustomError(registryImpl, "UUPSUnauthorizedCallContext");
|
|
});
|
|
});
|
|
});
|
|
});
|