├── isokratia-aggregator
├── python
│ ├── requirements.txt
│ ├── vkey.json
│ ├── field_helper.py
│ ├── script.py
│ └── curve_field_elements.py
├── .gitignore
├── gen-proof.sh
├── package.json
├── submitter.js
├── isokratia.abi.json
├── input
│ └── blank-proof.json
├── index.js
└── mimc.js
├── isokratia-contracts
├── .gitignore
├── .env.local
├── foundry.toml
├── scripts.sh
├── src
│ ├── Isokratia.sol
│ └── Verifier.sol
├── script
│ └── Isokratia.s.sol
├── test
│ └── Isokratia.t.sol
└── broadcast
│ └── Isokratia.s.sol
│ └── 5
│ └── run-1660185967.json
├── isokratia-client
├── .npmrc
├── .eslintrc.json
├── lib
│ ├── misc.ts
│ ├── isokratia.abi.json
│ └── mimc.ts
├── postcss.config.js
├── next.config.js
├── next-env.d.ts
├── tailwind.config.js
├── types.ts
├── pages
│ ├── api
│ │ ├── basic-proposal.ts
│ │ ├── proposal
│ │ │ └── [proposal_id].ts
│ │ ├── proposal-eligible.ts
│ │ ├── votes
│ │ │ └── [proposal_id].ts
│ │ └── proposal.ts
│ ├── _app.tsx
│ ├── index.tsx
│ └── proposal
│ │ ├── [id].tsx
│ │ └── new.tsx
├── styles
│ ├── globals.css
│ └── Home.module.css
├── tsconfig.json
├── .gitignore
├── components
│ ├── Nav.tsx
│ ├── Loading.tsx
│ ├── ProposalStatus.tsx
│ └── Sidebar.tsx
├── prisma
│ └── schema.prisma
├── package.json
└── README.md
├── README.md
├── .gitmodules
└── USAGE.md
/isokratia-aggregator/python/requirements.txt:
--------------------------------------------------------------------------------
1 | py_ecc
--------------------------------------------------------------------------------
/isokratia-contracts/.gitignore:
--------------------------------------------------------------------------------
1 | out
2 | cache
3 | .env
--------------------------------------------------------------------------------
/isokratia-client/.npmrc:
--------------------------------------------------------------------------------
1 | strict-peer-dependencies = false
2 |
--------------------------------------------------------------------------------
/isokratia-client/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/isokratia-client/lib/misc.ts:
--------------------------------------------------------------------------------
1 | export const baseURL = "https://isokratia.xyz";
2 |
--------------------------------------------------------------------------------
/isokratia-client/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/isokratia-contracts/.env.local:
--------------------------------------------------------------------------------
1 | PRIVATE_KEY=0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba
2 | RPC_URL=http://127.0.0.1:8545
--------------------------------------------------------------------------------
/isokratia-client/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: true,
4 | };
5 |
6 | module.exports = nextConfig;
7 |
--------------------------------------------------------------------------------
/isokratia-aggregator/.gitignore:
--------------------------------------------------------------------------------
1 | circuit
2 | node_modules
3 | input
4 | !input/blank-proof.json
5 | prover-input
6 | prover-output
7 | python/isokratia
8 | python/__pycache__
9 | .env
--------------------------------------------------------------------------------
/isokratia-contracts/foundry.toml:
--------------------------------------------------------------------------------
1 | [profile.default]
2 | src = 'src'
3 | out = 'out'
4 | libs = ['lib']
5 |
6 | # See more config options https://github.com/foundry-rs/foundry/tree/master/config
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Isokratia
2 |
3 | ## Infinitely Compressible Governance using Recursive SNARKs
4 |
5 | 
6 |
7 | Check out the blog for more details: https://nibnalin.me/dust-nib/isokratia.html
8 |
--------------------------------------------------------------------------------
/isokratia-client/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/basic-features/typescript for more information.
6 |
--------------------------------------------------------------------------------
/isokratia-client/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | "./pages/**/*.{js,ts,jsx,tsx}",
5 | "./components/**/*.{js,ts,jsx,tsx}",
6 | ],
7 | theme: {
8 | extend: {},
9 | },
10 | plugins: [],
11 | };
12 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "circom-pairing"]
2 | path = circom-pairing
3 | url = https://github.com/nalinbhardwaj/circom-pairing.git
4 | branch = isokratia
5 | [submodule "isokratia-contracts/lib/forge-std"]
6 | path = isokratia-contracts/lib/forge-std
7 | url = https://github.com/foundry-rs/forge-std
8 |
--------------------------------------------------------------------------------
/isokratia-contracts/scripts.sh:
--------------------------------------------------------------------------------
1 | # Build
2 | forge build
3 | # Deploy
4 | forge script script/Isokratia.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast
5 | # Verify
6 | forge script script/Isokratia.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --verify --etherscan-api-key $ETHERSCAN_API_KEY
--------------------------------------------------------------------------------
/isokratia-client/types.ts:
--------------------------------------------------------------------------------
1 | export type Proposal = {
2 | id: number;
3 | title: string;
4 | description: string;
5 | merkleRoot: string;
6 | endBlock: string;
7 | merkleLeaves: string[];
8 | options: string[];
9 | };
10 |
11 | export type Vote = {
12 | id: number;
13 | address: string;
14 | proposal_id: number;
15 | vote: string;
16 | sig: string;
17 | pubkey: string;
18 | };
19 |
--------------------------------------------------------------------------------
/isokratia-client/pages/api/basic-proposal.ts:
--------------------------------------------------------------------------------
1 | import { PrismaClient } from "@prisma/client";
2 | import type { NextApiRequest, NextApiResponse } from "next";
3 |
4 | const prisma = new PrismaClient();
5 |
6 | export default async function handler(
7 | req: NextApiRequest,
8 | res: NextApiResponse
9 | ) {
10 | if (req.method === "GET") {
11 | const proposals = await prisma.proposal.findMany();
12 | res.json(proposals);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/isokratia-aggregator/gen-proof.sh:
--------------------------------------------------------------------------------
1 | echo "$1"
2 | cd circuit/dev_cpp
3 | ./dev ../../prover-input/"$1".json ../../prover-output/"$1".wtns
4 | cd ..
5 | /data/rapidsnark/build/prover dev.zkey ../prover-output/"$1".wtns ../prover-output/"$1"-proof.json ../prover-output/"$1"-public.json
6 | cd .. && cd python && source isokratia/bin/activate
7 | python3 script.py "$1"-proof.json
8 | cd ..
9 | npx snarkjs zkesc prover-output/"$1"-public.json prover-output/"$1"-proof.json > prover-output/"$1"-calldata.json
10 |
--------------------------------------------------------------------------------
/isokratia-aggregator/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "isokratia-aggregator",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "type": "module",
7 | "dependencies": {
8 | "big-integer": "^1.6.51",
9 | "ethers": "^5.6.9",
10 | "fixed-merkle-tree": "^0.7.3",
11 | "keccak256": "^1.0.6",
12 | "node-fetch": "^3.2.10",
13 | "shelljs": "^0.8.5"
14 | },
15 | "scripts": {
16 | "refreshABI": "forge inspect ../isokratia-contracts/src/Isokratia.sol:Isokratia abi > isokratia.abi.json"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/isokratia-client/styles/globals.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | padding: 0;
4 | margin: 0;
5 | /* overflow: hidden; */
6 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
7 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
8 | /* overflow: hidden; */
9 | /* position: fixed; */
10 | /* height: 100%; */
11 | }
12 |
13 | a {
14 | color: inherit;
15 | text-decoration: none;
16 | }
17 |
18 | * {
19 | box-sizing: border-box;
20 | }
21 |
22 | @tailwind base;
23 | @tailwind components;
24 | @tailwind utilities;
25 |
--------------------------------------------------------------------------------
/isokratia-client/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2020",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "incremental": true
17 | },
18 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
19 | "exclude": ["node_modules"]
20 | }
21 |
--------------------------------------------------------------------------------
/isokratia-client/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 | .pnpm-debug.log*
27 |
28 | # local env files
29 | .env.local
30 | .env.development.local
31 | .env.test.local
32 | .env.production.local
33 | .env
34 |
35 | # vercel
36 | .vercel
37 |
38 | # typescript
39 | *.tsbuildinfo
40 |
--------------------------------------------------------------------------------
/isokratia-client/components/Nav.tsx:
--------------------------------------------------------------------------------
1 | import { ConnectButton } from "@rainbow-me/rainbowkit";
2 | import { useRouter } from "next/router";
3 |
4 | export const Nav = ({ title }: { title: string }) => {
5 | const router = useRouter();
6 | return (
7 |
22 | );
23 | };
24 |
--------------------------------------------------------------------------------
/isokratia-client/components/Loading.tsx:
--------------------------------------------------------------------------------
1 | export const Loading = ({ colored }: { colored?: boolean }) => {
2 | return (
3 |
25 | );
26 | };
27 |
--------------------------------------------------------------------------------
/isokratia-client/components/ProposalStatus.tsx:
--------------------------------------------------------------------------------
1 | import { useBlockNumber } from "wagmi";
2 |
3 | export const ProposalStatus = ({ blockNumber }: { blockNumber: number }) => {
4 | const { data: currentBlockNumber } = useBlockNumber();
5 | return (
6 |
13 |
20 | {currentBlockNumber && currentBlockNumber < blockNumber
21 | ? "Active"
22 | : "Expired"}
23 |
24 |
25 | );
26 | };
27 |
--------------------------------------------------------------------------------
/isokratia-client/prisma/schema.prisma:
--------------------------------------------------------------------------------
1 | generator client {
2 | provider = "prisma-client-js"
3 | }
4 |
5 | datasource db {
6 | provider = "mysql"
7 | url = env("DATABASE_URL")
8 | }
9 |
10 | model merkle {
11 | id Int @id @default(autoincrement())
12 | merkleRoot String @db.VarChar(255)
13 | merkleLeaf String @db.VarChar(255)
14 | }
15 |
16 | model proposal {
17 | id Int @id @default(autoincrement())
18 | title String @db.VarChar(255)
19 | description String @db.VarChar(1023)
20 | merkleRoot String @db.VarChar(255)
21 | endBlock String @db.VarChar(255)
22 | }
23 |
24 | model vote {
25 | id Int @id @default(autoincrement())
26 | address String @db.VarChar(255)
27 | proposal_id Int
28 | vote String @db.VarChar(255)
29 | sig String @db.VarChar(255)
30 | pubkey String @db.VarChar(255)
31 | }
32 |
33 | model proposalOptions {
34 | proposal_id Int
35 | option String @db.VarChar(255)
36 | id Int @id @default(autoincrement())
37 | }
38 |
--------------------------------------------------------------------------------
/isokratia-client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "isokratia-frontend",
3 | "private": true,
4 | "version": "0.1.0",
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "refreshABI": "forge inspect ../isokratia-contracts/src/Isokratia.sol:Isokratia abi > lib/isokratia.abi.json",
10 | "lint": "next lint",
11 | "postinstall": "npx prisma generate"
12 | },
13 | "dependencies": {
14 | "@noble/secp256k1": "^1.6.0",
15 | "@prisma/client": "^3.15.2",
16 | "@rainbow-me/rainbowkit": "^0.3.4",
17 | "autoprefixer": "^10.4.7",
18 | "ethers": "^5.6.9",
19 | "fixed-merkle-tree": "^0.7.3",
20 | "keccak256": "^1.0.6",
21 | "next": "^12.1.6",
22 | "postcss": "^8.4.14",
23 | "react": "^18.1.0",
24 | "react-dom": "^18.1.0",
25 | "tailwindcss": "^3.1.6",
26 | "wagmi": "^0.4.2"
27 | },
28 | "devDependencies": {
29 | "@types/node": "^17.0.35",
30 | "@types/react": "^18.0.9",
31 | "eslint": "^8.15.0",
32 | "eslint-config-next": "^12.1.6",
33 | "typescript": "^4.7.2"
34 | }
35 | }
--------------------------------------------------------------------------------
/isokratia-client/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import "../styles/globals.css";
2 | import "@rainbow-me/rainbowkit/styles.css";
3 | import type { AppProps } from "next/app";
4 | import { RainbowKitProvider, getDefaultWallets } from "@rainbow-me/rainbowkit";
5 | import { chain, configureChains, createClient, WagmiConfig } from "wagmi";
6 | import { alchemyProvider } from "wagmi/providers/alchemy";
7 | import { publicProvider } from "wagmi/providers/public";
8 |
9 | const { chains, provider, webSocketProvider } = configureChains(
10 | [chain.goerli],
11 | [alchemyProvider(), publicProvider()]
12 | );
13 |
14 | const { connectors } = getDefaultWallets({
15 | appName: "isokratia",
16 | chains,
17 | });
18 |
19 | const wagmiClient = createClient({
20 | autoConnect: true,
21 | connectors,
22 | provider,
23 | webSocketProvider,
24 | });
25 |
26 | function MyApp({ Component, pageProps }: AppProps) {
27 | return (
28 |
29 |
30 |
31 |
32 |
33 | );
34 | }
35 |
36 | export default MyApp;
37 |
--------------------------------------------------------------------------------
/isokratia-client/pages/api/proposal/[proposal_id].ts:
--------------------------------------------------------------------------------
1 | import { PrismaClient } from "@prisma/client";
2 | import type { NextApiRequest, NextApiResponse } from "next";
3 | import { useRouter } from "next/router";
4 |
5 | const prisma = new PrismaClient();
6 |
7 | export default async function handler(
8 | req: NextApiRequest,
9 | res: NextApiResponse
10 | ) {
11 | if (req.method === "GET") {
12 | const proposal = await prisma.proposal.findFirst({
13 | where: {
14 | id: Number(req.query.proposal_id),
15 | },
16 | });
17 | const optionRows = await prisma.proposalOptions.findMany({
18 | where: {
19 | proposal_id: Number(req.query.proposal_id),
20 | },
21 | });
22 | const options = optionRows.map((option) => option.option);
23 |
24 | const includeLeafs = req.query.includeLeafs === "true";
25 |
26 | if (includeLeafs) {
27 | const merkleLeafRows = await prisma.merkle.findMany({
28 | where: {
29 | merkleRoot: proposal!.merkleRoot,
30 | },
31 | });
32 | const merkleLeaves = merkleLeafRows.map((row: any) => row.merkleLeaf);
33 | res.json({ proposal, merkleLeaves, options: options });
34 | } else {
35 | res.json({ proposal, options: options });
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/USAGE.md:
--------------------------------------------------------------------------------
1 | # Running an aggregator node
2 |
3 | This guide details how to set up an aggregator node for Isokratia. To run a node, you will need:
4 |
5 | - A reasonably beefy AWS Machine: Our aggregator runs on an AWS r5.8xlarge instance with 32-core 3.1GHz, 256G RAM machine with 1T hard drive and 400G swap, although you can likely get away with much lower hard disk, swap and RAM.
6 | - A wallet with GoerliETH: Since Isokratia runs on the Goerli testnet right now, you’ll need to be able to make transactions to it.
7 |
8 | ## Setup
9 |
10 | Start by setting up the machine and clone this git repository to it.
11 |
12 | Then, create empty subfolders “prover-input” and “prover-output” in the isokratia-aggregator folder.
13 |
14 | Download the circuits folder from this [Google Drive link](https://drive.google.com/drive/folders/1P6SVqZcwCE-yPKb86n6DCVWlxUO5opga?usp=sharing) and place it into the “isokratia-aggregator” folder as well.
15 |
16 | Now, install the python dependencies of the repo using `pip install -r python/requirements.txt` and the node dependencies using `npm install`.
17 |
18 | Now, running `node index.js` starts the aggregation node. You can run this in the background and log it’s output to a file using `node index.js > log.out 2>&1 &`
19 |
20 | Feel free to reach out if you have issues.
21 |
--------------------------------------------------------------------------------
/isokratia-client/pages/api/proposal-eligible.ts:
--------------------------------------------------------------------------------
1 | import { PrismaClient } from "@prisma/client";
2 | import MerkleTree from "fixed-merkle-tree";
3 | import type { NextApiRequest, NextApiResponse } from "next";
4 | import mimcHash from "../../lib/mimc";
5 |
6 | const prisma = new PrismaClient();
7 |
8 | type Proposal = {
9 | title: string;
10 | description: string;
11 | endBlock: string;
12 | };
13 |
14 | function hasher(x: string | number) {
15 | return mimcHash(123)(BigInt(x)).toString();
16 | }
17 |
18 | function hasher2(x: string | number, y: string | number) {
19 | return mimcHash(123)(BigInt(x), BigInt(y)).toString();
20 | }
21 |
22 | export default async function handler(
23 | req: NextApiRequest,
24 | res: NextApiResponse
25 | ) {
26 | if (req.method === "GET") {
27 | // Handle a GET request
28 | const address = req.query.address as string;
29 | const proposal_id = req.query.proposal_id as string;
30 | if (!address || !proposal_id) return;
31 | const proposal = await prisma.proposal.findFirst({
32 | where: {
33 | id: Number(proposal_id),
34 | },
35 | });
36 | if (!proposal) return;
37 | const merkleLeafFromAddress = hasher(address);
38 | const inMerkleTree = await prisma.merkle.findFirst({
39 | where: {
40 | merkleRoot: proposal.merkleRoot,
41 | merkleLeaf: merkleLeafFromAddress,
42 | },
43 | });
44 | res.json({
45 | canVote: inMerkleTree ? true : false,
46 | });
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/isokratia-client/README.md:
--------------------------------------------------------------------------------
1 | This is a [RainbowKit](https://rainbowkit.com) + [wagmi](https://wagmi.sh) + [Next.js](https://nextjs.org/) project bootstrapped with [`create-rainbowkit`](https://github.com/rainbow-me/rainbowkit/tree/main/packages/create-rainbowkit).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | ```
10 |
11 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
12 |
13 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
14 |
15 | ## Learn More
16 |
17 | To learn more about this stack, take a look at the following resources:
18 |
19 | - [RainbowKit Documentation](https://rainbowkit.com) - Learn how to customize your wallet connection flow.
20 | - [wagmi Documentation](https://wagmi.sh) - Learn how to interact with Ethereum.
21 | - [Next.js Documentation](https://nextjs.org/docs) - Learn how to build a Next.js application.
22 |
23 | You can check out [the RainbowKit GitHub repository](https://github.com/rainbow-me/rainbowkit) - your feedback and contributions are welcome!
24 |
25 | ## Deploy on Vercel
26 |
27 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
28 |
29 | Check out the [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
30 |
--------------------------------------------------------------------------------
/isokratia-aggregator/submitter.js:
--------------------------------------------------------------------------------
1 | import fs from "fs";
2 | import { BigNumber, Contract, ethers, Wallet } from "ethers";
3 |
4 | export async function submit(proposalId, option) {
5 | const RPC = process.env.RPC_URL;
6 | const privateKey = process.env.PRIVATE_KEY;
7 | const isokratiaContractAddr = process.env.ISOKRATIA_CONTRACT_ADDR;
8 |
9 | console.log(RPC, privateKey, isokratiaContractAddr);
10 |
11 | const IsokratiaABIJSON = JSON.parse(fs.readFileSync("isokratia.abi.json"));
12 |
13 | console.log(`connecting to Ethereum JSON RPC ${RPC}`);
14 | const ethProvider = new ethers.providers.JsonRpcProvider(RPC);
15 | const contract = new Contract(isokratiaContractAddr, IsokratiaABIJSON, ethProvider);
16 | const ethWallet = new Wallet(privateKey, ethProvider);
17 | const contractWithSigner = contract.connect(ethWallet);
18 |
19 | const argData = JSON.parse(fs.readFileSync(`prover-output/${proposalId}-${option}-calldata.json`));
20 | const txOptions = { gasLimit: 2000000 };
21 |
22 | const tx = await contractWithSigner.functions["postAggregation"](
23 | ...argData,
24 | txOptions
25 | );
26 |
27 | while (true) {
28 | console.log(`Submitted ${tx.hash}, waiting for confirmation`);
29 | await sleep(1000);
30 | const receipt = await ethProvider.getTransactionReceipt(tx.hash);
31 | if (receipt == null) {
32 | console.log('Not yet confirmed');
33 | continue;
34 | }
35 | if (receipt.status === 1) {
36 | console.log('Transaction succeeded')
37 | } else {
38 | console.log('Transaction failed')
39 | console.log(receipt);
40 | }
41 | break;
42 | }
43 | }
44 |
45 | function sleep(time) {
46 | return new Promise((resolve) => setTimeout(resolve, time));
47 | }
48 |
--------------------------------------------------------------------------------
/isokratia-client/styles/Home.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | padding: 0 2rem;
3 | }
4 |
5 | .main {
6 | min-height: 100vh;
7 | padding: 2rem 0;
8 | flex: 1;
9 | display: flex;
10 | flex-direction: column;
11 | justify-content: center;
12 | align-items: center;
13 | }
14 |
15 | .footer {
16 | display: flex;
17 | flex: 1;
18 | padding: 2rem 0;
19 | border-top: 1px solid #eaeaea;
20 | justify-content: center;
21 | align-items: center;
22 | }
23 |
24 | .footer a {
25 | display: flex;
26 | justify-content: center;
27 | align-items: center;
28 | flex-grow: 1;
29 | }
30 |
31 | .title a {
32 | color: #0d76fc;
33 | text-decoration: none;
34 | }
35 |
36 | .title a:hover,
37 | .title a:focus,
38 | .title a:active {
39 | text-decoration: underline;
40 | }
41 |
42 | .title {
43 | margin: 3rem 0;
44 | line-height: 1;
45 | font-size: 2.5rem;
46 | }
47 |
48 | .title,
49 | .description {
50 | text-align: center;
51 | }
52 |
53 | .description {
54 | margin: 0 0 2rem;
55 | line-height: 1.5;
56 | font-size: 1.5rem;
57 | }
58 |
59 | .grid {
60 | display: flex;
61 | align-items: center;
62 | justify-content: center;
63 | flex-wrap: wrap;
64 | max-width: 800px;
65 | }
66 |
67 | .card {
68 | margin: 1rem;
69 | padding: 1.5rem;
70 | text-align: left;
71 | color: inherit;
72 | text-decoration: none;
73 | border: 1px solid #eaeaea;
74 | border-radius: 10px;
75 | transition: color 0.15s ease, border-color 0.15s ease;
76 | width: 100%;
77 | }
78 |
79 | .card:hover,
80 | .card:focus,
81 | .card:active {
82 | color: #0d76fc;
83 | border-color: #0d76fc;
84 | }
85 |
86 | .card h2 {
87 | margin: 0 0 1rem 0;
88 | font-size: 1.2rem;
89 | }
90 |
91 | .card p {
92 | margin: 0;
93 | font-size: 1.2rem;
94 | line-height: 1.5;
95 | }
96 |
97 | @media (max-width: 600px) {
98 | .grid {
99 | width: 100%;
100 | flex-direction: column;
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/isokratia-client/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import { ConnectButton } from "@rainbow-me/rainbowkit";
2 | import type { NextPage } from "next";
3 | import Head from "next/head";
4 | import Link from "next/link";
5 | import { useBlockNumber } from "wagmi";
6 | import { Nav } from "../components/Nav";
7 | import { ProposalStatus } from "../components/ProposalStatus";
8 | import { Sidebar } from "../components/Sidebar";
9 | import { baseURL } from "../lib/misc";
10 | import styles from "../styles/Home.module.css";
11 | import { Proposal } from "../types";
12 |
13 | const Home: NextPage<{ proposals: Proposal[] }> = ({ proposals }) => {
14 | return (
15 |
16 |
17 |
isokratia
18 |
22 |
23 |
24 |
25 |
26 |
33 |
34 |
35 |
36 | {[...proposals]
37 | .sort((a, b) => b.id - a.id)
38 | .map((proposal: Proposal, index: number) => {
39 | return (
40 |
56 | );
57 | })}
58 |
59 |
60 |
61 |
62 | );
63 | };
64 |
65 | // This gets called on every request
66 | export async function getServerSideProps() {
67 | // Fetch data from external API
68 | const res = await fetch(`${baseURL}/api/basic-proposal`);
69 | const proposals = await res.json();
70 |
71 | // Pass data to the page via props
72 | return { props: { proposals } };
73 | }
74 |
75 | export default Home;
76 |
--------------------------------------------------------------------------------
/isokratia-aggregator/python/vkey.json:
--------------------------------------------------------------------------------
1 | {
2 | "protocol": "groth16",
3 | "curve": "bn128",
4 | "nPublic": 1,
5 | "vk_alpha_1": [
6 | "20491192805390485299153009773594534940189261866228447918068658471970481763042",
7 | "9383485363053290200918347156157836566562967994039712273449902621266178545958",
8 | "1"
9 | ],
10 | "vk_beta_2": [
11 | [
12 | "6375614351688725206403948262868962793625744043794305715222011528459656738731",
13 | "4252822878758300859123897981450591353533073413197771768651442665752259397132"
14 | ],
15 | [
16 | "10505242626370262277552901082094356697409835680220590971873171140371331206856",
17 | "21847035105528745403288232691147584728191162732299865338377159692350059136679"
18 | ],
19 | [
20 | "1",
21 | "0"
22 | ]
23 | ],
24 | "vk_gamma_2": [
25 | [
26 | "10857046999023057135944570762232829481370756359578518086990519993285655852781",
27 | "11559732032986387107991004021392285783925812861821192530917403151452391805634"
28 | ],
29 | [
30 | "8495653923123431417604973247489272438418190587263600148770280649306958101930",
31 | "4082367875863433681332203403145435568316851327593401208105741076214120093531"
32 | ],
33 | [
34 | "1",
35 | "0"
36 | ]
37 | ],
38 | "vk_delta_2": [
39 | [
40 | "18663854126529038456366775629343214145151888306033417279573710037906499173415",
41 | "5973621563733861405623480110159658945229906859514934902138790212137481366769"
42 | ],
43 | [
44 | "1295626130386430412571447908098540686782565822741566042801736583322422911819",
45 | "9508176675406799030331063455658394160028524360798331535836005748963346087306"
46 | ],
47 | [
48 | "1",
49 | "0"
50 | ]
51 | ],
52 | "vk_alphabeta_12": [
53 | [
54 | [
55 | "2029413683389138792403550203267699914886160938906632433982220835551125967885",
56 | "21072700047562757817161031222997517981543347628379360635925549008442030252106"
57 | ],
58 | [
59 | "5940354580057074848093997050200682056184807770593307860589430076672439820312",
60 | "12156638873931618554171829126792193045421052652279363021382169897324752428276"
61 | ],
62 | [
63 | "7898200236362823042373859371574133993780991612861777490112507062703164551277",
64 | "7074218545237549455313236346927434013100842096812539264420499035217050630853"
65 | ]
66 | ],
67 | [
68 | [
69 | "7077479683546002997211712695946002074877511277312570035766170199895071832130",
70 | "10093483419865920389913245021038182291233451549023025229112148274109565435465"
71 | ],
72 | [
73 | "4595479056700221319381530156280926371456704509942304414423590385166031118820",
74 | "19831328484489333784475432780421641293929726139240675179672856274388269393268"
75 | ],
76 | [
77 | "11934129596455521040620786944827826205713621633706285934057045369193958244500",
78 | "8037395052364110730298837004334506829870972346962140206007064471173334027475"
79 | ]
80 | ]
81 | ],
82 | "IC": [
83 | [
84 | "2496844451885833432824096806416557499214264711015324386520936125098688615613",
85 | "14629877535584054045396860904063333615289315185715201372572426609117299460882",
86 | "1"
87 | ],
88 | [
89 | "20553880061351188313734961831898909352358550578577018251431250607538377844",
90 | "11497045777900447273865655657210559889388291494891917154106692735310227061356",
91 | "1"
92 | ]
93 | ]
94 | }
--------------------------------------------------------------------------------
/isokratia-client/components/Sidebar.tsx:
--------------------------------------------------------------------------------
1 | import Link from "next/link";
2 | import { useRouter } from "next/router";
3 | import Image from "next/image";
4 | import IsokratiaLogo from "../assets/isokratia.svg";
5 |
6 | export const Sidebar = () => {
7 | const router = useRouter();
8 | return (
9 |
87 | );
88 | };
89 |
--------------------------------------------------------------------------------
/isokratia-aggregator/python/field_helper.py:
--------------------------------------------------------------------------------
1 | from curve_field_elements import field_modulus, FQ, FQ2, FQ12, inv
2 |
3 | def numberToBase(num, b):
4 | num = abs(num)
5 | # assume num >= 0
6 | if num==0:
7 | return [0]
8 | registers = []
9 | while num:
10 | registers.append(int(num % b))
11 | num //= b
12 | return registers
13 |
14 | def numberToArray(num, n, k):
15 | num = abs(num)
16 | # assume num >= 0
17 | registers = []
18 | for i in range(k):
19 | registers.append(int(num % (2**n)))
20 | num //= 2**n
21 | return registers
22 |
23 | def hamming_weight(x):
24 | num = abs(x)
25 | ones = 0;
26 | while num:
27 | if num & 1:
28 | ones = ones + 1
29 | num //= 2
30 | return ones
31 |
32 | def printEllipticPoint(P, n, k):
33 | print(numberToArray(num=P[0].n, n=n, k=k), numberToArray(num=P[1].n, n=n, k=k))
34 |
35 | def printFQ(x, n, k):
36 | print("[", end="")
37 | A = numberToArray(x.n, n, k)
38 | for idx in range(len(A)):
39 | print(f'"{A[idx]}"', end="")
40 | if idx != len(A)-1:
41 | print(",")
42 | print("]", end="")
43 |
44 | def printFQ2(X, n, k):
45 | in22 = X.coeffs
46 | print("[")
47 | for i in range(len(in22)):
48 | printFQ(in22[i], n, k)
49 | if i != len(in22)-1:
50 | print(",")
51 | print("]")
52 |
53 | def Fp12convert(X, n, k, xi=1):
54 | basis1 = X.coeffs
55 | ret = []
56 | for i in range(6):
57 | fq2elt = FQ2([basis1[i].n, 0]) + FQ2([basis1[i+6].n, 0]) * FQ2([xi,1])
58 | ret.append([ numberToArray(fq2elt.coeffs[0].n, n, k) , numberToArray(fq2elt.coeffs[1].n, n, k) ])
59 | return ret
60 |
61 | def convert_out_to_Fp12(out, n, k):
62 | twelve = []
63 | for i in range(6):
64 | fp2 = []
65 | for j in range(2):
66 | num = 0;
67 | for idx in range(k):
68 | num = num + int(out[2*k * i + j*k + idx]) * (2 ** (n*idx))
69 | fp2.append(num)
70 | twelve.append( fp2 )
71 | coeff = [0] * 12
72 | for i in range(6):
73 | coeff[i] = twelve[i][0] - twelve[i][1]
74 | coeff[i+6] = twelve[i][1]
75 | return FQ12(coeff)
76 |
77 | def printFQ12(X, n, k, xi=1):
78 | in62 = Fp12convert(X, n, k, xi)
79 | print("[")
80 | for i in range(len(in62)):
81 | print("[", end="")
82 | C = in62[i]
83 | for j in range(len(C)):
84 | print("[", end="")
85 | A = C[j]
86 | for idx in range(len(A)):
87 | print(f'"{A[idx]}"', end="")
88 | if idx != len(A)-1:
89 | print(",")
90 | print("]", end="")
91 | if j != len(C)-1:
92 | print(",")
93 | print("]", end="")
94 | if i != len(in62)-1:
95 | print(",")
96 | print("]")
97 |
98 | def print_fq12_frobenius_coeff(q, n, k, xi=1):
99 | gamma = [[0]*6]*12
100 | for j in range(12):
101 | gamma[j] = [ FQ2([xi,1]) ** ( (i*(q**j-1)//6) % (q**2-1) ) for i in range(6)]
102 | for j in range(12):
103 | for i in range(6):
104 | A, B = gamma[j][i].coeffs
105 | a = A.n
106 | b = B.n
107 | for r in range(k):
108 | print(f"coeff[{j}][{i}][0][{r}] = {a%(2**n)};")
109 | a //= 2**n
110 | print("")
111 | for r in range(k):
112 | print(f"coeff[{j}][{i}][1][{r}] = {b%(2**n)};")
113 | b //= 2**n
114 | print("")
115 |
--------------------------------------------------------------------------------
/isokratia-client/pages/api/votes/[proposal_id].ts:
--------------------------------------------------------------------------------
1 | import { PrismaClient } from "@prisma/client";
2 | import * as secp from "@noble/secp256k1";
3 | import keccak256 from "keccak256";
4 | import type { NextApiRequest, NextApiResponse } from "next";
5 | import { ethers } from "ethers";
6 |
7 | const prisma = new PrismaClient();
8 |
9 | type Vote = {
10 | address: string;
11 | pubkey: string;
12 | proposal_id: number;
13 | vote: string;
14 | sig: string;
15 | };
16 |
17 | // bigendian
18 | function bigint_to_Uint8Array(x: bigint) {
19 | var ret = new Uint8Array(32);
20 | for (var idx = 31; idx >= 0; idx--) {
21 | ret[idx] = Number(x % 256n);
22 | x = x / 256n;
23 | }
24 | return ret;
25 | }
26 |
27 | // bigendian
28 | function Uint8Array_to_bigint(x: Buffer) {
29 | var ret = 0n;
30 | for (var idx = 0; idx < x.length; idx++) {
31 | ret = ret * 256n;
32 | ret = ret + BigInt(x[idx]);
33 | }
34 | return ret;
35 | }
36 |
37 | async function createVote(vote: Vote) {
38 | const msg =
39 | "isokratia vote " + vote.vote + " for proposal " + vote.proposal_id;
40 | console.log("MESSSAGE: " + msg);
41 |
42 | // let prefix = "\x19Ethereum Signed Message:\n";
43 | // prefix += String(msg.length);
44 |
45 | // const prefixed = prefix.concat(msg);
46 | // console.log(prefixed);
47 |
48 | // const msghash_bigint = Uint8Array_to_bigint(keccak256(prefixed));
49 | // const msghash = bigint_to_Uint8Array(msghash_bigint);
50 | // // console.log("VOTE", vote);
51 | // console.log("SIG", vote.sig);
52 | // console.log("VOTE", vote);
53 | // console.log("HASH", msghash);
54 | // console.log("PUBKEY", vote.pubkey);
55 |
56 | // // if (!secp.verify(vote.sig, msghash, vote.pubkey)) {
57 | // // console.log("nope");
58 | // // return 400;
59 | // // }
60 |
61 | const address = ethers.utils.verifyMessage(msg, vote.sig);
62 | console.log("returned", address);
63 | if (address !== vote.address) {
64 | console.log("nope");
65 | return 400;
66 | }
67 |
68 | // check if already voted in prisma
69 | const existing = await prisma.vote.findFirst({
70 | where: {
71 | address: vote.address,
72 | proposal_id: vote.proposal_id,
73 | },
74 | });
75 | if (existing) {
76 | return 400;
77 | }
78 |
79 | console.log("creating vote...");
80 | await prisma.vote.create({
81 | data: {
82 | ...vote,
83 | },
84 | });
85 |
86 | console.log("done");
87 |
88 | return 200;
89 | }
90 |
91 | export default async function handler(
92 | req: NextApiRequest,
93 | res: NextApiResponse
94 | ) {
95 | if (req.method === "POST") {
96 | const bobody = req.body;
97 | const body = JSON.parse(bobody);
98 | const proposal_id = Number(body.proposal_id);
99 | const address = body.address as string;
100 | const pubkey = body.pubkey as string;
101 | const vote = body.vote as string;
102 | const sig = body.sig as string;
103 | console.log(proposal_id, address, pubkey, vote, sig);
104 | if (!proposal_id || !address || !pubkey || !vote || !sig) {
105 | console.log("missing fields");
106 | return res.status(400).send("missing parameters");
107 | }
108 | // Process a POST request
109 | console.log("Calling createVote()");
110 | const statusCode = await createVote({
111 | address,
112 | pubkey,
113 | proposal_id,
114 | vote,
115 | sig,
116 | });
117 | console.log("STATUSCODE", statusCode);
118 | res.status(statusCode).end();
119 | } else if (req.method === "GET") {
120 | // Handle a GET request
121 | const votes = await prisma.vote.findMany({
122 | where: {
123 | proposal_id: Number(req.query.proposal_id),
124 | },
125 | });
126 | return res.json(votes);
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/isokratia-aggregator/python/script.py:
--------------------------------------------------------------------------------
1 |
2 | from ast import arg
3 | from py_ecc.fields import (
4 | bn128_FQ as FQ,
5 | bn128_FQ2 as FQ2,
6 | bn128_FQ12 as FQ12,
7 | )
8 | from py_ecc.bn128 import (
9 | bn128_curve as curve
10 | )
11 | from field_helper import (
12 | numberToArray,
13 | numberToBase,
14 | hamming_weight,
15 | printEllipticPoint,
16 | printFQ,
17 | printFQ2,
18 | Fp12convert,
19 | printFQ12,
20 | print_fq12_frobenius_coeff
21 | )
22 | import math
23 |
24 | from py_ecc.fields import (
25 | bn128_FQ as FQ,
26 | bn128_FQ2 as FQ2,
27 | bn128_FQ12 as FQ12,
28 | )
29 | from py_ecc.bn128 import (
30 | bn128_curve as curve,
31 | bn128_pairing as pairing
32 | )
33 | import json
34 | import sys
35 |
36 | # get cli arg
37 | if len(sys.argv) != 2:
38 | print("Usage: python3 script.py ")
39 | exit(1)
40 |
41 | input_filename = sys.argv[1]
42 | with open("../prover-output/" + input_filename, 'r') as input_file:
43 | input_data = input_file.read()
44 | proof = json.loads(input_data)
45 |
46 |
47 | with open('vkey.json', 'r') as vkey_file:
48 | vkey_data = vkey_file.read()
49 | vkey = json.loads(vkey_data)
50 |
51 | x, y, z = tuple([FQ((int(x))) for x in vkey["vk_alpha_1"]])
52 | negalpha = ( x / z, -(y / z) )
53 | # print("negalpha", negalpha)
54 |
55 | x, y, z = tuple([ FQ2([int(x[0]), int(x[1])]) for x in vkey["vk_beta_2"]])
56 | beta = ( x / z, y / z )
57 |
58 | # print("beta", beta)
59 |
60 |
61 | x, y, z = tuple([ FQ2([int(x[0]), int(x[1])]) for x in vkey["vk_gamma_2"]])
62 | gamma = ( x / z, y / z )
63 |
64 | # print("gamma", gamma)
65 |
66 |
67 | x, y, z = tuple([ FQ2([int(x[0]), int(x[1])]) for x in vkey["vk_delta_2"]])
68 | delta = ( x / z, y / z )
69 |
70 | # print("delta", delta)
71 |
72 | public_input_count = vkey["nPublic"]
73 |
74 | ICs = []
75 | for i in range(public_input_count + 1):
76 | x, y, z = tuple([ FQ(int(x)) for x in vkey["IC"][i]])
77 | ICs.append( ( x / z, y / z ) )
78 |
79 | negalphabeta = pairing.pairing( beta, negalpha )
80 | #print("negalphabeta", negalphabeta)
81 |
82 | def Fpconvert(X, n, k):
83 | return numberToArray(X.n, n, k)
84 |
85 | def Fp2convert(X, n, k):
86 | return [ numberToArray(X.coeffs[0].n, n, k) , numberToArray(X.coeffs[1].n, n, k) ]
87 |
88 | def Fp12convert(X, n, k):
89 | basis1 = X.coeffs
90 | ret = []
91 | for i in range(6):
92 | fq2elt = FQ2([basis1[i].n, 0]) + FQ2([basis1[i+6].n, 0]) * FQ2([9,1])
93 | ret.append(Fp2convert(fq2elt, n, k))
94 | return ret
95 |
96 | n = 43
97 | k = 6
98 |
99 | inputParameters = {
100 | "gamma2": [ Fp2convert(gamma[0], n, k), Fp2convert(gamma[1], n, k)],
101 | "delta2": [ Fp2convert(delta[0], n, k), Fp2convert(delta[1], n, k)],
102 | "negalfa1xbeta2": Fp12convert(negalphabeta, n, k),
103 | "IC": [[Fpconvert(IC[0], n, k), Fpconvert(IC[1], n, k)] for IC in ICs],
104 | }
105 |
106 | print("inputParameters", inputParameters)
107 |
108 | # with open('proof.json', 'r') as proof_file:
109 | # proof_data = proof_file.read()
110 | # proof = json.loads(proof_data)
111 |
112 | x, y, z = tuple([FQ((int(x))) for x in proof["pi_a"]])
113 | negpi_a = (x / z, - (y / z))
114 |
115 | x, y, z = tuple([ FQ2([int(x[0]), int(x[1])]) for x in proof["pi_b"]])
116 | pi_b = (x / z, y / z)
117 |
118 | x, y, z = tuple([FQ((int(x))) for x in proof["pi_c"]])
119 | pi_c = (x / z, y / z)
120 |
121 | proofParameters = {
122 | "negpa": [Fpconvert(negpi_a[0], n, k), Fpconvert(negpi_a[1], n, k)],
123 | "pb": [ Fp2convert(pi_b[0], n, k), Fp2convert(pi_b[1], n, k)],
124 | "pc": [Fpconvert(pi_c[0], n, k), Fpconvert(pi_c[1], n, k)],
125 | }
126 |
127 | print("proofParameters", proofParameters)
128 |
129 | fullCircomInput = {**inputParameters, **proofParameters}
130 |
131 | with open('../input/' + input_filename, 'w') as outfile:
132 | json.dump(fullCircomInput, outfile)
133 |
--------------------------------------------------------------------------------
/isokratia-client/pages/api/proposal.ts:
--------------------------------------------------------------------------------
1 | import { PrismaClient, proposalOptions } from "@prisma/client";
2 | import { ethers } from "ethers";
3 | import MerkleTree from "fixed-merkle-tree";
4 | import type { NextApiRequest, NextApiResponse } from "next";
5 | import mimcHash from "../../lib/mimc";
6 |
7 | const prisma = new PrismaClient();
8 |
9 | type Proposal = {
10 | title: string;
11 | description: string;
12 | endBlock: string;
13 | };
14 |
15 | function hasher(x: string | number) {
16 | return mimcHash(123)(BigInt(x)).toString();
17 | }
18 |
19 | function hasher2(x: string | number, y: string | number) {
20 | return mimcHash(123)(BigInt(x), BigInt(y)).toString();
21 | }
22 |
23 | async function fetchOwners(contractAddr: string) {
24 | const requestOptions = {
25 | method: "GET",
26 | };
27 |
28 | const apiKey = "demo";
29 | const baseURL = `https://eth-mainnet.alchemyapi.io/nft/v2/${apiKey}/getOwnersForCollection`;
30 | const fetchURL = `${baseURL}?contractAddress=${contractAddr}`;
31 | const resp = await fetch(fetchURL, requestOptions);
32 | let filteredAddresses: string[] = [];
33 | try {
34 | const respJson = await resp.json();
35 | filteredAddresses = respJson.ownerAddresses.filter(
36 | (addr: string) => addr !== ethers.constants.AddressZero
37 | );
38 | } catch (e) {
39 | console.error(e);
40 | }
41 |
42 | console.log("ownerAddresses", filteredAddresses);
43 | return filteredAddresses;
44 | }
45 |
46 | async function createProposal(
47 | prop: Proposal,
48 | contractAddr: string,
49 | options: string[]
50 | ): Promise {
51 | const merkleLeaves = await fetchOwners(contractAddr);
52 | const leafs = merkleLeaves.map((addr: string) => hasher(addr));
53 | console.log("leafs", leafs);
54 | const tree = new MerkleTree(22, leafs, { hashFunction: hasher2 });
55 | const randproof = tree.path(0);
56 |
57 | console.log("randproof", randproof);
58 |
59 | console.log("prop", prop);
60 | console.log("merkleLeaves", merkleLeaves);
61 | console.log("root", tree.root);
62 | const propModel = await prisma.proposal.create({
63 | data: {
64 | ...prop,
65 | merkleRoot: tree.root.toString(),
66 | },
67 | });
68 | const allLeafs = leafs.map((leaf) => ({
69 | merkleRoot: tree.root.toString(),
70 | merkleLeaf: leaf,
71 | }));
72 | for (let i = 0; i < allLeafs.length; i += 1000) {
73 | const chunk = allLeafs.slice(i, i + 1000);
74 | const createRes = await prisma.merkle.createMany({
75 | data: chunk,
76 | skipDuplicates: true,
77 | });
78 | console.log("createRes", createRes);
79 | }
80 |
81 | for (const option of options) {
82 | await prisma.proposalOptions.create({
83 | data: {
84 | proposal_id: propModel.id,
85 | option,
86 | },
87 | });
88 | }
89 | console.log("inserted everything");
90 | return propModel.id;
91 | }
92 |
93 | export default async function handler(
94 | req: NextApiRequest,
95 | res: NextApiResponse
96 | ) {
97 | if (req.method === "POST") {
98 | // Process a POST request
99 | const body = JSON.parse(req.body);
100 | console.log(
101 | "req.body",
102 | req.body,
103 | body.proposal,
104 | body.contractAddr,
105 | body.options
106 | );
107 | const proposalId = await createProposal(
108 | body.proposal,
109 | body.contractAddr,
110 | body.options
111 | );
112 | res.json({ msg: "Proposal created", proposal_id: proposalId });
113 | } else if (req.method === "GET") {
114 | // Handle a GET request
115 | const proposals = await prisma.proposal.findMany();
116 | const ans = [];
117 | for (const proposal of proposals) {
118 | const optionRows = await prisma.proposalOptions.findMany({
119 | where: {
120 | proposal_id: proposal.id,
121 | },
122 | });
123 | const options = optionRows.map((option) => option.option);
124 | ans.push({ ...proposal, options });
125 | }
126 | res.json(ans);
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/isokratia-contracts/src/Isokratia.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: UNLICENSED
2 | pragma solidity ^0.8.13;
3 |
4 | import "./Verifier.sol";
5 |
6 | contract Isokratia is Verifier {
7 | uint256 constant k1 = 4;
8 | uint256 constant k2 = 6;
9 |
10 | event ProposalCreated(address creator, uint256 proposalId, uint256 endBlock);
11 | event AggregateCreated(uint256 proposalId, string option, uint256 voteCount);
12 |
13 | struct Proposal {
14 | uint256 id;
15 | uint256 endBlock;
16 | uint256 eligibleRoot;
17 | mapping(string => uint64[k1]) options;
18 | mapping(string => uint256) voteCount;
19 | }
20 |
21 | mapping(uint256 => Proposal) proposals;
22 | uint256[6][2][6] negalfa1xbeta2;
23 | uint256[6][2][2] gamma2;
24 | uint256[6][2][2] delta2;
25 | uint256[6][2][2] IC;
26 |
27 | function createProposal(uint256 proposalId,
28 | uint256 endBlock,
29 | uint256 eligibleRoot,
30 | uint64[k1][] memory options,
31 | string[] memory optionText) public {
32 | require(proposals[proposalId].id == 0, "Proposal already exists");
33 | proposals[proposalId].id = proposalId;
34 | proposals[proposalId].endBlock = endBlock;
35 | proposals[proposalId].eligibleRoot = eligibleRoot;
36 | for (uint256 i = 0; i < options.length; i++) {
37 | proposals[proposalId].options[optionText[i]] = options[i];
38 | }
39 | emit ProposalCreated(msg.sender, proposalId, endBlock);
40 | }
41 |
42 | function postAggregation(uint256 proposalId,
43 | string memory option,
44 | uint256 voteCount,
45 | uint256 voterRoot,
46 | uint256[2] memory _a,
47 | uint256[2][2] memory _b,
48 | uint256[2] memory _c,
49 | uint256[1] memory _input) public {
50 | require(block.number <= proposals[proposalId].endBlock, "Proposal has expired");
51 | require(verifyProof(_a, _b, _c, _input), "Bad proof");
52 |
53 | uint256[3 + k1 + 6 * 2 * k2 + 3 * 2 * 2 * k2] memory commitmentInputs;
54 | commitmentInputs[0] = voteCount;
55 | commitmentInputs[1] = proposals[proposalId].eligibleRoot;
56 | commitmentInputs[2] = voterRoot;
57 | uint256 hasherIdx = 3;
58 | for (uint256 i = 0;i < k1;i++) {
59 | commitmentInputs[hasherIdx] = proposals[proposalId].options[option][i];
60 | hasherIdx++;
61 | }
62 |
63 | for (uint256 i = 0;i < 6;i++) {
64 | for (uint256 j = 0;j < 2;j++) {
65 | for (uint256 idx = 0;idx < k2;idx++) {
66 | commitmentInputs[hasherIdx] = negalfa1xbeta2[i][j][idx];
67 | hasherIdx++;
68 | }
69 | }
70 | }
71 |
72 | for (uint256 i = 0;i < 2;i++) {
73 | for (uint256 j = 0;j < 2;j++) {
74 | for (uint256 idx = 0;idx < k2;idx++) {
75 | commitmentInputs[hasherIdx] = gamma2[i][j][idx];
76 | hasherIdx++;
77 | }
78 | }
79 | }
80 |
81 | for (uint256 i = 0;i < 2;i++) {
82 | for (uint256 j = 0;j < 2;j++) {
83 | for (uint256 idx = 0;idx < k2;idx++) {
84 | commitmentInputs[hasherIdx] = delta2[i][j][idx];
85 | hasherIdx++;
86 | }
87 | }
88 | }
89 |
90 | for (uint256 i = 0;i < 2;i++) {
91 | for (uint256 j = 0;j < 2;j++) {
92 | for (uint256 idx = 0;idx < k2;idx++) {
93 | commitmentInputs[hasherIdx] = IC[i][j][idx];
94 | hasherIdx++;
95 | }
96 | }
97 | }
98 |
99 | uint256 hash = uint256(sha256(abi.encode(commitmentInputs))) >> 6;
100 | require(_input[0] == hash, "Bad public commitment");
101 |
102 | if (voteCount > proposals[proposalId].voteCount[option]) {
103 | proposals[proposalId].voteCount[option] = voteCount;
104 | emit AggregateCreated(proposalId, option, voteCount);
105 | }
106 | }
107 |
108 | constructor(
109 | uint256[6][2][6] memory _negalfa1xbeta2,
110 | uint256[6][2][2] memory _gamma2,
111 | uint256[6][2][2] memory _delta2,
112 | uint256[6][2][2] memory _IC
113 | ) {
114 | negalfa1xbeta2 = _negalfa1xbeta2;
115 | gamma2 = _gamma2;
116 | delta2 = _delta2;
117 | IC = _IC;
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/isokratia-aggregator/isokratia.abi.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "inputs": [
4 | {
5 | "internalType": "uint256[6][2][6]",
6 | "name": "_negalfa1xbeta2",
7 | "type": "uint256[6][2][6]"
8 | },
9 | {
10 | "internalType": "uint256[6][2][2]",
11 | "name": "_gamma2",
12 | "type": "uint256[6][2][2]"
13 | },
14 | {
15 | "internalType": "uint256[6][2][2]",
16 | "name": "_delta2",
17 | "type": "uint256[6][2][2]"
18 | },
19 | {
20 | "internalType": "uint256[6][2][2]",
21 | "name": "_IC",
22 | "type": "uint256[6][2][2]"
23 | }
24 | ],
25 | "stateMutability": "nonpayable",
26 | "type": "constructor"
27 | },
28 | {
29 | "anonymous": false,
30 | "inputs": [
31 | {
32 | "indexed": false,
33 | "internalType": "uint256",
34 | "name": "proposalId",
35 | "type": "uint256"
36 | },
37 | {
38 | "indexed": false,
39 | "internalType": "uint256",
40 | "name": "option",
41 | "type": "uint256"
42 | },
43 | {
44 | "indexed": false,
45 | "internalType": "uint256",
46 | "name": "voteCount",
47 | "type": "uint256"
48 | }
49 | ],
50 | "name": "AggregateCreated",
51 | "type": "event"
52 | },
53 | {
54 | "anonymous": false,
55 | "inputs": [
56 | {
57 | "indexed": false,
58 | "internalType": "address",
59 | "name": "creator",
60 | "type": "address"
61 | },
62 | {
63 | "indexed": false,
64 | "internalType": "uint256",
65 | "name": "proposalId",
66 | "type": "uint256"
67 | },
68 | {
69 | "indexed": false,
70 | "internalType": "uint256",
71 | "name": "endBlock",
72 | "type": "uint256"
73 | }
74 | ],
75 | "name": "ProposalCreated",
76 | "type": "event"
77 | },
78 | {
79 | "inputs": [
80 | {
81 | "internalType": "uint256",
82 | "name": "proposalId",
83 | "type": "uint256"
84 | },
85 | {
86 | "internalType": "uint256",
87 | "name": "endBlock",
88 | "type": "uint256"
89 | },
90 | {
91 | "internalType": "uint256",
92 | "name": "eligibleRoot",
93 | "type": "uint256"
94 | },
95 | {
96 | "internalType": "uint64[4][]",
97 | "name": "options",
98 | "type": "uint64[4][]"
99 | },
100 | {
101 | "internalType": "string[]",
102 | "name": "optionText",
103 | "type": "string[]"
104 | }
105 | ],
106 | "name": "createProposal",
107 | "outputs": [],
108 | "stateMutability": "nonpayable",
109 | "type": "function"
110 | },
111 | {
112 | "inputs": [
113 | {
114 | "internalType": "uint256",
115 | "name": "proposalId",
116 | "type": "uint256"
117 | },
118 | {
119 | "internalType": "string",
120 | "name": "option",
121 | "type": "string"
122 | },
123 | {
124 | "internalType": "uint256",
125 | "name": "voteCount",
126 | "type": "uint256"
127 | },
128 | {
129 | "internalType": "uint256",
130 | "name": "voterRoot",
131 | "type": "uint256"
132 | },
133 | {
134 | "internalType": "uint256[2]",
135 | "name": "_a",
136 | "type": "uint256[2]"
137 | },
138 | {
139 | "internalType": "uint256[2][2]",
140 | "name": "_b",
141 | "type": "uint256[2][2]"
142 | },
143 | {
144 | "internalType": "uint256[2]",
145 | "name": "_c",
146 | "type": "uint256[2]"
147 | },
148 | {
149 | "internalType": "uint256[1]",
150 | "name": "_input",
151 | "type": "uint256[1]"
152 | }
153 | ],
154 | "name": "postAggregation",
155 | "outputs": [],
156 | "stateMutability": "nonpayable",
157 | "type": "function"
158 | },
159 | {
160 | "inputs": [
161 | {
162 | "internalType": "uint256[2]",
163 | "name": "a",
164 | "type": "uint256[2]"
165 | },
166 | {
167 | "internalType": "uint256[2][2]",
168 | "name": "b",
169 | "type": "uint256[2][2]"
170 | },
171 | {
172 | "internalType": "uint256[2]",
173 | "name": "c",
174 | "type": "uint256[2]"
175 | },
176 | {
177 | "internalType": "uint256[1]",
178 | "name": "input",
179 | "type": "uint256[1]"
180 | }
181 | ],
182 | "name": "verifyProof",
183 | "outputs": [
184 | {
185 | "internalType": "bool",
186 | "name": "r",
187 | "type": "bool"
188 | }
189 | ],
190 | "stateMutability": "view",
191 | "type": "function"
192 | }
193 | ]
194 |
--------------------------------------------------------------------------------
/isokratia-client/lib/isokratia.abi.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "inputs": [
4 | {
5 | "internalType": "uint256[6][2][6]",
6 | "name": "_negalfa1xbeta2",
7 | "type": "uint256[6][2][6]"
8 | },
9 | {
10 | "internalType": "uint256[6][2][2]",
11 | "name": "_gamma2",
12 | "type": "uint256[6][2][2]"
13 | },
14 | {
15 | "internalType": "uint256[6][2][2]",
16 | "name": "_delta2",
17 | "type": "uint256[6][2][2]"
18 | },
19 | {
20 | "internalType": "uint256[6][2][2]",
21 | "name": "_IC",
22 | "type": "uint256[6][2][2]"
23 | }
24 | ],
25 | "stateMutability": "nonpayable",
26 | "type": "constructor"
27 | },
28 | {
29 | "anonymous": false,
30 | "inputs": [
31 | {
32 | "indexed": false,
33 | "internalType": "uint256",
34 | "name": "proposalId",
35 | "type": "uint256"
36 | },
37 | {
38 | "indexed": false,
39 | "internalType": "uint256",
40 | "name": "option",
41 | "type": "uint256"
42 | },
43 | {
44 | "indexed": false,
45 | "internalType": "uint256",
46 | "name": "voteCount",
47 | "type": "uint256"
48 | }
49 | ],
50 | "name": "AggregateCreated",
51 | "type": "event"
52 | },
53 | {
54 | "anonymous": false,
55 | "inputs": [
56 | {
57 | "indexed": false,
58 | "internalType": "address",
59 | "name": "creator",
60 | "type": "address"
61 | },
62 | {
63 | "indexed": false,
64 | "internalType": "uint256",
65 | "name": "proposalId",
66 | "type": "uint256"
67 | },
68 | {
69 | "indexed": false,
70 | "internalType": "uint256",
71 | "name": "endBlock",
72 | "type": "uint256"
73 | }
74 | ],
75 | "name": "ProposalCreated",
76 | "type": "event"
77 | },
78 | {
79 | "inputs": [
80 | {
81 | "internalType": "uint256",
82 | "name": "proposalId",
83 | "type": "uint256"
84 | },
85 | {
86 | "internalType": "uint256",
87 | "name": "endBlock",
88 | "type": "uint256"
89 | },
90 | {
91 | "internalType": "uint256",
92 | "name": "eligibleRoot",
93 | "type": "uint256"
94 | },
95 | {
96 | "internalType": "uint64[4][]",
97 | "name": "options",
98 | "type": "uint64[4][]"
99 | },
100 | {
101 | "internalType": "string[]",
102 | "name": "optionText",
103 | "type": "string[]"
104 | }
105 | ],
106 | "name": "createProposal",
107 | "outputs": [],
108 | "stateMutability": "nonpayable",
109 | "type": "function"
110 | },
111 | {
112 | "inputs": [
113 | {
114 | "internalType": "uint256",
115 | "name": "proposalId",
116 | "type": "uint256"
117 | },
118 | {
119 | "internalType": "string",
120 | "name": "option",
121 | "type": "string"
122 | },
123 | {
124 | "internalType": "uint256",
125 | "name": "voteCount",
126 | "type": "uint256"
127 | },
128 | {
129 | "internalType": "uint256",
130 | "name": "voterRoot",
131 | "type": "uint256"
132 | },
133 | {
134 | "internalType": "uint256[2]",
135 | "name": "_a",
136 | "type": "uint256[2]"
137 | },
138 | {
139 | "internalType": "uint256[2][2]",
140 | "name": "_b",
141 | "type": "uint256[2][2]"
142 | },
143 | {
144 | "internalType": "uint256[2]",
145 | "name": "_c",
146 | "type": "uint256[2]"
147 | },
148 | {
149 | "internalType": "uint256[1]",
150 | "name": "_input",
151 | "type": "uint256[1]"
152 | }
153 | ],
154 | "name": "postAggregation",
155 | "outputs": [],
156 | "stateMutability": "nonpayable",
157 | "type": "function"
158 | },
159 | {
160 | "inputs": [
161 | {
162 | "internalType": "uint256[2]",
163 | "name": "a",
164 | "type": "uint256[2]"
165 | },
166 | {
167 | "internalType": "uint256[2][2]",
168 | "name": "b",
169 | "type": "uint256[2][2]"
170 | },
171 | {
172 | "internalType": "uint256[2]",
173 | "name": "c",
174 | "type": "uint256[2]"
175 | },
176 | {
177 | "internalType": "uint256[1]",
178 | "name": "input",
179 | "type": "uint256[1]"
180 | }
181 | ],
182 | "name": "verifyProof",
183 | "outputs": [
184 | {
185 | "internalType": "bool",
186 | "name": "r",
187 | "type": "bool"
188 | }
189 | ],
190 | "stateMutability": "view",
191 | "type": "function"
192 | }
193 | ]
194 |
--------------------------------------------------------------------------------
/isokratia-aggregator/input/blank-proof.json:
--------------------------------------------------------------------------------
1 | {
2 | "gamma2": [
3 | [
4 | [
5 | 5896345417453,
6 | 4240670514135,
7 | 6172078461917,
8 | 219834884668,
9 | 2138480846496,
10 | 206187650596
11 | ],
12 | [
13 | 6286472319682,
14 | 5759053266064,
15 | 8549822680278,
16 | 8639745994386,
17 | 912741836299,
18 | 219532437284
19 | ]
20 | ],
21 | [
22 | [
23 | 4404069170602,
24 | 525855202521,
25 | 8311963231281,
26 | 825823174727,
27 | 854139906743,
28 | 161342114743
29 | ],
30 | [
31 | 3147424765787,
32 | 7086132606363,
33 | 7632907980226,
34 | 5320198199754,
35 | 6592898451945,
36 | 77528801456
37 | ]
38 | ]
39 | ],
40 | "delta2": [
41 | [
42 | [
43 | 7729836325927,
44 | 8517956451685,
45 | 4033364554740,
46 | 4001789754505,
47 | 7653645210298,
48 | 354447782510
49 | ],
50 | [
51 | 1388103822577,
52 | 8404010102298,
53 | 856053778201,
54 | 3507911936631,
55 | 8206162100929,
56 | 113445856491
57 | ]
58 | ],
59 | [
60 | [
61 | 8793217999691,
62 | 7106301969696,
63 | 7718490619722,
64 | 7819179045430,
65 | 4590999760248,
66 | 24605411388
67 | ],
68 | [
69 | 5042627280266,
70 | 157842999214,
71 | 5958854182355,
72 | 950781649488,
73 | 8416741364710,
74 | 180571071519
75 | ]
76 | ]
77 | ],
78 | "negalfa1xbeta2": [
79 | [
80 | [
81 | 4063420080633,
82 | 6555003798509,
83 | 3528875089017,
84 | 5800537096256,
85 | 8041381108016,
86 | 203518374640
87 | ],
88 | [
89 | 7676269984398,
90 | 1145806392863,
91 | 6738515895690,
92 | 5144301275423,
93 | 8547057760405,
94 | 353834589854
95 | ]
96 | ],
97 | [
98 | [
99 | 5712635615088,
100 | 8763475698695,
101 | 7480760495871,
102 | 1630925336586,
103 | 5902994417779,
104 | 229051200835
105 | ],
106 | [
107 | 1066113280330,
108 | 5452941452156,
109 | 130670027992,
110 | 6364438679415,
111 | 8227984268724,
112 | 117895881848
113 | ]
114 | ],
115 | [
116 | [
117 | 2720638156466,
118 | 8183746692879,
119 | 2805734624200,
120 | 4541538633192,
121 | 1476702149455,
122 | 162434980571
123 | ],
124 | [
125 | 4093955238700,
126 | 4839352246179,
127 | 5773319594517,
128 | 5269728708172,
129 | 8404179905859,
130 | 4522318692
131 | ]
132 | ],
133 | [
134 | [
135 | 7907150524416,
136 | 8555524456643,
137 | 2425990496019,
138 | 5117607179458,
139 | 886559720121,
140 | 343845114320
141 | ],
142 | [
143 | 3348806304058,
144 | 5295378168489,
145 | 5426585403009,
146 | 4313512356362,
147 | 2882006508456,
148 | 312905790371
149 | ]
150 | ],
151 | [
152 | [
153 | 6984987484510,
154 | 4411212100320,
155 | 517962775393,
156 | 5578757090043,
157 | 1344911245314,
158 | 115782940661
159 | ],
160 | [
161 | 4257694794763,
162 | 5641455412912,
163 | 2987387394488,
164 | 6147130513016,
165 | 8766894161060,
166 | 7451503335
167 | ]
168 | ],
169 | [
170 | [
171 | 3338043330865,
172 | 3023333978926,
173 | 4787719622265,
174 | 3729967781503,
175 | 2489094582823,
176 | 396043239802
177 | ],
178 | [
179 | 3390886416082,
180 | 169102433935,
181 | 2279828268438,
182 | 1618451670976,
183 | 7055320302964,
184 | 48334526481
185 | ]
186 | ]
187 | ],
188 | "IC": [
189 | [
190 | [
191 | 1305955898557,
192 | 3221302193155,
193 | 3753836914638,
194 | 7483109180474,
195 | 113006122330,
196 | 47417911287
197 | ],
198 | [
199 | 2759575456530,
200 | 474829102102,
201 | 6863269531525,
202 | 3805895321977,
203 | 5414803739806,
204 | 277837986502
205 | ]
206 | ],
207 | [
208 | [
209 | 3369381598324,
210 | 6418327256523,
211 | 4972793884908,
212 | 1416394741695,
213 | 1069284332536,
214 | 390341521
215 | ],
216 | [
217 | 3118450096748,
218 | 1714056947546,
219 | 2837809434155,
220 | 97863249691,
221 | 2733156090833,
222 | 218341954120
223 | ]
224 | ]
225 | ],
226 | "negpa": [
227 | [
228 | 4547012633514,
229 | 3734179826641,
230 | 5701694206140,
231 | 8228603303588,
232 | 8166810032284,
233 | 287697405641
234 | ],
235 | [
236 | 7936624725970,
237 | 5244155220483,
238 | 2614633990827,
239 | 769045586806,
240 | 7030737374514,
241 | 321864557515
242 | ]
243 | ],
244 | "pb": [
245 | [
246 | [
247 | 944636897239,
248 | 2776026065075,
249 | 1052759613897,
250 | 5780317904717,
251 | 5008189681848,
252 | 89969650957
253 | ],
254 | [
255 | 3432532114129,
256 | 7420952041056,
257 | 6865904018167,
258 | 7700392694090,
259 | 5183103606674,
260 | 213665093717
261 | ]
262 | ],
263 | [
264 | [
265 | 1138264339255,
266 | 5370856292517,
267 | 3766509021664,
268 | 5376206092247,
269 | 5029956457933,
270 | 16160391664
271 | ],
272 | [
273 | 8712702116539,
274 | 713287588602,
275 | 1958004124298,
276 | 842368814564,
277 | 7187709731941,
278 | 183564221142
279 | ]
280 | ]
281 | ],
282 | "pc": [
283 | [
284 | 159892654859,
285 | 6048361664285,
286 | 962553760636,
287 | 5954803622503,
288 | 6717344616646,
289 | 374465385590
290 | ],
291 | [
292 | 7118012697894,
293 | 1204924798223,
294 | 2274080347035,
295 | 2492021970419,
296 | 6421980123332,
297 | 183539435855
298 | ]
299 | ]
300 | }
--------------------------------------------------------------------------------
/isokratia-contracts/script/Isokratia.s.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: UNLICENSED
2 | pragma solidity ^0.8.13;
3 |
4 | import "forge-std/Script.sol";
5 | import "../src/Isokratia.sol";
6 |
7 | contract ContractScript is Script {
8 | function setUp() public {}
9 |
10 | uint256[][][] NEGALFA1XBETA2 = [
11 | [
12 | [
13 | 4063420080633,
14 | 6555003798509,
15 | 3528875089017,
16 | 5800537096256,
17 | 8041381108016,
18 | 203518374640
19 | ],
20 | [
21 | 7676269984398,
22 | 1145806392863,
23 | 6738515895690,
24 | 5144301275423,
25 | 8547057760405,
26 | 353834589854
27 | ]
28 | ],
29 | [
30 | [
31 | 5712635615088,
32 | 8763475698695,
33 | 7480760495871,
34 | 1630925336586,
35 | 5902994417779,
36 | 229051200835
37 | ],
38 | [
39 | 1066113280330,
40 | 5452941452156,
41 | 130670027992,
42 | 6364438679415,
43 | 8227984268724,
44 | 117895881848
45 | ]
46 | ],
47 | [
48 | [
49 | 2720638156466,
50 | 8183746692879,
51 | 2805734624200,
52 | 4541538633192,
53 | 1476702149455,
54 | 162434980571
55 | ],
56 | [
57 | 4093955238700,
58 | 4839352246179,
59 | 5773319594517,
60 | 5269728708172,
61 | 8404179905859,
62 | 4522318692
63 | ]
64 | ],
65 | [
66 | [
67 | 7907150524416,
68 | 8555524456643,
69 | 2425990496019,
70 | 5117607179458,
71 | 886559720121,
72 | 343845114320
73 | ],
74 | [
75 | 3348806304058,
76 | 5295378168489,
77 | 5426585403009,
78 | 4313512356362,
79 | 2882006508456,
80 | 312905790371
81 | ]
82 | ],
83 | [
84 | [
85 | 6984987484510,
86 | 4411212100320,
87 | 517962775393,
88 | 5578757090043,
89 | 1344911245314,
90 | 115782940661
91 | ],
92 | [
93 | 4257694794763,
94 | 5641455412912,
95 | 2987387394488,
96 | 6147130513016,
97 | 8766894161060,
98 | 7451503335
99 | ]
100 | ],
101 | [
102 | [
103 | 3338043330865,
104 | 3023333978926,
105 | 4787719622265,
106 | 3729967781503,
107 | 2489094582823,
108 | 396043239802
109 | ],
110 | [
111 | 3390886416082,
112 | 169102433935,
113 | 2279828268438,
114 | 1618451670976,
115 | 7055320302964,
116 | 48334526481
117 | ]
118 | ]
119 | ];
120 |
121 | uint256[][][] GAMMA2 = [
122 | [
123 | [
124 | 5896345417453,
125 | 4240670514135,
126 | 6172078461917,
127 | 219834884668,
128 | 2138480846496,
129 | 206187650596
130 | ],
131 | [
132 | 6286472319682,
133 | 5759053266064,
134 | 8549822680278,
135 | 8639745994386,
136 | 912741836299,
137 | 219532437284
138 | ]
139 | ],
140 | [
141 | [
142 | 4404069170602,
143 | 525855202521,
144 | 8311963231281,
145 | 825823174727,
146 | 854139906743,
147 | 161342114743
148 | ],
149 | [
150 | 3147424765787,
151 | 7086132606363,
152 | 7632907980226,
153 | 5320198199754,
154 | 6592898451945,
155 | 77528801456
156 | ]
157 | ]
158 | ];
159 |
160 | uint256[][][] DELTA2 = [
161 | [
162 | [
163 | 7729836325927,
164 | 8517956451685,
165 | 4033364554740,
166 | 4001789754505,
167 | 7653645210298,
168 | 354447782510
169 | ],
170 | [
171 | 1388103822577,
172 | 8404010102298,
173 | 856053778201,
174 | 3507911936631,
175 | 8206162100929,
176 | 113445856491
177 | ]
178 | ],
179 | [
180 | [
181 | 8793217999691,
182 | 7106301969696,
183 | 7718490619722,
184 | 7819179045430,
185 | 4590999760248,
186 | 24605411388
187 | ],
188 | [
189 | 5042627280266,
190 | 157842999214,
191 | 5958854182355,
192 | 950781649488,
193 | 8416741364710,
194 | 180571071519
195 | ]
196 | ]
197 | ];
198 |
199 | uint256[][][] IC = [
200 | [
201 | [
202 | 1305955898557,
203 | 3221302193155,
204 | 3753836914638,
205 | 7483109180474,
206 | 113006122330,
207 | 47417911287
208 | ],
209 | [
210 | 2759575456530,
211 | 474829102102,
212 | 6863269531525,
213 | 3805895321977,
214 | 5414803739806,
215 | 277837986502
216 | ]
217 | ],
218 | [
219 | [
220 | 3369381598324,
221 | 6418327256523,
222 | 4972793884908,
223 | 1416394741695,
224 | 1069284332536,
225 | 390341521
226 | ],
227 | [
228 | 3118450096748,
229 | 1714056947546,
230 | 2837809434155,
231 | 97863249691,
232 | 2733156090833,
233 | 218341954120
234 | ]
235 | ]
236 | ];
237 |
238 | function run() public {
239 | vm.startBroadcast();
240 |
241 | uint256[6][2][6] memory _negalfa1xbeta2;
242 | for (uint i = 0;i < 6;i++) {
243 | for (uint j = 0;j < 2;j++) {
244 | for (uint k = 0;k < 6;k++) {
245 | _negalfa1xbeta2[i][j][k] = NEGALFA1XBETA2[i][j][k];
246 | }
247 | }
248 | }
249 |
250 | uint256[6][2][2] memory _gamma2;
251 | for (uint i = 0;i < 2;i++) {
252 | for (uint j = 0;j < 2;j++) {
253 | for (uint k = 0;k < 6;k++) {
254 | _gamma2[i][j][k] = GAMMA2[i][j][k];
255 | }
256 | }
257 | }
258 |
259 | uint256[6][2][2] memory _delta2;
260 | for (uint i = 0;i < 2;i++) {
261 | for (uint j = 0;j < 2;j++) {
262 | for (uint k = 0;k < 6;k++) {
263 | _delta2[i][j][k] = DELTA2[i][j][k];
264 | }
265 | }
266 | }
267 |
268 | uint256[6][2][2] memory _ic;
269 | for (uint i = 0;i < 2;i++) {
270 | for (uint j = 0;j < 2;j++) {
271 | for (uint k = 0;k < 6;k++) {
272 | _ic[i][j][k] = IC[i][j][k];
273 | }
274 | }
275 | }
276 | Isokratia isokratia = new Isokratia(
277 | _negalfa1xbeta2,
278 | _gamma2,
279 | _delta2,
280 | _ic
281 | );
282 | console.log(address(isokratia));
283 |
284 | vm.stopBroadcast();
285 | }
286 | }
287 |
--------------------------------------------------------------------------------
/isokratia-client/pages/proposal/[id].tsx:
--------------------------------------------------------------------------------
1 | import { ethers } from "ethers";
2 | import type { NextPage } from "next";
3 | import Head from "next/head";
4 | import { useRouter } from "next/router";
5 | import { useEffect, useState } from "react";
6 | import { useAccount, useSignMessage } from "wagmi";
7 | import { Loading } from "../../components/Loading";
8 | import { Nav } from "../../components/Nav";
9 | import { ProposalStatus } from "../../components/ProposalStatus";
10 | import { Sidebar } from "../../components/Sidebar";
11 | import mimcHash from "../../lib/mimc";
12 | import { baseURL } from "../../lib/misc";
13 | import { Proposal, Vote } from "../../types";
14 |
15 | const getPublicKey = (signatureString: string, signText: string) => {
16 | const msgHash = ethers.utils.hashMessage(signText);
17 | const publicKey = ethers.utils.recoverPublicKey(
18 | msgHash,
19 | ethers.utils.arrayify(signatureString)
20 | );
21 | return publicKey;
22 | };
23 |
24 | const ProposalPage: NextPage<{
25 | proposal: Proposal;
26 | options: string[];
27 | }> = ({ proposal, options }) => {
28 | const router = useRouter();
29 | const proposalId = Number(router.query.id);
30 | // const proposal = proposals.find((p) => p.id === proposalId)!;
31 | const [votes, setVotes] = useState([]);
32 | const [canVote, setCanVote] = useState(false);
33 | const [hasVoted, setHasVoted] = useState(false);
34 | const [loadingVote, setLoadingVote] = useState(false);
35 | const [votingStatus, setVotingStatus] = useState("Loading...");
36 | const { data: account } = useAccount();
37 | const { signMessageAsync } = useSignMessage();
38 |
39 | function hasher(x: string | number) {
40 | return mimcHash(123)(BigInt(x)).toString();
41 | }
42 |
43 | useEffect(() => {
44 | if (!account) {
45 | setVotingStatus("Connect wallet to vote");
46 | return;
47 | }
48 | if (hasVoted) {
49 | setVotingStatus("You have already voted");
50 | return;
51 | }
52 | if (canVote) {
53 | setVotingStatus("Cast your vote");
54 | return;
55 | }
56 | setVotingStatus("You are not eligible to vote.");
57 | }, [canVote, hasVoted, account]);
58 |
59 | useEffect(() => {
60 | const fetchVotes = async () => {
61 | const votesFromAPI = await fetch(`${baseURL}/api/votes/${proposalId}`, {
62 | method: "GET",
63 | });
64 | const res = await votesFromAPI.json();
65 | setVotes(res);
66 | if (!account) {
67 | setHasVoted(false);
68 | setCanVote(false);
69 | return;
70 | }
71 | const hasVoted =
72 | res.filter((vote: Vote) => {
73 | return vote.address === account.address;
74 | }).length > 0;
75 | setHasVoted(hasVoted);
76 | const canVote = await fetch(
77 | `${baseURL}/api/proposal-eligible?proposal_id=${proposalId}&address=${account.address}`,
78 | {
79 | method: "GET",
80 | }
81 | );
82 | const eligibilityCheck = await canVote.json();
83 | const tmpCanVote =
84 | account !== undefined &&
85 | account.address !== undefined &&
86 | eligibilityCheck.canVote &&
87 | !hasVoted;
88 | setCanVote(tmpCanVote);
89 | };
90 |
91 | fetchVotes();
92 | }, [proposalId, account, hasVoted]);
93 |
94 | const handleOptionClick = async (option: string) => {
95 | console.log("ACCOUNT", account);
96 | if (!account) return;
97 | setLoadingVote(true);
98 | const message = "isokratia vote " + option + " for proposal " + proposalId;
99 | console.log("message", message);
100 | const data = await signMessageAsync({ message });
101 | console.log("sig", data);
102 |
103 | const recoveredPubKey = getPublicKey(data, message);
104 |
105 | const req = await fetch(`${baseURL}/api/votes/${proposalId}`, {
106 | method: "POST",
107 | body: JSON.stringify({
108 | address: account.address,
109 | pubkey: recoveredPubKey,
110 | proposal_id: proposalId,
111 | vote: option,
112 | sig: data,
113 | }),
114 | });
115 | if (req.body && req.status === 200) {
116 | setLoadingVote(false);
117 | setHasVoted(true);
118 | setCanVote(false);
119 | }
120 | console.log("post", req.body);
121 | };
122 |
123 | return (
124 |
125 |
126 |
127 | isokratia Proposal {proposal.id} - {proposal.title}
128 |
129 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
{proposal.title}
143 |
144 |
145 |
146 |
147 | Description
148 |
149 |
{proposal.description}
150 |
151 |
152 | Current results
153 |
154 |
155 | {options.map((option, index) => {
156 | const numVotesForOption = votes.filter(
157 | (vote) => vote.vote == option
158 | ).length;
159 | return (
160 |
161 |
162 |
{option}
163 |
164 | {numVotesForOption} vote
165 | {numVotesForOption > 1 || numVotesForOption == 0
166 | ? "s"
167 | : ""}
168 |
169 |
170 |
179 |
180 | );
181 | })}
182 |
183 | {votingStatus}
184 | {loadingVote && }
185 | {canVote &&
186 | !loadingVote &&
187 | options.map((option, index) => {
188 | return (
189 |
196 | );
197 | })}
198 |
199 |
200 |
201 | );
202 | };
203 |
204 | // This gets called on every request
205 | export async function getServerSideProps(context: any) {
206 | // Fetch data from external API
207 | const proposalId = Number(context.query.id);
208 | const res = await fetch(`${baseURL}/api/proposal/${proposalId}`);
209 | console.log(res);
210 | const proposal = await res.json();
211 | console.log("PROPOSAL", proposal.options);
212 |
213 | // Pass data to the page via props
214 | return {
215 | props: { proposal: proposal.proposal, options: proposal.options },
216 | };
217 | }
218 |
219 | export default ProposalPage;
220 |
--------------------------------------------------------------------------------
/isokratia-aggregator/python/curve_field_elements.py:
--------------------------------------------------------------------------------
1 | '''
2 | MODIFIED FROM https://github.com/ethereum/py_pairing/blob/master/py_ecc/bn128/bn128_field_elements.py
3 | '''
4 |
5 | # The prime modulus of the field
6 | field_modulus = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab
7 | # See, it's prime!
8 | assert pow(2, field_modulus, field_modulus) == 2
9 |
10 | # The modulus of the polynomial in this representation of FQ12
11 | # F_{q^2} = F_q[u] / (u^2 + 1)
12 | # F_{q^6} = F_{q^2}[v] / (v^3 - u - 1)
13 | # F_{q^12} = F_{q^6}[w] / (w^2 - v)
14 | # so F_{q^12} = F_q[t] / (t^12 - 2t^6 + 2)
15 | FQ12_modulus_coeffs = [2, 0, 0, 0, 0, 0, -2, 0, 0, 0, 0, 0] # Implied + [1]
16 |
17 |
18 | # Extended euclidean algorithm to find modular inverses for
19 | # integers
20 | def inv(a, n):
21 | if a == 0:
22 | return 0
23 | lm, hm = 1, 0
24 | low, high = a % n, n
25 | while low > 1:
26 | r = high//low
27 | nm, new = hm-lm*r, high-low*r
28 | lm, low, hm, high = nm, new, lm, low
29 | return lm % n
30 |
31 | # A class for field elements in FQ. Wrap a number in this class,
32 | # and it becomes a field element.
33 | class FQ():
34 | def __init__(self, n):
35 | if isinstance(n, self.__class__):
36 | self.n = n.n
37 | else:
38 | self.n = n % field_modulus
39 | assert isinstance(self.n, (int,))
40 |
41 | def __add__(self, other):
42 | on = other.n if isinstance(other, FQ) else other
43 | return FQ((self.n + on) % field_modulus)
44 |
45 | def __mul__(self, other):
46 | on = other.n if isinstance(other, FQ) else other
47 | return FQ((self.n * on) % field_modulus)
48 |
49 | def __rmul__(self, other):
50 | return self * other
51 |
52 | def __radd__(self, other):
53 | return self + other
54 |
55 | def __rsub__(self, other):
56 | on = other.n if isinstance(other, FQ) else other
57 | return FQ((on - self.n) % field_modulus)
58 |
59 | def __sub__(self, other):
60 | on = other.n if isinstance(other, FQ) else other
61 | return FQ((self.n - on) % field_modulus)
62 |
63 | def __div__(self, other):
64 | on = other.n if isinstance(other, FQ) else other
65 | assert isinstance(on, (int,))
66 | return FQ(self.n * inv(on, field_modulus) % field_modulus)
67 |
68 | def __truediv__(self, other):
69 | return self.__div__(other)
70 |
71 | def __rdiv__(self, other):
72 | on = other.n if isinstance(other, FQ) else other
73 | assert isinstance(on, (int,)), on
74 | return FQ(inv(self.n, field_modulus) * on % field_modulus)
75 |
76 | def __rtruediv__(self, other):
77 | return self.__rdiv__(other)
78 |
79 | def __pow__(self, other):
80 | if other == 0:
81 | return FQ(1)
82 | elif other == 1:
83 | return FQ(self.n)
84 | elif other % 2 == 0:
85 | return (self * self) ** (other // 2)
86 | else:
87 | return ((self * self) ** int(other // 2)) * self
88 |
89 | def __eq__(self, other):
90 | if isinstance(other, FQ):
91 | return self.n == other.n
92 | else:
93 | return self.n == other
94 |
95 | def __ne__(self, other):
96 | return not self == other
97 |
98 | def __neg__(self):
99 | return FQ(-self.n)
100 |
101 | def __repr__(self):
102 | return repr(self.n)
103 |
104 | @classmethod
105 | def one(cls):
106 | return cls(1)
107 |
108 | @classmethod
109 | def zero(cls):
110 | return cls(0)
111 |
112 | # Utility methods for polynomial math
113 | def deg(p):
114 | d = len(p) - 1
115 | while p[d] == 0 and d:
116 | d -= 1
117 | return d
118 |
119 | def poly_rounded_div(a, b):
120 | dega = deg(a)
121 | degb = deg(b)
122 | temp = [x for x in a]
123 | o = [0 for x in a]
124 | for i in range(dega - degb, -1, -1):
125 | o[i] += temp[degb + i] / b[degb]
126 | for c in range(degb + 1):
127 | temp[c + i] -= o[c]
128 | return o[:deg(o)+1]
129 |
130 | # A class for elements in polynomial extension fields
131 | class FQP():
132 | def __init__(self, coeffs, modulus_coeffs):
133 | assert len(coeffs) == len(modulus_coeffs)
134 | self.coeffs = [FQ(c) for c in coeffs]
135 | # The coefficients of the modulus, without the leading [1]
136 | self.modulus_coeffs = modulus_coeffs
137 | # The degree of the extension field
138 | self.degree = len(self.modulus_coeffs)
139 |
140 | def __add__(self, other):
141 | assert isinstance(other, self.__class__)
142 | return self.__class__([x+y for x,y in zip(self.coeffs, other.coeffs)])
143 |
144 | def __sub__(self, other):
145 | assert isinstance(other, self.__class__)
146 | return self.__class__([x-y for x,y in zip(self.coeffs, other.coeffs)])
147 |
148 | def __mul__(self, other):
149 | if isinstance(other, (FQ, int,)):
150 | return self.__class__([c * other for c in self.coeffs])
151 | else:
152 | assert isinstance(other, self.__class__)
153 | b = [FQ(0) for i in range(self.degree * 2 - 1)]
154 | for i in range(self.degree):
155 | for j in range(self.degree):
156 | b[i + j] += self.coeffs[i] * other.coeffs[j]
157 | while len(b) > self.degree:
158 | exp, top = len(b) - self.degree - 1, b.pop()
159 | for i in range(self.degree):
160 | b[exp + i] -= top * FQ(self.modulus_coeffs[i])
161 | return self.__class__(b)
162 |
163 | def __rmul__(self, other):
164 | return self * other
165 |
166 | def __div__(self, other):
167 | if isinstance(other, (FQ, int,)):
168 | return self.__class__([c / other for c in self.coeffs])
169 | else:
170 | assert isinstance(other, self.__class__)
171 | return self * other.inv()
172 |
173 | def __truediv__(self, other):
174 | return self.__div__(other)
175 |
176 | def __pow__(self, other):
177 | if other == 0:
178 | return self.__class__([1] + [0] * (self.degree - 1))
179 | elif other == 1:
180 | return self.__class__(self.coeffs)
181 | elif other % 2 == 0:
182 | return (self * self) ** (other // 2)
183 | else:
184 | return ((self * self) ** int(other // 2)) * self
185 |
186 | # Extended euclidean algorithm used to find the modular inverse
187 | def inv(self):
188 | lm, hm = [1] + [0] * self.degree, [0] * (self.degree + 1)
189 | low, high = self.coeffs + [0], self.modulus_coeffs + [1]
190 | while deg(low):
191 | r = poly_rounded_div(high, low)
192 | r += [0] * (self.degree + 1 - len(r))
193 | nm = [x for x in hm]
194 | new = [x for x in high]
195 | assert len(lm) == len(hm) == len(low) == len(high) == len(nm) == len(new) == self.degree + 1
196 | for i in range(self.degree + 1):
197 | for j in range(self.degree + 1 - i):
198 | nm[i+j] -= lm[i] * r[j]
199 | new[i+j] -= low[i] * r[j]
200 | lm, low, hm, high = nm, new, lm, low
201 | return self.__class__(lm[:self.degree]) / low[0]
202 |
203 | def __repr__(self):
204 | return repr(self.coeffs)
205 |
206 | def __eq__(self, other):
207 | assert isinstance(other, self.__class__)
208 | for c1, c2 in zip(self.coeffs, other.coeffs):
209 | if c1 != c2:
210 | return False
211 | return True
212 |
213 | def __ne__(self, other):
214 | return not self == other
215 |
216 | def __neg__(self):
217 | return self.__class__([-c for c in self.coeffs])
218 |
219 | @classmethod
220 | def one(cls):
221 | return cls([1] + [0] * (cls.degree - 1))
222 |
223 | @classmethod
224 | def zero(cls):
225 | return cls([0] * cls.degree)
226 |
227 | # The quadratic extension field
228 | class FQ2(FQP):
229 | def __init__(self, coeffs):
230 | self.coeffs = [FQ(c) for c in coeffs]
231 | self.modulus_coeffs = [1, 0]
232 | self.degree = 2
233 | self.__class__.degree = 2
234 |
235 | # The 12th-degree extension field
236 | class FQ12(FQP):
237 | def __init__(self, coeffs):
238 | self.coeffs = [FQ(c) for c in coeffs]
239 | self.modulus_coeffs = FQ12_modulus_coeffs
240 | self.degree = 12
241 | self.__class__.degree = 12
242 |
--------------------------------------------------------------------------------
/isokratia-aggregator/index.js:
--------------------------------------------------------------------------------
1 | import fs from "fs";
2 | import mimcHash from "./mimc.js";
3 | import fetch from "node-fetch";
4 | import keccak256 from "keccak256";
5 | import shell from "shelljs";
6 | import { MerkleTree } from "fixed-merkle-tree";
7 | import { submit } from "./submitter.js";
8 | import { BigNumber, Contract, ethers, Wallet } from "ethers";
9 |
10 | const baseURL = "https://isokratia.xyz";
11 |
12 | function getPastSnark(proposal, option) {
13 | const proofFileName = `input/${proposal.id}-${option}-proof.json`;
14 | const voterFileName = `input/${proposal.id}-${option}-voters.json`;
15 | try {
16 | const proofFs = fs.readFileSync(proofFileName);
17 | const votersFs = fs.readFileSync(voterFileName);
18 | const proofData = JSON.parse(proofFs);
19 | const voterData = JSON.parse(votersFs);
20 | console.log(proofData, voterData);
21 | return { pastProof: proofData, pastVoters: voterData };
22 | } catch (err) {
23 | // console.log("caught err", err);
24 | const proofData = JSON.parse(fs.readFileSync("input/blank-proof.json"));
25 | const voterData = [];
26 | return { pastProof: proofData, pastVoters: voterData };
27 | }
28 | }
29 |
30 | // bigendian
31 | function bigint_to_Uint8Array(x) {
32 | var ret = new Uint8Array(32);
33 | for (var idx = 31; idx >= 0; idx--) {
34 | ret[idx] = Number(x % 256n);
35 | x = x / 256n;
36 | }
37 | return ret;
38 | }
39 |
40 | // bigendian
41 | function Uint8Array_to_bigint(x) {
42 | var ret = 0n;
43 | for (var idx = 0; idx < x.length; idx++) {
44 | ret = ret * 256n;
45 | ret = ret + BigInt(x[idx]);
46 | }
47 | return ret;
48 | }
49 |
50 | const fromHexString = (hexString) =>
51 | new Uint8Array(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
52 |
53 | const intToHex = (intString) => ethers.BigNumber.from(intString).toHexString();
54 |
55 | const hexStringTobigInt = (hexString) => {
56 | return Uint8Array_to_bigint(fromHexString(hexString));
57 | };
58 |
59 | function bigint_to_array(n, k, x) {
60 | let mod = 1n;
61 | for (var idx = 0; idx < n; idx++) {
62 | mod = mod * 2n;
63 | }
64 |
65 | let ret = [];
66 | var x_temp = x;
67 | for (var idx = 0; idx < k; idx++) {
68 | ret.push(x_temp % mod);
69 | x_temp = x_temp / mod;
70 | }
71 | return ret;
72 | }
73 |
74 | function parsePubkey(pk) {
75 | const sliced_pk = pk.slice(4);
76 | const pk_x_hex = sliced_pk.slice(0, 64);
77 | const pk_y_hex = sliced_pk.slice(64, 128);
78 | const pk_x_bigint = hexStringTobigInt(pk_x_hex);
79 | const pk_y_bigint = hexStringTobigInt(pk_y_hex);
80 | const pk_x_arr = bigint_to_array(64, 4, pk_x_bigint);
81 | const pk_y_arr = bigint_to_array(64, 4, pk_y_bigint);
82 | console.log("pk stuff", pk, pk_x_arr, pk_y_arr);
83 | return [pk_x_arr.map((x) => x.toString()), pk_y_arr.map((x) => x.toString())];
84 | }
85 |
86 | function parseSignature(sig) {
87 | console.log("sig", sig);
88 | const r_hex = sig.slice(2, 66);
89 | const s_hex = sig.slice(66, 66 + 64);
90 | // console.log("sig stuff", sig_arr.length, sig_arr);
91 | var r_bigint = hexStringTobigInt(r_hex);
92 | var s_bigint = hexStringTobigInt(s_hex);
93 | var r_array = bigint_to_array(64, 4, r_bigint);
94 | var s_array = bigint_to_array(64, 4, s_bigint);
95 | console.log("s_bigint", s_bigint);
96 | return [r_array, s_array];
97 | }
98 |
99 | const mimcHasher = mimcHash(123);
100 |
101 | function commitmentComputer(
102 | voteCount,
103 | eligibleRoot,
104 | voterRoot,
105 | msghash,
106 | proof
107 | ) {
108 | const commitmentInputsAny = [
109 | voteCount,
110 | eligibleRoot,
111 | voterRoot,
112 | ...msghash,
113 | ...proof.negalfa1xbeta2.flat(20),
114 | ...proof.gamma2.flat(20),
115 | ...proof.delta2.flat(20),
116 | ...proof.IC.flat(20),
117 | ];
118 | const commitmentInputs = commitmentInputsAny.map((x) => x.toString());
119 | const commitmentInputTypes = [];
120 | for (var idx = 0; idx < commitmentInputs.length; idx++)
121 | commitmentInputTypes.push("uint256");
122 |
123 | return BigNumber.from(
124 | ethers.utils.soliditySha256(commitmentInputTypes, commitmentInputs)
125 | )
126 | .shr(6)
127 | .toString();
128 | }
129 |
130 | function runProver(proposal, option, vote, input, allVoters) {
131 | console.log("processing prover run", proposal, option, vote, input);
132 | const JSONdata = JSON.stringify(input);
133 | fs.writeFileSync(`prover-input/${proposal.id}-${option}.json`, JSONdata);
134 |
135 | console.log("running prover");
136 | shell.exec(`./gen-proof.sh ${proposal.id}-${option}`);
137 | console.log("generated proof");
138 |
139 | const voterFileName = `input/${proposal.id}-${option}-voters.json`;
140 | fs.writeFileSync(voterFileName, JSON.stringify(allVoters));
141 |
142 | const calldataFileName = `prover-output/${proposal.id}-${option}-calldata.json`;
143 | const preCalldata = JSON.stringify([proposal.id.toString(), option, input.voteCount.toString(), input.voterRoot])
144 | const proofCalldata = fs.readFileSync(calldataFileName);
145 | const fullCallData = preCalldata.slice(0, preCalldata.length - 1) + "," + proofCalldata + "]";
146 | fs.writeFileSync(calldataFileName, fullCallData);
147 |
148 | submit(proposal.id, option);
149 | }
150 |
151 | function processVote(proposal, option, vote, pastProof, pastVoters) {
152 | const msg_noPrefix =
153 | "isokratia vote " + vote.vote + " for proposal " + vote.proposal_id;
154 | const msg = "\x19Ethereum Signed Message:\n" + msg_noPrefix.length.toString() + msg_noPrefix;
155 | console.log("processing vote", proposal, option, vote, pastProof, pastVoters, msg);
156 | const msghash_bigint = Uint8Array_to_bigint(keccak256(msg));
157 | const msghash_array = bigint_to_array(64, 4, msghash_bigint);
158 | const parsedPubkey = parsePubkey(vote.pubkey);
159 | const parsedSig = parseSignature(vote.sig);
160 |
161 | const eligibleTree = new MerkleTree(22, proposal.merkleLeaves, {
162 | hashFunction: mimcHasher,
163 | });
164 | const selfMimc = mimcHasher(BigInt(vote.address)).toString();
165 | console.log("selfMimc", selfMimc, vote.address);
166 | console.log("merkleLeaves", proposal.merkleLeaves);
167 | const selfIdx = proposal.merkleLeaves.findIndex((x) => x === selfMimc);
168 | console.log("selfIdx", selfIdx);
169 | const eligiblePathData = eligibleTree.proof(selfMimc);
170 | const eligibleRoot = eligiblePathData.pathRoot;
171 | console.log("eligiblePathData", eligiblePathData);
172 |
173 | const voterLeafs = [];
174 | for (var i = 0; i < proposal.merkleLeaves.length; i++) {
175 | voterLeafs.push(0);
176 | }
177 |
178 | const voterTree = new MerkleTree(22, voterLeafs, {
179 | hashFunction: mimcHasher,
180 | });
181 | for (const pastVoter of pastVoters) {
182 | const pastVoterMimc = mimcHasher(BigInt(pastVoter));
183 | const pastVoterIdx = proposal.merkleLeaves.findIndex(
184 | (x) => x == pastVoterMimc
185 | );
186 | voterTree.update(pastVoterIdx, pastVoterMimc);
187 | }
188 | voterTree.update(selfIdx, selfMimc);
189 | const voterPathData = voterTree.proof(selfMimc);
190 | const voterRoot = voterPathData.pathRoot;
191 | console.log("voterPathData", voterPathData);
192 |
193 | const voteCount = pastVoters.length + 1;
194 | const semiPublicCommitment = commitmentComputer(
195 | voteCount,
196 | eligibleRoot,
197 | voterRoot,
198 | msghash_array,
199 | pastProof
200 | );
201 |
202 | const nextInput = {
203 | semiPublicCommitment,
204 | voteCount,
205 | msghash: msghash_array.map((x) => x.toString()),
206 | pubkey: parsedPubkey,
207 | r: parsedSig[0].map((x) => x.toString()),
208 | s: parsedSig[1].map((x) => x.toString()),
209 | eligiblePathElements: eligiblePathData.pathElements.map((x) =>
210 | x.toString()
211 | ),
212 | voterPathElements: voterPathData.pathElements.map((x) => x.toString()),
213 | pathIndices: eligiblePathData.pathIndices,
214 | eligibleRoot: eligibleRoot.toString(),
215 | voterRoot: voterRoot.toString(),
216 | ...pastProof,
217 | };
218 |
219 | const newVoters = pastVoters.concat([vote.address]);
220 |
221 | runProver(proposal, option, vote, nextInput, newVoters);
222 | }
223 |
224 | async function processProposalOption(proposalStub, option) {
225 | console.log('proposalStub', proposalStub);
226 | const proposalFetch = await (await fetch(`${baseURL}/api/proposal/${proposalStub.id}?includeLeafs=true`)).json();
227 | const proposal = {...proposalFetch.proposal, merkleLeaves: proposalFetch.merkleLeaves, options: proposalFetch.options};
228 | console.log("proposal option", proposal, option);
229 | const req = await fetch(`${baseURL}/api/votes/${proposal.id}`);
230 | const allCurrentVotes = await req.json();
231 | const { pastProof, pastVoters } = getPastSnark(proposal, option);
232 |
233 | for (const voter of allCurrentVotes) {
234 | if (!pastVoters.includes(voter.address) && voter.vote == option) {
235 | processVote(proposal, option, voter, pastProof, pastVoters);
236 | return true;
237 | }
238 | }
239 | return false;
240 | }
241 |
242 | async function processAll() {
243 | const res = await fetch(`${baseURL}/api/proposal`);
244 | const proposals = await res.json();
245 |
246 | for (const proposal of proposals) {
247 | for (const option of proposal.options) {
248 | let didProcess = true;
249 | while (didProcess) {
250 | didProcess = await processProposalOption(proposal, option);
251 | }
252 | }
253 | }
254 | }
255 |
256 | processAll();
257 |
--------------------------------------------------------------------------------
/isokratia-contracts/test/Isokratia.t.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: UNLICENSED
2 | pragma solidity ^0.8.13;
3 |
4 | import "forge-std/Test.sol";
5 | import "../src/Isokratia.sol";
6 |
7 | contract ContractTest is Test {
8 |
9 |
10 | uint256[][][] NEGALFA1XBETA2 = [
11 | [
12 | [
13 | 4063420080633,
14 | 6555003798509,
15 | 3528875089017,
16 | 5800537096256,
17 | 8041381108016,
18 | 203518374640
19 | ],
20 | [
21 | 7676269984398,
22 | 1145806392863,
23 | 6738515895690,
24 | 5144301275423,
25 | 8547057760405,
26 | 353834589854
27 | ]
28 | ],
29 | [
30 | [
31 | 5712635615088,
32 | 8763475698695,
33 | 7480760495871,
34 | 1630925336586,
35 | 5902994417779,
36 | 229051200835
37 | ],
38 | [
39 | 1066113280330,
40 | 5452941452156,
41 | 130670027992,
42 | 6364438679415,
43 | 8227984268724,
44 | 117895881848
45 | ]
46 | ],
47 | [
48 | [
49 | 2720638156466,
50 | 8183746692879,
51 | 2805734624200,
52 | 4541538633192,
53 | 1476702149455,
54 | 162434980571
55 | ],
56 | [
57 | 4093955238700,
58 | 4839352246179,
59 | 5773319594517,
60 | 5269728708172,
61 | 8404179905859,
62 | 4522318692
63 | ]
64 | ],
65 | [
66 | [
67 | 7907150524416,
68 | 8555524456643,
69 | 2425990496019,
70 | 5117607179458,
71 | 886559720121,
72 | 343845114320
73 | ],
74 | [
75 | 3348806304058,
76 | 5295378168489,
77 | 5426585403009,
78 | 4313512356362,
79 | 2882006508456,
80 | 312905790371
81 | ]
82 | ],
83 | [
84 | [
85 | 6984987484510,
86 | 4411212100320,
87 | 517962775393,
88 | 5578757090043,
89 | 1344911245314,
90 | 115782940661
91 | ],
92 | [
93 | 4257694794763,
94 | 5641455412912,
95 | 2987387394488,
96 | 6147130513016,
97 | 8766894161060,
98 | 7451503335
99 | ]
100 | ],
101 | [
102 | [
103 | 3338043330865,
104 | 3023333978926,
105 | 4787719622265,
106 | 3729967781503,
107 | 2489094582823,
108 | 396043239802
109 | ],
110 | [
111 | 3390886416082,
112 | 169102433935,
113 | 2279828268438,
114 | 1618451670976,
115 | 7055320302964,
116 | 48334526481
117 | ]
118 | ]
119 | ];
120 |
121 | uint256[][][] GAMMA2 = [
122 | [
123 | [
124 | 5896345417453,
125 | 4240670514135,
126 | 6172078461917,
127 | 219834884668,
128 | 2138480846496,
129 | 206187650596
130 | ],
131 | [
132 | 6286472319682,
133 | 5759053266064,
134 | 8549822680278,
135 | 8639745994386,
136 | 912741836299,
137 | 219532437284
138 | ]
139 | ],
140 | [
141 | [
142 | 4404069170602,
143 | 525855202521,
144 | 8311963231281,
145 | 825823174727,
146 | 854139906743,
147 | 161342114743
148 | ],
149 | [
150 | 3147424765787,
151 | 7086132606363,
152 | 7632907980226,
153 | 5320198199754,
154 | 6592898451945,
155 | 77528801456
156 | ]
157 | ]
158 | ];
159 |
160 | uint256[][][] DELTA2 = [
161 | [
162 | [
163 | 7729836325927,
164 | 8517956451685,
165 | 4033364554740,
166 | 4001789754505,
167 | 7653645210298,
168 | 354447782510
169 | ],
170 | [
171 | 1388103822577,
172 | 8404010102298,
173 | 856053778201,
174 | 3507911936631,
175 | 8206162100929,
176 | 113445856491
177 | ]
178 | ],
179 | [
180 | [
181 | 8793217999691,
182 | 7106301969696,
183 | 7718490619722,
184 | 7819179045430,
185 | 4590999760248,
186 | 24605411388
187 | ],
188 | [
189 | 5042627280266,
190 | 157842999214,
191 | 5958854182355,
192 | 950781649488,
193 | 8416741364710,
194 | 180571071519
195 | ]
196 | ]
197 | ];
198 |
199 | uint256[][][] IC = [
200 | [
201 | [
202 | 1305955898557,
203 | 3221302193155,
204 | 3753836914638,
205 | 7483109180474,
206 | 113006122330,
207 | 47417911287
208 | ],
209 | [
210 | 2759575456530,
211 | 474829102102,
212 | 6863269531525,
213 | 3805895321977,
214 | 5414803739806,
215 | 277837986502
216 | ]
217 | ],
218 | [
219 | [
220 | 3369381598324,
221 | 6418327256523,
222 | 4972793884908,
223 | 1416394741695,
224 | 1069284332536,
225 | 390341521
226 | ],
227 | [
228 | 3118450096748,
229 | 1714056947546,
230 | 2837809434155,
231 | 97863249691,
232 | 2733156090833,
233 | 218341954120
234 | ]
235 | ]
236 | ];
237 |
238 | Isokratia isokratia;
239 |
240 | function setUp() public {
241 | uint256[6][2][6] memory _negalfa1xbeta2;
242 | for (uint i = 0;i < 6;i++) {
243 | for (uint j = 0;j < 2;j++) {
244 | for (uint k = 0;k < 6;k++) {
245 | _negalfa1xbeta2[i][j][k] = NEGALFA1XBETA2[i][j][k];
246 | }
247 | }
248 | }
249 |
250 | uint256[6][2][2] memory _gamma2;
251 | for (uint i = 0;i < 2;i++) {
252 | for (uint j = 0;j < 2;j++) {
253 | for (uint k = 0;k < 6;k++) {
254 | _gamma2[i][j][k] = GAMMA2[i][j][k];
255 | }
256 | }
257 | }
258 |
259 | uint256[6][2][2] memory _delta2;
260 | for (uint i = 0;i < 2;i++) {
261 | for (uint j = 0;j < 2;j++) {
262 | for (uint k = 0;k < 6;k++) {
263 | _delta2[i][j][k] = DELTA2[i][j][k];
264 | }
265 | }
266 | }
267 |
268 | uint256[6][2][2] memory _ic;
269 | for (uint i = 0;i < 2;i++) {
270 | for (uint j = 0;j < 2;j++) {
271 | for (uint k = 0;k < 6;k++) {
272 | _ic[i][j][k] = IC[i][j][k];
273 | }
274 | }
275 | }
276 | isokratia = new Isokratia(
277 | _negalfa1xbeta2,
278 | _gamma2,
279 | _delta2,
280 | _ic
281 | );
282 | }
283 |
284 | uint64[4][] _options;
285 | string[] _optionText;
286 | uint256[2] _a;
287 | uint256[2][2] _b;
288 | uint256[2] _c;
289 | uint256[1] _input;
290 |
291 | /*
292 | [
293 | "0x11baa61b1da261be30df83a64e30b531bb6834372f7ae0b40ce934e007639fc4",
294 | "0x1c072409cb5bf579170848718d5a6df66f5e9eaa5486088696a1131027dc009e"
295 | ],
296 | [
297 | [
298 | "0x1357df0394211d76fd839785ea6092b6af84013b505c421ad8147d1764cbedb5",
299 | "0x0ba17198b4da5ab8b752c71f4b10d7ecc991440758dd064ab50e31c8997c1d68"
300 | ],
301 | [
302 | "0x26ba6cc940672ddcfc5e59adb6b6c9519507702b20e3459d5a2e926661e2c08f",
303 | "0x2eb00257635ce1312027d4c0fb69038c3b40e2d21ae49f20325b30711d42d855"
304 | ]
305 | ],
306 | [
307 | "0x037f28c5984683c10d6dc90377b90925b85adead62317e5e57b6ca3150d4e989",
308 | "0x0a621776d0fbbd79c35317173b4f521add7e1dbc7467c3de9b97e39cbf251e8c"
309 | ],
310 | [
311 | "0x1cfd215abf3ecc9b246207cebbe2c8bd1c8ad4a3cd19ee6c3f41c97c0b2a2dcf"
312 | ]
313 | */
314 |
315 |
316 | function testFlow() public {
317 | _options.push([6245642652743125481, 3101373935687845800, 1748451034013447512, 12613057489227889884]);
318 | _options.push([9010510721521564763, 6991613417003311714, 14997001407434824448, 13306855292224131118]);
319 | _optionText.push("Yes");
320 | _optionText.push("No");
321 | isokratia.createProposal(35,
322 | 7375973,
323 | 18812586667611147222983163006546754153040663896785594427558828361574221715663,
324 | _options,
325 | _optionText
326 | );
327 |
328 | _a[0] = 0x0211081741217172fa54a6a0b373eecc517f6b1f81cb28d28aa725f393a8c307;
329 | _a[1] = 0x1063c5044fd2deddcf9836a282c0c31ebb4b71ae49bc89b9008fce96730cb31e;
330 | _b[0][0] = 0x296bba85ffa4da38eda708c970595c72fdc879fed0ab016930793269eb59793e;
331 | _b[0][1] = 0x06d6af6b93ff6d0c432757817628a3e034e91fe50299cf2774fe1ea515ae1325;
332 | _b[1][0] = 0x137e15e65a82495a8a65c350c822a6288630659548f7dcd0c5b39dc8fc028bf9;
333 | _b[1][1] = 0x2a5934f9f0c361cc03d8ae39fcdcc487a81768cc8a2563603ad90ba3f613d56a;
334 | _c[0] = 0x0867e24e1b0d46653150e684369b81b4f22af5036bdd85396b6c07c07ed94ed9;
335 | _c[1] = 0x17dcaa8917eb6676fd08b07e1f976baaeed4107077255af7f3b2537cc35018c3;
336 | _input[0] = 0x00b381287084a77c97d5be95f5c9741914440e0656cfdee1cf00050f98a3fc92;
337 |
338 | isokratia.postAggregation(
339 | 35,
340 | "Yes",
341 | 1,
342 | 3229823353917200201071081337758342217310743602957200225342297391115753930820,
343 | _a,
344 | _b,
345 | _c,
346 | _input
347 | );
348 |
349 |
350 | assertTrue(true);
351 | }
352 |
353 | // function testSha() public {
354 | // _options.push([6245642652743125481, 3101373935687845800, 1748451034013447512, 12613057489227889884]);
355 | // _options.push([9010510721521564763, 6991613417003311714, 14997001407434824448, 13306855292224131118]);
356 | // _optionText.push("Yes");
357 | // _optionText.push("No");
358 | // isokratia.createProposal(35,
359 | // 7375973,
360 | // 18812586667611147222983163006546754153040663896785594427558828361574221715663,
361 | // _options,
362 | // _optionText
363 | // );
364 |
365 | // uint256 hash = isokratia.tester();
366 | // assertEq(1, hash);
367 | // }
368 | }
369 |
--------------------------------------------------------------------------------
/isokratia-contracts/src/Verifier.sol:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright 2017 Christian Reitwiessner
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
5 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6 | //
7 | // 2019 OKIMS
8 | // ported to solidity 0.6
9 | // fixed linter warnings
10 | // added requiere error messages
11 | //
12 | //
13 | // SPDX-License-Identifier: GPL-3.0
14 | pragma solidity ^0.8.13;
15 | library Pairing {
16 | struct G1Point {
17 | uint X;
18 | uint Y;
19 | }
20 | // Encoding of field elements is: X[0] * z + X[1]
21 | struct G2Point {
22 | uint[2] X;
23 | uint[2] Y;
24 | }
25 | /// @return the generator of G1
26 | function P1() internal pure returns (G1Point memory) {
27 | return G1Point(1, 2);
28 | }
29 | /// @return the generator of G2
30 | function P2() internal pure returns (G2Point memory) {
31 | // Original code point
32 | return G2Point(
33 | [11559732032986387107991004021392285783925812861821192530917403151452391805634,
34 | 10857046999023057135944570762232829481370756359578518086990519993285655852781],
35 | [4082367875863433681332203403145435568316851327593401208105741076214120093531,
36 | 8495653923123431417604973247489272438418190587263600148770280649306958101930]
37 | );
38 |
39 | /*
40 | // Changed by Jordi point
41 | return G2Point(
42 | [10857046999023057135944570762232829481370756359578518086990519993285655852781,
43 | 11559732032986387107991004021392285783925812861821192530917403151452391805634],
44 | [8495653923123431417604973247489272438418190587263600148770280649306958101930,
45 | 4082367875863433681332203403145435568316851327593401208105741076214120093531]
46 | );
47 | */
48 | }
49 | /// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
50 | function negate(G1Point memory p) internal pure returns (G1Point memory r) {
51 | // The prime q in the base field F_q for G1
52 | uint q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;
53 | if (p.X == 0 && p.Y == 0)
54 | return G1Point(0, 0);
55 | return G1Point(p.X, q - (p.Y % q));
56 | }
57 | /// @return r the sum of two points of G1
58 | function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
59 | uint[4] memory input;
60 | input[0] = p1.X;
61 | input[1] = p1.Y;
62 | input[2] = p2.X;
63 | input[3] = p2.Y;
64 | bool success;
65 | // solium-disable-next-line security/no-inline-assembly
66 | assembly {
67 | success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
68 | // Use "invalid" to make gas estimation work
69 | switch success case 0 { invalid() }
70 | }
71 | require(success,"pairing-add-failed");
72 | }
73 | /// @return r the product of a point on G1 and a scalar, i.e.
74 | /// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
75 | function scalar_mul(G1Point memory p, uint s) internal view returns (G1Point memory r) {
76 | uint[3] memory input;
77 | input[0] = p.X;
78 | input[1] = p.Y;
79 | input[2] = s;
80 | bool success;
81 | // solium-disable-next-line security/no-inline-assembly
82 | assembly {
83 | success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
84 | // Use "invalid" to make gas estimation work
85 | switch success case 0 { invalid() }
86 | }
87 | require (success,"pairing-mul-failed");
88 | }
89 | /// @return the result of computing the pairing check
90 | /// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
91 | /// For example pairing([P1(), P1().negate()], [P2(), P2()]) should
92 | /// return true.
93 | function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) {
94 | require(p1.length == p2.length,"pairing-lengths-failed");
95 | uint elements = p1.length;
96 | uint inputSize = elements * 6;
97 | uint[] memory input = new uint[](inputSize);
98 | for (uint i = 0; i < elements; i++)
99 | {
100 | input[i * 6 + 0] = p1[i].X;
101 | input[i * 6 + 1] = p1[i].Y;
102 | input[i * 6 + 2] = p2[i].X[0];
103 | input[i * 6 + 3] = p2[i].X[1];
104 | input[i * 6 + 4] = p2[i].Y[0];
105 | input[i * 6 + 5] = p2[i].Y[1];
106 | }
107 | uint[1] memory out;
108 | bool success;
109 | // solium-disable-next-line security/no-inline-assembly
110 | assembly {
111 | success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
112 | // Use "invalid" to make gas estimation work
113 | switch success case 0 { invalid() }
114 | }
115 | require(success,"pairing-opcode-failed");
116 | return out[0] != 0;
117 | }
118 | /// Convenience method for a pairing check for two pairs.
119 | function pairingProd2(G1Point memory a1, G2Point memory a2, G1Point memory b1, G2Point memory b2) internal view returns (bool) {
120 | G1Point[] memory p1 = new G1Point[](2);
121 | G2Point[] memory p2 = new G2Point[](2);
122 | p1[0] = a1;
123 | p1[1] = b1;
124 | p2[0] = a2;
125 | p2[1] = b2;
126 | return pairing(p1, p2);
127 | }
128 | /// Convenience method for a pairing check for three pairs.
129 | function pairingProd3(
130 | G1Point memory a1, G2Point memory a2,
131 | G1Point memory b1, G2Point memory b2,
132 | G1Point memory c1, G2Point memory c2
133 | ) internal view returns (bool) {
134 | G1Point[] memory p1 = new G1Point[](3);
135 | G2Point[] memory p2 = new G2Point[](3);
136 | p1[0] = a1;
137 | p1[1] = b1;
138 | p1[2] = c1;
139 | p2[0] = a2;
140 | p2[1] = b2;
141 | p2[2] = c2;
142 | return pairing(p1, p2);
143 | }
144 | /// Convenience method for a pairing check for four pairs.
145 | function pairingProd4(
146 | G1Point memory a1, G2Point memory a2,
147 | G1Point memory b1, G2Point memory b2,
148 | G1Point memory c1, G2Point memory c2,
149 | G1Point memory d1, G2Point memory d2
150 | ) internal view returns (bool) {
151 | G1Point[] memory p1 = new G1Point[](4);
152 | G2Point[] memory p2 = new G2Point[](4);
153 | p1[0] = a1;
154 | p1[1] = b1;
155 | p1[2] = c1;
156 | p1[3] = d1;
157 | p2[0] = a2;
158 | p2[1] = b2;
159 | p2[2] = c2;
160 | p2[3] = d2;
161 | return pairing(p1, p2);
162 | }
163 | }
164 | contract Verifier {
165 | using Pairing for *;
166 | struct VerifyingKey {
167 | Pairing.G1Point alfa1;
168 | Pairing.G2Point beta2;
169 | Pairing.G2Point gamma2;
170 | Pairing.G2Point delta2;
171 | Pairing.G1Point[] IC;
172 | }
173 | struct Proof {
174 | Pairing.G1Point A;
175 | Pairing.G2Point B;
176 | Pairing.G1Point C;
177 | }
178 | function verifyingKey() internal pure returns (VerifyingKey memory vk) {
179 | vk.alfa1 = Pairing.G1Point(20491192805390485299153009773594534940189261866228447918068658471970481763042,9383485363053290200918347156157836566562967994039712273449902621266178545958);
180 | vk.beta2 = Pairing.G2Point([4252822878758300859123897981450591353533073413197771768651442665752259397132,6375614351688725206403948262868962793625744043794305715222011528459656738731], [21847035105528745403288232691147584728191162732299865338377159692350059136679,10505242626370262277552901082094356697409835680220590971873171140371331206856]);
181 | vk.gamma2 = Pairing.G2Point([11559732032986387107991004021392285783925812861821192530917403151452391805634,10857046999023057135944570762232829481370756359578518086990519993285655852781], [4082367875863433681332203403145435568316851327593401208105741076214120093531,8495653923123431417604973247489272438418190587263600148770280649306958101930]);
182 | vk.delta2 = Pairing.G2Point([5973621563733861405623480110159658945229906859514934902138790212137481366769,18663854126529038456366775629343214145151888306033417279573710037906499173415], [9508176675406799030331063455658394160028524360798331535836005748963346087306,1295626130386430412571447908098540686782565822741566042801736583322422911819]);
183 | vk.IC = new Pairing.G1Point[](2);
184 | vk.IC[0] = Pairing.G1Point(2496844451885833432824096806416557499214264711015324386520936125098688615613,14629877535584054045396860904063333615289315185715201372572426609117299460882);
185 | vk.IC[1] = Pairing.G1Point(20553880061351188313734961831898909352358550578577018251431250607538377844,11497045777900447273865655657210559889388291494891917154106692735310227061356);
186 |
187 | }
188 | function verify(uint[] memory input, Proof memory proof) internal view returns (uint) {
189 | uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
190 | VerifyingKey memory vk = verifyingKey();
191 | require(input.length + 1 == vk.IC.length,"verifier-bad-input");
192 | // Compute the linear combination vk_x
193 | Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0);
194 | for (uint i = 0; i < input.length; i++) {
195 | require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field");
196 | vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i]));
197 | }
198 | vk_x = Pairing.addition(vk_x, vk.IC[0]);
199 | if (!Pairing.pairingProd4(
200 | Pairing.negate(proof.A), proof.B,
201 | vk.alfa1, vk.beta2,
202 | vk_x, vk.gamma2,
203 | proof.C, vk.delta2
204 | )) return 1;
205 | return 0;
206 | }
207 | /// @return r bool true if proof is valid
208 | function verifyProof(
209 | uint[2] memory a,
210 | uint[2][2] memory b,
211 | uint[2] memory c,
212 | uint[1] memory input
213 | ) public view returns (bool r) {
214 | Proof memory proof;
215 | proof.A = Pairing.G1Point(a[0], a[1]);
216 | proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
217 | proof.C = Pairing.G1Point(c[0], c[1]);
218 | uint[] memory inputValues = new uint[](input.length);
219 | for(uint i = 0; i < input.length; i++){
220 | inputValues[i] = input[i];
221 | }
222 | if (verify(inputValues, proof) == 0) {
223 | return true;
224 | } else {
225 | return false;
226 | }
227 | }
228 | }
229 |
--------------------------------------------------------------------------------
/isokratia-client/pages/proposal/new.tsx:
--------------------------------------------------------------------------------
1 | import { ConnectButton } from "@rainbow-me/rainbowkit";
2 | import type { NextPage } from "next";
3 | import Head from "next/head";
4 | import Link from "next/link";
5 | import { useRouter } from "next/router";
6 | import React, { useEffect, useState } from "react";
7 | import { useAccount, useBlockNumber, useContractWrite } from "wagmi";
8 | import { Loading } from "../../components/Loading";
9 | import { Nav } from "../../components/Nav";
10 | import { Sidebar } from "../../components/Sidebar";
11 | import contractInterface from "../../lib/isokratia.abi.json";
12 | import keccak256 from "keccak256";
13 | import { baseURL } from "../../lib/misc";
14 |
15 | const contractConfig = {
16 | addressOrName: "0x8ff131B05aBE019b4Dc1cf29ABEc51083389b0B8",
17 | contractInterface,
18 | chainId: 5,
19 | };
20 |
21 | // bigendian
22 | function Uint8Array_to_bigint(x: Uint8Array) {
23 | var ret = 0n;
24 | for (var idx = 0; idx < x.length; idx++) {
25 | ret = ret * 256n;
26 | ret = ret + BigInt(x[idx]);
27 | }
28 | return ret;
29 | }
30 |
31 | function bigint_to_array(n: number, k: number, x: bigint) {
32 | let mod = 1n;
33 | for (var idx = 0; idx < n; idx++) {
34 | mod = mod * 2n;
35 | }
36 |
37 | let ret = [];
38 | var x_temp = x;
39 | for (var idx = 0; idx < k; idx++) {
40 | ret.push(x_temp % mod);
41 | x_temp = x_temp / mod;
42 | }
43 | return ret;
44 | }
45 |
46 | const ProposalPage: NextPage<{}> = () => {
47 | const [title, setTitle] = useState("");
48 | const [description, setDescription] = useState("");
49 | const [contractAddress, setContractAddress] = useState("");
50 | const [endBlock, setEndBlock] = useState("");
51 | const [options, setOptions] = useState(["Yes", "No"]);
52 | const [canCreateProposal, setCanCreateProposal] = useState(false);
53 | const [loading, setLoading] = useState(false);
54 | const [newOption, setNewOption] = useState("");
55 | const { data: account } = useAccount();
56 | const { data: currentBlock } = useBlockNumber();
57 | const {
58 | data: createData,
59 | write: createProposalOnChain,
60 | isLoading: isCreateLoading,
61 | isSuccess: isCreateStarted,
62 | } = useContractWrite(contractConfig, "createProposal");
63 |
64 | const router = useRouter();
65 |
66 | // useEffect(() => {
67 | // if (!account) {
68 | // setCanCreateProposal(false);
69 | // } else {
70 | // setCanCreateProposal(true);
71 | // }
72 | // }, [account]);
73 |
74 | const handleTitleChange = (e: React.ChangeEvent) => {
75 | setTitle(e.target.value);
76 | };
77 |
78 | const handleEndBlockChange = (e: React.ChangeEvent) => {
79 | setEndBlock(e.target.value);
80 | };
81 |
82 | const handlePopulateEndBlock = () => {
83 | if (!currentBlock) return;
84 | setEndBlock(currentBlock.toString());
85 | };
86 |
87 | const handleNewOption = () => {
88 | const optionIsDuplicate = options.includes(newOption);
89 | if (newOption.length > 0 && !optionIsDuplicate) {
90 | setOptions([...options, newOption]);
91 | setNewOption("");
92 | }
93 | };
94 |
95 | const handleDescriptionChange = (
96 | e: React.ChangeEvent
97 | ) => {
98 | setDescription(e.target.value);
99 | };
100 |
101 | const handleContractAddressChange = async (
102 | e: React.ChangeEvent
103 | ) => {
104 | setContractAddress(e.target.value);
105 | };
106 |
107 | const handleCreateClick = async () => {
108 | setLoading(true);
109 | console.log(title, description, contractAddress);
110 | const req = await fetch(`${baseURL}/api/proposal`, {
111 | method: "POST",
112 | body: JSON.stringify({
113 | proposal: {
114 | title,
115 | description,
116 | endBlock,
117 | },
118 | contractAddr: contractAddress,
119 | // options: JSON.parse(options),
120 | options: options,
121 | }),
122 | });
123 |
124 | if (req.status !== 200) return;
125 |
126 | const res = await req.json();
127 |
128 | const proposalDetails = await (
129 | await fetch(`${baseURL}/api/proposal/${res.proposal_id}`)
130 | ).json();
131 |
132 | const optionTextHash = proposalDetails.options.map((option: string) => {
133 | const msg_noPrefix =
134 | "isokratia vote " +
135 | option +
136 | " for proposal " +
137 | proposalDetails.proposal.id;
138 | const msg =
139 | "\x19Ethereum Signed Message:\n" +
140 | msg_noPrefix.length.toString() +
141 | msg_noPrefix;
142 | const msghash_bigint = Uint8Array_to_bigint(keccak256(msg));
143 | const msghash_array = bigint_to_array(64, 4, msghash_bigint);
144 | return msghash_array.map((x) => x.toString());
145 | });
146 |
147 | const args = [
148 | proposalDetails.proposal.id.toString(),
149 | proposalDetails.proposal.endBlock.toString(),
150 | proposalDetails.proposal.merkleRoot.toString(),
151 | optionTextHash,
152 | proposalDetails.options,
153 | ];
154 | console.log("args", args);
155 | createProposalOnChain({ args });
156 |
157 | setLoading(false);
158 | router.push("/proposal/[id]", `/proposal/${proposalDetails.proposal.id}`);
159 | };
160 |
161 | return (
162 |
163 |
164 |
Create new proposal
165 |
166 |
167 |
168 |
169 |
170 |
171 | {/*
*/}
172 |
173 |
174 |
175 |
183 |
184 |
185 |
186 |
189 |
197 |
198 |
199 |
200 |
201 |
202 |
210 |
216 |
217 |
218 |
219 |
220 |
223 |
227 |
235 |
236 |
237 |
238 |
239 |
240 | {options.map((option, index) => (
241 |
245 |
{option}
246 |
{
249 | setOptions(options.filter((_, i) => i !== index));
250 | }}
251 | >
252 |
253 |
254 |
255 | ))}
256 |
257 |
258 | ) => {
265 | setNewOption(e.target.value);
266 | }}
267 | />
268 |
274 |
275 |
276 |
286 |
287 |
288 |
289 |
290 | );
291 | };
292 |
293 | const DeleteButton = () => {
294 | return (
295 |
309 | );
310 | };
311 |
312 | export default ProposalPage;
313 |
--------------------------------------------------------------------------------
/isokratia-aggregator/mimc.js:
--------------------------------------------------------------------------------
1 | import bigInt from "big-integer";
2 |
3 | const p = bigInt(
4 | "21888242871839275222246405745257275088548364400416034343698204186575808495617"
5 | );
6 |
7 | const c = [
8 | "0",
9 | "7120861356467848435263064379192047478074060781135320967663101236819528304084",
10 | "5024705281721889198577876690145313457398658950011302225525409148828000436681",
11 | "17980351014018068290387269214713820287804403312720763401943303895585469787384",
12 | "19886576439381707240399940949310933992335779767309383709787331470398675714258",
13 | "1213715278223786725806155661738676903520350859678319590331207960381534602599",
14 | "18162138253399958831050545255414688239130588254891200470934232514682584734511",
15 | "7667462281466170157858259197976388676420847047604921256361474169980037581876",
16 | "7207551498477838452286210989212982851118089401128156132319807392460388436957",
17 | "9864183311657946807255900203841777810810224615118629957816193727554621093838",
18 | "4798196928559910300796064665904583125427459076060519468052008159779219347957",
19 | "17387238494588145257484818061490088963673275521250153686214197573695921400950",
20 | "10005334761930299057035055370088813230849810566234116771751925093634136574742",
21 | "11897542014760736209670863723231849628230383119798486487899539017466261308762",
22 | "16771780563523793011283273687253985566177232886900511371656074413362142152543",
23 | "749264854018824809464168489785113337925400687349357088413132714480582918506",
24 | "3683645737503705042628598550438395339383572464204988015434959428676652575331",
25 | "7556750851783822914673316211129907782679509728346361368978891584375551186255",
26 | "20391289379084797414557439284689954098721219201171527383291525676334308303023",
27 | "18146517657445423462330854383025300323335289319277199154920964274562014376193",
28 | "8080173465267536232534446836148661251987053305394647905212781979099916615292",
29 | "10796443006899450245502071131975731672911747129805343722228413358507805531141",
30 | "5404287610364961067658660283245291234008692303120470305032076412056764726509",
31 | "4623894483395123520243967718315330178025957095502546813929290333264120223168",
32 | "16845753148201777192406958674202574751725237939980634861948953189320362207797",
33 | "4622170486584704769521001011395820886029808520586507873417553166762370293671",
34 | "16688277490485052681847773549197928630624828392248424077804829676011512392564",
35 | "11878652861183667748838188993669912629573713271883125458838494308957689090959",
36 | "2436445725746972287496138382764643208791713986676129260589667864467010129482",
37 | "1888098689545151571063267806606510032698677328923740058080630641742325067877",
38 | "148924106504065664829055598316821983869409581623245780505601526786791681102",
39 | "18875020877782404439294079398043479420415331640996249745272087358069018086569",
40 | "15189693413320228845990326214136820307649565437237093707846682797649429515840",
41 | "19669450123472657781282985229369348220906547335081730205028099210442632534079",
42 | "5521922218264623411380547905210139511350706092570900075727555783240701821773",
43 | "4144769320246558352780591737261172907511489963810975650573703217887429086546",
44 | "10097732913112662248360143041019433907849917041759137293018029019134392559350",
45 | "1720059427972723034107765345743336447947522473310069975142483982753181038321",
46 | "6302388219880227251325608388535181451187131054211388356563634768253301290116",
47 | "6745410632962119604799318394592010194450845483518862700079921360015766217097",
48 | "10858157235265583624235850660462324469799552996870780238992046963007491306222",
49 | "20241898894740093733047052816576694435372877719072347814065227797906130857593",
50 | "10165780782761211520836029617746977303303335603838343292431760011576528327409",
51 | "2832093654883670345969792724123161241696170611611744759675180839473215203706",
52 | "153011722355526826233082383360057587249818749719433916258246100068258954737",
53 | "20196970640587451358539129330170636295243141659030208529338914906436009086943",
54 | "3180973917010545328313139835982464870638521890385603025657430208141494469656",
55 | "17198004293191777441573635123110935015228014028618868252989374962722329283022",
56 | "7642160509228669138628515458941659189680509753651629476399516332224325757132",
57 | "19346204940546791021518535594447257347218878114049998691060016493806845179755",
58 | "11501810868606870391127866188394535330696206817602260610801897042898616817272",
59 | "3113973447392053821824427670386252797811804954746053461397972968381571297505",
60 | "6545064306297957002139416752334741502722251869537551068239642131448768236585",
61 | "5203908808704813498389265425172875593837960384349653691918590736979872578408",
62 | "2246692432011290582160062129070762007374502637007107318105405626910313810224",
63 | "11760570435432189127645691249600821064883781677693087773459065574359292849137",
64 | "5543749482491340532547407723464609328207990784853381797689466144924198391839",
65 | "8837549193990558762776520822018694066937602576881497343584903902880277769302",
66 | "12855514863299373699594410385788943772765811961581749194183533625311486462501",
67 | "5363660674689121676875069134269386492382220935599781121306637800261912519729",
68 | "13162342403579303950549728848130828093497701266240457479693991108217307949435",
69 | "916941639326869583414469202910306428966657806899788970948781207501251816730",
70 | "15618589556584434434009868216186115416835494805174158488636000580759692174228",
71 | "8959562060028569701043973060670353733575345393653685776974948916988033453971",
72 | "16390754464333401712265575949874369157699293840516802426621216808905079127650",
73 | "168282396747788514908709091757591226095443902501365500003618183905496160435",
74 | "8327443473179334761744301768309008451162322941906921742120510244986704677004",
75 | "17213012626801210615058753489149961717422101711567228037597150941152495100640",
76 | "10394369641533736715250242399198097296122982486516256408681925424076248952280",
77 | "17784386835392322654196171115293700800825771210400152504776806618892170162248",
78 | "16533189939837087893364000390641148516479148564190420358849587959161226782982",
79 | "18725396114211370207078434315900726338547621160475533496863298091023511945076",
80 | "7132325028834551397904855671244375895110341505383911719294705267624034122405",
81 | "148317947440800089795933930720822493695520852448386394775371401743494965187",
82 | "19001050671757720352890779127693793630251266879994702723636759889378387053056",
83 | "18824274411769830274877839365728651108434404855803844568234862945613766611460",
84 | "12771414330193951156383998390424063470766226667986423961689712557338777174205",
85 | "11332046574800279729678603488745295198038913503395629790213378101166488244657",
86 | "9607550223176946388146938069307456967842408600269548190739947540821716354749",
87 | "8756385288462344550200229174435953103162307705310807828651304665320046782583",
88 | "176061952957067086877570020242717222844908281373122372938833890096257042779",
89 | "12200212977482648306758992405065921724409841940671166017620928947866825250857",
90 | "10868453624107875516866146499877130701929063632959660262366632833504750028858",
91 | "2016095394399807253596787752134573207202567875457560571095586743878953450738",
92 | "21815578223768330433802113452339488275704145896544481092014911825656390567514",
93 | "4923772847693564777744725640710197015181591950368494148029046443433103381621",
94 | "1813584943682214789802230765734821149202472893379265320098816901270224589984",
95 | "10810123816265612772922113403831964815724109728287572256602010709288980656498",
96 | "1153669123397255702524721206511185557982017410156956216465120456256288427021",
97 | "5007518659266430200134478928344522649876467369278722765097865662497773767152",
98 | "2511432546938591792036639990606464315121646668029252285288323664350666551637",
99 | "32883284540320451295484135704808083452381176816565850047310272290579727564",
100 | "10484856914279112612610993418405543310546746652738541161791501150994088679557",
101 | "2026733759645519472558796412979210009170379159866522399881566309631434814953",
102 | "14731806221235869882801331463708736361296174006732553130708107037190460654379",
103 | "14740327483193277147065845135561988641238516852487657117813536909482068950652",
104 | "18787428285295558781869865751953016580493190547148386433580291216673009884554",
105 | "3804047064713122820157099453648459188816376755739202017447862327783289895072",
106 | "16709604795697901641948603019242067672006293290826991671766611326262532802914",
107 | "11061717085931490100602849654034280576915102867237101935487893025907907250695",
108 | "2821730726367472966906149684046356272806484545281639696873240305052362149654",
109 | "17467794879902895769410571945152708684493991588672014763135370927880883292655",
110 | "1571520786233540988201616650622796363168031165456869481368085474420849243232",
111 | "10041051776251223165849354194892664881051125330236567356945669006147134614302",
112 | "3981753758468103976812813304477670033098707002886030847251581853700311567551",
113 | "4365864398105436789177703571412645548020537580493599380018290523813331678900",
114 | "2391801327305361293476178683853802679507598622000359948432171562543560193350",
115 | "214219368547551689972421167733597094823289857206402800635962137077096090722",
116 | "18192064100315141084242006659317257023098826945893371479835220462302399655674",
117 | "15487549757142039139328911515400805508248576685795694919457041092150651939253",
118 | "10142447197759703415402259672441315777933858467700579946665223821199077641122",
119 | "11246573086260753259993971254725613211193686683988426513880826148090811891866",
120 | "6574066859860991369704567902211886840188702386542112593710271426704432301235",
121 | "11311085442652291634822798307831431035776248927202286895207125867542470350078",
122 | "20977948360215259915441258687649465618185769343138135384346964466965010873779",
123 | "792781492853909872425531014397300057232399608769451037135936617996830018501",
124 | "5027602491523497423798779154966735896562099398367163998686335127580757861872",
125 | "14595204575654316237672764823862241845410365278802914304953002937313300553572",
126 | "13973538843621261113924259058427434053808430378163734641175100160836376897004",
127 | "16395063164993626722686882727042150241125309409717445381854913964674649318585",
128 | "8465768840047024550750516678171433288207841931251654898809033371655109266663",
129 | "21345603324471810861925019445720576814602636473739003852898308205213912255830",
130 | "21171984405852590343970239018692870799717057961108910523876770029017785940991",
131 | "10761027113757988230637066281488532903174559953630210849190212601991063767647",
132 | "6678298831065390834922566306988418588227382406175769592902974103663687992230",
133 | "4993662582188632374202316265508850988596880036291765531885657575099537176757",
134 | "18364168158495573675698600238443218434246806358811328083953887470513967121206",
135 | "3506345610354615013737144848471391553141006285964325596214723571988011984829",
136 | "248732676202643792226973868626360612151424823368345645514532870586234380100",
137 | "10090204501612803176317709245679152331057882187411777688746797044706063410969",
138 | "21297149835078365363970699581821844234354988617890041296044775371855432973500",
139 | "16729368143229828574342820060716366330476985824952922184463387490091156065099",
140 | "4467191506765339364971058668792642195242197133011672559453028147641428433293",
141 | "8677548159358013363291014307402600830078662555833653517843708051504582990832",
142 | "1022951765127126818581466247360193856197472064872288389992480993218645055345",
143 | "1888195070251580606973417065636430294417895423429240431595054184472931224452",
144 | "4221265384902749246920810956363310125115516771964522748896154428740238579824",
145 | "2825393571154632139467378429077438870179957021959813965940638905853993971879",
146 | "19171031072692942278056619599721228021635671304612437350119663236604712493093",
147 | "10780807212297131186617505517708903709488273075252405602261683478333331220733",
148 | "18230936781133176044598070768084230333433368654744509969087239465125979720995",
149 | "16901065971871379877929280081392692752968612240624985552337779093292740763381",
150 | "146494141603558321291767829522948454429758543710648402457451799015963102253",
151 | "2492729278659146790410698334997955258248120870028541691998279257260289595548",
152 | "2204224910006646535594933495262085193210692406133533679934843341237521233504",
153 | "16062117410185840274616925297332331018523844434907012275592638570193234893570",
154 | "5894928453677122829055071981254202951712129328678534592916926069506935491729",
155 | "4947482739415078212217504789923078546034438919537985740403824517728200332286",
156 | "16143265650645676880461646123844627780378251900510645261875867423498913438066",
157 | "397690828254561723549349897112473766901585444153303054845160673059519614409",
158 | "11272653598912269895509621181205395118899451234151664604248382803490621227687",
159 | "15566927854306879444693061574322104423426072650522411176731130806720753591030",
160 | "14222898219492484180162096141564251903058269177856173968147960855133048449557",
161 | "16690275395485630428127725067513114066329712673106153451801968992299636791385",
162 | "3667030990325966886479548860429670833692690972701471494757671819017808678584",
163 | "21280039024501430842616328642522421302481259067470872421086939673482530783142",
164 | "15895485136902450169492923978042129726601461603404514670348703312850236146328",
165 | "7733050956302327984762132317027414325566202380840692458138724610131603812560",
166 | "438123800976401478772659663183448617575635636575786782566035096946820525816",
167 | "814913922521637742587885320797606426167962526342166512693085292151314976633",
168 | "12368712287081330853637674140264759478736012797026621876924395982504369598764",
169 | "2494806857395134874309386694756263421445039103814920780777601708371037591569",
170 | "16101132301514338989512946061786320637179843435886825102406248183507106312877",
171 | "6252650284989960032925831409804233477770646333900692286731621844532438095656",
172 | "9277135875276787021836189566799935097400042171346561246305113339462708861695",
173 | "10493603554686607050979497281838644324893776154179810893893660722522945589063",
174 | "8673089750662709235894359384294076697329948991010184356091130382437645649279",
175 | "9558393272910366944245875920138649617479779893610128634419086981339060613250",
176 | "19012287860122586147374214541764572282814469237161122489573881644994964647218",
177 | "9783723818270121678386992630754842961728702994964214799008457449989291229500",
178 | "15550788416669474113213749561488122552422887538676036667630838378023479382689",
179 | "15016165746156232864069722572047169071786333815661109750860165034341572904221",
180 | "6506225705710197163670556961299945987488979904603689017479840649664564978574",
181 | "10796631184889302076168355684722130903785890709107732067446714470783437829037",
182 | "19871836214837460419845806980869387567383718044439891735114283113359312279540",
183 | "20871081766843466343749609089986071784031203517506781251203251608363835140622",
184 | "5100105771517691442278432864090229416166996183792075307747582375962855820797",
185 | "8777887112076272395250620301071581171386440850451972412060638225741125310886",
186 | "5300440870136391278944213332144327695659161151625757537632832724102670898756",
187 | "1205448543652932944633962232545707633928124666868453915721030884663332604536",
188 | "5542499997310181530432302492142574333860449305424174466698068685590909336771",
189 | "11028094245762332275225364962905938096659249161369092798505554939952525894293",
190 | "19187314764836593118404597958543112407224947638377479622725713735224279297009",
191 | "17047263688548829001253658727764731047114098556534482052135734487985276987385",
192 | "19914849528178967155534624144358541535306360577227460456855821557421213606310",
193 | "2929658084700714257515872921366736697080475676508114973627124569375444665664",
194 | "15092262360719700162343163278648422751610766427236295023221516498310468956361",
195 | "21578580340755653236050830649990190843552802306886938815497471545814130084980",
196 | "1258781501221760320019859066036073675029057285507345332959539295621677296991",
197 | "3819598418157732134449049289585680301176983019643974929528867686268702720163",
198 | "8653175945487997845203439345797943132543211416447757110963967501177317426221",
199 | "6614652990340435611114076169697104582524566019034036680161902142028967568142",
200 | "19212515502973904821995111796203064175854996071497099383090983975618035391558",
201 | "18664315914479294273286016871365663486061896605232511201418576829062292269769",
202 | "11498264615058604317482574216318586415670903094838791165247179252175768794889",
203 | "10814026414212439999107945133852431304483604215416531759535467355316227331774",
204 | "17566185590731088197064706533119299946752127014428399631467913813769853431107",
205 | "14016139747289624978792446847000951708158212463304817001882956166752906714332",
206 | "8242601581342441750402731523736202888792436665415852106196418942315563860366",
207 | "9244680976345080074252591214216060854998619670381671198295645618515047080988",
208 | "12216779172735125538689875667307129262237123728082657485828359100719208190116",
209 | "10702811721859145441471328511968332847175733707711670171718794132331147396634",
210 | "6479667912792222539919362076122453947926362746906450079329453150607427372979",
211 | "15117544653571553820496948522381772148324367479772362833334593000535648316185",
212 | "6842203153996907264167856337497139692895299874139131328642472698663046726780",
213 | "12732823292801537626009139514048596316076834307941224506504666470961250728055",
214 | "6936272626871035740815028148058841877090860312517423346335878088297448888663",
215 | "17297554111853491139852678417579991271009602631577069694853813331124433680030",
216 | "16641596134749940573104316021365063031319260205559553673368334842484345864859",
217 | "7400481189785154329569470986896455371037813715804007747228648863919991399081",
218 | "2273205422216987330510475127669563545720586464429614439716564154166712854048",
219 | "15162538063742142685306302282127534305212832649282186184583465569986719234456",
220 | "5628039096440332922248578319648483863204530861778160259559031331287721255522",
221 | "16085392195894691829567913404182676871326863890140775376809129785155092531260",
222 | "14227467863135365427954093998621993651369686288941275436795622973781503444257",
223 | "18224457394066545825553407391290108485121649197258948320896164404518684305122",
224 | "274945154732293792784580363548970818611304339008964723447672490026510689427",
225 | "11050822248291117548220126630860474473945266276626263036056336623671308219529",
226 | "2119542016932434047340813757208803962484943912710204325088879681995922344971",
227 | "0",
228 | ].map((n) => bigInt(n));
229 |
230 | class FeistelState {
231 | constructor(rounds, k) {
232 | this.l = bigInt(0);
233 | this.r = bigInt(0);
234 | this.rounds = rounds;
235 | this.k = k;
236 | }
237 |
238 | inject(elt) {
239 | this.l = this.l.add(elt).mod(p);
240 | }
241 |
242 | mix() {
243 | for (let i = 0; i < this.rounds - 1; i++) {
244 | const t = this.k.add(this.l).add(c[i]).mod(p);
245 | const lNew = t.modPow(5, p).add(this.r).mod(p);
246 | this.r = this.l;
247 | this.l = lNew;
248 | }
249 | const t = this.k.add(this.l).mod(p);
250 | this.r = t.modPow(5, p).add(this.r).mod(p);
251 | }
252 | }
253 |
254 | function mimcSponge(inputs, nOutputs, rounds, key) {
255 | const state = new FeistelState(rounds, bigInt(key));
256 | for (const elt of inputs) {
257 | state.inject(elt);
258 | state.mix();
259 | }
260 | const outputs = [state.l];
261 | for (let i = 0; i < nOutputs - 1; i++) {
262 | state.mix();
263 | outputs.push(state.l);
264 | }
265 | return outputs;
266 | }
267 |
268 | /**
269 | * Modulo a number with the LOCATION_ID_UB constant.
270 | * If the result is < 0, the LOCATION_ID_UB will then be added.
271 | *
272 | * @param x The number to modulo against LOCATION_ID_UB
273 | */
274 | function modPBigInt(x) {
275 | let ret = bigInt(x).mod(p);
276 | if (ret.lesser(bigInt(0))) {
277 | ret = ret.add(p);
278 | }
279 | return ret;
280 | }
281 |
282 | /**
283 | * Modulo a BigInt with the LOCATION_ID_UB constant.
284 | * If the result is < 0, the LOCATION_ID_UB will then be added.
285 | *
286 | * @param x The number to modulo against LOCATION_ID_UB
287 | */
288 | function modPBigIntNative(x) {
289 | let ret = x.mod(p);
290 | if (ret.lesser(bigInt(0))) {
291 | ret = ret.add(p);
292 | }
293 | return ret;
294 | }
295 |
296 | const mimcWithRounds =
297 | (rounds, key) =>
298 | (...inputs) =>
299 | mimcSponge(
300 | inputs.map((n) => modPBigInt(n)),
301 | 1,
302 | rounds,
303 | key
304 | )[0];
305 |
306 | /**
307 | * The primary function used to build any MiMC hashing algorithm for Dark Forest.
308 | *
309 | * @param key The key for the MiMC algorithm. Will usually be PLANETHASH_KEY, SPACETYPE_KEY, or BIOMEBASE_KEY.
310 | */
311 |
312 | export default function mimcHash(key) {
313 | return mimcWithRounds(220, key);
314 | }
315 |
--------------------------------------------------------------------------------
/isokratia-client/lib/mimc.ts:
--------------------------------------------------------------------------------
1 | import bigInt, { BigInteger } from 'big-integer';
2 |
3 | export const p = bigInt(
4 | '21888242871839275222246405745257275088548364400416034343698204186575808495617'
5 | );
6 |
7 | const c = [
8 | '0',
9 | '7120861356467848435263064379192047478074060781135320967663101236819528304084',
10 | '5024705281721889198577876690145313457398658950011302225525409148828000436681',
11 | '17980351014018068290387269214713820287804403312720763401943303895585469787384',
12 | '19886576439381707240399940949310933992335779767309383709787331470398675714258',
13 | '1213715278223786725806155661738676903520350859678319590331207960381534602599',
14 | '18162138253399958831050545255414688239130588254891200470934232514682584734511',
15 | '7667462281466170157858259197976388676420847047604921256361474169980037581876',
16 | '7207551498477838452286210989212982851118089401128156132319807392460388436957',
17 | '9864183311657946807255900203841777810810224615118629957816193727554621093838',
18 | '4798196928559910300796064665904583125427459076060519468052008159779219347957',
19 | '17387238494588145257484818061490088963673275521250153686214197573695921400950',
20 | '10005334761930299057035055370088813230849810566234116771751925093634136574742',
21 | '11897542014760736209670863723231849628230383119798486487899539017466261308762',
22 | '16771780563523793011283273687253985566177232886900511371656074413362142152543',
23 | '749264854018824809464168489785113337925400687349357088413132714480582918506',
24 | '3683645737503705042628598550438395339383572464204988015434959428676652575331',
25 | '7556750851783822914673316211129907782679509728346361368978891584375551186255',
26 | '20391289379084797414557439284689954098721219201171527383291525676334308303023',
27 | '18146517657445423462330854383025300323335289319277199154920964274562014376193',
28 | '8080173465267536232534446836148661251987053305394647905212781979099916615292',
29 | '10796443006899450245502071131975731672911747129805343722228413358507805531141',
30 | '5404287610364961067658660283245291234008692303120470305032076412056764726509',
31 | '4623894483395123520243967718315330178025957095502546813929290333264120223168',
32 | '16845753148201777192406958674202574751725237939980634861948953189320362207797',
33 | '4622170486584704769521001011395820886029808520586507873417553166762370293671',
34 | '16688277490485052681847773549197928630624828392248424077804829676011512392564',
35 | '11878652861183667748838188993669912629573713271883125458838494308957689090959',
36 | '2436445725746972287496138382764643208791713986676129260589667864467010129482',
37 | '1888098689545151571063267806606510032698677328923740058080630641742325067877',
38 | '148924106504065664829055598316821983869409581623245780505601526786791681102',
39 | '18875020877782404439294079398043479420415331640996249745272087358069018086569',
40 | '15189693413320228845990326214136820307649565437237093707846682797649429515840',
41 | '19669450123472657781282985229369348220906547335081730205028099210442632534079',
42 | '5521922218264623411380547905210139511350706092570900075727555783240701821773',
43 | '4144769320246558352780591737261172907511489963810975650573703217887429086546',
44 | '10097732913112662248360143041019433907849917041759137293018029019134392559350',
45 | '1720059427972723034107765345743336447947522473310069975142483982753181038321',
46 | '6302388219880227251325608388535181451187131054211388356563634768253301290116',
47 | '6745410632962119604799318394592010194450845483518862700079921360015766217097',
48 | '10858157235265583624235850660462324469799552996870780238992046963007491306222',
49 | '20241898894740093733047052816576694435372877719072347814065227797906130857593',
50 | '10165780782761211520836029617746977303303335603838343292431760011576528327409',
51 | '2832093654883670345969792724123161241696170611611744759675180839473215203706',
52 | '153011722355526826233082383360057587249818749719433916258246100068258954737',
53 | '20196970640587451358539129330170636295243141659030208529338914906436009086943',
54 | '3180973917010545328313139835982464870638521890385603025657430208141494469656',
55 | '17198004293191777441573635123110935015228014028618868252989374962722329283022',
56 | '7642160509228669138628515458941659189680509753651629476399516332224325757132',
57 | '19346204940546791021518535594447257347218878114049998691060016493806845179755',
58 | '11501810868606870391127866188394535330696206817602260610801897042898616817272',
59 | '3113973447392053821824427670386252797811804954746053461397972968381571297505',
60 | '6545064306297957002139416752334741502722251869537551068239642131448768236585',
61 | '5203908808704813498389265425172875593837960384349653691918590736979872578408',
62 | '2246692432011290582160062129070762007374502637007107318105405626910313810224',
63 | '11760570435432189127645691249600821064883781677693087773459065574359292849137',
64 | '5543749482491340532547407723464609328207990784853381797689466144924198391839',
65 | '8837549193990558762776520822018694066937602576881497343584903902880277769302',
66 | '12855514863299373699594410385788943772765811961581749194183533625311486462501',
67 | '5363660674689121676875069134269386492382220935599781121306637800261912519729',
68 | '13162342403579303950549728848130828093497701266240457479693991108217307949435',
69 | '916941639326869583414469202910306428966657806899788970948781207501251816730',
70 | '15618589556584434434009868216186115416835494805174158488636000580759692174228',
71 | '8959562060028569701043973060670353733575345393653685776974948916988033453971',
72 | '16390754464333401712265575949874369157699293840516802426621216808905079127650',
73 | '168282396747788514908709091757591226095443902501365500003618183905496160435',
74 | '8327443473179334761744301768309008451162322941906921742120510244986704677004',
75 | '17213012626801210615058753489149961717422101711567228037597150941152495100640',
76 | '10394369641533736715250242399198097296122982486516256408681925424076248952280',
77 | '17784386835392322654196171115293700800825771210400152504776806618892170162248',
78 | '16533189939837087893364000390641148516479148564190420358849587959161226782982',
79 | '18725396114211370207078434315900726338547621160475533496863298091023511945076',
80 | '7132325028834551397904855671244375895110341505383911719294705267624034122405',
81 | '148317947440800089795933930720822493695520852448386394775371401743494965187',
82 | '19001050671757720352890779127693793630251266879994702723636759889378387053056',
83 | '18824274411769830274877839365728651108434404855803844568234862945613766611460',
84 | '12771414330193951156383998390424063470766226667986423961689712557338777174205',
85 | '11332046574800279729678603488745295198038913503395629790213378101166488244657',
86 | '9607550223176946388146938069307456967842408600269548190739947540821716354749',
87 | '8756385288462344550200229174435953103162307705310807828651304665320046782583',
88 | '176061952957067086877570020242717222844908281373122372938833890096257042779',
89 | '12200212977482648306758992405065921724409841940671166017620928947866825250857',
90 | '10868453624107875516866146499877130701929063632959660262366632833504750028858',
91 | '2016095394399807253596787752134573207202567875457560571095586743878953450738',
92 | '21815578223768330433802113452339488275704145896544481092014911825656390567514',
93 | '4923772847693564777744725640710197015181591950368494148029046443433103381621',
94 | '1813584943682214789802230765734821149202472893379265320098816901270224589984',
95 | '10810123816265612772922113403831964815724109728287572256602010709288980656498',
96 | '1153669123397255702524721206511185557982017410156956216465120456256288427021',
97 | '5007518659266430200134478928344522649876467369278722765097865662497773767152',
98 | '2511432546938591792036639990606464315121646668029252285288323664350666551637',
99 | '32883284540320451295484135704808083452381176816565850047310272290579727564',
100 | '10484856914279112612610993418405543310546746652738541161791501150994088679557',
101 | '2026733759645519472558796412979210009170379159866522399881566309631434814953',
102 | '14731806221235869882801331463708736361296174006732553130708107037190460654379',
103 | '14740327483193277147065845135561988641238516852487657117813536909482068950652',
104 | '18787428285295558781869865751953016580493190547148386433580291216673009884554',
105 | '3804047064713122820157099453648459188816376755739202017447862327783289895072',
106 | '16709604795697901641948603019242067672006293290826991671766611326262532802914',
107 | '11061717085931490100602849654034280576915102867237101935487893025907907250695',
108 | '2821730726367472966906149684046356272806484545281639696873240305052362149654',
109 | '17467794879902895769410571945152708684493991588672014763135370927880883292655',
110 | '1571520786233540988201616650622796363168031165456869481368085474420849243232',
111 | '10041051776251223165849354194892664881051125330236567356945669006147134614302',
112 | '3981753758468103976812813304477670033098707002886030847251581853700311567551',
113 | '4365864398105436789177703571412645548020537580493599380018290523813331678900',
114 | '2391801327305361293476178683853802679507598622000359948432171562543560193350',
115 | '214219368547551689972421167733597094823289857206402800635962137077096090722',
116 | '18192064100315141084242006659317257023098826945893371479835220462302399655674',
117 | '15487549757142039139328911515400805508248576685795694919457041092150651939253',
118 | '10142447197759703415402259672441315777933858467700579946665223821199077641122',
119 | '11246573086260753259993971254725613211193686683988426513880826148090811891866',
120 | '6574066859860991369704567902211886840188702386542112593710271426704432301235',
121 | '11311085442652291634822798307831431035776248927202286895207125867542470350078',
122 | '20977948360215259915441258687649465618185769343138135384346964466965010873779',
123 | '792781492853909872425531014397300057232399608769451037135936617996830018501',
124 | '5027602491523497423798779154966735896562099398367163998686335127580757861872',
125 | '14595204575654316237672764823862241845410365278802914304953002937313300553572',
126 | '13973538843621261113924259058427434053808430378163734641175100160836376897004',
127 | '16395063164993626722686882727042150241125309409717445381854913964674649318585',
128 | '8465768840047024550750516678171433288207841931251654898809033371655109266663',
129 | '21345603324471810861925019445720576814602636473739003852898308205213912255830',
130 | '21171984405852590343970239018692870799717057961108910523876770029017785940991',
131 | '10761027113757988230637066281488532903174559953630210849190212601991063767647',
132 | '6678298831065390834922566306988418588227382406175769592902974103663687992230',
133 | '4993662582188632374202316265508850988596880036291765531885657575099537176757',
134 | '18364168158495573675698600238443218434246806358811328083953887470513967121206',
135 | '3506345610354615013737144848471391553141006285964325596214723571988011984829',
136 | '248732676202643792226973868626360612151424823368345645514532870586234380100',
137 | '10090204501612803176317709245679152331057882187411777688746797044706063410969',
138 | '21297149835078365363970699581821844234354988617890041296044775371855432973500',
139 | '16729368143229828574342820060716366330476985824952922184463387490091156065099',
140 | '4467191506765339364971058668792642195242197133011672559453028147641428433293',
141 | '8677548159358013363291014307402600830078662555833653517843708051504582990832',
142 | '1022951765127126818581466247360193856197472064872288389992480993218645055345',
143 | '1888195070251580606973417065636430294417895423429240431595054184472931224452',
144 | '4221265384902749246920810956363310125115516771964522748896154428740238579824',
145 | '2825393571154632139467378429077438870179957021959813965940638905853993971879',
146 | '19171031072692942278056619599721228021635671304612437350119663236604712493093',
147 | '10780807212297131186617505517708903709488273075252405602261683478333331220733',
148 | '18230936781133176044598070768084230333433368654744509969087239465125979720995',
149 | '16901065971871379877929280081392692752968612240624985552337779093292740763381',
150 | '146494141603558321291767829522948454429758543710648402457451799015963102253',
151 | '2492729278659146790410698334997955258248120870028541691998279257260289595548',
152 | '2204224910006646535594933495262085193210692406133533679934843341237521233504',
153 | '16062117410185840274616925297332331018523844434907012275592638570193234893570',
154 | '5894928453677122829055071981254202951712129328678534592916926069506935491729',
155 | '4947482739415078212217504789923078546034438919537985740403824517728200332286',
156 | '16143265650645676880461646123844627780378251900510645261875867423498913438066',
157 | '397690828254561723549349897112473766901585444153303054845160673059519614409',
158 | '11272653598912269895509621181205395118899451234151664604248382803490621227687',
159 | '15566927854306879444693061574322104423426072650522411176731130806720753591030',
160 | '14222898219492484180162096141564251903058269177856173968147960855133048449557',
161 | '16690275395485630428127725067513114066329712673106153451801968992299636791385',
162 | '3667030990325966886479548860429670833692690972701471494757671819017808678584',
163 | '21280039024501430842616328642522421302481259067470872421086939673482530783142',
164 | '15895485136902450169492923978042129726601461603404514670348703312850236146328',
165 | '7733050956302327984762132317027414325566202380840692458138724610131603812560',
166 | '438123800976401478772659663183448617575635636575786782566035096946820525816',
167 | '814913922521637742587885320797606426167962526342166512693085292151314976633',
168 | '12368712287081330853637674140264759478736012797026621876924395982504369598764',
169 | '2494806857395134874309386694756263421445039103814920780777601708371037591569',
170 | '16101132301514338989512946061786320637179843435886825102406248183507106312877',
171 | '6252650284989960032925831409804233477770646333900692286731621844532438095656',
172 | '9277135875276787021836189566799935097400042171346561246305113339462708861695',
173 | '10493603554686607050979497281838644324893776154179810893893660722522945589063',
174 | '8673089750662709235894359384294076697329948991010184356091130382437645649279',
175 | '9558393272910366944245875920138649617479779893610128634419086981339060613250',
176 | '19012287860122586147374214541764572282814469237161122489573881644994964647218',
177 | '9783723818270121678386992630754842961728702994964214799008457449989291229500',
178 | '15550788416669474113213749561488122552422887538676036667630838378023479382689',
179 | '15016165746156232864069722572047169071786333815661109750860165034341572904221',
180 | '6506225705710197163670556961299945987488979904603689017479840649664564978574',
181 | '10796631184889302076168355684722130903785890709107732067446714470783437829037',
182 | '19871836214837460419845806980869387567383718044439891735114283113359312279540',
183 | '20871081766843466343749609089986071784031203517506781251203251608363835140622',
184 | '5100105771517691442278432864090229416166996183792075307747582375962855820797',
185 | '8777887112076272395250620301071581171386440850451972412060638225741125310886',
186 | '5300440870136391278944213332144327695659161151625757537632832724102670898756',
187 | '1205448543652932944633962232545707633928124666868453915721030884663332604536',
188 | '5542499997310181530432302492142574333860449305424174466698068685590909336771',
189 | '11028094245762332275225364962905938096659249161369092798505554939952525894293',
190 | '19187314764836593118404597958543112407224947638377479622725713735224279297009',
191 | '17047263688548829001253658727764731047114098556534482052135734487985276987385',
192 | '19914849528178967155534624144358541535306360577227460456855821557421213606310',
193 | '2929658084700714257515872921366736697080475676508114973627124569375444665664',
194 | '15092262360719700162343163278648422751610766427236295023221516498310468956361',
195 | '21578580340755653236050830649990190843552802306886938815497471545814130084980',
196 | '1258781501221760320019859066036073675029057285507345332959539295621677296991',
197 | '3819598418157732134449049289585680301176983019643974929528867686268702720163',
198 | '8653175945487997845203439345797943132543211416447757110963967501177317426221',
199 | '6614652990340435611114076169697104582524566019034036680161902142028967568142',
200 | '19212515502973904821995111796203064175854996071497099383090983975618035391558',
201 | '18664315914479294273286016871365663486061896605232511201418576829062292269769',
202 | '11498264615058604317482574216318586415670903094838791165247179252175768794889',
203 | '10814026414212439999107945133852431304483604215416531759535467355316227331774',
204 | '17566185590731088197064706533119299946752127014428399631467913813769853431107',
205 | '14016139747289624978792446847000951708158212463304817001882956166752906714332',
206 | '8242601581342441750402731523736202888792436665415852106196418942315563860366',
207 | '9244680976345080074252591214216060854998619670381671198295645618515047080988',
208 | '12216779172735125538689875667307129262237123728082657485828359100719208190116',
209 | '10702811721859145441471328511968332847175733707711670171718794132331147396634',
210 | '6479667912792222539919362076122453947926362746906450079329453150607427372979',
211 | '15117544653571553820496948522381772148324367479772362833334593000535648316185',
212 | '6842203153996907264167856337497139692895299874139131328642472698663046726780',
213 | '12732823292801537626009139514048596316076834307941224506504666470961250728055',
214 | '6936272626871035740815028148058841877090860312517423346335878088297448888663',
215 | '17297554111853491139852678417579991271009602631577069694853813331124433680030',
216 | '16641596134749940573104316021365063031319260205559553673368334842484345864859',
217 | '7400481189785154329569470986896455371037813715804007747228648863919991399081',
218 | '2273205422216987330510475127669563545720586464429614439716564154166712854048',
219 | '15162538063742142685306302282127534305212832649282186184583465569986719234456',
220 | '5628039096440332922248578319648483863204530861778160259559031331287721255522',
221 | '16085392195894691829567913404182676871326863890140775376809129785155092531260',
222 | '14227467863135365427954093998621993651369686288941275436795622973781503444257',
223 | '18224457394066545825553407391290108485121649197258948320896164404518684305122',
224 | '274945154732293792784580363548970818611304339008964723447672490026510689427',
225 | '11050822248291117548220126630860474473945266276626263036056336623671308219529',
226 | '2119542016932434047340813757208803962484943912710204325088879681995922344971',
227 | '0',
228 | ].map((n) => bigInt(n));
229 |
230 | class FeistelState {
231 | l: BigInteger;
232 | r: BigInteger;
233 | rounds: number;
234 | k: BigInteger;
235 |
236 | constructor(rounds: number, k: BigInteger) {
237 | this.l = bigInt(0);
238 | this.r = bigInt(0);
239 | this.rounds = rounds;
240 | this.k = k;
241 | }
242 |
243 | inject(elt: BigInteger): void {
244 | this.l = this.l.add(elt).mod(p);
245 | }
246 |
247 | mix(): void {
248 | for (let i = 0; i < this.rounds - 1; i++) {
249 | const t = this.k.add(this.l).add(c[i]).mod(p);
250 | const lNew = t.modPow(5, p).add(this.r).mod(p);
251 | this.r = this.l;
252 | this.l = lNew;
253 | }
254 | const t = this.k.add(this.l).mod(p);
255 | this.r = t.modPow(5, p).add(this.r).mod(p);
256 | }
257 | }
258 |
259 | export function mimcSponge(
260 | inputs: BigInteger[],
261 | nOutputs: number,
262 | rounds: number,
263 | key: number
264 | ): BigInteger[] {
265 | const state = new FeistelState(rounds, bigInt(key));
266 | for (const elt of inputs) {
267 | state.inject(elt);
268 | state.mix();
269 | }
270 | const outputs: BigInteger[] = [state.l];
271 | for (let i = 0; i < nOutputs - 1; i++) {
272 | state.mix();
273 | outputs.push(state.l);
274 | }
275 | return outputs;
276 | }
277 |
278 | /**
279 | * Modulo a number with the LOCATION_ID_UB constant.
280 | * If the result is < 0, the LOCATION_ID_UB will then be added.
281 | *
282 | * @param x The number to modulo against LOCATION_ID_UB
283 | */
284 | export function modPBigInt(x: bigint) {
285 | let ret = bigInt(x.toString()).mod(p);
286 | if (ret.lesser(bigInt(0))) {
287 | ret = ret.add(p);
288 | }
289 | return ret;
290 | }
291 |
292 | /**
293 | * Modulo a BigInt with the LOCATION_ID_UB constant.
294 | * If the result is < 0, the LOCATION_ID_UB will then be added.
295 | *
296 | * @param x The number to modulo against LOCATION_ID_UB
297 | */
298 | export function modPBigIntNative(x: BigInteger) {
299 | let ret = x.mod(p);
300 | if (ret.lesser(bigInt(0))) {
301 | ret = ret.add(p);
302 | }
303 | return ret;
304 | }
305 |
306 | export const mimcWithRounds =
307 | (rounds: number, key: number) =>
308 | (...inputs: bigint[]) =>
309 | mimcSponge(
310 | inputs.map((n) => modPBigInt(n)),
311 | 1,
312 | rounds,
313 | key
314 | )[0];
315 |
316 | /**
317 | * The primary function used to build any MiMC hashing algorithm for Dark Forest.
318 | *
319 | * @param key The key for the MiMC algorithm. Will usually be PLANETHASH_KEY, SPACETYPE_KEY, or BIOMEBASE_KEY.
320 | */
321 | function mimcHash(key: number) {
322 | return mimcWithRounds(220, key);
323 | }
324 |
325 | export const perlinRandHash = (key: number) => mimcWithRounds(4, key);
326 |
327 | export default mimcHash;
--------------------------------------------------------------------------------
/isokratia-contracts/broadcast/Isokratia.s.sol/5/run-1660185967.json:
--------------------------------------------------------------------------------
1 | {
2 | "transactions": [
3 | {
4 | "hash": "0x3ce7a286ab203c5abadc01207e7e98c9fbc5fad8266d413e1df559e7b95cfe20",
5 | "transactionType": "CREATE",
6 | "contractName": "Isokratia",
7 | "contractAddress": "0xe7bcaaab7e52b2fce1a14bdc5d702efe8254d324",
8 | "function": null,
9 | "arguments": null,
10 | "transaction": {
11 | "type": "0x02",
12 | "from": "0x9a57d792cc04a7bceb5d1f8b1b7af5f8e5695e54",
13 | "gas": "0x62472f",
14 | "value": "0x0",
15 | "data": "0x60806040523480156200001157600080fd5b50604051620021e6380380620021e683398101604081905262000034916200039c565b6200004360018560066200007e565b50620000536049846002620000d0565b50620000636061836002620000d0565b50620000736079826002620000d0565b50505050506200044d565b604883019183908215620000be579160200282015b82811115620000be578251620000ad908390600262000110565b50916020019190600c019062000093565b50620000cc9291506200015e565b5090565b601883019183908215620000be579160200282015b82811115620000be578251620000ff908390600262000110565b50916020019190600c0190620000e5565b600c8301918390821562000150579160200282015b82811115620001505782516200013f90839060066200017f565b509160200191906006019062000125565b50620000cc929150620001be565b80821115620000cc576000620001758282620001df565b50600c016200015e565b8260068101928215620001b0579160200282015b82811115620001b057825182559160200191906001019062000193565b50620000cc92915062000201565b80821115620000cc576000620001d5828262000218565b50600601620001be565b506000620001ee828262000218565b50620001ff90600601600062000218565b565b5b80821115620000cc576000815560010162000202565b506200022990600681019062000201565b50565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b03811182821017156200026757620002676200022c565b60405290565b60405160c081016001600160401b03811182821017156200026757620002676200022c565b6000601f8381840112620002a557600080fd5b620002af62000242565b80610180850186811115620002c357600080fd5b855b818110156200032c578785820112620002de5760008081fd5b620002e86200026d565b8060c083018a811115620002fc5760008081fd5b835b8181101562000318578051845260209384019301620002fe565b505085525060209093019260c001620002c5565b50909695505050505050565b600082601f8301126200034a57600080fd5b6200035462000242565b806103008401858111156200036857600080fd5b845b8181101562000391576200037f878262000292565b8452602090930192610180016200036a565b509095945050505050565b6000806000806112008587031215620003b457600080fd5b85601f860112620003c457600080fd5b620003ce6200026d565b80610900870188811115620003e257600080fd5b875b818110156200040b57620003f98a8262000292565b845260209093019261018001620003e4565b508196506200041b898262000338565b95505050506200043086610c00870162000338565b91506200044286610f00870162000338565b905092959194509250565b611d89806200045d6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806343753b4d14610046578063c089202f1461006d578063d8cf99e914610082575b600080fd5b61005961005436600461187a565b610095565b604051901515815260200160405180910390f35b61008061007b366004611943565b6101aa565b005b610080610090366004611a97565b61079d565b600061009f6114cb565b60408051808201825287518152602080890151818301529083528151608081018352875151818401908152885183015160608301528152825180840184528883018051518252518301518184015281830152838201528151808301835286518152868201518183015283830152815160018082528184019093526000929091828101908036833701905050905060005b600181101561017e5784816001811061014a5761014a611bc5565b602002015182828151811061016157610161611bc5565b60209081029190910101528061017681611bf1565b91505061012f565b506101898183610891565b60000361019b576001925050506101a2565b6000925050505b949350505050565b6000888152602081905260409020600101544311156102075760405162461bcd60e51b8152602060048201526014602482015273141c9bdc1bdcd85b081a185cc8195e1c1a5c995960621b60448201526064015b60405180910390fd5b61021384848484610095565b61024b5760405162461bcd60e51b81526020600482015260096024820152682130b210383937b7b360b91b60448201526064016101fe565b61025361151c565b868152600089815260208181526040808320600201549184019190915282018790526003905b6004811015610323576000808c81526020019081526020016000206003018a6040516102a59190611c3a565b908152602001604051809103902081600481106102c4576102c4611bc5565b600491828204019190066008029054906101000a90046001600160401b03166001600160401b03168383609781106102fe576102fe611bc5565b60200201528161030d81611bf1565b925050808061031b90611bf1565b915050610279565b5060005b60068110156103e45760005b60028110156103d15760005b60068110156103be576001836006811061035b5761035b611bc5565b600c0201826002811061037057610370611bc5565b60060201816006811061038557610385611bc5565b015485856097811061039957610399611bc5565b6020020152836103a881611bf1565b94505080806103b690611bf1565b91505061033f565b50806103c981611bf1565b915050610333565b50806103dc81611bf1565b915050610327565b5060005b60028110156104a55760005b60028110156104925760005b600681101561047f576049836002811061041c5761041c611bc5565b600c0201826002811061043157610431611bc5565b60060201816006811061044657610446611bc5565b015485856097811061045a5761045a611bc5565b60200201528361046981611bf1565b945050808061047790611bf1565b915050610400565b508061048a81611bf1565b9150506103f4565b508061049d81611bf1565b9150506103e8565b5060005b60028110156105665760005b60028110156105535760005b600681101561054057606183600281106104dd576104dd611bc5565b600c020182600281106104f2576104f2611bc5565b60060201816006811061050757610507611bc5565b015485856097811061051b5761051b611bc5565b60200201528361052a81611bf1565b945050808061053890611bf1565b9150506104c1565b508061054b81611bf1565b9150506104b5565b508061055e81611bf1565b9150506104a9565b5060005b60028110156106275760005b60028110156106145760005b6006811015610601576079836002811061059e5761059e611bc5565b600c020182600281106105b3576105b3611bc5565b6006020181600681106105c8576105c8611bc5565b01548585609781106105dc576105dc611bc5565b6020020152836105eb81611bf1565b94505080806105f990611bf1565b915050610582565b508061060c81611bf1565b915050610576565b508061061f81611bf1565b91505061056a565b506000600660028460405160200161063f9190611c56565b60408051601f198184030181529082905261065991611c3a565b602060405180830381855afa158015610676573d6000803e3d6000fd5b5050506040513d601f19601f820116820180604052508101906106999190611c88565b8551911c915081146106e55760405162461bcd60e51b8152602060048201526015602482015274109859081c1d589b1a58c818dbdb5b5a5d1b595b9d605a1b60448201526064016101fe565b6000808c81526020019081526020016000206004018a6040516107089190611c3a565b90815260200160405180910390205489111561079057886000808d81526020019081526020016000206004018b6040516107429190611c3a565b9081526020016040518091039020819055507fb9e1d2d0c115879858328b4eaf2e7d2cc1ad5749e07463095d767829c1ac33c58b8b8b60405161078793929190611ca1565b60405180910390a15b5050505050505050505050565b6000858152602081905260408120868155600181018690556002018490555b8251811015610848578281815181106107d7576107d7611bc5565b602002602001015160008088815260200190815260200160002060030183838151811061080657610806611bc5565b602002602001015160405161081b9190611c3a565b90815260405190819003602001902061083591600461153b565b508061084081611bf1565b9150506107bc565b5060408051338152602081018790529081018590527f5fa1acbdcb8142d84e87165149f77e37c91bcf8055862afe7b9e7c6bac70404b9060600160405180910390a15050505050565b60007f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001816108bd610a83565b9050806080015151855160016108d39190611ce3565b146109155760405162461bcd60e51b81526020600482015260126024820152711d995c9a599a595c8b5898590b5a5b9c1d5d60721b60448201526064016101fe565b604080518082019091526000808252602082018190525b8651811015610a06578387828151811061094857610948611bc5565b60200260200101511061099d5760405162461bcd60e51b815260206004820152601f60248201527f76657269666965722d6774652d736e61726b2d7363616c61722d6669656c640060448201526064016101fe565b6109f2826109ed85608001518460016109b69190611ce3565b815181106109c6576109c6611bc5565b60200260200101518a85815181106109e0576109e0611bc5565b6020026020010151610e1b565b610eb1565b9150806109fe81611bf1565b91505061092c565b50610a2f818360800151600081518110610a2257610a22611bc5565b6020026020010151610eb1565b9050610a65610a418660000151610f4a565b8660200151846000015185602001518587604001518b604001518960600151610fe9565b610a755760019350505050610a7d565b600093505050505b92915050565b610a8b6115e0565b6040805180820182527f2d4d9aa7e302d9df41749d5507949d05dbea33fbb16c643b22f599a2be6df2e281527f14bedd503c37ceb061d8ec60209fe345ce89830a19230301f076caff004d19266020808301919091529083528151608080820184527f0967032fcbf776d1afc985f88877f182d38480a653f2decaa9794cbc3bf3060c8285019081527f0e187847ad4c798374d0d6732bf501847dd68bc0e071241e0213bc7fc13db7ab606080850191909152908352845180860186527f304cfbd1e08a704a99f5e847d93f8c3caafddec46b7a0d379da69a4d112346a781527f1739c1b1a457a8c7313123d24d2f9192f896b7c63eea05a9d57f06547ad0cec8818601528385015285840192909252835180820185527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c28186019081527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed828501528152845180860186527f090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b81527f12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa818601528185015285850152835190810184527f0d34f33275f76a56082c16617fb094ee31d43201c67d25b04b70d143316f6cf18185019081527f29435df9376f600cdd2ba7477a837912eac5d0bcfd3df9ee25eb2f07be25fc27828401528152835180850185527f15056ff20ffa7ace113e61babe0144a15ad9d8c174c12601683d74961401fd8a81527f02dd4c641e42cece8ed78e3916c7646dc146790fd2b3b484d62907ff54a2a34b818501528184015281850152825160028082529181019093529082015b6040805180820190915260008082526020820152815260200190600190039081610d0457505060808201908152604080518082019091527f058529f3fb81a4fb0955ad9c98210874da808769f397702495601930110994bd81527f2058379d634ecbb74149e6ec4213d2f38f7eaf83e143747028e0b2828383cb12602082015290518051600090610d9757610d97611bc5565b602002602001018190525060405180604001604052807e0ba211c88f8f65013f82938f692f7f2174673c3b2eb310edee5b107ecb147481526020017f196b18e92427c5ccc43d102d92355e36a52ea7e38acc78ae0b3ad2d6121c3a6c8152508160800151600181518110610e0d57610e0d611bc5565b602002602001018190525090565b6040805180820190915260008082526020820152610e37611631565b835181526020808501519082015260408101839052600060608360808460076107d05a03fa90508080610e6657fe5b5080610ea95760405162461bcd60e51b81526020600482015260126024820152711c185a5c9a5b99cb5b5d5b0b59985a5b195960721b60448201526064016101fe565b505092915050565b6040805180820190915260008082526020820152610ecd61164f565b8351815260208085015181830152835160408301528301516060808301919091526000908360c08460066107d05a03fa90508080610f0757fe5b5080610ea95760405162461bcd60e51b81526020600482015260126024820152711c185a5c9a5b99cb5859190b59985a5b195960721b60448201526064016101fe565b604080518082019091526000808252602082015281517f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4790158015610f9157506020830151155b15610fb15750506040805180820190915260008082526020820152919050565b604051806040016040528084600001518152602001828560200151610fd69190611cfb565b610fe09084611d1d565b90529392505050565b60408051600480825260a08201909252600091829190816020015b604080518082019091526000808252602082015281526020019060019003908161100457505060408051600480825260a0820190925291925060009190602082015b61104e61166d565b8152602001906001900390816110465790505090508a8260008151811061107757611077611bc5565b6020026020010181905250888260018151811061109657611096611bc5565b602002602001018190525086826002815181106110b5576110b5611bc5565b602002602001018190525084826003815181106110d4576110d4611bc5565b602002602001018190525089816000815181106110f3576110f3611bc5565b6020026020010181905250878160018151811061111257611112611bc5565b6020026020010181905250858160028151811061113157611131611bc5565b6020026020010181905250838160038151811061115057611150611bc5565b60200260200101819052506111658282611174565b9b9a5050505050505050505050565b600081518351146111c05760405162461bcd60e51b81526020600482015260166024820152751c185a5c9a5b99cb5b195b99dd1a1ccb59985a5b195960521b60448201526064016101fe565b825160006111cf826006611d34565b90506000816001600160401b038111156111eb576111eb6116de565b604051908082528060200260200182016040528015611214578160200160208202803683370190505b50905060005b8381101561144f5786818151811061123457611234611bc5565b6020026020010151600001518282600661124e9190611d34565b611259906000611ce3565b8151811061126957611269611bc5565b60200260200101818152505086818151811061128757611287611bc5565b602002602001015160200151828260066112a19190611d34565b6112ac906001611ce3565b815181106112bc576112bc611bc5565b6020026020010181815250508581815181106112da576112da611bc5565b60209081029190910101515151826112f3836006611d34565b6112fe906002611ce3565b8151811061130e5761130e611bc5565b60200260200101818152505085818151811061132c5761132c611bc5565b60209081029190910181015151015182611347836006611d34565b611352906003611ce3565b8151811061136257611362611bc5565b60200260200101818152505085818151811061138057611380611bc5565b60200260200101516020015160006002811061139e5761139e611bc5565b6020020151826113af836006611d34565b6113ba906004611ce3565b815181106113ca576113ca611bc5565b6020026020010181815250508581815181106113e8576113e8611bc5565b60200260200101516020015160016002811061140657611406611bc5565b602002015182611417836006611d34565b611422906005611ce3565b8151811061143257611432611bc5565b60209081029190910101528061144781611bf1565b91505061121a565b5061145861168d565b6000602082602086026020860160086107d05a03fa9050808061147757fe5b50806114bd5760405162461bcd60e51b81526020600482015260156024820152741c185a5c9a5b99cb5bdc18dbd9194b59985a5b1959605a1b60448201526064016101fe565b505115159695505050505050565b6040805160a0810190915260006060820181815260808301919091528152602081016114f561166d565b8152602001611517604051806040016040528060008152602001600081525090565b905290565b604051806112e001604052806097906020820280368337509192915050565b6001830191839082156115d05791602002820160005b8382111561159b57835183826101000a8154816001600160401b0302191690836001600160401b031602179055509260200192600801602081600701049283019260010302611551565b80156115ce5782816101000a8154906001600160401b03021916905560080160208160070104928301926001030261159b565b505b506115dc9291506116ab565b5090565b6040805160e08101909152600060a0820181815260c083019190915281526020810161160a61166d565b815260200161161761166d565b815260200161162461166d565b8152602001606081525090565b60405180606001604052806003906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b60405180604001604052806116806116c0565b81526020016115176116c0565b60405180602001604052806001906020820280368337509192915050565b5b808211156115dc57600081556001016116ac565b60405180604001604052806002906020820280368337509192915050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715611716576117166116de565b60405290565b604051608081016001600160401b0381118282101715611716576117166116de565b604051601f8201601f191681016001600160401b0381118282101715611766576117666116de565b604052919050565b600082601f83011261177f57600080fd5b6117876116f4565b80604084018581111561179957600080fd5b845b818110156117b357803584526020938401930161179b565b509095945050505050565b600082601f8301126117cf57600080fd5b6117d76116f4565b8060808401858111156117e957600080fd5b845b818110156117b3576117fd878261176e565b84526020909301926040016117eb565b600082601f83011261181e57600080fd5b60405160208082018281106001600160401b0382111715611841576118416116de565b604052818482018681111561185557600080fd5b855b8181101561186e5780358352918301918301611857565b50929695505050505050565b600080600080610120858703121561189157600080fd5b61189b868661176e565b93506118aa86604087016117be565b92506118b98660c0870161176e565b91506118c986610100870161180d565b905092959194509250565b600082601f8301126118e557600080fd5b81356001600160401b038111156118fe576118fe6116de565b611911601f8201601f191660200161173e565b81815284602083860101111561192657600080fd5b816020850160208301376000918101602001919091529392505050565b6000806000806000806000806101a0898b03121561196057600080fd5b8835975060208901356001600160401b0381111561197d57600080fd5b6119898b828c016118d4565b97505060408901359550606089013594506119a78a60808b0161176e565b93506119b68a60c08b016117be565b92506119c68a6101408b0161176e565b91506119d68a6101808b0161180d565b90509295985092959890939650565b60006001600160401b038211156119fe576119fe6116de565b5060051b60200190565b600082601f830112611a1957600080fd5b81356020611a2e611a29836119e5565b61173e565b82815260059290921b84018101918181019086841115611a4d57600080fd5b8286015b84811015611a8c5780356001600160401b03811115611a705760008081fd5b611a7e8986838b01016118d4565b845250918301918301611a51565b509695505050505050565b600080600080600060a08688031215611aaf57600080fd5b8535945060208087013594506040870135935060608701356001600160401b0380821115611adc57600080fd5b818901915089601f830112611af057600080fd5b8135611afe611a29826119e5565b81815260079190911b8301840190848101908c831115611b1d57600080fd5b938501935b82851015611b92578c601f860112611b3a5760008081fd5b611b4261171c565b80608087018f811115611b555760008081fd5b875b81811015611b7d5780358881168114611b705760008081fd5b8452928901928901611b57565b50508352506080949094019390850190611b22565b965050506080890135925080831115611baa57600080fd5b5050611bb888828901611a08565b9150509295509295909350565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201611c0357611c03611bdb565b5060010190565b60005b83811015611c25578181015183820152602001611c0d565b83811115611c34576000848401525b50505050565b60008251611c4c818460208701611c0a565b9190910192915050565b6112e08101818360005b6097811015611c7f578151835260209283019290910190600101611c60565b50505092915050565b600060208284031215611c9a57600080fd5b5051919050565b8381526060602082015260008351806060840152611cc6816080850160208801611c0a565b604083019390935250601f91909101601f19160160800192915050565b60008219821115611cf657611cf6611bdb565b500190565b600082611d1857634e487b7160e01b600052601260045260246000fd5b500690565b600082821015611d2f57611d2f611bdb565b500390565b6000816000190483118215151615611d4e57611d4e611bdb565b50029056fea26469706673582212202605486fc9f5632cfb4e0d8599d80dbe6c32642d0e34fb10d23aa8b013bcbe1564736f6c634300080f0033000000000000000000000000000000000000000000000000000003b216b5e1f9000000000000000000000000000000000000000000000000000005f634ac43ed00000000000000000000000000000000000000000000000000000335a1589c79000000000000000000000000000000000000000000000000000005468af400400000000000000000000000000000000000000000000000000000075047aa19300000000000000000000000000000000000000000000000000000002f62a3f2f0000000000000000000000000000000000000000000000000000006fb45587a8e0000000000000000000000000000000000000000000000000000010ac7620e1f00000000000000000000000000000000000000000000000000000620eed8a58a000000000000000000000000000000000000000000000000000004adc040091f000000000000000000000000000000000000000000000000000007c60457789500000000000000000000000000000000000000000000000000000052622f5e9e00000000000000000000000000000000000000000000000000000532139dd770000000000000000000000000000000000000000000000000000007f867db2407000000000000000000000000000000000000000000000000000006cdc0126eff0000000000000000000000000000000000000000000000000000017bbab9b00a0000000000000000000000000000000000000000000000000000055e65e2a873000000000000000000000000000000000000000000000000000000355483f543000000000000000000000000000000000000000000000000000000f8394da94a000000000000000000000000000000000000000000000000000004f59ca3637c0000000000000000000000000000000000000000000000000000001e6c8a64d8000000000000000000000000000000000000000000000000000005c9d61b4f770000000000000000000000000000000000000000000000000000077bba145db40000000000000000000000000000000000000000000000000000001b732464780000000000000000000000000000000000000000000000000000027972abbeb2000000000000000000000000000000000000000000000000000007716d50870f0000000000000000000000000000000000000000000000000000028d42d0cbc80000000000000000000000000000000000000000000000000000042168cc05e800000000000000000000000000000000000000000000000000000157d24e9b4f00000000000000000000000000000000000000000000000000000025d1e11adb000000000000000000000000000000000000000000000000000003b932bf6b2c00000000000000000000000000000000000000000000000000000466bfdf1fa30000000000000000000000000000000000000000000000000000054034a9e215000000000000000000000000000000000000000000000000000004caf44ec64c000000000000000000000000000000000000000000000000000007a4c0286d43000000000000000000000000000000000000000000000000000000010d8d1b640000000000000000000000000000000000000000000000000000073106e5f000000000000000000000000000000000000000000000000000000007c7fcff00c300000000000000000000000000000000000000000000000000000234d84d3f13000000000000000000000000000000000000000000000000000004a7892874c2000000000000000000000000000000000000000000000000000000ce6b13c2b9000000000000000000000000000000000000000000000000000000500ec411d00000000000000000000000000000000000000000000000000000030bb469013a000000000000000000000000000000000000000000000000000004d0ed227aa9000000000000000000000000000000000000000000000000000004ef79b1fe81000000000000000000000000000000000000000000000000000003ec515f2a0a0000000000000000000000000000000000000000000000000000029f04f963a800000000000000000000000000000000000000000000000000000048daa373a30000000000000000000000000000000000000000000000000000065a51b2a15e0000000000000000000000000000000000000000000000000000040310baf2e00000000000000000000000000000000000000000000000000000007898fcbb6100000000000000000000000000000000000000000000000000000512e7d5aafb0000000000000000000000000000000000000000000000000000013922f500020000000000000000000000000000000000000000000000000000001af53377f5000000000000000000000000000000000000000000000000000003df5262c40b0000000000000000000000000000000000000000000000000000052180f226b0000000000000000000000000000000000000000000000000000002b78e2a19b8000000000000000000000000000000000000000000000000000005973d87d678000000000000000000000000000000000000000000000000000007f9339cbca400000000000000000000000000000000000000000000000000000001bc24eae70000000000000000000000000000000000000000000000000000030932e31131000000000000000000000000000000000000000000000000000002bfecbf732e0000000000000000000000000000000000000000000000000000045aba53ce79000000000000000000000000000000000000000000000000000003647367967f00000000000000000000000000000000000000000000000000000243899932270000000000000000000000000000000000000000000000000000005c3604417a0000000000000000000000000000000000000000000000000000031580948ed2000000000000000000000000000000000000000000000000000000275f4a5e8f00000000000000000000000000000000000000000000000000000212d05aa59600000000000000000000000000000000000000000000000000000178d33ca7c00000000000000000000000000000000000000000000000000000066ab1dc45740000000000000000000000000000000000000000000000000000000b40f658110000000000000000000000000000000000000000000000000000055cd992f6ed000000000000000000000000000000000000000000000000000003db5ba8dbd70000000000000000000000000000000000000000000000000000059d0c8b53dd000000000000000000000000000000000000000000000000000000332f2e223c000000000000000000000000000000000000000000000000000001f1e76426a00000000000000000000000000000000000000000000000000000003001bdde24000000000000000000000000000000000000000000000000000005b7aef312c20000000000000000000000000000000000000000000000000000053ce252fc90000000000000000000000000000000000000000000000000000007c6a924ccd6000000000000000000000000000000000000000000000000000007db98fdae92000000000000000000000000000000000000000000000000000000d483a7260b000000000000000000000000000000000000000000000000000000331d2727240000000000000000000000000000000000000000000000000000040166fa7daa0000000000000000000000000000000000000000000000000000007a6f699cd90000000000000000000000000000000000000000000000000000078f479da431000000000000000000000000000000000000000000000000000000c046e5a047000000000000000000000000000000000000000000000000000000c6deb4aab70000000000000000000000000000000000000000000000000000002590bd4bb7000000000000000000000000000000000000000000000000000002dcd122975b00000000000000000000000000000000000000000000000000000671de6ab59b000000000000000000000000000000000000000000000000000006f12cc4cdc2000000000000000000000000000000000000000000000000000004d6b48619ca000000000000000000000000000000000000000000000000000005ff075ec9e9000000000000000000000000000000000000000000000000000000120d13a0b000000000000000000000000000000000000000000000000000000707be25fc27000000000000000000000000000000000000000000000000000007bf3dc4bd65000000000000000000000000000000000000000000000000000003ab1742f3f4000000000000000000000000000000000000000000000000000003a3bd41bc89000000000000000000000000000000000000000000000000000006f600cdd2ba0000000000000000000000000000000000000000000000000000005286bbf26e00000000000000000000000000000000000000000000000000000143316f6cf1000000000000000000000000000000000000000000000000000007a4b6096e1a000000000000000000000000000000000000000000000000000000c750c8071900000000000000000000000000000000000000000000000000000330bfd84a7700000000000000000000000000000000000000000000000000000776a56082c10000000000000000000000000000000000000000000000000000001a69e664eb000000000000000000000000000000000000000000000000000007ff54a2a34b00000000000000000000000000000000000000000000000000000676909ac5200000000000000000000000000000000000000000000000000000070519e43f4a0000000000000000000000000000000000000000000000000000071c8b63b2360000000000000000000000000000000000000000000000000000042cece8ed7800000000000000000000000000000000000000000000000000000005ba98c83c000000000000000000000000000000000000000000000000000004961401fd8a00000000000000000000000000000000000000000000000000000024c02d07ae0000000000000000000000000000000000000000000000000000056b676305d3000000000000000000000000000000000000000000000000000000dd5f00a250000000000000000000000000000000000000000000000000000007a7ace113e60000000000000000000000000000000000000000000000000000002a0adfe41f00000000000000000000000000000000000000000000000000000130110994bd000000000000000000000000000000000000000000000000000002ee0492ac030000000000000000000000000000000000000000000000000000036a021da7ce000000000000000000000000000000000000000000000000000006ce4c10843a0000000000000000000000000000000000000000000000000000001a4fb0955a0000000000000000000000000000000000000000000000000000000b0a53e7f7000000000000000000000000000000000000000000000000000002828383cb120000000000000000000000000000000000000000000000000000006e8e051c160000000000000000000000000000000000000000000000000000063dfabe0f85000000000000000000000000000000000000000000000000000003762109e979000000000000000000000000000000000000000000000000000004ecbb74149e00000000000000000000000000000000000000000000000000000040b06f3ac6000000000000000000000000000000000000000000000000000003107ecb1474000000000000000000000000000000000000000000000000000005d6621dbdcb00000000000000000000000000000000000000000000000000000485d19cf0ec00000000000000000000000000000000000000000000000000000149c7b497bf000000000000000000000000000000000000000000000000000000f8f65013f80000000000000000000000000000000000000000000000000000000017442391000000000000000000000000000000000000000000000000000002d6121c3a6c0000000000000000000000000000000000000000000000000000018f15c1675a00000000000000000000000000000000000000000000000000000294ba9f8e2b00000000000000000000000000000000000000000000000000000016c91aaf1b0000000000000000000000000000000000000000000000000000027c5ccc43d100000000000000000000000000000000000000000000000000000032d631d248",
16 | "nonce": "0x6",
17 | "accessList": []
18 | }
19 | }
20 | ],
21 | "receipts": [],
22 | "libraries": [],
23 | "pending": [
24 | "0x3ce7a286ab203c5abadc01207e7e98c9fbc5fad8266d413e1df559e7b95cfe20"
25 | ],
26 | "path": "broadcast/Isokratia.s.sol/5/run-latest.json",
27 | "returns": {},
28 | "timestamp": 1660185967
29 | }
--------------------------------------------------------------------------------