├── 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 | ![](https://nibnalin.me/assets/isokratia/cover.png) 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 | 11 | 19 | 24 | 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 |
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 |
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 |
289 |
290 | ); 291 | }; 292 | 293 | const DeleteButton = () => { 294 | return ( 295 | 302 | 308 | 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 | } --------------------------------------------------------------------------------