simple move test

This commit is contained in:
kilyig
2023-03-14 23:48:28 -04:00
parent 7354613f10
commit 606bed00fd
12 changed files with 144 additions and 125 deletions

5
.gitignore vendored
View File

@@ -12,3 +12,8 @@ artifacts
# circom extras
*.r1cs
*.sym
*_cpp
*_js
*.wasm
*.zkey
ptau

View File

@@ -1,4 +1,5 @@
include "../node_modules/circomlib/circuits/poseidon.circom";
include "./set_operations.circom";
template Move() {
signal input xOld;
@@ -11,12 +12,19 @@ template Move() {
signal input saltNew;
signal output posHashNew;
// verify the old hash
component oldHashChecker = Poseidon(3);
oldHashChecker.inputs[0] <== xOld;
oldHashChecker.inputs[1] <== yOld;
oldHashChecker.inputs[2] <== saltOld;
posHashOld === oldHashChecker.out;
// chess kings can only move to one of their Moore neighbors
component possibleSquares = VisibleSquares();
// produce the hash for the new position
component newHashGenerator = Poseidon(3);
newHashGenerator.inputs[0] <== xNew;
newHashGenerator.inputs[1] <== yNew;

9
circuits/move.json Normal file
View File

@@ -0,0 +1,9 @@
{
"xOld": "0",
"yOld": "0",
"saltOld": "12345",
"posHashOld": "2321794270632629049109131152230501273451975640760836008986566812209223148844",
"xNew": "0",
"yNew": "1",
"saltNew": "12345"
}

1
circuits/move.vkey.json Normal file
View File

@@ -0,0 +1 @@
{"protocol":"groth16","curve":"bn128","nPublic":2,"vk_alpha_1":["20491192805390485299153009773594534940189261866228447918068658471970481763042","9383485363053290200918347156157836566562967994039712273449902621266178545958","1"],"vk_beta_2":[["6375614351688725206403948262868962793625744043794305715222011528459656738731","4252822878758300859123897981450591353533073413197771768651442665752259397132"],["10505242626370262277552901082094356697409835680220590971873171140371331206856","21847035105528745403288232691147584728191162732299865338377159692350059136679"],["1","0"]],"vk_gamma_2":[["10857046999023057135944570762232829481370756359578518086990519993285655852781","11559732032986387107991004021392285783925812861821192530917403151452391805634"],["8495653923123431417604973247489272438418190587263600148770280649306958101930","4082367875863433681332203403145435568316851327593401208105741076214120093531"],["1","0"]],"vk_delta_2":[["11377128597735879021622360903045069097412621576574291907159414133493915260453","8716571390944861277971267551725025206258009161176855904806311635057491901677"],["2861081928609901668097431581878231610252099555665736351017075153886697877772","13554251175355426001797871842533481691442937219832974449306312132444599263879"],["1","0"]],"vk_alphabeta_12":[[["2029413683389138792403550203267699914886160938906632433982220835551125967885","21072700047562757817161031222997517981543347628379360635925549008442030252106"],["5940354580057074848093997050200682056184807770593307860589430076672439820312","12156638873931618554171829126792193045421052652279363021382169897324752428276"],["7898200236362823042373859371574133993780991612861777490112507062703164551277","7074218545237549455313236346927434013100842096812539264420499035217050630853"]],[["7077479683546002997211712695946002074877511277312570035766170199895071832130","10093483419865920389913245021038182291233451549023025229112148274109565435465"],["4595479056700221319381530156280926371456704509942304414423590385166031118820","19831328484489333784475432780421641293929726139240675179672856274388269393268"],["11934129596455521040620786944827826205713621633706285934057045369193958244500","8037395052364110730298837004334506829870972346962140206007064471173334027475"]]],"IC":[["10949745416203741753861666003392260431354756070229883865289399583857266626873","4752309395416276455687127811956182629017861296766033750094835229557888182163","1"],["6681688297283077922224793909077601140641366659527375085275419804338075561691","13496422065519917963443266301163620335101452437762361899898963868378832044582","1"],["15023341891295437508357259311319910621355185477288801447736711177077669711379","7552267576198300157303859398700949767122932653089581929751811660821602384802","1"]]}

0
circuits/psi1.json Normal file
View File

0
circuits/psi2.json Normal file
View File

0
circuits/psi3.json Normal file
View File

View File

@@ -3,7 +3,28 @@ import "@nomicfoundation/hardhat-toolbox";
import "hardhat-circom";
const config: HardhatUserConfig = {
solidity: "0.8.18",
solidity: {
compilers: [
{
version: "0.6.11"
},
{
version: "0.8.17"
}],
},
circom: {
// (optional) Base path for input files, defaults to `./circuits/`
inputBasePath: "./circuits",
// (required) The final ptau file, relative to inputBasePath, from a Phase 1 ceremony
ptau: "./ptau/powersOfTau28_hez_final_15.ptau",
// (required) Each object in this array refers to a separate circuit
circuits: [
{ name: "move" },
// { name: "psi1" },
// { name: "psi2" },
// { name: "psi3" }
],
},
};
export default config;

View File

@@ -12,6 +12,14 @@ async function main() {
console.log(
`ZheroTag deployed to ${zheroTag.address} at time ${unlockTime}`
);
// deploy the move verifier
const MoveVerifier = await ethers.getContractFactory("contracts/MoveVerifier.sol:Verifier");
const moveVerifier = await MoveVerifier.deploy();
await moveVerifier.deployed();
console.log(
`MoveVerifier.sol deployed to ${moveVerifier.address}. Time: ${Date.now()}`
);
}
// We recommend this pattern to be able to use async/await everywhere

View File

@@ -1,124 +0,0 @@
import { time, loadFixture } from "@nomicfoundation/hardhat-network-helpers";
import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs";
import { expect } from "chai";
import { ethers } from "hardhat";
describe("Lock", function () {
// We define a fixture to reuse the same setup in every test.
// We use loadFixture to run this setup once, snapshot that state,
// and reset Hardhat Network to that snapshot in every test.
async function deployOneYearLockFixture() {
const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60;
const ONE_GWEI = 1_000_000_000;
const lockedAmount = ONE_GWEI;
const unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS;
// Contracts are deployed using the first signer/account by default
const [owner, otherAccount] = await ethers.getSigners();
const Lock = await ethers.getContractFactory("Lock");
const lock = await Lock.deploy(unlockTime, { value: lockedAmount });
return { lock, unlockTime, lockedAmount, owner, otherAccount };
}
describe("Deployment", function () {
it("Should set the right unlockTime", async function () {
const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture);
expect(await lock.unlockTime()).to.equal(unlockTime);
});
it("Should set the right owner", async function () {
const { lock, owner } = await loadFixture(deployOneYearLockFixture);
expect(await lock.owner()).to.equal(owner.address);
});
it("Should receive and store the funds to lock", async function () {
const { lock, lockedAmount } = await loadFixture(
deployOneYearLockFixture
);
expect(await ethers.provider.getBalance(lock.address)).to.equal(
lockedAmount
);
});
it("Should fail if the unlockTime is not in the future", async function () {
// We don't use the fixture here because we want a different deployment
const latestTime = await time.latest();
const Lock = await ethers.getContractFactory("Lock");
await expect(Lock.deploy(latestTime, { value: 1 })).to.be.revertedWith(
"Unlock time should be in the future"
);
});
});
describe("Withdrawals", function () {
describe("Validations", function () {
it("Should revert with the right error if called too soon", async function () {
const { lock } = await loadFixture(deployOneYearLockFixture);
await expect(lock.withdraw()).to.be.revertedWith(
"You can't withdraw yet"
);
});
it("Should revert with the right error if called from another account", async function () {
const { lock, unlockTime, otherAccount } = await loadFixture(
deployOneYearLockFixture
);
// We can increase the time in Hardhat Network
await time.increaseTo(unlockTime);
// We use lock.connect() to send a transaction from another account
await expect(lock.connect(otherAccount).withdraw()).to.be.revertedWith(
"You aren't the owner"
);
});
it("Shouldn't fail if the unlockTime has arrived and the owner calls it", async function () {
const { lock, unlockTime } = await loadFixture(
deployOneYearLockFixture
);
// Transactions are sent using the first signer by default
await time.increaseTo(unlockTime);
await expect(lock.withdraw()).not.to.be.reverted;
});
});
describe("Events", function () {
it("Should emit an event on withdrawals", async function () {
const { lock, unlockTime, lockedAmount } = await loadFixture(
deployOneYearLockFixture
);
await time.increaseTo(unlockTime);
await expect(lock.withdraw())
.to.emit(lock, "Withdrawal")
.withArgs(lockedAmount, anyValue); // We accept any value as `when` arg
});
});
describe("Transfers", function () {
it("Should transfer the funds to the owner", async function () {
const { lock, unlockTime, lockedAmount, owner } = await loadFixture(
deployOneYearLockFixture
);
await time.increaseTo(unlockTime);
await expect(lock.withdraw()).to.changeEtherBalances(
[owner, lock],
[lockedAmount, -lockedAmount]
);
});
});
});
});

76
test/ZheroTagLocal.ts Normal file
View File

@@ -0,0 +1,76 @@
import { time, loadFixture } from "@nomicfoundation/hardhat-network-helpers";
import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs";
import { expect } from "chai";
import { ethers } from "hardhat";
import { int } from "hardhat/internal/core/params/argumentTypes";
import { BigNumber } from "ethers";
import { groth16 } from "snarkjs";
import fs from "fs";
const MOVE_WASM_FILE_PATH = "circuits/move.wasm";
const MOVE_ZKEY_FILE_PATH = "circuits/move.zkey";
const MOVE_VKEY_FILE_PATH = "circuits/move.vkey.json";
import { generateProof } from "./utils/snark-utils";
// x: 0 y: 0 salt: 12345
// 2321794270632629049109131152230501273451975640760836008986566812209223148844
// x: 5 y: 5 salt: 12345
// 9435539296313397007849595282098379346206722261888911142952399734225356376203
describe("ZheroTagLocal", function () {
// We define a fixture to reuse the same setup in every test.
// We use loadFixture to run this setup once, snapshot that state,
// and reset Hardhat Network to that snapshot in every test.
async function fixture() {
console.log("Running the fixture");
}
describe("Move", function () {
it("Basic move", async function () {
const circuitInputs = {
xOld: 0,
yOld: 0,
saltOld: 12345,
posHashOld: BigInt("2321794270632629049109131152230501273451975640760836008986566812209223148844"),
xNew: 0,
yNew: 0,
saltNew: 12345
}
const [proof, publicSignals] = await generateProof(
circuitInputs,
MOVE_WASM_FILE_PATH,
MOVE_ZKEY_FILE_PATH
);
console.log(proof);
console.log(publicSignals);
const vKey = JSON.parse(fs.readFileSync(MOVE_VKEY_FILE_PATH, 'utf-8'));
const res = await groth16.verify(vKey, publicSignals, proof);
if (res === true) {
console.log("Verification OK");
} else {
console.log("Invalid proof");
}
});
it("Should set the right owner", async function () {
//expect(await lock.owner()).to.equal(owner.address);
});
it("Should receive and store the funds to lock", async function () {
});
});
});
// sources: https://betterprogramming.pub/zero-knowledge-proofs-using-snarkjs-and-circom-fac6c4d63202
// ^^^^ for groth16.verify

15
test/utils/snark-utils.ts Normal file
View File

@@ -0,0 +1,15 @@
import { groth16 } from "snarkjs";
import { ethers } from "hardhat";
export async function generateProof(circuitInputs: any, filePathWASM: any, filePathZKEY: any) {
//const file_wasm = fs.readFileSync(filePathWASM);
//const file_zkey = fs.readFileSync(filePathZKEY);
const { proof, publicSignals } = await groth16.fullProve(
circuitInputs,
filePathWASM,
filePathZKEY
);
return [proof, publicSignals];
}