├── cairo
├── contracts
│ ├── main.json
│ ├── main_abi.json
│ ├── Core_address.json
│ ├── main2_address.json
│ ├── ERC721URIStorage.cairo
│ ├── ERC721.cairo
│ ├── Storage.cairo
│ ├── utils.cairo
│ └── Getters.cairo
├── hash
│ ├── input.json
│ └── circuit.cairo
├── encryption
│ ├── input.json
│ └── circuit.cairo
└── utils
│ ├── encrypt.cairo
│ ├── mimc.cairo
│ └── ec_math.cairo
├── deployments
└── ropsten
│ ├── Core.json
│ └── Getters.json
├── public
├── dev
│ ├── Pairing.json
│ ├── DarkForestUtils.json
│ ├── EncryptionVerifier.json
│ └── DarkForestCore.json
├── cairo.json
├── favicon.png
├── contracts
│ ├── prod
│ │ ├── Pairing.json
│ │ ├── DarkForestUtils.json
│ │ ├── IFactRegistry.json
│ │ ├── EncryptionVerifier.json
│ │ ├── DarkForestCore.json
│ │ └── Getters.json
│ └── Getters.json
├── main2_address.json
├── circuits
│ ├── keys
│ │ ├── Hash.zkey
│ │ ├── BlurImage.zkey
│ │ └── Encryption.zkey
│ ├── wasm
│ │ ├── Hash.wasm
│ │ ├── BlurImage.wasm
│ │ ├── Encryption.wasm
│ │ └── SharedKey.wasm
│ └── verification_keys
│ │ ├── SharedKey.json
│ │ ├── Hash.json
│ │ └── Encryption.json
├── fonts
│ ├── Roboto-subset.woff2
│ ├── Roboto-Mono-Regular.woff2
│ ├── static
│ │ ├── RobotoMono-Bold.ttf
│ │ ├── RobotoMono-Italic.ttf
│ │ ├── RobotoMono-Light.ttf
│ │ ├── RobotoMono-Medium.ttf
│ │ ├── RobotoMono-Thin.ttf
│ │ ├── RobotoMono-Regular.ttf
│ │ ├── RobotoMono-SemiBold.ttf
│ │ ├── RobotoMono-BoldItalic.ttf
│ │ ├── RobotoMono-ExtraLight.ttf
│ │ ├── RobotoMono-LightItalic.ttf
│ │ ├── RobotoMono-ThinItalic.ttf
│ │ ├── RobotoMono-MediumItalic.ttf
│ │ ├── RobotoMono-ExtraLightItalic.ttf
│ │ └── RobotoMono-SemiBoldItalic.ttf
│ ├── RobotoMono-VariableFont_wght.ttf
│ ├── RobotoMono-Italic-VariableFont_wght.ttf
│ └── README.txt
├── icons8-delete.svg
├── keys.json
└── index.html
├── config
├── index.js
└── config.js
├── src
├── types
│ ├── snarkjs.d.ts
│ ├── content.ts
│ └── index.ts
├── index.tsx
├── utils
│ ├── utils.ts
│ ├── api.ts
│ ├── parsers.ts
│ ├── errors.ts
│ ├── signature.ts
│ └── prover.ts
├── app
│ ├── OurThemeProvider.tsx
│ ├── PropertyToggle.tsx
│ ├── Page.tsx
│ ├── App.tsx
│ ├── NavigationBar.tsx
│ └── Ipfs.tsx
├── components
│ ├── Button.tsx
│ ├── Spinner.tsx
│ ├── TextArea.tsx
│ ├── Date.tsx
│ ├── Toggle.tsx
│ ├── Modal.tsx
│ ├── Resize.tsx
│ ├── text.tsx
│ └── TextInput.tsx
├── styles
│ └── theme.ts
└── pages
│ ├── ChooseUser.tsx
│ ├── Content.tsx
│ ├── content
│ ├── Hash.tsx
│ └── Blur.tsx
│ ├── Tokens.tsx
│ └── NewToken.tsx
├── test
└── spec.js
├── circuits
├── hash
│ ├── input.json
│ ├── public.json
│ └── circuit.circom
├── dark-forest
│ ├── input.json
│ └── circuit.circom
├── blur-image
│ ├── input.json
│ └── circuit.circom
├── encryption
│ ├── input.json
│ ├── public.json
│ └── circuit.circom
├── test
│ ├── encryption.test.js
│ ├── df.test.js
│ ├── blurredImage.test.js
│ └── hash.test.js
└── utils
│ ├── ecdh.circom
│ └── encrypt.circom
├── artifacts
├── contracts
│ ├── Core.sol
│ │ ├── Core.dbg.json
│ │ ├── DarkForestCore.dbg.json
│ │ ├── IFactRegistry.dbg.json
│ │ ├── IFactRegistry.json
│ │ └── DarkForestCore.json
│ ├── Getters.sol
│ │ ├── ICore.dbg.json
│ │ └── Getters.dbg.json
│ ├── Pairing.sol
│ │ ├── Pairing.dbg.json
│ │ └── Pairing.json
│ ├── Verifier.sol
│ │ └── Verifier.dbg.json
│ ├── DarkForestCore.sol
│ │ ├── DarkForestCore.dbg.json
│ │ └── DarkForestCore.json
│ ├── ContractStorage.sol
│ │ └── ContractStorage.dbg.json
│ └── DarkForestUtils.sol
│ │ ├── DarkForestUtils.dbg.json
│ │ └── DarkForestUtils.json
└── @openzeppelin
│ └── contracts
│ ├── access
│ └── Ownable.sol
│ │ ├── Ownable.dbg.json
│ │ └── Ownable.json
│ ├── utils
│ ├── Address.sol
│ │ ├── Address.dbg.json
│ │ └── Address.json
│ ├── Context.sol
│ │ ├── Context.dbg.json
│ │ └── Context.json
│ ├── Counters.sol
│ │ ├── Counters.dbg.json
│ │ └── Counters.json
│ ├── Strings.sol
│ │ ├── Strings.dbg.json
│ │ └── Strings.json
│ ├── introspection
│ │ ├── ERC165.sol
│ │ │ ├── ERC165.dbg.json
│ │ │ └── ERC165.json
│ │ └── IERC165.sol
│ │ │ ├── IERC165.dbg.json
│ │ │ └── IERC165.json
│ └── structs
│ │ └── EnumerableSet.sol
│ │ ├── EnumerableSet.dbg.json
│ │ └── EnumerableSet.json
│ ├── token
│ └── ERC721
│ │ ├── ERC721.sol
│ │ └── ERC721.dbg.json
│ │ ├── IERC721.sol
│ │ └── IERC721.dbg.json
│ │ ├── IERC721Receiver.sol
│ │ ├── IERC721Receiver.dbg.json
│ │ └── IERC721Receiver.json
│ │ └── extensions
│ │ ├── ERC721URIStorage.sol
│ │ └── ERC721URIStorage.dbg.json
│ │ └── IERC721Metadata.sol
│ │ └── IERC721Metadata.dbg.json
│ └── proxy
│ └── utils
│ └── Initializable.sol
│ ├── Initializable.dbg.json
│ └── Initializable.json
├── jest.config.js
├── .gitignore
├── .env.example
├── scripts
├── cairoCompile.js
├── cairoDeploy.js
├── cairoCall.js
├── deploy.ts
├── utils.ts
├── buildConfig.ts
├── build_readme.js
├── solbuilder.ts
└── builder.ts
├── contracts
├── DarkForestUtils.sol
├── DarkForestCore.sol
├── ContractStorage.sol
└── Getters.sol
├── tsconfig.json
├── .github
└── workflows
│ └── config.yml
├── crypto
├── test.js
├── test.py
├── package.json
├── index.js
└── babyjub.js
├── .eslintrc.json
├── app.py
├── hardhat.config.ts
├── webpack.config.js
└── README.md
/cairo/contracts/main.json:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/cairo/contracts/main_abi.json:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/deployments/ropsten/Core.json:
--------------------------------------------------------------------------------
1 | {"address":"0x6d0ED701C55D33816EB205D9Cb1A9A69325FA8df"}
--------------------------------------------------------------------------------
/deployments/ropsten/Getters.json:
--------------------------------------------------------------------------------
1 | {"address":"0xD210BF9FBB9E9aB9D155dD017c7982Dd07D54aB2"}
--------------------------------------------------------------------------------
/public/dev/Pairing.json:
--------------------------------------------------------------------------------
1 | {"abi":[],"address":"0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB"}
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | const config = require('./config.json');
2 |
3 | export default config;
4 |
--------------------------------------------------------------------------------
/public/cairo.json:
--------------------------------------------------------------------------------
1 | {"address":"0x078b1a2be50394f490f14525a9f122ae749138ed8e57f1373f34f85d8ddb58f0"}
--------------------------------------------------------------------------------
/public/dev/DarkForestUtils.json:
--------------------------------------------------------------------------------
1 | {"abi":[],"address":"0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0"}
--------------------------------------------------------------------------------
/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/favicon.png
--------------------------------------------------------------------------------
/public/contracts/prod/Pairing.json:
--------------------------------------------------------------------------------
1 | {"abi":[],"address":"0x64eFDCafFBCCe475C6C478e1FEF173de021Db3dA"}
--------------------------------------------------------------------------------
/public/contracts/prod/DarkForestUtils.json:
--------------------------------------------------------------------------------
1 | {"abi":[],"address":"0x94CF1176D393F0515C6968E5a42EA77E1c6e2302"}
--------------------------------------------------------------------------------
/cairo/contracts/Core_address.json:
--------------------------------------------------------------------------------
1 | {"address":"0x03735564c4c38aaa072c6a9a64401d185adb6aa2e38772920070960201b091c0"}
--------------------------------------------------------------------------------
/public/main2_address.json:
--------------------------------------------------------------------------------
1 | { "address": "0x0310ce421df97989efddf111df5067eb123500a6b799b1a662c3b10433c2fecb" }
2 |
--------------------------------------------------------------------------------
/src/types/snarkjs.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'snarkjs' {
2 | let _snarkjs: any;
3 | export = _snarkjs;
4 | }
5 |
--------------------------------------------------------------------------------
/cairo/contracts/main2_address.json:
--------------------------------------------------------------------------------
1 | {"address":"0x078b1a2be50394f490f14525a9f122ae749138ed8e57f1373f34f85d8ddb58f0"}
--------------------------------------------------------------------------------
/public/circuits/keys/Hash.zkey:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/circuits/keys/Hash.zkey
--------------------------------------------------------------------------------
/public/circuits/wasm/Hash.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/circuits/wasm/Hash.wasm
--------------------------------------------------------------------------------
/public/fonts/Roboto-subset.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/fonts/Roboto-subset.woff2
--------------------------------------------------------------------------------
/public/circuits/keys/BlurImage.zkey:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/circuits/keys/BlurImage.zkey
--------------------------------------------------------------------------------
/public/circuits/keys/Encryption.zkey:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/circuits/keys/Encryption.zkey
--------------------------------------------------------------------------------
/public/circuits/wasm/BlurImage.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/circuits/wasm/BlurImage.wasm
--------------------------------------------------------------------------------
/public/circuits/wasm/Encryption.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/circuits/wasm/Encryption.wasm
--------------------------------------------------------------------------------
/public/circuits/wasm/SharedKey.wasm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/circuits/wasm/SharedKey.wasm
--------------------------------------------------------------------------------
/public/fonts/Roboto-Mono-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/fonts/Roboto-Mono-Regular.woff2
--------------------------------------------------------------------------------
/test/spec.js:
--------------------------------------------------------------------------------
1 | describe('My Test Suite', () => {
2 | it('My Test Case', () => {
3 | expect(true).toEqual(true);
4 | });
5 | });
6 |
--------------------------------------------------------------------------------
/public/fonts/static/RobotoMono-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/fonts/static/RobotoMono-Bold.ttf
--------------------------------------------------------------------------------
/public/fonts/static/RobotoMono-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/fonts/static/RobotoMono-Italic.ttf
--------------------------------------------------------------------------------
/public/fonts/static/RobotoMono-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/fonts/static/RobotoMono-Light.ttf
--------------------------------------------------------------------------------
/public/fonts/static/RobotoMono-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/fonts/static/RobotoMono-Medium.ttf
--------------------------------------------------------------------------------
/public/fonts/static/RobotoMono-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/fonts/static/RobotoMono-Thin.ttf
--------------------------------------------------------------------------------
/public/fonts/static/RobotoMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/fonts/static/RobotoMono-Regular.ttf
--------------------------------------------------------------------------------
/public/fonts/static/RobotoMono-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/fonts/static/RobotoMono-SemiBold.ttf
--------------------------------------------------------------------------------
/circuits/hash/input.json:
--------------------------------------------------------------------------------
1 | {"preimage": "29047", "key": "863137912040348132018052427834338243447822049650932826602125816581803776895", "salt": "0"}
2 |
--------------------------------------------------------------------------------
/public/fonts/RobotoMono-VariableFont_wght.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/fonts/RobotoMono-VariableFont_wght.ttf
--------------------------------------------------------------------------------
/public/fonts/static/RobotoMono-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/fonts/static/RobotoMono-BoldItalic.ttf
--------------------------------------------------------------------------------
/public/fonts/static/RobotoMono-ExtraLight.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/fonts/static/RobotoMono-ExtraLight.ttf
--------------------------------------------------------------------------------
/public/fonts/static/RobotoMono-LightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/fonts/static/RobotoMono-LightItalic.ttf
--------------------------------------------------------------------------------
/public/fonts/static/RobotoMono-ThinItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/fonts/static/RobotoMono-ThinItalic.ttf
--------------------------------------------------------------------------------
/public/fonts/static/RobotoMono-MediumItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/fonts/static/RobotoMono-MediumItalic.ttf
--------------------------------------------------------------------------------
/artifacts/contracts/Core.sol/Core.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/public/fonts/static/RobotoMono-ExtraLightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/fonts/static/RobotoMono-ExtraLightItalic.ttf
--------------------------------------------------------------------------------
/public/fonts/static/RobotoMono-SemiBoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/fonts/static/RobotoMono-SemiBoldItalic.ttf
--------------------------------------------------------------------------------
/artifacts/contracts/Getters.sol/ICore.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/public/fonts/RobotoMono-Italic-VariableFont_wght.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nulven/EthDataMarketplace/HEAD/public/fonts/RobotoMono-Italic-VariableFont_wght.ttf
--------------------------------------------------------------------------------
/artifacts/contracts/Core.sol/DarkForestCore.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/contracts/Core.sol/IFactRegistry.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/contracts/Getters.sol/Getters.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/contracts/Pairing.sol/Pairing.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/contracts/Verifier.sol/Verifier.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/contracts/DarkForestCore.sol/DarkForestCore.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../build-info/5e4333c8bbbb21d862c2d525f394e5b8.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/contracts/ContractStorage.sol/ContractStorage.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/contracts/DarkForestUtils.sol/DarkForestUtils.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../build-info/5e4333c8bbbb21d862c2d525f394e5b8.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/access/Ownable.sol/Ownable.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/utils/Address.sol/Address.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/utils/Context.sol/Context.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/utils/Counters.sol/Counters.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/utils/Strings.sol/Strings.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/token/ERC721/ERC721.sol/ERC721.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../../../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/token/ERC721/IERC721.sol/IERC721.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../../../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/utils/introspection/ERC165.sol/ERC165.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../../../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/utils/introspection/IERC165.sol/IERC165.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../../../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/proxy/utils/Initializable.sol/Initializable.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../../../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/utils/structs/EnumerableSet.sol/EnumerableSet.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../../../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol/IERC721Receiver.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../../../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | verbose: false,
3 | silent: false,
4 | transform: {
5 | '^.+\\.(js|jsx)$': 'babel-jest',
6 | },
7 | roots: ['test/'],
8 | testTimeout: 100000000,
9 | };
10 |
--------------------------------------------------------------------------------
/cairo/hash/input.json:
--------------------------------------------------------------------------------
1 | {"preimage": 6841721, "key": 310189428346541121036033531041731175623531917337868002290492097685460605462, "hash": 1842142978386328626522018142232649629105807214573323389063844912639141478400, "salt": 0}
2 |
--------------------------------------------------------------------------------
/circuits/dark-forest/input.json:
--------------------------------------------------------------------------------
1 | {"x":"1","y":"1","key":"19130618009890855922213564313454862638312549259625450262135402362633118556279","hash":"1829932551766186818808046918715427926359016229497829135073351261774593201598","salt":"100"}
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import 'regenerator-runtime/runtime';
4 |
5 | import App from './app/App';
6 |
7 | ReactDOM.render(, document.getElementById('root'));
8 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol/ERC721URIStorage.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../../../../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol/IERC721Metadata.dbg.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-dbg-1",
3 | "buildInfo": "../../../../../../build-info/4d92d0003d1c0ee40921df925193f59a.json"
4 | }
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .env
2 | node_modules
3 | dist
4 |
5 | cache
6 | deployments/localhost
7 | typechain
8 | compiledCircuits
9 | public/circuits
10 | public/contracts
11 | circuits/pots
12 | circuits/**/public.json
13 | config/config.json
14 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | beacon=69420753206121746f776e206f652deadbeef69420
2 |
3 | NODE_ENV='production'
4 | DARK_FOREST_CHECK=true
5 | NETWORK='ethereum'
6 | ETH_NETWORK='goerli'
7 | INFURA_ID=
8 | PRIVATE_KEY=
9 |
10 | STARKWARE_APP=
11 | IPFS_HOST=
12 |
--------------------------------------------------------------------------------
/circuits/blur-image/input.json:
--------------------------------------------------------------------------------
1 | {"preimage":["1","0","1","0","1","1","0","1","0","1","1","0","1","0","1","0"],"key":"2359184173113251141614141781742266818757016097618414078533744063756205446350","blurred_image":["1","1","0","1","1","1","1","0","0","1","0","0","0","0","0","0"]}
2 |
--------------------------------------------------------------------------------
/public/contracts/prod/IFactRegistry.json:
--------------------------------------------------------------------------------
1 | {"abi":[{"inputs":[{"internalType":"bytes32","name":"fact","type":"bytes32"}],"name":"isValid","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}],"address":"0x1cE427292A0dA0313137A63Bb0f11423Bdb001A1"}
--------------------------------------------------------------------------------
/src/utils/utils.ts:
--------------------------------------------------------------------------------
1 | import { eddsa } from 'circomlib';
2 | const { prv2pub } = eddsa;
3 |
4 |
5 | export function generateKey() {
6 | const privateKey = Math.floor(Math.random()*1000000);
7 | const publicKey = prv2pub(privateKey.toString());
8 | return { publicKey: publicKey, privateKey };
9 | }
10 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/utils/Context.sol/Context.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-artifact-1",
3 | "contractName": "Context",
4 | "sourceName": "@openzeppelin/contracts/utils/Context.sol",
5 | "abi": [],
6 | "bytecode": "0x",
7 | "deployedBytecode": "0x",
8 | "linkReferences": {},
9 | "deployedLinkReferences": {}
10 | }
11 |
--------------------------------------------------------------------------------
/circuits/hash/public.json:
--------------------------------------------------------------------------------
1 | [
2 | "6331698529128173312328724742553669832712458337385102597780718268796728386482",
3 | "15854378775706544503278420080651022665425062488776096820298013246903470039624",
4 | "3705634327351415498095981027258195433370633503803501871539062401300116082061",
5 | "15854378775706544503278420080651022665425062488776096820298013246903470039624",
6 | "0"
7 | ]
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/proxy/utils/Initializable.sol/Initializable.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-artifact-1",
3 | "contractName": "Initializable",
4 | "sourceName": "@openzeppelin/contracts/proxy/utils/Initializable.sol",
5 | "abi": [],
6 | "bytecode": "0x",
7 | "deployedBytecode": "0x",
8 | "linkReferences": {},
9 | "deployedLinkReferences": {}
10 | }
11 |
--------------------------------------------------------------------------------
/public/icons8-delete.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/circuits/encryption/input.json:
--------------------------------------------------------------------------------
1 | {
2 | "seller_private_key":"6050663213771722621313293647329553549388461959418068286695329582459496967523",
3 | "key":"8729111262329839830241629585398569384244836146053820612763916981345632638716",
4 | "buyer_public_key":["16980282661484878115671214823287432953665344253059199523584632944160508460651","6266136043108930971487815715909907304874922097403409717197353895245287358351"]}
5 |
--------------------------------------------------------------------------------
/src/app/OurThemeProvider.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { selfTheme } from '../styles/theme';
3 | import { ThemeProvider } from 'styled-components';
4 |
5 | type Props = {
6 | theme?: Object,
7 | children?: any,
8 | };
9 |
10 | const OurThemeProvider = ({ theme = selfTheme, children }: Props) => (
11 | {children}
12 | );
13 |
14 | export default OurThemeProvider;
15 |
--------------------------------------------------------------------------------
/circuits/encryption/public.json:
--------------------------------------------------------------------------------
1 | [
2 | "12231577831664109427884491305237465844870033304822640483867883774744043015449",
3 | "12231577831664109427884491305237465844870033304822640483867883774744043015449",
4 | "2157403240208156454308356452700593366942236299976858890111358881414927320818",
5 | "16980282661484878115671214823287432953665344253059199523584632944160508460651",
6 | "6266136043108930971487815715909907304874922097403409717197353895245287358351"
7 | ]
--------------------------------------------------------------------------------
/scripts/cairoCompile.js:
--------------------------------------------------------------------------------
1 | const { execSync } = require('child_process');
2 |
3 | const circuitName = process.argv[2];
4 |
5 |
6 | execSync(`cairo-compile ./cairo/${circuitName}/circuit.cairo --output ./cairo/${circuitName}/output.json`, {
7 | stdio: 'inherit',
8 | });
9 | execSync(`cairo-run \ --program=./cairo/${circuitName}/output.json --print_output \ --layout=all --program_input=./cairo/${circuitName}/input.json`, {
10 | stdio: 'inherit',
11 | });
12 |
--------------------------------------------------------------------------------
/public/dev/EncryptionVerifier.json:
--------------------------------------------------------------------------------
1 | {"abi":[{"inputs":[{"internalType":"uint256[2]","name":"a","type":"uint256[2]"},{"internalType":"uint256[2][2]","name":"b","type":"uint256[2][2]"},{"internalType":"uint256[2]","name":"c","type":"uint256[2]"},{"internalType":"uint256[5]","name":"input","type":"uint256[5]"}],"name":"verifyProof","outputs":[{"internalType":"bool","name":"r","type":"bool"}],"stateMutability":"view","type":"function"}],"address":"0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690"}
--------------------------------------------------------------------------------
/cairo/encryption/input.json:
--------------------------------------------------------------------------------
1 | {
2 | "key":188190603173226452571209614695,
3 | "private_key": 452315666663287642995187579731270268772761801114665528803054973637467813437,
4 | "hash": 961326435832323455569339044438442358059148004349324307818006513300038135549,
5 | "public_key":[
6 | 2349423674861681350081252861006308915679459427386583835881580551903189209824,
7 | 600605024227393229893796219070733899582636276087691818644927186376150058074
8 | ]
9 | }
10 |
--------------------------------------------------------------------------------
/public/contracts/prod/EncryptionVerifier.json:
--------------------------------------------------------------------------------
1 | {"abi":[{"inputs":[{"internalType":"uint256[2]","name":"a","type":"uint256[2]"},{"internalType":"uint256[2][2]","name":"b","type":"uint256[2][2]"},{"internalType":"uint256[2]","name":"c","type":"uint256[2]"},{"internalType":"uint256[5]","name":"input","type":"uint256[5]"}],"name":"verifyProof","outputs":[{"internalType":"bool","name":"r","type":"bool"}],"stateMutability":"view","type":"function"}],"address":"0xC18ce1889e9f68d4eb77a1aCDC6ed9b2b3B4e726"}
--------------------------------------------------------------------------------
/public/keys.json:
--------------------------------------------------------------------------------
1 | {"key1": {"priv_key": 2621838962916445197872527623277104754506935728346448963222041947773872800877, "pub_key": [1189160554838062097962858633664725757945894819485155525299130256407169751231, 142963258474582096651275112205309753001937346823816204038395665243523575827]}, "key2": {"priv_key": 2973705177717982310042568628434942162446394144671186307436975577552595979581, "pub_key": [966946800390168890985276145999481310047700216190650127572317484086078517193, 1980286241577643615848147569966616802818827878816275753535351630041743387241]}}
--------------------------------------------------------------------------------
/circuits/test/encryption.test.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const { Keypair } = require('maci-domainobjs');
3 |
4 | const key1 = new Keypair();
5 | const key2 = new Keypair();
6 | const sharedKey = Keypair.genEcdhSharedKey(key1.privKey, key2.pubKey);
7 |
8 | const input = {
9 | seller_private_key: key1.privKey.asCircuitInputs(),
10 | key: sharedKey.toString(),
11 | buyer_public_key: key2.pubKey.asCircuitInputs(),
12 | };
13 |
14 | fs.writeFile(
15 | './circuits/encryption/input.json',
16 | JSON.stringify(input),
17 | () => {},
18 | );
19 |
--------------------------------------------------------------------------------
/contracts/DarkForestUtils.sol:
--------------------------------------------------------------------------------
1 | library DarkForestUtils {
2 | struct Planet {
3 | address owner;
4 | bool isHomePlanet;
5 | }
6 |
7 | struct SnarkConstants {
8 | uint256 PLANETHASH_KEY;
9 | }
10 |
11 | struct GameStorage {
12 | mapping(uint256 => Planet) planets;
13 | SnarkConstants snarkConstants;
14 | }
15 |
16 | function getGameStorage() public pure returns (GameStorage storage ret) {
17 | bytes32 position = bytes32(uint256(1));
18 | assembly {
19 | ret.slot := position
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/app/PropertyToggle.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Toggle from '../components/Toggle';
4 | import { ContentProperties } from '../types';
5 |
6 | type PropertyToggleProps = {
7 | property: string;
8 | setProperty: (value: ContentProperties) => void;
9 | };
10 |
11 | const PropertyToggle = (props: PropertyToggleProps) => {
12 |
13 | return (
14 |
19 | );
20 | };
21 |
22 | export default PropertyToggle;
23 |
--------------------------------------------------------------------------------
/artifacts/contracts/Pairing.sol/Pairing.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-artifact-1",
3 | "contractName": "Pairing",
4 | "sourceName": "contracts/Pairing.sol",
5 | "abi": [],
6 | "bytecode": "0x602d6037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea164736f6c6343000803000a",
7 | "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea164736f6c6343000803000a",
8 | "linkReferences": {},
9 | "deployedLinkReferences": {}
10 | }
11 |
--------------------------------------------------------------------------------
/src/components/Button.tsx:
--------------------------------------------------------------------------------
1 | import styled from 'styled-components';
2 |
3 | export const Button = styled.button`
4 | font-family: ${props => props.theme.fontFamily};
5 | height: 40px;
6 | display: flex;
7 | justify-content: center;
8 | align-items: center;
9 | padding: 0;
10 | border-radius: 5px;
11 | border-width: 1px;
12 | border-style: solid;
13 | font-variation-settings: 'wght' 500;
14 | cursor: pointer;
15 | background-color: ${props => props.theme.color.primary};
16 | :hover {
17 | background-color: ${props => props.theme.color.secondary};
18 | }
19 | `;
20 |
--------------------------------------------------------------------------------
/circuits/test/df.test.js:
--------------------------------------------------------------------------------
1 | const { mimcsponge } = require('circomlib');
2 | const fs = require('fs');
3 | const { Keypair } = require('maci-domainobjs');
4 |
5 | const x = '1';
6 | const y = '1';
7 |
8 | const key1 = new Keypair();
9 | const key2 = new Keypair();
10 |
11 | const sharedKey = Keypair.genEcdhSharedKey(key1.privKey, key2.pubKey);
12 | const hash = mimcsponge.multiHash([x, y], BigInt(100), 1);
13 |
14 | const input = {
15 | x,
16 | y,
17 | key: sharedKey.toString(),
18 | hash: hash.toString(),
19 | salt: '100',
20 | };
21 |
22 | fs.writeFile('./circuits/df/input.json', JSON.stringify(input), () => {});
23 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/utils/Address.sol/Address.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-artifact-1",
3 | "contractName": "Address",
4 | "sourceName": "@openzeppelin/contracts/utils/Address.sol",
5 | "abi": [],
6 | "bytecode": "0x602d6037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea164736f6c6343000803000a",
7 | "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea164736f6c6343000803000a",
8 | "linkReferences": {},
9 | "deployedLinkReferences": {}
10 | }
11 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/utils/Counters.sol/Counters.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-artifact-1",
3 | "contractName": "Counters",
4 | "sourceName": "@openzeppelin/contracts/utils/Counters.sol",
5 | "abi": [],
6 | "bytecode": "0x602d6037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea164736f6c6343000803000a",
7 | "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea164736f6c6343000803000a",
8 | "linkReferences": {},
9 | "deployedLinkReferences": {}
10 | }
11 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/utils/Strings.sol/Strings.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-artifact-1",
3 | "contractName": "Strings",
4 | "sourceName": "@openzeppelin/contracts/utils/Strings.sol",
5 | "abi": [],
6 | "bytecode": "0x602d6037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea164736f6c6343000803000a",
7 | "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea164736f6c6343000803000a",
8 | "linkReferences": {},
9 | "deployedLinkReferences": {}
10 | }
11 |
--------------------------------------------------------------------------------
/config/config.js:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 | const env = process.env.NODE_ENV;
3 |
4 | const defaultConfig = {
5 | enableDarkForestCheck: process.env.DARK_FOREST_CHECK === 'true',
6 | ipfsHost: process.env.IPFS_HOST,
7 | chain: process.env.NETWORK,
8 | starkwareApp: process.env.STARKWARE_APP,
9 | infuraId: process.env.INFURA_ID,
10 | };
11 |
12 | const config = {
13 | development: {
14 | env: 'development',
15 | ...defaultConfig,
16 | },
17 | production: {
18 | env: 'production',
19 | ...defaultConfig,
20 | },
21 | };
22 | const export_config = config[env];
23 |
24 | module.exports = export_config;
25 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/utils/structs/EnumerableSet.sol/EnumerableSet.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-artifact-1",
3 | "contractName": "EnumerableSet",
4 | "sourceName": "@openzeppelin/contracts/utils/structs/EnumerableSet.sol",
5 | "abi": [],
6 | "bytecode": "0x602d6037600b82828239805160001a607314602a57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600080fdfea164736f6c6343000803000a",
7 | "deployedBytecode": "0x73000000000000000000000000000000000000000030146080604052600080fdfea164736f6c6343000803000a",
8 | "linkReferences": {},
9 | "deployedLinkReferences": {}
10 | }
11 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "jsx": "react",
4 | "outDir": "./dist/",
5 | "esModuleInterop": true,
6 | "module": "commonjs",
7 | "target": "es6",
8 | "allowJs": true,
9 | "skipLibCheck": true,
10 | "allowSyntheticDefaultImports": true,
11 | "sourceMap": true,
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "noEmit": false,
15 | "noImplicitThis": false,
16 | "types": ["node"]
17 | },
18 | "include": [
19 | "*.ts",
20 | "**/*.ts"
21 | ],
22 | "exclude": [
23 | "node_modules"
24 | ],
25 | "plugins": [
26 | {
27 | "transform": "@zerollup/ts-transform-paths"
28 | }
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/artifacts/contracts/Core.sol/IFactRegistry.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-artifact-1",
3 | "contractName": "IFactRegistry",
4 | "sourceName": "contracts/Core.sol",
5 | "abi": [
6 | {
7 | "inputs": [
8 | {
9 | "internalType": "bytes32",
10 | "name": "fact",
11 | "type": "bytes32"
12 | }
13 | ],
14 | "name": "isValid",
15 | "outputs": [
16 | {
17 | "internalType": "bool",
18 | "name": "",
19 | "type": "bool"
20 | }
21 | ],
22 | "stateMutability": "view",
23 | "type": "function"
24 | }
25 | ],
26 | "bytecode": "0x",
27 | "deployedBytecode": "0x",
28 | "linkReferences": {},
29 | "deployedLinkReferences": {}
30 | }
31 |
--------------------------------------------------------------------------------
/circuits/utils/ecdh.circom:
--------------------------------------------------------------------------------
1 | include "../../node_modules/circomlib/circuits/bitify.circom";
2 | include "../../node_modules/circomlib/circuits/escalarmulany.circom";
3 |
4 |
5 | template Ecdh() {
6 | // Note: private key
7 | // Needs to be hashed, and then pruned before
8 | // supplying it to the circuit
9 | signal private input private_key;
10 | signal input public_key[2];
11 |
12 | signal output shared_key;
13 |
14 | var n = 253
15 |
16 | component privBits = Num2Bits(n);
17 | privBits.in <== private_key;
18 |
19 | component mulFix = EscalarMulAny(n);
20 | mulFix.p[0] <== public_key[0];
21 | mulFix.p[1] <== public_key[1];
22 |
23 | for (var i = 0; i < n; i++) {
24 | mulFix.e[i] <== privBits.out[i];
25 | }
26 |
27 | shared_key <== mulFix.out[0];
28 | }
29 |
--------------------------------------------------------------------------------
/artifacts/contracts/DarkForestUtils.sol/DarkForestUtils.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-artifact-1",
3 | "contractName": "DarkForestUtils",
4 | "sourceName": "contracts/DarkForestUtils.sol",
5 | "abi": [],
6 | "bytecode": "0x6059610038600b82828239805160001a607314602b57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe730000000000000000000000000000000000000000301460806040526004361060335760003560e01c8063630cf433146038575b600080fd5b600160405190815260200160405180910390f3fea164736f6c6343000803000a",
7 | "deployedBytecode": "0x730000000000000000000000000000000000000000301460806040526004361060335760003560e01c8063630cf433146038575b600080fd5b600160405190815260200160405180910390f3fea164736f6c6343000803000a",
8 | "linkReferences": {},
9 | "deployedLinkReferences": {}
10 | }
11 |
--------------------------------------------------------------------------------
/.github/workflows/config.yml:
--------------------------------------------------------------------------------
1 | name: Build webpack
2 | on: [push]
3 |
4 | jobs:
5 | build:
6 | runs-on: ubuntu-latest
7 | steps:
8 | - uses: actions/checkout@v2
9 | - uses: actions/setup-node@v1
10 | - run: echo NODE_ENV=production >> .env
11 | - run: echo ETH_NETWORK='goerli' >> .env
12 | - run: echo NETWORK='ethereum' >> .env
13 | - run: echo STARKWARE_APP='https://fossairdrop.com' >> .env
14 | - run: echo IPFS_HOST='fossairdrop.com' >> .env
15 | - run: echo INFURA_ID=secrets.INFURA_ID >> .env
16 | - run: npm install
17 | - run: npm run build
18 | - run: echo privatenfts.xyz >> ./dist/CNAME
19 | - uses: peaceiris/actions-gh-pages@v3
20 | with:
21 | deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
22 | publish_dir: ./dist
23 |
--------------------------------------------------------------------------------
/scripts/cairoDeploy.js:
--------------------------------------------------------------------------------
1 | const { execSync, exec } = require('child_process');
2 | const fs = require('fs');
3 | const path = require('path');
4 |
5 | const contractName = process.argv[2];
6 |
7 | const cwd = process.cwd();
8 | const directory = path.resolve(`${cwd}/cairo/contracts`);
9 |
10 | execSync(`starknet-compile ./cairo/contracts/${contractName}.cairo \ --output ./cairo/contracts/${contractName}.json \ --abi ./cairo/contracts/${contractName}_abi.json`, {
11 | stdio: 'inherit',
12 | });
13 | exec(`starknet deploy --contract ./cairo/contracts/${contractName}.json`, (error, stdout, stderr) => {
14 | if (error) {
15 | console.log(error);
16 | }
17 | const address = stdout.match('(?<=Contract address: ).*')[0];
18 | fs.writeFileSync(`${directory}/${contractName}_address.json`, JSON.stringify({ address }));
19 | });
20 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/utils/introspection/ERC165.sol/ERC165.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-artifact-1",
3 | "contractName": "ERC165",
4 | "sourceName": "@openzeppelin/contracts/utils/introspection/ERC165.sol",
5 | "abi": [
6 | {
7 | "inputs": [
8 | {
9 | "internalType": "bytes4",
10 | "name": "interfaceId",
11 | "type": "bytes4"
12 | }
13 | ],
14 | "name": "supportsInterface",
15 | "outputs": [
16 | {
17 | "internalType": "bool",
18 | "name": "",
19 | "type": "bool"
20 | }
21 | ],
22 | "stateMutability": "view",
23 | "type": "function"
24 | }
25 | ],
26 | "bytecode": "0x",
27 | "deployedBytecode": "0x",
28 | "linkReferences": {},
29 | "deployedLinkReferences": {}
30 | }
31 |
--------------------------------------------------------------------------------
/src/components/Spinner.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components';
3 | import Loader from 'react-loader-spinner';
4 | import { Large } from '../components/text';
5 |
6 |
7 | const SpinnerWrapper = styled.div`
8 | display: flex;
9 | width: 40%;
10 | flex: 1;
11 | margin-left: 30%;
12 | margin-right: 30%;
13 | margin-top: 20%;
14 | flex-direction: column;
15 | align-items: center;
16 | `;
17 |
18 | type SpinnerProps = {
19 | loadingMessage: string;
20 | }
21 |
22 | const Title = styled(Large)`
23 | margin-top: 30px;
24 | `;
25 |
26 | const Spinner = (props: SpinnerProps) => {
27 | return (
28 |
29 |
30 | {props.loadingMessage}
31 |
32 | );
33 | };
34 |
35 |
36 | export default Spinner;
37 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/utils/introspection/IERC165.sol/IERC165.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-artifact-1",
3 | "contractName": "IERC165",
4 | "sourceName": "@openzeppelin/contracts/utils/introspection/IERC165.sol",
5 | "abi": [
6 | {
7 | "inputs": [
8 | {
9 | "internalType": "bytes4",
10 | "name": "interfaceId",
11 | "type": "bytes4"
12 | }
13 | ],
14 | "name": "supportsInterface",
15 | "outputs": [
16 | {
17 | "internalType": "bool",
18 | "name": "",
19 | "type": "bool"
20 | }
21 | ],
22 | "stateMutability": "view",
23 | "type": "function"
24 | }
25 | ],
26 | "bytecode": "0x",
27 | "deployedBytecode": "0x",
28 | "linkReferences": {},
29 | "deployedLinkReferences": {}
30 | }
31 |
--------------------------------------------------------------------------------
/crypto/test.js:
--------------------------------------------------------------------------------
1 | const BN = require('bn.js');
2 | const hash = require('hash.js');
3 | const { curves: eCurves, ec: EllipticCurve } = require('elliptic');
4 | const assert = require('assert');
5 | const { constantPoints, pedersen } = require('./signature.js');
6 |
7 | const LOW_PART_BITS = 248
8 | const LOW_PART_MASK = 2**248-1
9 | const N_ELEMENT_BIT_HASH = 250;
10 | function processSingleElement(element, p1, p2) {
11 | const highNibble = element >> LOW_PART_BITS;
12 | console.log(p1);
13 | const lowPart = element & LOW_PART_MASK;
14 | return lowPart * p1 + highNibble * p2;
15 | }
16 |
17 | const shiftPoint = constantPoints[0];
18 | const P_0 = constantPoints[2]
19 | const P_1 = constantPoints[2 + LOW_PART_BITS]
20 | const P_2 = constantPoints[2 + N_ELEMENT_BIT_HASH]
21 | const P_3 = constantPoints[2 + N_ELEMENT_BIT_HASH + LOW_PART_BITS]
22 |
23 | console.log(BigInt(`0x${pedersen([BigInt(1), BigInt(2)])}`));
24 |
--------------------------------------------------------------------------------
/public/contracts/prod/DarkForestCore.json:
--------------------------------------------------------------------------------
1 | {"abi":[{"inputs":[{"internalType":"uint256","name":"key","type":"uint256"}],"name":"planets","outputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"isHomePlanet","type":"bool"}],"internalType":"struct DarkForestCore.Planet","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"s","outputs":[{"components":[{"internalType":"uint256","name":"PLANETHASH_KEY","type":"uint256"}],"internalType":"struct DarkForestCore.SnarkConstants","name":"snarkConstants","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"snarkConstants","outputs":[{"components":[{"internalType":"uint256","name":"PLANETHASH_KEY","type":"uint256"}],"internalType":"struct DarkForestCore.SnarkConstants","name":"","type":"tuple"}],"stateMutability":"view","type":"function"}],"address":"0x201BECFfca76f54E3366EF7589FB6008E3F3B281"}
--------------------------------------------------------------------------------
/src/types/content.ts:
--------------------------------------------------------------------------------
1 | import { Snark, Stark, ZKTypes } from '../types';
2 |
3 | interface InputProps {
4 | preimage: string;
5 | setPreimage: (value: string) => void;
6 | }
7 |
8 | interface DisplayProps {
9 | property: any;
10 | message?: any;
11 | }
12 |
13 | interface ContentSkeleton {
14 | display: (props: DisplayProps) => JSX.Element;
15 | input: (props: InputProps) => JSX.Element;
16 | list: (props: DisplayProps) => JSX.Element;
17 | decrypt: (zk: ZKTypes, ciphertext: any, key: BigInt) => any;
18 | computeProperty: (preimage: any, key?: BigInt) => any[];
19 | prover: Record Promise>;
20 | verifier: Record Promise>;
21 | assertProofInputs: (args: any[]) => void;
22 | assertContent: (content: any) => void;
23 | assertMessage: (message: any) => void;
24 | }
25 |
26 | export {
27 | InputProps,
28 | ContentSkeleton,
29 | };
30 |
--------------------------------------------------------------------------------
/circuits/test/blurredImage.test.js:
--------------------------------------------------------------------------------
1 | function dec2bin(dec) {
2 | return dec.toString(2);
3 | }
4 |
5 | function blurImage(preImage, key) {
6 | const keyBits = dec2bin(key);
7 | const blurredImage = preImage.map((bit, index) => {
8 | return bit^keyBits[keyBits.length-1-index];
9 | });
10 | return blurredImage;
11 | }
12 |
13 | const fs = require('fs');
14 | const { Keypair } = require('maci-domainobjs');
15 |
16 | const preimage = [1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0];
17 |
18 | const key1 = new Keypair();
19 | const key2 = new Keypair();
20 |
21 | const sharedKey = Keypair.genEcdhSharedKey(key1.privKey, key2.pubKey);
22 |
23 | const input = {
24 | preimage: preimage.map(_ => _.toString()),
25 | key: sharedKey.toString(),
26 | blurred_image: blurImage(preimage, sharedKey).map(_ => _.toString()),
27 | };
28 |
29 | fs.writeFile(
30 | './circuits/blur-image/input.json',
31 | JSON.stringify(input),
32 | () => {},
33 | );
34 |
--------------------------------------------------------------------------------
/circuits/blur-image/circuit.circom:
--------------------------------------------------------------------------------
1 | include "../../node_modules/circomlib/circuits/bitify.circom"
2 | include "../../node_modules/circomlib/circuits/mimc.circom"
3 |
4 | template Main() {
5 | var N = 16;
6 | signal private input preimage[N];
7 | signal private input key;
8 | signal input blurred_image[N];
9 | signal output hash;
10 | signal output computed_image[N];
11 |
12 | // hash of key
13 | component mimc = MultiMiMC7(1, 91);
14 | mimc.in[0] <== key;
15 | mimc.k <== 0;
16 | hash <== mimc.out;
17 |
18 | // proof of property & encryption of message (blur)
19 | component num2bits = Num2Bits(256);
20 | num2bits.in <== key;
21 | signal key_bits[N];
22 | for (var i=0; i (hash: felt):
11 | let (hash) = hash2{hash_ptr=pedersen_ptr}(x, y)
12 | return (hash)
13 | end
14 |
15 | func Encrypt{pedersen_ptr: HashBuiltin*}(plaintext: felt, shared_key: felt) -> (out: Ciphertext):
16 | let (hash1) = get_hash_pedersen(plaintext, 0)
17 |
18 | let (hash2) = get_hash_pedersen(shared_key, hash1)
19 |
20 | let b = plaintext + hash2
21 | let out = Ciphertext(a=hash1, b=b)
22 | return (out)
23 | end
24 |
25 | func Decrypt{pedersen_ptr: HashBuiltin*}(ciphertext: Ciphertext, shared_key: felt) -> (out: felt):
26 | let (hash) = get_hash_pedersen(shared_key, ciphertext.a)
27 | let out = ciphertext.b - hash
28 | return (out)
29 | end
30 |
--------------------------------------------------------------------------------
/contracts/DarkForestCore.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >=0.7.6;
2 | pragma experimental ABIEncoderV2;
3 |
4 | import "./DarkForestUtils.sol";
5 |
6 | contract DarkForestCore {
7 | DarkForestUtils.GameStorage public s;
8 |
9 | constructor() public {
10 | DarkForestUtils.Planet memory planet = DarkForestUtils.Planet({
11 | owner: msg.sender,
12 | isHomePlanet: true
13 | });
14 |
15 | uint256 location = 5228530872000388647816463285860870411975878209802611613611963004792914824074;
16 | s.planets[location] = planet;
17 |
18 | s.snarkConstants = DarkForestUtils.SnarkConstants({
19 | PLANETHASH_KEY: 2149252641268674884343858554091843927095993520400352350070838229268101760471
20 | });
21 | }
22 |
23 | function planets(uint256 key) public view returns (DarkForestUtils.Planet memory) {
24 | return s.planets[key];
25 | }
26 |
27 | function snarkConstants() public view returns (DarkForestUtils.SnarkConstants memory) {
28 | return s.snarkConstants;
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/crypto/test.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | from starkware.crypto.signature.math_utils import ec_add, ec_mult
4 | from starkware.crypto.signature.signature import get_random_private_key, private_key_to_ec_point_on_stark_curve, FIELD_PRIME
5 | from starkware.crypto.signature.fast_pedersen_hash import pedersen_hash
6 |
7 |
8 | def genKeypair():
9 | priv_key = get_random_private_key()
10 | public_key = private_key_to_ec_point_on_stark_curve(priv_key)
11 |
12 | keypair = { 'priv_key': priv_key, 'pub_key': public_key }
13 | return keypair
14 |
15 | def gen_shared_key(priv_key, pub_key):
16 | return ec_mult(priv_key, pub_key, 1, FIELD_PRIME)[0]
17 |
18 |
19 | def gen_keys():
20 | key_pair1 = genKeypair()
21 | key_pair2 = genKeypair()
22 | data = { 'key1': key_pair1, 'key2': key_pair2 }
23 | with open('./public/keys.json', 'w') as f:
24 | json.dump(data, f)
25 |
26 |
27 | print(private_key_to_ec_point_on_stark_curve(1463287801087371787425637237490104066531018057258318019831177542025430958080))
28 |
--------------------------------------------------------------------------------
/circuits/hash/circuit.circom:
--------------------------------------------------------------------------------
1 | include "../../node_modules/circomlib/circuits/mimcsponge.circom"
2 | include "../../node_modules/circomlib/circuits/bitify.circom"
3 |
4 | include "../utils/encrypt.circom";
5 | include "../utils/ecdh.circom";
6 |
7 | template Main() {
8 | signal private input preimage;
9 | signal private input key;
10 | signal input salt;
11 | signal output key_hash;
12 | signal output ciphertext[2];
13 | signal output hash;
14 |
15 | // hash of key
16 | component mimcKey = MultiMiMC7(1, 91);
17 | mimcKey.in[0] <== key;
18 | mimcKey.k <== 0;
19 | key_hash <== mimcKey.out;
20 |
21 | // proof of property (hash)
22 | component mimc = MultiMiMC7(1, 91);
23 | mimc.in[0] <== preimage;
24 | mimc.k <== salt;
25 | mimc.out ==> hash;
26 |
27 | // encryption of message
28 | component encrypt = Encrypt();
29 | encrypt.plaintext <== preimage;
30 | encrypt.shared_key <== key;
31 | ciphertext[0] <== encrypt.out[0];
32 | ciphertext[1] <== encrypt.out[1];
33 | }
34 |
35 | component main = Main();
36 |
--------------------------------------------------------------------------------
/circuits/test/hash.test.js:
--------------------------------------------------------------------------------
1 | function stringToBits(string) {
2 | const buff = Buffer.from(string);
3 | let bitString = '';
4 | buff.forEach(integer => {
5 | const bits = integer.toString(2).padStart(8, '0');
6 | bitString += bits;
7 | });
8 | return bitString;
9 | }
10 |
11 | function stringToNum(string) {
12 | const bitString = stringToBits(string);
13 | const number = BigInt(parseInt(bitString, 2));
14 | return number;
15 | }
16 |
17 | const { mimc7 } = require('circomlib');
18 | const fs = require('fs');
19 | const { Keypair } = require('maci-domainobjs');
20 |
21 | const preimage = 'hello';
22 | const preimageNum = stringToNum(preimage);
23 |
24 | const key1 = new Keypair();
25 | const key2 = new Keypair();
26 |
27 | const sharedKey = Keypair.genEcdhSharedKey(key1.privKey, key2.pubKey);
28 | const hash = mimc7.multiHash([preimageNum], BigInt(100));
29 |
30 | const input = {
31 | preimage: preimageNum.toString(),
32 | key: sharedKey.toString(),
33 | hash: hash.toString(),
34 | salt: '100',
35 | };
36 |
37 | fs.writeFile('./circuits/hash/input.json', JSON.stringify(input), () => {});
38 |
--------------------------------------------------------------------------------
/circuits/dark-forest/circuit.circom:
--------------------------------------------------------------------------------
1 | include "../../node_modules/circomlib/circuits/mimcsponge.circom"
2 | include "../../node_modules/circomlib/circuits/bitify.circom"
3 |
4 | include "../utils/ecdh.circom";
5 | include "../utils/encrypt.circom";
6 |
7 | template Main() {
8 | signal private input x;
9 | signal private input y;
10 | signal private input key;
11 | signal input hash;
12 | signal input salt;
13 | signal output key_hash;
14 | signal output ciphertext[3];
15 |
16 | // hash of key
17 | component mimcKey = MultiMiMC7(1, 91);
18 | mimcKey.in[0] <== key;
19 | mimcKey.k <== 0;
20 | key_hash <== mimcKey.out;
21 |
22 | // proof of property (hash)
23 | component mimc = MiMCSponge(2, 220, 1);
24 | mimc.ins[0] <== x;
25 | mimc.ins[1] <== y;
26 | mimc.k <== salt;
27 | mimc.outs[0] === hash;
28 |
29 | // encryption of message
30 | component encrypt = EncryptBits(2);
31 | encrypt.plaintext[0] <== x;
32 | encrypt.plaintext[1] <== y;
33 | encrypt.shared_key <== key;
34 | ciphertext[0] <== encrypt.out[0];
35 | ciphertext[1] <== encrypt.out[1];
36 | ciphertext[2] <== encrypt.out[2];
37 |
38 | }
39 |
40 | component main = Main();
41 |
--------------------------------------------------------------------------------
/crypto/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "starkware_crypto",
3 | "version": "0.1.4",
4 | "description": "Signatures, keys and Pedersen hash on STARK friendly elliptic curve",
5 | "main": "signature.js",
6 | "scripts": {
7 | "test": "mocha",
8 | "lint": "eslint -f unix --ext=.js ./"
9 | },
10 | "keywords": [
11 | "stark",
12 | "signature",
13 | "EC",
14 | "Elliptic",
15 | "curve",
16 | "Cryptography"
17 | ],
18 | "files": [
19 | "signature.js",
20 | "test/signature_test.js",
21 | "signature_example.js",
22 | "constant_points.json",
23 | "keys_precomputed.json",
24 | "signature_test_data.json"
25 | ],
26 | "dependencies": {
27 | "elliptic": "git://github.com/indutny/elliptic.git#v6.5.0",
28 | "bn.js": "^4.4.0",
29 | "brorand": "^1.0.1",
30 | "hash.js": "^1.0.0",
31 | "hmac-drbg": "^1.0.0",
32 | "inherits": "^2.0.1",
33 | "minimalistic-assert": "^1.0.0",
34 | "minimalistic-crypto-utils": "^1.0.0"
35 | },
36 | "devDependencies": {
37 | "chai": "^4.2.0",
38 | "eslint": "^6.8.0",
39 | "mocha": "^7.1.0"
40 | },
41 | "author": "StarkWare Industries Ltd.",
42 | "license": "Apache-2.0"
43 | }
44 |
--------------------------------------------------------------------------------
/src/components/TextArea.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components';
3 |
4 | type Props = {
5 | id?: string,
6 | placeholder: string,
7 | handleEnter?: (string) => void,
8 | onChange: (value: string) => void,
9 | value: string,
10 | style?: object,
11 | };
12 |
13 | const TextAreaWrapper = styled.textarea`
14 | font-family: 'Roboto Variable';
15 | padding: 8px;
16 | height: 40px;
17 | width: calc(100% - 16px);
18 | display: flex;
19 | border-radius: 5px;
20 | border-width: 1px;
21 | border-style: solid;
22 | border-color: ${props => props.theme.color.primary};
23 | font-variation-settings: 'wght' 500;
24 | `;
25 |
26 | function TextArea (props: Props) {
27 | const detectEnter = (e: any) => {
28 | if (e.key === 'Enter' && props.handleEnter) {
29 | props.handleEnter(e.target.value);
30 | }
31 | };
32 |
33 | return (
34 | props.onChange(e.target.value)}
38 | onKeyPress={detectEnter}
39 | placeholder={props.placeholder}
40 | value={props.value}
41 | />
42 | );
43 | }
44 |
45 | export default TextArea;
46 |
--------------------------------------------------------------------------------
/cairo/contracts/ERC721URIStorage.cairo:
--------------------------------------------------------------------------------
1 | %lang starknet
2 |
3 | from starkware.starknet.common.storage import Storage
4 | from starkware.cairo.common.cairo_builtins import HashBuiltin
5 |
6 | @storage_var
7 | func _tokenURIs(token: felt) -> (uri: (felt, felt)):
8 | end
9 |
10 | func _setTokenURI{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}(token_id: felt, _token_uri1: felt, _token_uri2: felt):
11 | #require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
12 | let _token_uri: (felt, felt) = (_token_uri1, _token_uri2)
13 | _tokenURIs.write(token_id, _token_uri)
14 |
15 | return ()
16 | end
17 |
18 | func tokenURI{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}(token_id: felt) -> (uri: (felt, felt)):
19 | #require(_exists(tokenId), "ERC721URIStorage: URI query for nonexistent token");
20 |
21 | let (_tokenURI) = _tokenURIs.read(token_id)
22 | return (uri=_tokenURI)
23 | #let (base) = _baseURI()
24 |
25 | #if (bytes(base).length == 0):
26 | #return _tokenURI
27 | #end
28 |
29 | #if (bytes(_tokenURI).length > 0):
30 | #return string(abi.encodePacked(base, _tokenURI))
31 | #end
32 |
33 | #return tokenURI(token_id)
34 | end
35 |
--------------------------------------------------------------------------------
/src/app/Page.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import { Route } from 'react-router-dom';
3 |
4 | import NavigationBar from './NavigationBar';
5 | import OurThemeProvider from './OurThemeProvider';
6 | import { selfTheme } from '../styles/theme';
7 |
8 | interface Props {
9 | path: string;
10 | Subpage: any;
11 | navbar: boolean;
12 | signer: any;
13 | web3: any;
14 | }
15 |
16 | export default function Page(props: Props) {
17 | const { path, Subpage, navbar } = props;
18 |
19 | document.body.style.backgroundColor = selfTheme.color.light;
20 |
21 | useEffect(() => {
22 | if (document) {
23 | const title = 'Data Marketplace';
24 | document.title = title;
25 | }
26 | }, [path]);
27 |
28 | return (
29 | (
32 |
33 | {navbar ?
34 |
40 | : null}
41 |
42 |
43 | )}
44 | />
45 | );
46 | }
47 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol/IERC721Receiver.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-artifact-1",
3 | "contractName": "IERC721Receiver",
4 | "sourceName": "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol",
5 | "abi": [
6 | {
7 | "inputs": [
8 | {
9 | "internalType": "address",
10 | "name": "operator",
11 | "type": "address"
12 | },
13 | {
14 | "internalType": "address",
15 | "name": "from",
16 | "type": "address"
17 | },
18 | {
19 | "internalType": "uint256",
20 | "name": "tokenId",
21 | "type": "uint256"
22 | },
23 | {
24 | "internalType": "bytes",
25 | "name": "data",
26 | "type": "bytes"
27 | }
28 | ],
29 | "name": "onERC721Received",
30 | "outputs": [
31 | {
32 | "internalType": "bytes4",
33 | "name": "",
34 | "type": "bytes4"
35 | }
36 | ],
37 | "stateMutability": "nonpayable",
38 | "type": "function"
39 | }
40 | ],
41 | "bytecode": "0x",
42 | "deployedBytecode": "0x",
43 | "linkReferences": {},
44 | "deployedLinkReferences": {}
45 | }
46 |
--------------------------------------------------------------------------------
/circuits/encryption/circuit.circom:
--------------------------------------------------------------------------------
1 | include "../../node_modules/circomlib/circuits/mimcsponge.circom"
2 | include "../../node_modules/circomlib/circuits/bitify.circom"
3 |
4 | include "../utils/encrypt.circom";
5 | include "../utils/ecdh.circom";
6 |
7 | template Main() {
8 | signal private input key;
9 | signal private input seller_private_key;
10 | signal input buyer_public_key[2];
11 | signal output hash;
12 | signal output out[2];
13 |
14 | component mimc = MultiMiMC7(1, 91);
15 | mimc.in[0] <== key;
16 | mimc.k <== 0;
17 | mimc.out ==> hash;
18 |
19 | // encrypt preimage
20 | component ecdh = Ecdh();
21 |
22 | ecdh.private_key <== seller_private_key;
23 | ecdh.public_key[0] <== buyer_public_key[0];
24 | ecdh.public_key[1] <== buyer_public_key[1];
25 |
26 | signal shared_key;
27 | shared_key <== ecdh.shared_key;
28 |
29 | component encrypt = Encrypt();
30 | encrypt.plaintext <== key;
31 | encrypt.shared_key <== shared_key;
32 | out[0] <== encrypt.out[0];
33 | out[1] <== encrypt.out[1];
34 |
35 | /*
36 | component decrypt = Decrypt();
37 | decrypt.message[0] <== out[0];
38 | decrypt.message[1] <== out[1];
39 | decrypt.shared_key <== shared_key;
40 | signal output m;
41 | m <== decrypt.out;
42 | */
43 | }
44 |
45 | component main = Main();
46 |
--------------------------------------------------------------------------------
/src/components/Date.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components';
3 |
4 |
5 | const DateWrapper = styled.div`
6 | display: block;
7 | color: ${props => props.theme.color.grey50};
8 | `;
9 |
10 | type TimeBreakType = [number, string];
11 | type TimeBreaksType = TimeBreakType[];
12 | const TimeBreaks: TimeBreaksType = [
13 | [1*7*24*60*60*1000, '1 week ago'],
14 | [6*24*60*60*1000, '6 days ago'],
15 | [5*24*60*60*1000, '5 days ago'],
16 | [4*24*60*60*1000, '4 days ago'],
17 | [3*24*60*60*1000, '3 days ago'],
18 | [2*24*60*60*1000, '2 days ago'],
19 | [1*24*60*60*1000, '1 day ago'],
20 | [2*60*60*1000, '2 hours ago'],
21 | [1*60*60*1000, '1 hour ago'],
22 | [6*60*1000, '5 minutes ago'],
23 | [5*60*1000, '4 minutes ago'],
24 | [4*60*1000, '3 minutes ago'],
25 | [3*60*1000, '2 minutes ago'],
26 | [2*60*1000, '1 minutes ago'],
27 | [1*60*1000, 'seconds ago'],
28 | ]; // breaks in milliseconds
29 |
30 | type DateProps = {
31 | timestamp: Date;
32 | };
33 |
34 | const DateDiv = (props: DateProps) => {
35 |
36 | const now = new Date();
37 | const elapsedTime = now.getTime() - props.timestamp.getTime();
38 | var text = props.timestamp.toLocaleDateString();
39 | TimeBreaks.forEach(([diff, value]) => {
40 | if (elapsedTime < diff) {
41 | text = value;
42 | }
43 | });
44 |
45 | return (
46 | {text}
47 | );
48 | };
49 |
50 | export default DateDiv;
51 |
--------------------------------------------------------------------------------
/src/styles/theme.ts:
--------------------------------------------------------------------------------
1 | const unit = 8;
2 |
3 | const selfTheme = {
4 | spacing: (multiple: number) => (multiple * unit).toString() + 'px',
5 | fontFamily: 'Roboto Variable',
6 | color: {
7 | primary: '#3182ce',
8 | secondary: '#3182ce63',
9 | white: '#FFFFFF',
10 | darkText: '#091F43',
11 | grey90: '#545E6F',
12 | grey80: '#657287',
13 | grey70: '#738198',
14 | grey60: '#8894A8',
15 | grey50: '#A4AEBD',
16 | grey40: '#B9C1CE',
17 | grey30: '#D4DAE2',
18 | grey20: '#EEF0F5',
19 | grey10: '#F8F9FB',
20 | blue: '#0068FF',
21 | red: 'red',
22 | dark: 'rgb(20, 20, 20)',
23 | light: '#FFFFFF',
24 | },
25 | text: {
26 | small: { size: '14px', lineHeight: '1.71' },
27 | regular: { size: '16px', lineHeight: '1.50' },
28 | medium: { size: '18px', lineHeight: '1.56' },
29 | large: { size: '20px', lineHeight: '1.60' },
30 | xlarge: { size: '32px', lineHeight: '1.80' },
31 | },
32 | borderRadii: {
33 | standard: '4px',
34 | curvy: '8px',
35 | circle: '50%',
36 | },
37 | get buttonSizes() {
38 | return {
39 | small: { height: this.spacing(4), padding: this.spacing(2) },
40 | medium: { height: this.spacing(5), padding: this.spacing(3) },
41 | large: { height: this.spacing(6), padding: this.spacing(4) },
42 | };
43 | },
44 | get border() {
45 | return ('1px solid ' + this.color.grey30);
46 | },
47 | };
48 |
49 | export { selfTheme };
50 |
--------------------------------------------------------------------------------
/src/components/Toggle.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components';
3 |
4 |
5 | const ToggleWrapper = styled.div`
6 | display: flex;
7 | flex-direction: row;
8 | align-items: center;
9 | height: 60px;
10 | background-color: white;
11 | margin-bottom: 10px;
12 | margin-left: auto;
13 | margin-right: auto;
14 | `;
15 |
16 | type ElementDivProps = {
17 | active: boolean;
18 | };
19 |
20 | const ElementDiv = styled.div`
21 | display: block;
22 | box-sizing: border-box;
23 | width: 100px;
24 | height: 100%;
25 | text-align: center;
26 | padding: 20px 0px;
27 | background-color: ${props => (props.active ?
28 | props.theme.color.secondary : props.theme.color.grey30)};
29 | :hover {
30 | background-color: ${props => props.theme.color.secondary};
31 | }
32 | `;
33 |
34 | type ToggleProps = {
35 | element: string;
36 | elements: object;
37 | setElement: (value) => void;
38 | };
39 |
40 | const Toggle = (props: ToggleProps) => {
41 |
42 | const setElement = (value) => () => {
43 | props.setElement(value);
44 | };
45 |
46 | return (
47 |
48 | {Object.keys(props.elements).map(key => (
49 | {key}
54 | ))}
55 |
56 | );
57 | };
58 |
59 | export default Toggle;
60 |
--------------------------------------------------------------------------------
/cairo/hash/circuit.cairo:
--------------------------------------------------------------------------------
1 | %builtins output pedersen range_check bitwise
2 |
3 | from starkware.cairo.common.cairo_builtins import HashBuiltin
4 | from starkware.cairo.common.cairo_builtins import BitwiseBuiltin
5 | from starkware.cairo.common.serialize import serialize_word
6 |
7 | from cairo.utils.encrypt import (Encrypt, Decrypt, Ciphertext, get_hash_pedersen)
8 |
9 | struct HashOutput:
10 | member key_hash : felt
11 |
12 | member ciphertext_1 : felt
13 | member ciphertext_2 : felt
14 |
15 | member hash : felt
16 | member salt : felt
17 | end
18 |
19 | func main{output_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() -> ():
20 | alloc_locals
21 |
22 | local preimage
23 | local key
24 |
25 | %{
26 | ids.preimage = program_input['preimage']
27 | ids.key = program_input['key']
28 | %}
29 |
30 | let output = cast(output_ptr, HashOutput*)
31 | let output_ptr = output_ptr + HashOutput.SIZE
32 | local output_ptr: felt* = output_ptr
33 |
34 | # proof of property (hash)
35 | let (preimage_hash) = get_hash_pedersen(preimage, 0)
36 | assert output.hash = preimage_hash
37 | assert output.salt = 0
38 |
39 | # hash of key
40 | let (key_hash) = get_hash_pedersen(key, 0)
41 | assert output.key_hash = key_hash
42 |
43 | # encryption of message
44 | let (ciphertext: Ciphertext) = Encrypt(preimage, key)
45 | assert output.ciphertext_1 = ciphertext.a
46 | assert output.ciphertext_2 = ciphertext.b
47 |
48 | return ()
49 | end
50 |
--------------------------------------------------------------------------------
/scripts/cairoCall.js:
--------------------------------------------------------------------------------
1 | const { execSync } = require('child_process');
2 | const fs = require('fs');
3 | const path = require('path');
4 |
5 | const contractName = process.argv[2];
6 | const func = process.argv[3];
7 | const type = process.argv[4];
8 | const inputs = process.argv.slice(5);
9 |
10 | const cwd = process.cwd();
11 | const directory = path.resolve(`${cwd}/cairo/contracts`);
12 | const contractAbi = JSON.parse(fs.readFileSync(`${directory}/${contractName}_abi.json`));
13 | const CONTRACT_ADDRESS = JSON.parse(fs.readFileSync(`${directory}/${contractName}_address.json`)).address;
14 |
15 | if (type === 'invoke') {
16 | if (inputs.length > 0) {
17 | execSync(`starknet invoke \ --address ${CONTRACT_ADDRESS} \ --abi ./cairo/contracts/${contractName}_abi.json \ --function ${func} \ --inputs ${inputs.join(' ')}`, {
18 | stdio: 'inherit',
19 | });
20 | } else {
21 | execSync(`starknet invoke \ --address ${CONTRACT_ADDRESS} \ --abi ./cairo/contracts/${contractName}_abi.json \ --function ${func}`, {
22 | stdio: 'inherit',
23 | });
24 | }
25 | } else {
26 | if (inputs.length > 0) {
27 | execSync(`starknet call \ --address ${CONTRACT_ADDRESS} \ --abi ./cairo/contracts/${contractName}_abi.json \ --function ${func} \ --inputs ${inputs.join(' ')}`, {
28 | stdio: 'inherit',
29 | });
30 | } else {
31 | execSync(`starknet call \ --address ${CONTRACT_ADDRESS} \ --abi ./cairo/contracts/${contractName}_abi.json \ --function ${func}`, {
32 | stdio: 'inherit',
33 | });
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/utils/api.ts:
--------------------------------------------------------------------------------
1 | // params is given as a JSON
2 | export function get(endpoint) {
3 | return fetch(endpoint, {
4 | headers: {
5 | 'Access-Control-Allow-Origin': '*',
6 | },
7 | }).then(res => {
8 | if(res.ok){
9 | return res.json();
10 | } else{
11 | return res;
12 | }
13 | });
14 | }
15 |
16 | //make sure headers includes 'Content-type': 'application/json'
17 | export function post(endpoint, params) {
18 | return fetch(endpoint, {
19 | method: 'post',
20 | headers: {
21 | 'Accept': 'application/json',
22 | 'Content-Type': 'application/json',
23 | 'Access-Control-Allow-Origin': '*',
24 | },
25 | body: JSON.stringify(params)
26 | }).then(res => {
27 | if(res.ok){
28 | return res.json();
29 | } else{
30 | return res
31 | }
32 | });
33 | }
34 |
35 | export function put(endpoint, params) {
36 | return fetch(endpoint, {
37 | method: 'put',
38 | headers: {
39 | 'Accept': 'application/json',
40 | 'Content-Type': 'application/json'
41 | },
42 | body: JSON.stringify(params)
43 | }).then(res => {
44 | if(res.ok){
45 | return res.json()
46 | } else{
47 | return res
48 | }
49 | });
50 | }
51 |
52 | export function getJsonFromUrl(url) {
53 | if(!url) url = location.search;
54 | var query = url.substr(1);
55 | var result = {};
56 | query.split("&").forEach(function(part) {
57 | var item = part.split("=");
58 | result[item[0]] = decodeURIComponent(item[1]);
59 | });
60 | return result;
61 | }
62 |
63 |
--------------------------------------------------------------------------------
/src/components/Modal.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components';
3 |
4 | import { Button } from './Button';
5 |
6 | const ModalWrapper = styled.div`
7 | position: fixed;
8 | display: flex;
9 | flex-direction: column;
10 | top: 50%;
11 | left: 50%;
12 | height: 500px;
13 | width: 500px;
14 | background: white;
15 | border: 1px solid #ccc;
16 | transition: 1.1s ease-out;
17 | box-shadow: -2rem 2rem 2rem rgba(0, 0, 0, 0.2);
18 | filter: blur(0);
19 | transform: translate(-50%,-50%);
20 | opacity: 1;
21 | visibility: visible;
22 | padding: 10px;
23 | z-index: 1;
24 | `;
25 |
26 | const ModalButton = styled(Button)`
27 | margin-top: auto;
28 | `;
29 |
30 | const CloseIcon = styled.img`
31 | position: fixed;
32 | right: 10px;
33 | top: 10px;
34 | width: 30px;
35 | height: 30px;
36 | :hover {
37 | cursor: pointer;
38 | }
39 | `;
40 |
41 | type ModalProps = {
42 | onClose: () => void;
43 | show: boolean;
44 | buttonLabel: string;
45 | children: any;
46 | }
47 |
48 | export default function Modal(props: ModalProps) {
49 | const onClose = () => {
50 | props.onClose();
51 | };
52 |
53 | return (
54 | <>
55 | {props.show ?
56 |
57 | <>
58 | {props.children}
59 | >
60 |
61 |
62 | {props.buttonLabel}
63 |
64 |
65 | : null}
66 | >
67 | );
68 | }
69 |
--------------------------------------------------------------------------------
/scripts/deploy.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Full goerli deploy including any permissions that need to be set.
3 | */
4 | import { task } from 'hardhat/config';
5 | import fs from 'fs';
6 | import { save } from './utils';
7 |
8 | let NETWORK: string;
9 |
10 | task('deploy', 'Full deployment', async (_taskArgs, hre) => {
11 | NETWORK = hre.network.name;
12 | console.log(`Deploying on ${NETWORK}`);
13 |
14 | if (!fs.existsSync(`./deployments/${NETWORK}`)) {
15 | fs.mkdirSync(`./deployments/${NETWORK}`, { recursive: true });
16 | }
17 |
18 | console.log('Deploying Libraries');
19 | const verifierFactory = await hre.ethers.getContractFactory('Verifier');
20 | const verifier = await verifierFactory.deploy();
21 | const pairingFactory = await hre.ethers.getContractFactory('Pairing');
22 | const pairing = await pairingFactory.deploy();
23 | await verifier.deployed();
24 | await pairing.deployed();
25 |
26 | console.log('Deploying Core');
27 | const coreFactory = await hre.ethers.getContractFactory('Core', {
28 | libraries: {
29 | Verifier: verifier.address,
30 | },
31 | });
32 | const core = await coreFactory.deploy(
33 | '1141005542993923374493036937263227815234315019152226250678688752414333038841',
34 | '0xAB43bA48c9edF4C2C4bB01237348D1D7B28ef168',
35 | );
36 | await core.deployed();
37 | save('Core', core, NETWORK);
38 |
39 | console.log('Deploying Getters');
40 | const gettersFactory = await hre.ethers.getContractFactory('Getters');
41 | const getters = await gettersFactory.deploy(core.address);
42 | await getters.deployed();
43 | save('Getters', getters, NETWORK);
44 | });
45 |
--------------------------------------------------------------------------------
/artifacts/@openzeppelin/contracts/access/Ownable.sol/Ownable.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-artifact-1",
3 | "contractName": "Ownable",
4 | "sourceName": "@openzeppelin/contracts/access/Ownable.sol",
5 | "abi": [
6 | {
7 | "anonymous": false,
8 | "inputs": [
9 | {
10 | "indexed": true,
11 | "internalType": "address",
12 | "name": "previousOwner",
13 | "type": "address"
14 | },
15 | {
16 | "indexed": true,
17 | "internalType": "address",
18 | "name": "newOwner",
19 | "type": "address"
20 | }
21 | ],
22 | "name": "OwnershipTransferred",
23 | "type": "event"
24 | },
25 | {
26 | "inputs": [],
27 | "name": "owner",
28 | "outputs": [
29 | {
30 | "internalType": "address",
31 | "name": "",
32 | "type": "address"
33 | }
34 | ],
35 | "stateMutability": "view",
36 | "type": "function"
37 | },
38 | {
39 | "inputs": [],
40 | "name": "renounceOwnership",
41 | "outputs": [],
42 | "stateMutability": "nonpayable",
43 | "type": "function"
44 | },
45 | {
46 | "inputs": [
47 | {
48 | "internalType": "address",
49 | "name": "newOwner",
50 | "type": "address"
51 | }
52 | ],
53 | "name": "transferOwnership",
54 | "outputs": [],
55 | "stateMutability": "nonpayable",
56 | "type": "function"
57 | }
58 | ],
59 | "bytecode": "0x",
60 | "deployedBytecode": "0x",
61 | "linkReferences": {},
62 | "deployedLinkReferences": {}
63 | }
64 |
--------------------------------------------------------------------------------
/src/types/index.ts:
--------------------------------------------------------------------------------
1 |
2 | enum ZKTypes {
3 | SNARK = 'snark',
4 | STARK = 'stark',
5 | }
6 |
7 | enum ContentProperties {
8 | HASH = 'hash',
9 | BLUR = 'blur',
10 | DF = 'df',
11 | }
12 |
13 | enum EthFunctions {
14 | GET_URLS = 'getUrls',
15 | GET_URL_DATA = 'getUrlData',
16 | POST_URL = 'postUrl',
17 | GET_CIPHERTEXT = 'getCiphertext',
18 | BUY_TOKEN = 'buyToken',
19 | GET_TOKENS = 'getTokens',
20 | REDEEM = 'redeem',
21 | GET_OWNER = 'getOwner',
22 | CHECK_OWNERSHIP = 'checkOwnership',
23 | CHECK_NFT = 'checkNFT',
24 | CHECK_CREATOR = 'checkCreator',
25 | GET_CREATOR = 'getCreator',
26 | GET_PUBLIC_KEY = 'getPublicKey',
27 | GET_PROPERTY = 'getProperty',
28 | GET_PROPERTIES = 'getProperties',
29 | }
30 |
31 | enum TokenStates {
32 | UNPURCHASED = 'unpurchased',
33 | OWNED = 'owned',
34 | SELLER = 'seller',
35 | NULL = 'null',
36 | }
37 |
38 | interface Snark {
39 | proof: {
40 | pi_a: BigInt[],
41 | pi_b: BigInt[][],
42 | pi_c: BigInt[],
43 | };
44 | publicSignals: BigInt[];
45 | }
46 | const EmptySnark = {
47 | proof: {
48 | pi_a: [],
49 | pi_b: [[], []],
50 | pi_c: [],
51 | },
52 | publicSignals: [],
53 | };
54 |
55 | interface Stark {
56 | fact: string,
57 | programOutputs: BigInt[],
58 | }
59 | const EmptyStark = {
60 | fact: '',
61 | programOutputs: [],
62 | };
63 |
64 | interface IpfsResponse {
65 | path: string;
66 | CID: any;
67 | size: number;
68 | }
69 |
70 | interface Ciphertext {
71 | iv: BigInt;
72 | data: BigInt[];
73 | }
74 |
75 |
76 | export {
77 | ContentProperties,
78 | TokenStates,
79 | ZKTypes,
80 | Snark,
81 | EmptySnark,
82 | Stark,
83 | EmptyStark,
84 | IpfsResponse,
85 | Ciphertext,
86 | EthFunctions,
87 | };
88 |
--------------------------------------------------------------------------------
/circuits/utils/encrypt.circom:
--------------------------------------------------------------------------------
1 | include "../../node_modules/circomlib/circuits/mimc.circom"
2 |
3 | template EncryptBits(N) {
4 | signal private input plaintext[N];
5 | signal input shared_key;
6 | signal output out[N+1];
7 |
8 | component mimc = MultiMiMC7(N, 91);
9 | for (var i=0; i {
10 | if (i == 0) {
11 | return _;
12 | } else {
13 | return _[0].toUpperCase() + _.slice(1);
14 | }
15 | }).join('');
16 | }
17 |
18 | export function upperCase(str) {
19 | return str.split('-').map((_, i) => {
20 | return _[0].toUpperCase() + _.slice(1);
21 | }).join('');
22 | }
23 |
24 | export function getAddress(contract: string, network: string) {
25 | try {
26 | return JSON.parse(fs.readFileSync(`./deployments/${network}/${contract}.json`).toString()).address;
27 | } catch (err) {
28 | throw Error(`${contract} deployment on ${network} not found, run 'yarn deploy:${network}'`);
29 | }
30 | }
31 |
32 | export function getAccounts(network: string) {
33 | const files = fs.readdirSync(`./deployments/${network}`);
34 | return files.filter(file => file.slice(0, 7) === 'Account').map(file => {
35 | return file.split('-')[1].split('.')[0];
36 | });
37 | }
38 |
39 | export function parseCalldata(calldata: string, layer: number, network: string) {
40 | const _calldata = calldata ? calldata.split(',') : [];
41 | const accounts = getAccounts(network);
42 | return _calldata.map((input: string) => {
43 | if (accounts.includes(input)) {
44 | return BigInt(getAddress(`Account-${input}`, network)).toString();
45 | } else {
46 | return input;
47 | }
48 | });
49 | }
50 |
51 | export function save(name: string, contract: any, network: string) {
52 | fs.writeFileSync(`${DEPLOYMENTS_DIR}/${network}/${name}.json`, JSON.stringify({
53 | 'address': contract.address,
54 | }));
55 | }
56 |
--------------------------------------------------------------------------------
/cairo/contracts/ERC721.cairo:
--------------------------------------------------------------------------------
1 | %lang starknet
2 |
3 | from starkware.starknet.common.storage import Storage
4 | from starkware.cairo.common.cairo_builtins import HashBuiltin
5 |
6 | @storage_var
7 | func _owners(token_id: felt) -> (owners: felt):
8 | end
9 |
10 | @storage_var
11 | func _balances(address: felt) -> (balance: felt):
12 | end
13 |
14 | @storage_var
15 | func _tokenApprovals(token_id: felt) -> (address: felt):
16 | end
17 |
18 | @storage_var
19 | func _operatorApprovals(address1: felt, address2: felt) -> (bool: felt):
20 | end
21 |
22 | func balanceOf{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}(owner: felt) -> (balance: felt):
23 | #require(owner != address(0), "ERC721: balance query for the zero address");
24 | let (balance) = _balances.read(owner)
25 | return (balance)
26 | end
27 |
28 | func ownerOf{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}(token_id: felt) -> (address: felt):
29 | let (owner) = _owners.read(token_id)
30 | #require(owner != address(0), "ERC721: owner query for nonexistent token");
31 | return (owner)
32 | end
33 |
34 | func tokenURI(token_id: felt) -> (uri: felt):
35 | #require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
36 |
37 | #string memory baseURI = _baseURI();
38 | #return bytes(baseURI).length > 0
39 | #? string(abi.encodePacked(baseURI, tokenId.toString()))
40 | #: '';
41 | end
42 |
43 | func _mint{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}(to: felt, token_id: felt):
44 | #require(to != address(0), "ERC721: mint to the zero address");
45 | #require(!_exists(tokenId), "ERC721: token already minted");
46 |
47 | let (balance) = _balances.read(to)
48 | _balances.write(to, balance+1)
49 | _owners.write(token_id, to)
50 |
51 | return ()
52 | end
53 |
--------------------------------------------------------------------------------
/src/utils/parsers.ts:
--------------------------------------------------------------------------------
1 | import { ContentProperties, ZKTypes, Snark, Stark } from '../types';
2 |
3 |
4 | const hashParser = (outputs): Output => {
5 | const _hash = BigInt(outputs[3]);
6 | const _ciphertext = {
7 | iv: BigInt(outputs[1]),
8 | data: [BigInt(outputs[2])],
9 | };
10 |
11 | return { contentProperty: _hash, ciphertext: _ciphertext };
12 | };
13 |
14 | const dfParser = (outputs): Output => {
15 | const _hash = BigInt(outputs[4]);
16 | const _ciphertext = {
17 | iv: BigInt(outputs[1]),
18 | data: [
19 | BigInt(outputs[2]),
20 | BigInt(outputs[3]),
21 | ],
22 | };
23 | return { contentProperty: _hash, ciphertext: _ciphertext };
24 | };
25 |
26 | const blurParser = (outputs): Output => {
27 | const _blurredImage =
28 | outputs.slice(1, 17).map(Number);
29 | return {
30 | contentProperty: _blurredImage,
31 | ciphertext: _blurredImage,
32 | };
33 | };
34 |
35 | interface Output {
36 | contentProperty: any;
37 | ciphertext: any;
38 | }
39 |
40 |
41 | const snarkParser =
42 | (parser: (outputs: BigInt[]) => Output) => (proof: Snark): Output => {
43 | return parser(proof.publicSignals);
44 | };
45 |
46 | const starkParser = (parser: (proof: BigInt[]) => Output) => (proof: Stark) => {
47 | return parser(proof.programOutputs);
48 | };
49 |
50 | const SnarkParsers = {
51 | [ContentProperties.HASH]: snarkParser(hashParser),
52 | [ContentProperties.DF]: snarkParser(dfParser),
53 | [ContentProperties.BLUR]: snarkParser(blurParser),
54 | };
55 |
56 | const StarkParsers = {
57 | [ContentProperties.HASH]: starkParser(hashParser),
58 | [ContentProperties.DF]: starkParser(dfParser),
59 | [ContentProperties.BLUR]: starkParser(blurParser),
60 | };
61 |
62 | export const Parsers = {
63 | [ZKTypes.SNARK]: SnarkParsers,
64 | [ZKTypes.STARK]: StarkParsers,
65 | };
66 |
--------------------------------------------------------------------------------
/cairo/contracts/Storage.cairo:
--------------------------------------------------------------------------------
1 | %lang starknet
2 |
3 |
4 | struct Ciphertext:
5 | member a: felt
6 | member b: felt
7 | end
8 |
9 | struct PublicKey:
10 | member a: felt
11 | member b: felt
12 | end
13 |
14 | struct Account:
15 | member public_key: felt
16 | member token_balance: felt
17 | end
18 |
19 | struct State:
20 | member token_balance: felt
21 | end
22 |
23 | ### USERS ###
24 | @storage_var
25 | func publicKeys(address: felt, index: felt) -> (public_key: felt):
26 | end
27 |
28 |
29 | ### URLS ###
30 | @storage_var
31 | func urlIndex() -> (index: felt):
32 | end
33 | @storage_var
34 | func urls(index: felt) -> (url: (felt, felt)):
35 | end
36 | @storage_var
37 | func _urlCreators(url1: felt, url2: felt) -> (creator: felt):
38 | end
39 | @storage_var
40 | func prices(url1: felt, url2: felt) -> (price: felt):
41 | end
42 | @storage_var
43 | func urlToHash(url1: felt, url2: felt) -> (hash: felt):
44 | end
45 | @storage_var
46 | func urlToProperty(url1: felt, url2: felt) -> (property: felt):
47 | end
48 |
49 |
50 | ### TOKENS ###
51 | @storage_var
52 | func numOfTokens(url1: felt, url2: felt) -> (index: felt):
53 | end
54 | @storage_var
55 | func _tokenIds() -> (res: felt):
56 | end
57 | @storage_var
58 | func _urlTokens(url1: felt, url2: felt, index: felt) -> (token: felt):
59 | end
60 | @storage_var
61 | func tokenUrl(token_id: felt) -> (url: (felt, felt)):
62 | end
63 | @storage_var
64 | func tokenToCiphertext(token_id: felt, index: felt) -> (ciphertext: felt):
65 | end
66 | @storage_var
67 | func redeemed(token_id: felt) -> (bool: felt):
68 | end
69 |
70 |
71 | ### PROPERTIES ###
72 | @storage_var
73 | func numOfProperties() -> (int: felt):
74 | end
75 | @storage_var
76 | func _propertyIds() -> (res: felt):
77 | end
78 | @storage_var
79 | func properties(property: felt) -> (id: felt):
80 | end
81 | @storage_var
82 | func _idProperties(id: felt) -> (property: felt):
83 | end
84 |
--------------------------------------------------------------------------------
/src/components/Resize.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 |
3 | type ResizeProps = {
4 | containerRef: any;
5 | contentRef: any;
6 | slice: any;
7 | display: string;
8 | children: any;
9 | }
10 |
11 | const Resize = (props: ResizeProps) => {
12 | let display;
13 |
14 | useEffect(() => {
15 | const getHash = () => {
16 | display = props.display ? props.display : '';
17 | if (props.containerRef && props.contentRef) {
18 | check();
19 | }
20 | };
21 | getHash();
22 | window.addEventListener('resize', getHash);
23 | }, [props]);
24 |
25 | const isOverflow = () => {
26 | var c = document.createElement('canvas');
27 | var ctx = c.getContext('2d');
28 | ctx.font = '20px times new roman';
29 | var txt = display;
30 | const size = ctx.measureText(txt).width + 20;
31 |
32 | return props.containerRef.offsetWidth < size;
33 | };
34 |
35 | const checkOverflow = (start, end) => {
36 | const middle = Math.floor((start + end) / 2);
37 | if (!middle) {
38 | props.contentRef.innerHTML = display;
39 | return;
40 | }
41 | display = props.slice(middle);
42 | const _isOverflow = isOverflow();
43 | if (start === middle) {
44 | display = props.slice(
45 | end - (_isOverflow ? 3 : 1),
46 | );
47 | props.contentRef.innerHTML = display;
48 | return;
49 | }
50 | if (_isOverflow) {
51 | checkOverflow(start, middle);
52 | } else {
53 | checkOverflow(middle, end);
54 | }
55 | };
56 |
57 | const check = () => {
58 | if (isOverflow()) {
59 | checkOverflow(0, display.length - 1);
60 | } else {
61 | props.contentRef.innerHTML = display;
62 | }
63 | };
64 |
65 | return (
66 |
67 | {props.children}
68 |
69 | );
70 | };
71 |
72 | export default Resize;
73 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "extends": [
7 | "eslint:recommended",
8 | "plugin:react/recommended",
9 | "plugin:@typescript-eslint/eslint-recommended"
10 | ],
11 | "globals": {
12 | "Atomics": "readonly",
13 | "SharedArrayBuffer": "readonly",
14 | "require": true,
15 | "process": true,
16 | "module": true,
17 | "BigInt": true,
18 | "Buffer": true
19 | },
20 | "parser": "@typescript-eslint/parser",
21 | "parserOptions": {
22 | "ecmaFeatures": {
23 | "jsx": true
24 | },
25 | "ecmaVersion": 2018,
26 | "sourceType": "module"
27 | },
28 | "plugins": [
29 | "react",
30 | "@typescript-eslint"
31 | ],
32 | "settings": {
33 | "react": {
34 | "version": "detect"
35 | }
36 | },
37 | "ignorePatterns": [
38 | "webpack.config.js",
39 | "test/*",
40 | "node_modules/*",
41 | "dist/*",
42 | "public/*",
43 | "scripts/*"
44 | ],
45 | "rules": {
46 | "indent": [
47 | "error",
48 | 2,
49 | { "SwitchCase": 1 }
50 | ],
51 | "linebreak-style": [
52 | "error",
53 | "unix"
54 | ],
55 | "quotes": [
56 | "error",
57 | "single"
58 | ],
59 | "semi": [
60 | "error",
61 | "always"
62 | ],
63 | "max-len": [
64 | "error",
65 | {
66 | "code": 80,
67 | "ignoreUrls": true
68 | }
69 | ],
70 | "object-curly-spacing": ["error", "always", {
71 | "arraysInObjects": true,
72 | "objectsInObjects": true
73 | }],
74 | "comma-dangle": ["error", "always-multiline"],
75 | "no-unused-vars": "off",
76 | "@typescript-eslint/no-unused-vars": ["error"],
77 | "no-trailing-spaces": ["error"],
78 | "no-inner-declarations": "off"
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/cairo/utils/mimc.cairo:
--------------------------------------------------------------------------------
1 | struct Field:
2 | member x : felt
3 | end
4 |
5 | func iter(
6 | field_elements : Field*,
7 | k : felt,
8 | t7_1 : felt,
9 | n_steps
10 | ) -> (final_t, final_t6):
11 |
12 | # why doesn't the following work?
13 | # let t = k + t7_1 + field_elements.x
14 |
15 | [ap] = field_elements.x; ap++
16 | [ap] = t7_1 + [ap-1]; ap++ # t
17 | [ap] = [ap-1]*[ap-1]; ap++ # t2
18 | [ap] = [ap-1]*[ap-1]; ap++ # t4
19 | [ap] = [ap-1]*[ap-1]; ap++ # t6
20 |
21 | if n_steps != 0:
22 | let t7 = [ap-4]*[ap-1]
23 | iter(
24 | field_elements + Field.SIZE,
25 | k,
26 | t7,
27 | n_steps - 1
28 | )
29 | ret
30 | else:
31 | return (final_t=[ap-4], final_t6=[ap-1])
32 | end
33 | end
34 |
35 | func mimc7(
36 | field_elements : Field*,
37 | x_in : felt,
38 | k : felt,
39 | nrounds : felt
40 | ) -> (out):
41 | alloc_locals
42 |
43 | let t = k + x_in
44 | let t2 = t*t
45 | let t4 = t2*t2
46 | let t6 = t4*t4
47 |
48 | let t7 = t6*t
49 |
50 | let (__fp__, _) = get_fp_and_pc()
51 | let (final_t, final_t6) = iter(
52 | field_elements + Field.SIZE,
53 | k,
54 | t7,
55 | nrounds - 2
56 | )
57 | [ap] = final_t6; ap++
58 | [ap] = final_t; ap++
59 | [ap] = [ap-1]*[ap-2]; ap++
60 | [ap] = [ap-1] + k; ap++
61 | return (out=[ap-1])
62 | end
63 |
64 | func main():
65 | alloc_locals
66 |
67 | local field_elements : Field*
68 | local x_in : felt
69 | local k : felt
70 | local nrounds : felt
71 |
72 | %{
73 | field_elements1 = program_input['field_elements']
74 | x_in1 = program_input['x_in']
75 | k1 = program_input['k']
76 | nrounds1 = program_input['nrounds']
77 |
78 | ids.field_elements = field_elements = segments.add()
79 | for i, val in enumerate(field_elements1):
80 | memory[field_elements + i] = val
81 |
82 | ids.x_in = program_input['x_in']
83 | ids.k = program_input['k']
84 | ids.nrounds = program_inputs['nrounds']
85 | %}
86 |
87 | let (out) = mimc7(field_elements, x_in, k, nrounds)
88 | [ap] = out; ap++
89 | %{
90 | print('Hash', memory[ap-1])
91 | %}
92 | return ()
93 | end
94 |
--------------------------------------------------------------------------------
/cairo/encryption/circuit.cairo:
--------------------------------------------------------------------------------
1 | %builtins output pedersen range_check bitwise
2 |
3 | from starkware.cairo.common.cairo_builtins import HashBuiltin
4 | from starkware.cairo.common.cairo_builtins import BitwiseBuiltin
5 | from starkware.cairo.common.serialize import serialize_word
6 |
7 | from cairo.utils.ec_math import ec_mult, Point
8 | from cairo.utils.encrypt import (Encrypt, Decrypt, Ciphertext, get_hash_pedersen)
9 |
10 |
11 | struct PublicKey:
12 | member a : felt
13 | member b : felt
14 | end
15 |
16 | struct EncryptionOutput:
17 | member hash : felt
18 |
19 | member encryption_1 : felt
20 | member encryption_2 : felt
21 |
22 | member public_key_1 : felt
23 | member public_key_2 : felt
24 | end
25 |
26 | func main{output_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr, bitwise_ptr: BitwiseBuiltin*}() -> ():
27 | alloc_locals
28 |
29 | local key
30 | local seller_private_key
31 | local buyer_public_key: PublicKey*
32 |
33 | %{
34 | ids.key = program_input['key']
35 | ids.seller_private_key = program_input['seller_private_key']
36 |
37 | _buyer_public_key = program_input['buyer_public_key']
38 | ids.buyer_public_key = buyer_public_key = segments.add()
39 | for i, val in enumerate(_buyer_public_key):
40 | memory[buyer_public_key + i] = val
41 | %}
42 |
43 | let output = cast(output_ptr, EncryptionOutput*)
44 | let output_ptr = output_ptr + EncryptionOutput.SIZE
45 | local output_ptr: felt* = output_ptr
46 |
47 | assert output.public_key_1 = buyer_public_key.a
48 | assert output.public_key_2 = buyer_public_key.b
49 |
50 | # output key hash
51 | let (hash_out) = get_hash_pedersen(key, 0)
52 | assert output.hash = hash_out
53 | local pedersen_ptr: HashBuiltin* = pedersen_ptr
54 |
55 | # generate shared key
56 | let public_key_point = Point(x=buyer_public_key.a, y=buyer_public_key.b)
57 | let (point: Point) = ec_mult(seller_private_key, public_key_point)
58 | let shared_key = point.x
59 |
60 | # encrypt key
61 | let (encryption: Ciphertext) = Encrypt(key, shared_key)
62 |
63 | assert output.encryption_1 = encryption.a
64 | assert output.encryption_2 = encryption.b
65 |
66 | return ()
67 | end
68 |
--------------------------------------------------------------------------------
/src/components/text.tsx:
--------------------------------------------------------------------------------
1 | import styled, { css } from 'styled-components';
2 |
3 | const textWeights = {
4 | light: '\'wght\' 300',
5 | regular: '\'wght\' 400',
6 | medium: '\'wght\' 500',
7 | bold: '\'wght\' 700',
8 | };
9 |
10 | const textAlignment = {
11 | left: 'left',
12 | right: 'right',
13 | center: 'center',
14 | justify: 'justify',
15 | initial: 'initial',
16 | inherent: 'inherent',
17 | };
18 |
19 | const textStyles = {
20 | normal: 'normal',
21 | italic: 'italic',
22 | };
23 |
24 | const textTransformations = {
25 | uppercase: 'uppercase',
26 | lowercase: 'lowercase',
27 | capitalize: 'capitalize',
28 | };
29 |
30 | const Text = props => {
31 | const color = props.colored ?
32 | props.theme.color[props.colored] : props.theme.color.darkText;
33 | const weight = props.weight && textWeights[props.weight];
34 | const alignment = props.align && textAlignment[props.align];
35 | const transform = props.transform && textTransformations[props.transform];
36 | const style = props.styled && textStyles[props.styled];
37 | const font = props.theme.fontFamily;
38 |
39 | return css`
40 | color: ${color};
41 | font-variation-settings: ${weight};
42 | text-align: ${alignment};
43 | text-transform: ${transform};
44 | font-style: ${style};
45 | font-family: ${font};
46 | `;
47 | };
48 |
49 | export const Small = styled.div`
50 | ${Text};
51 | font-size: ${props => props.theme.text.small.size};
52 | line-height: ${props => props.theme.text.small.lineHeight};
53 | `;
54 |
55 | export const Medium = styled.div`
56 | ${Text};
57 | font-size: ${props => props.theme.text.medium.size};
58 | line-height: ${props => props.theme.text.medium.lineHeight};
59 | `;
60 |
61 | export const Large = styled.div`
62 | ${Text};
63 | font-size: ${props => props.theme.text.large.size};
64 | line-height: ${props => props.theme.text.large.lineHeight};
65 | `;
66 |
67 | export const Header = styled.div`
68 | ${Text};
69 | font-size: ${props => props.theme.text.xlarge.size};
70 | line-height: ${props => props.theme.text.xlarge.lineHeight};
71 | font-variation-settings: ${textWeights.bold};
72 | display: flex;
73 | justify-content: center;
74 | `;
75 |
--------------------------------------------------------------------------------
/artifacts/contracts/Core.sol/DarkForestCore.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-artifact-1",
3 | "contractName": "DarkForestCore",
4 | "sourceName": "contracts/Core.sol",
5 | "abi": [
6 | {
7 | "inputs": [
8 | {
9 | "internalType": "uint256",
10 | "name": "key",
11 | "type": "uint256"
12 | }
13 | ],
14 | "name": "planets",
15 | "outputs": [
16 | {
17 | "components": [
18 | {
19 | "internalType": "address",
20 | "name": "owner",
21 | "type": "address"
22 | },
23 | {
24 | "internalType": "bool",
25 | "name": "isHomePlanet",
26 | "type": "bool"
27 | }
28 | ],
29 | "internalType": "struct DarkForestCore.Planet",
30 | "name": "",
31 | "type": "tuple"
32 | }
33 | ],
34 | "stateMutability": "view",
35 | "type": "function"
36 | },
37 | {
38 | "inputs": [],
39 | "name": "s",
40 | "outputs": [
41 | {
42 | "components": [
43 | {
44 | "internalType": "uint256",
45 | "name": "PLANETHASH_KEY",
46 | "type": "uint256"
47 | }
48 | ],
49 | "internalType": "struct DarkForestCore.SnarkConstants",
50 | "name": "snarkConstants",
51 | "type": "tuple"
52 | }
53 | ],
54 | "stateMutability": "view",
55 | "type": "function"
56 | },
57 | {
58 | "inputs": [],
59 | "name": "snarkConstants",
60 | "outputs": [
61 | {
62 | "components": [
63 | {
64 | "internalType": "uint256",
65 | "name": "PLANETHASH_KEY",
66 | "type": "uint256"
67 | }
68 | ],
69 | "internalType": "struct DarkForestCore.SnarkConstants",
70 | "name": "",
71 | "type": "tuple"
72 | }
73 | ],
74 | "stateMutability": "view",
75 | "type": "function"
76 | }
77 | ],
78 | "bytecode": "0x",
79 | "deployedBytecode": "0x",
80 | "linkReferences": {},
81 | "deployedLinkReferences": {}
82 | }
83 |
--------------------------------------------------------------------------------
/scripts/buildConfig.ts:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import path from 'path';
3 | import config from '../config/config';
4 | import { upperCase } from './utils';
5 |
6 | const cwd = process.cwd();
7 |
8 | let network;
9 | if (config.env === 'production') {
10 | network = config.network;
11 | } else {
12 | network = 'localhost';
13 | }
14 |
15 | const deployedContractsDir = path.resolve(`${cwd}/deployments/${network}`);
16 | const contracts = fs.readdirSync(deployedContractsDir).map(_ => _.split('.')[0]);
17 | contracts.forEach(contract => {
18 | const contractName = upperCase(contract);
19 | const abiJson = JSON.parse(fs.readFileSync(`./artifacts/contracts/${contractName}.sol/${contractName}.json`).toString());
20 | let addressJson;
21 | addressJson = JSON.parse(fs.readFileSync(`./deployments/${network}/${contractName}.json`).toString());
22 |
23 | if (!fs.existsSync('./public/contracts')) {
24 | fs.mkdirSync('./public/contracts', { recursive: true });
25 | }
26 | fs.writeFileSync('./config/config.json', JSON.stringify(config));
27 | fs.writeFileSync(`./public/contracts/${contractName}.json`, JSON.stringify({
28 | address: addressJson.address,
29 | abi: abiJson.abi,
30 | }));
31 |
32 | if (!fs.existsSync('./public/circuits/key')) {
33 | fs.mkdirSync('./public/circuits/key', { recursive: true });
34 | }
35 | if (!fs.existsSync('./public/circuits/verification_key')) {
36 | fs.mkdirSync('./public/circuits/verification_key', { recursive: true });
37 | }
38 | if (!fs.existsSync('./public/circuits/wasm')) {
39 | fs.mkdirSync('./public/circuits/wasm', { recursive: true });
40 | }
41 | });
42 |
43 | const compiledCircuitsDir = path.resolve(`${cwd}/compiledCircuits`);
44 | const circuits = fs.readdirSync(compiledCircuitsDir);
45 | circuits.forEach(circuit => {
46 | fs.copyFileSync(
47 | `${compiledCircuitsDir}/${circuit}/circuit.wasm`,
48 | `${cwd}/public/circuits/wasm/${upperCase(circuit)}.wasm`,
49 | );
50 | fs.copyFileSync(
51 | `${compiledCircuitsDir}/${circuit}/verification_key.json`,
52 | `${cwd}/public/circuits/verification_key/${upperCase(circuit)}.json`,
53 | );
54 | fs.copyFileSync(
55 | `${compiledCircuitsDir}/${circuit}/circuit.zkey`,
56 | `${cwd}/public/circuits/key/${upperCase(circuit)}.zkey`,
57 | );
58 | });
59 |
--------------------------------------------------------------------------------
/src/pages/ChooseUser.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import styled from 'styled-components';
3 |
4 | import config from '../../config';
5 | import { Large } from '../components/text';
6 | import eth from '../utils/ethAPI';
7 |
8 | const Title = styled(Large)`
9 | margin-bottom: 10px;
10 | `;
11 |
12 | const ChooseUserWrapper = styled.div`
13 | display: flex;
14 | flex-direction: column;
15 | align-items: center;
16 | margin-left: 35%;
17 | margin-right: 35%;
18 | margin-top: 10%;
19 | `;
20 |
21 | const AddressWrapper = styled.div`
22 | display: flex;
23 | flex-direction: row;
24 | justify-content: space-between;
25 | width: calc(100%);
26 | height: 50px;
27 | background-color: ${props => props.theme.color.white};
28 | border: ${props => `1px solid ${props.theme.color.grey30}`};
29 | margin-bottom: 10px;
30 | border-radius: 4px;
31 | padding: 10px;
32 | padding-left: 20px;
33 | cursor: pointer;
34 | align-items: center;
35 | :hover {
36 | background-color: ${props => props.theme.color.grey10};
37 | }
38 | `;
39 |
40 | const AddressText = styled(Large)`
41 | font-size: 25px;
42 | `;
43 |
44 | type AddressProps = {
45 | key: string;
46 | name: string;
47 | onClick: () => void;
48 | };
49 |
50 | const Address = (props: AddressProps) => {
51 | return (
52 |
53 | {props.name.slice(0,6)}
54 |
55 | );
56 | };
57 |
58 | const ChooseUser = (props) => {
59 | const [addresses, setAddresses] = useState([]);
60 |
61 | useEffect(() => {
62 | if (props.signer) {
63 | props.signer.provider.listAccounts().then(setAddresses);
64 | }
65 | }, [props.signer]);
66 |
67 | const sendToTokens = () => {
68 | props.history.push('/tokens');
69 | };
70 |
71 | const selectAddress = (address: string) => () => {
72 | eth.setSigner(address);
73 | sendToTokens();
74 | };
75 |
76 | return (
77 |
78 | Select which address to use
79 | {addresses.map(address => )}
84 |
85 | );
86 | };
87 |
88 |
89 | export default ChooseUser;
90 |
--------------------------------------------------------------------------------
/src/pages/Content.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import styled from 'styled-components';
3 |
4 | import DarkForest from './content/DarkForest';
5 | import Blur from './content/Blur';
6 | import Hash from './content/Hash';
7 |
8 | import {
9 | ContentProperties,
10 | Ciphertext,
11 | } from '../types';
12 | import {
13 | InputProps,
14 | ContentSkeleton,
15 | } from '../types/content';
16 |
17 |
18 | const content: Record = {
19 | [ContentProperties.HASH]: Hash,
20 | [ContentProperties.BLUR]: Blur,
21 | [ContentProperties.DF]: DarkForest,
22 | };
23 |
24 | interface ContentInputProps extends InputProps {
25 | property: ContentProperties;
26 | }
27 |
28 | const ContentInput = (props: ContentInputProps) => {
29 |
30 | const PropertyInputElement = content[props.property].input;
31 |
32 | return (
33 | <>
34 |
38 | >
39 | );
40 | };
41 |
42 | const ContentWrapper = styled.div`
43 | display: flex;
44 | flex-direction: row;
45 | width: 100%;
46 | background-color: ${props => props.theme.color.grey10};
47 | margin-top: 10px;
48 | margin-bottom: 10px;
49 | `;
50 |
51 | type ContentProps = {
52 | property: string;
53 | zk: string;
54 | content: {
55 | cipher: number[] | Ciphertext,
56 | property: number[] | BigInt,
57 | };
58 | secretKey: BigInt | null;
59 | }
60 |
61 | const Content = (props: ContentProps) => {
62 | const [message, setMessage] = useState(null);
63 |
64 | const {
65 | display,
66 | assertContent,
67 | assertMessage,
68 | decrypt,
69 | } = content[props.property];
70 |
71 | useEffect(() => {
72 | assertContent(props.content);
73 | if (props.secretKey) {
74 | decrypt(
75 | props.zk,
76 | props.content.cipher,
77 | props.secretKey,
78 | ).then(_message => {
79 | assertMessage(_message);
80 | setMessage(_message);
81 | });
82 | }
83 | }, [props]);
84 |
85 | const PropertyElement = display;
86 |
87 | return (
88 |
89 |
90 |
91 | );
92 | };
93 |
94 | export {
95 | Content,
96 | ContentInput,
97 | content as ContentElements,
98 | };
99 |
--------------------------------------------------------------------------------
/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, request, jsonify
2 | from flask_cors import CORS
3 | from starkware.crypto.signature.fast_pedersen_hash import pedersen_hash
4 | from starkware.cairo.bootloader.generate_fact import get_program_output
5 | from starkware.cairo.sharp.sharp_client import init_client
6 | from starkware.cairo.bootloader.hash_program import compute_program_hash_chain
7 | from starkware.crypto.signature.math_utils import ec_add, ec_mult
8 | from starkware.crypto.signature.signature import get_random_private_key, private_key_to_ec_point_on_stark_curve, FIELD_PRIME
9 |
10 | import subprocess
11 | import logging
12 | import sys
13 | import os
14 | import json
15 | import re
16 |
17 | app = Flask('test')
18 | CORS(app, resources={r'/*': {'origins': '*'}})
19 |
20 | app.logger.setLevel(logging.INFO)
21 |
22 | sharp_client = init_client(bin_dir='', node_rpc_url='https://goerli.infura.io/v3/68283459972f4c5594019a8878ef1003')
23 | program = sharp_client.compile_cairo(source_code_path='/home/nulven/CairoMarketplace/cairo/encryption/circuit.cairo')
24 | print(sharp_client.contract_client.contract.address)
25 | print(compute_program_hash_chain(program))
26 |
27 |
28 | @app.route('/prove', methods=['POST'])
29 | def prove():
30 | circuit = request.json.get('circuit')
31 | inputs = request.json.get('inputs')
32 | parsed_inputs = {}
33 | for key, value in inputs.items():
34 | if type(value) is list:
35 | parsed_inputs.update({key: [int(_) for _ in value]})
36 | else:
37 | parsed_inputs[key] = int(value)
38 | print(circuit, parsed_inputs)
39 | with open('/home/nulven/CairoMarketplace/cairo/'+circuit+'/input.json', 'w') as f:
40 | json.dump(parsed_inputs, f)
41 |
42 | program = sharp_client.compile_cairo(source_code_path='/home/nulven/CairoMarketplace/cairo/' + circuit + '/circuit.cairo')
43 | print('PROGRAM')
44 | cairo_pie = sharp_client.run_program(
45 | program=program, program_input_path='/home/nulven/CairoMarketplace/cairo/' + circuit + '/input.json')
46 | print('CAIRO PIE')
47 | job_key = sharp_client.submit_cairo_pie(cairo_pie=cairo_pie)
48 | print('JOB KEY')
49 |
50 | fact = sharp_client.get_fact(cairo_pie)
51 | output = get_program_output(cairo_pie)
52 | output_new = [str(_) for _ in output]
53 | print(output_new)
54 | return jsonify({'res': {'programOutputs': output_new, 'fact': fact}})
55 |
56 | app.run(host='localhost', port=5002, debug=True)
57 |
--------------------------------------------------------------------------------
/cairo/contracts/utils.cairo:
--------------------------------------------------------------------------------
1 | %lang starknet
2 |
3 | from starkware.starknet.common.storage import Storage
4 | from starkware.cairo.common.cairo_builtins import (HashBuiltin, SignatureBuiltin)
5 | from cairo.contracts.ERC721 import (ownerOf, _mint)
6 | from cairo.contracts.ERC721URIStorage import (_setTokenURI, tokenURI)
7 | from cairo.contracts.Storage import (
8 | Ciphertext, PublicKey,
9 | publicKeys, urlIndex, urls, _urlCreators, prices, urlToHash, urlToProperty,
10 | numOfTokens, _tokenIds, _urlTokens, tokenUrl, tokenToCiphertext, redeemed,
11 | numOfProperties, _propertyIds, properties, _idProperties
12 | )
13 |
14 |
15 | func _setProperty{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
16 | url1: felt,
17 | url2: felt,
18 | property: felt
19 | ) -> (bool: felt):
20 |
21 | let (propertyId) = properties.read(property)
22 | # assert that property exists
23 |
24 | urlToProperty.write(url1, url2, property)
25 |
26 | return (bool=1)
27 | end
28 |
29 | func _mintToken{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
30 | to: felt,
31 | url1: felt,
32 | url2: felt
33 | ) -> ():
34 |
35 | let (tokenId) = _tokenIds.read()
36 | let url: (felt, felt) = (url1, url2)
37 | let (length) = numOfTokens.read(url[0], url[1])
38 |
39 | _urlTokens.write(url[0], url[1], length, tokenId)
40 | numOfTokens.write(url[0], url[1], length+1)
41 | _tokenIds.write(tokenId+1)
42 | tokenUrl.write(tokenId, url)
43 |
44 | _mint(to, tokenId)
45 | _setTokenURI(tokenId, url[0], url[1])
46 |
47 | return ()
48 | end
49 |
50 | func addPublicKey{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
51 | address: felt,
52 | public_key_a: felt,
53 | public_key_b: felt
54 | ) -> (bool: felt):
55 |
56 | # assert public key is not recorded
57 | let (public_key_a) = publicKeys.read(address, 0)
58 | assert public_key_a = 0
59 |
60 | publicKeys.write(address, 0, public_key_a)
61 | publicKeys.write(address, 1, public_key_b)
62 |
63 | return (bool=1)
64 | end
65 |
66 | func checkRedeem{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}(
67 | seller: felt,
68 | tokenId: felt
69 | ) -> (bool: felt):
70 |
71 | let (url) = tokenUrl.read(tokenId)
72 | let (creator) = _urlCreators.read(url[0], url[1])
73 | assert seller = creator
74 |
75 | # assert coin is not redeemed
76 | let (redeem) = redeemed.read(tokenId)
77 | assert redeem = 0
78 |
79 | return (bool=1)
80 | end
81 |
--------------------------------------------------------------------------------
/cairo/utils/ec_math.cairo:
--------------------------------------------------------------------------------
1 | from starkware.cairo.common.cairo_builtins import BitwiseBuiltin
2 | from starkware.cairo.common.math_cmp import is_nn
3 | from starkware.cairo.common.math import unsigned_div_rem
4 | from starkware.cairo.common.bitwise import bitwise_and
5 | from starkware.cairo.common.registers import get_fp_and_pc
6 | from starkware.cairo.common.alloc import alloc
7 | from cairo.utils.math import (MontgomeryDouble, Montgomery2Edwards, Edwards2Montgomery, MontgomeryAdd, BabyAdd)
8 |
9 |
10 | struct Point:
11 | member x: felt
12 | member y: felt
13 | end
14 |
15 | func div_mod{range_check_ptr}(n: felt, m: felt) -> (out: felt):
16 | alloc_locals
17 |
18 | let _m = m
19 |
20 | local a: felt
21 | local b: felt
22 | local c: felt
23 | %{
24 | from sympy.core.numbers import igcdex
25 | from starkware.crypto.signature.signature import FIELD_PRIME
26 | _a, _b, _c = igcdex(ids._m, FIELD_PRIME)
27 | ids.a = _a % FIELD_PRIME
28 | ids.b = _b % FIELD_PRIME
29 | ids.c = _c % FIELD_PRIME
30 | %}
31 | let num = n*a
32 | return (out=num)
33 | end
34 |
35 | func ec_add{range_check_ptr}(point1: Point, point2: Point) -> (out: Point):
36 | let a = point1.y - point2.y
37 | let b = point1.x - point2.x
38 | let (m) = div_mod(a, b)
39 |
40 | let m_squared = m*m
41 | let c = m_squared - point1.x
42 | let x = c - point2.x
43 |
44 | let d = point1.x - x
45 | let e = m*d
46 | let y = e - point1.y
47 |
48 | tempvar out = Point(x=x, y=y)
49 | return (out)
50 | end
51 |
52 | func ec_double{range_check_ptr}(point: Point, alpha: felt) -> (out: Point):
53 | let point_squared = point.x*point.x
54 | let a1 = 3*point_squared
55 | let a2 = a1 + alpha
56 | let b = 2*point.y
57 | let (m) = div_mod(a2, b)
58 | let m_squared = m*m
59 | let c = 2*point.x
60 | let x = m_squared - c
61 |
62 | let d = point.x-x
63 | let e = m*d
64 | let y = e-point.y
65 |
66 | tempvar out = Point(x=x, y=y)
67 | return (out)
68 | end
69 |
70 | func ec_mult{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(
71 | m: felt,
72 | point: Point
73 | ) -> (out: Point):
74 | alloc_locals
75 |
76 | if m == 1:
77 | return (out=point)
78 | end
79 | let (rem) = bitwise_and(m, 1)
80 | if rem == 0:
81 | let (dbl) = ec_double(point, 1)
82 | let m_over_2 = m/2
83 | let (out) = ec_mult(m_over_2, dbl)
84 | return (out)
85 | end
86 | let (mult) = ec_mult(m-1, point)
87 | let (add) = ec_add(mult, point)
88 | return (out=add)
89 | end
90 |
--------------------------------------------------------------------------------
/contracts/ContractStorage.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >=0.8.0;
2 | pragma experimental ABIEncoderV2;
3 |
4 | import "@openzeppelin/contracts/utils/Counters.sol";
5 | import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
6 |
7 | contract ContractStorage {
8 | struct Content {
9 | uint256 id;
10 | string url;
11 | string property;
12 | uint256 keyHash;
13 | address creator;
14 | uint256 price;
15 | string zk;
16 | }
17 |
18 | struct Token {
19 | uint256 id;
20 | uint256 contentId;
21 | uint256 ciphertext1;
22 | uint256 ciphertext2;
23 | bool redeemed;
24 | }
25 |
26 | using Counters for Counters.Counter;
27 |
28 | // URLS
29 | mapping(string => uint256) public contentIds;
30 | Content[] public contents;
31 |
32 | // TOKENS
33 | Counters.Counter public _tokenIds;
34 | Token[] public tokens;
35 | mapping(uint256 => EnumerableSet.UintSet) internal contentTokenIds;
36 |
37 | // PROPERTIES
38 | Counters.Counter public _propertyIds;
39 | mapping(string => uint256) public properties;
40 | mapping(uint256 => string) public _idProperties;
41 |
42 | // USERS
43 | mapping(address => mapping(string => uint256[2])) public publicKeys;
44 |
45 | function getPublicKey(address _address, string calldata zk) public view returns (uint256[2] memory publicKey) {
46 | return publicKeys[_address][zk];
47 | }
48 |
49 | function getContent(uint256 contentId) public view returns (Content memory) {
50 | return contents[contentId];
51 | }
52 |
53 | function contentCount() public view returns (uint256) {
54 | return contents.length;
55 | }
56 |
57 | function getToken(uint id) public view returns (Token memory) {
58 | return tokens[id];
59 | }
60 |
61 | function getTokenIds(uint256 contentId) public view returns (uint256[] memory) {
62 | EnumerableSet.UintSet storage _tokenIds = contentTokenIds[contentId];
63 | uint tokenCount = EnumerableSet.length(_tokenIds);
64 | uint256[] memory tokenIds = new uint256[](tokenCount);
65 | for (uint256 i = 0; i < tokenCount; i++) {
66 | tokenIds[i] = EnumerableSet.at(_tokenIds, i);
67 | }
68 | return tokenIds;
69 | }
70 |
71 | function getNumOfProperties() public view returns (uint256 length) {
72 | return _propertyIds.current();
73 | }
74 |
75 | function incrementProperty() public returns (bool) {
76 | _propertyIds.increment();
77 | return true;
78 | }
79 |
80 | function getProperty(uint256 id) public view returns (string memory) {
81 | return _idProperties[id];
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/utils/errors.ts:
--------------------------------------------------------------------------------
1 | class CustomError extends Error {
2 | constructor(json: { name: string, message: string }) {
3 | super(json.message);
4 | this.name = json.name;
5 | }
6 | }
7 |
8 | enum Errors {
9 | HashIsPosted = 'HashIsPosted',
10 | EthIsRedeemed = 'EthIsRedeemed',
11 | CiphertextNotReady = 'CiphertextNotReady',
12 | InvalidProof = 'InvalidProof',
13 | IncorrectHash = 'IncorrectHash',
14 | IncorrectPublicKey = 'IncorrectPublicKey',
15 | SolidityError = 'SolidityError',
16 | PropertyDoesNotExist = 'PropertyDoesNotExist',
17 | }
18 |
19 | const ErrorNames = {
20 | [Errors.HashIsPosted]: 'HASH_IS_POSTED',
21 | [Errors.EthIsRedeemed]: 'ETH_IS_REDEEMED',
22 | [Errors.CiphertextNotReady]: 'CIPHERTEXT_NOT_READY',
23 | [Errors.InvalidProof]: 'INVALID_PROOF',
24 | [Errors.IncorrectHash]: 'INCORRECT_HASH',
25 | [Errors.IncorrectPublicKey]: 'INCORRECT_PUBLIC_KEY',
26 | [Errors.PropertyDoesNotExist]: 'PROPERTY_DOES_NOT_EXIST',
27 | [Errors.SolidityError]: 'SOLIDITY_ERROR',
28 | };
29 |
30 | const ErrorMessages = {
31 | [Errors.HashIsPosted]: () => 'The hash has already been posted.',
32 | [Errors.EthIsRedeemed]:
33 | () => 'The Eth for this token has already been redeemed.',
34 | [Errors.CiphertextNotReady]:
35 | () => 'The Ciphertext for this token has not been posted yet.',
36 | [Errors.InvalidProof]: () => 'Invalid ZK proof.',
37 | [Errors.IncorrectHash]: () => 'Proof created using the incorrect hash.',
38 | [Errors.IncorrectPublicKey]:
39 | () => 'Proof created using the incorrect public key.',
40 | [Errors.PropertyDoesNotExist]: () => 'Property does not exist.',
41 | [Errors.SolidityError]: (error: string) => `Solidity error: ${error}`,
42 | };
43 |
44 | const SolidityErrors = {
45 | 'revert Hash already posted': Errors.HashIsPosted,
46 | 'revert ETH already redeemed': Errors.EthIsRedeemed,
47 | 'revert Ciphertext not posted yet': Errors.CiphertextNotReady,
48 | 'revert Proof invalid!': Errors.InvalidProof,
49 | 'revert Incorrect hash': Errors.IncorrectHash,
50 | 'revert Used wrong public key': Errors.IncorrectPublicKey,
51 | 'revert Property does not exist': Errors.PropertyDoesNotExist,
52 | };
53 |
54 | function createErrors(): Record CustomError> {
55 | const errors = {};
56 | for (const error in Errors) {
57 | errors[error] = (...args) => {
58 | return new CustomError({
59 | name: ErrorNames[error],
60 | message: ErrorMessages[error](...args),
61 | });
62 | };
63 | }
64 | // @ts-ignore
65 | return errors;
66 | }
67 |
68 | const OurErrors = createErrors();
69 |
70 | export {
71 | OurErrors,
72 | SolidityErrors,
73 | };
74 |
--------------------------------------------------------------------------------
/crypto/index.js:
--------------------------------------------------------------------------------
1 | const { randomBytes } = require('crypto');
2 | const { prv2pub } = require('./eddsa');
3 | const { mulPointEscalar } = require('./babyjub');
4 |
5 | const STARK_FIELD_SIZE = BigInt('3618502788666131213697322783095070105623107215331596699973092056135872020481');
6 |
7 | const lim = BigInt('0x10000000000000000000000000000000000000000000000000000000000000000');
8 |
9 | const min = (lim - STARK_FIELD_SIZE) % STARK_FIELD_SIZE;
10 |
11 | const genRandomBabyJubValue = () => {
12 |
13 | let rand;
14 | while (true) {
15 | rand = BigInt('0x' + randomBytes(32).toString('hex'));
16 |
17 | if (rand >= min) {
18 | break;
19 | }
20 | }
21 |
22 | const privKey = rand % STARK_FIELD_SIZE;
23 | //assert(privKey < STARK_FIELD_SIZE);
24 |
25 | return privKey;
26 | };
27 |
28 | /*
29 | type PrivKey = BigInt
30 | type PubKey = BigInt[]
31 |
32 | interface Keypair {
33 | privKey: PrivKey;
34 | pubKey: PubKey;
35 | }
36 | */
37 |
38 | const genPrivKey = () => {
39 |
40 | return genRandomBabyJubValue();
41 | };
42 |
43 | const bigInt2Buffer = (i) => {
44 | let hexStr = i.toString(16);
45 | while (hexStr.length < 64) {
46 | hexStr = '0' + hexStr;
47 | }
48 | return Buffer.from(hexStr, 'hex');
49 | };
50 |
51 | const genPubKey = (privKey) => {
52 | privKey = BigInt(privKey.toString());
53 | //assert(privKey < STARK_FIELD_SIZE);
54 | return prv2pub(bigInt2Buffer(privKey));
55 | };
56 |
57 | const genKeypair = () => {
58 | const privKey = genPrivKey();
59 | const pubKey = genPubKey(privKey);
60 |
61 | const Keypair = { privKey, pubKey };
62 |
63 | return Keypair;
64 | };
65 |
66 | function pruneBuffer(_buff) {
67 | const buff = Buffer.from(_buff);
68 | buff[0] = buff[0] & 0xF8;
69 | buff[31] = buff[31] & 0x7F;
70 | buff[31] = buff[31] | 0x40;
71 | return buff;
72 | }
73 |
74 | const createBlakeHash = require('blake-hash');
75 | const ff = require('ffjavascript');
76 | const formatPrivKeyForBabyJub = (privKey) => {
77 | const sBuff = pruneBuffer(
78 | createBlakeHash('blake512').update(
79 | bigInt2Buffer(privKey),
80 | ).digest().slice(0,32),
81 | );
82 | const s = ff.utils.leBuff2int(sBuff);
83 | return ff.Scalar.shr(s, 3);
84 | };
85 |
86 | const genEcdhSharedKey = (
87 | privKey,
88 | pubKey,
89 | ) => {
90 | return mulPointEscalar(pubKey, formatPrivKeyForBabyJub(privKey))[0];
91 | };
92 |
93 | const key1 = genKeypair();
94 | const key2 = genKeypair();
95 |
96 | const shared_key1 = genEcdhSharedKey(key1.privKey, key2.pubKey);
97 | const shared_key2 = genEcdhSharedKey(key2.privKey, key1.pubKey);
98 | console.log(shared_key1);
99 | console.log(shared_key2);
100 |
--------------------------------------------------------------------------------
/cairo/contracts/Getters.cairo:
--------------------------------------------------------------------------------
1 |
2 | @view
3 | func getPublicKey{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}(address: felt) -> (a: felt, b: felt):
4 | let (a) = publicKeys.read(address, 0)
5 | let (b) = publicKeys.read(address, 1)
6 | return (a, b)
7 | end
8 |
9 | @view
10 | func getCiphertext{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}(token_id: felt) -> (a: felt, b: felt):
11 | let (redeem) = redeemed.read(token_id)
12 | #assert redeem = 1, 'Ciphertext not posted yet'
13 | let (a) = tokenToCiphertext.read(token_id, 0)
14 | let (b) = tokenToCiphertext.read(token_id, 1)
15 | return (a, b)
16 | end
17 |
18 | @view
19 | func getUrl{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}(index: felt) -> (url1: felt, url2: felt):
20 | let (url) = urls.read(index)
21 | return (url[0], url[1])
22 | end
23 | @view
24 | func getUrlData{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}(url1: felt, url2: felt) -> (url1: felt, url2: felt, property: felt, price: felt):
25 | let (property) = urlToProperty.read(url1, url2)
26 | let (price) = prices.read(url1, url2)
27 | #let (data: Url) = Url(url=url, property=property, price=price)
28 | return (url1, url2, property, price)
29 | end
30 | @view
31 | func getUrlIndex{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (index: felt):
32 | let (index) = urlIndex.read()
33 | return (index)
34 | end
35 |
36 | @view
37 | func getProperty{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}(url1: felt, url2: felt) -> (property: felt):
38 | let (property) = urlToProperty.read(url1, url2)
39 | return (property)
40 | end
41 |
42 | @view
43 | func getPropertyId{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}(index: felt) -> (property: felt):
44 | let (property) = _idProperties.read(index)
45 | return (property)
46 | end
47 |
48 | @view
49 | func getNumOfProperties{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}() -> (num: felt):
50 | let (num) = numOfProperties.read()
51 | return (num)
52 | end
53 |
54 | @view
55 | func getNumOfTokens{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}(url1: felt, url2: felt) -> (num: felt):
56 | let (num) = numOfTokens.read(url1, url2)
57 | return (num)
58 | end
59 |
60 | @view
61 | func getToken{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}(url1: felt, url2: felt, index: felt) -> (token: felt):
62 | let (token_id) = _urlTokens.read(url1, url2, index)
63 | return (token=token_id)
64 | end
65 |
66 | @view
67 | func getCreator{storage_ptr: Storage*, pedersen_ptr: HashBuiltin*, range_check_ptr}(url1: felt, url2: felt) -> (address: felt):
68 | let (creator) = _urlCreators.read(url1, url2)
69 | return (address=creator)
70 | end
71 |
72 |
--------------------------------------------------------------------------------
/scripts/build_readme.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 |
3 | const circuitName = process.argv[2];
4 |
5 | const readme = fs.readFileSync('./README.md').toString();
6 | const sections = readme.split('\n## ').map((_, index) => {
7 | if (index !== 0) {
8 | return `## ${_}`;
9 | } else {
10 | return _;
11 | }
12 | });
13 | const circuitsSection = sections.filter(_ => {
14 | return _.split('\n')[0] === '## Circuits';
15 | })[0];
16 |
17 | const circuit = fs.readFileSync(`./circuits/${circuitName}/circuit.circom`).toString();
18 | const lines = circuit.split('\n').map(_ => {
19 | let firstChar;
20 | _.split('').forEach((char, index) => {
21 | if (char !== ' ' && typeof firstChar !== 'number') {
22 | firstChar = index;
23 | }
24 | });
25 | return _.slice(firstChar);
26 | });
27 | const signals = lines.filter(_ => _.slice(0, 6) === 'signal');
28 | const inputs = [];
29 | const outputs = [];
30 | signals.forEach(_ => {
31 | const modifiers = _.split(' ');
32 | const variable = modifiers[modifiers.length-1];
33 | let type;
34 | let name;
35 | if (variable[variable.length-2] === ']') {
36 | const size = variable[variable.length-3];
37 | type = `Array[${size}]`;
38 | name = variable.slice(0, variable.length-4);
39 | } else {
40 | type = 'BigInt';
41 | name = variable.slice(0, variable.length-1);
42 | }
43 | switch (modifiers[1]) {
44 | case 'private':
45 | inputs.push({ name, 'private': true, type });
46 | break;
47 | case 'input':
48 | inputs.push({ name, 'private': false, type });
49 | break;
50 | case 'output':
51 | return outputs.push({ name, type });
52 | break;
53 | }
54 | });
55 |
56 | const header = `#### ${circuitName}`;
57 | const inputHeader = '##### Inputs';
58 | const inputTableHeader = '| signal | private | type | description |\n|-|-|-|-|';
59 | const inputTableBody = inputs.map(({ name, private, type }) => {
60 | return `| ${name} | ${private} | ${type} | |`;
61 | }).join('\n');
62 | const inputTable = `${inputTableHeader}\n${inputTableBody}`;
63 | const outputHeader = '##### Outputs';
64 | const outputTableHeader = '| signal | type | description |\n|-|-|-|';
65 | const outputTableBody = outputs.map(({ name, type }) => {
66 | return `| ${name} | ${type} | |`;
67 | }).join('\n');
68 | const outputTable = `${outputTableHeader}\n${outputTableBody}`;
69 | const inputsSubsection = `${inputHeader}\n${inputTable}`;
70 | const outputsSubsection = `${outputHeader}\n${outputTable}`;
71 | const circuitSubsection = `${header}\n\n${inputsSubsection}\n\n${outputsSubsection}\n\n\n`;
72 | const subsection = `${circuitsSection}\n${circuitSubsection}`;
73 | const newReadme = sections.map(_ => {
74 | if (_.split('\n')[0] === '## Circuits') {
75 | return subsection;
76 | } else {
77 | return _;
78 | }
79 | }).join('\n');
80 |
81 | fs.writeFileSync('./README.md', newReadme);
82 |
--------------------------------------------------------------------------------
/public/fonts/README.txt:
--------------------------------------------------------------------------------
1 | Roboto Mono Variable Font
2 | =========================
3 |
4 | This download contains Roboto Mono as both variable fonts and static fonts.
5 |
6 | Roboto Mono is a variable font with this axis:
7 | wght
8 |
9 | This means all the styles are contained in these files:
10 | RobotoMono-VariableFont_wght.ttf
11 | RobotoMono-Italic-VariableFont_wght.ttf
12 |
13 | If your app fully supports variable fonts, you can now pick intermediate styles
14 | that aren’t available as static fonts. Not all apps support variable fonts, and
15 | in those cases you can use the static font files for Roboto Mono:
16 | static/RobotoMono-Thin.ttf
17 | static/RobotoMono-ExtraLight.ttf
18 | static/RobotoMono-Light.ttf
19 | static/RobotoMono-Regular.ttf
20 | static/RobotoMono-Medium.ttf
21 | static/RobotoMono-SemiBold.ttf
22 | static/RobotoMono-Bold.ttf
23 | static/RobotoMono-ThinItalic.ttf
24 | static/RobotoMono-ExtraLightItalic.ttf
25 | static/RobotoMono-LightItalic.ttf
26 | static/RobotoMono-Italic.ttf
27 | static/RobotoMono-MediumItalic.ttf
28 | static/RobotoMono-SemiBoldItalic.ttf
29 | static/RobotoMono-BoldItalic.ttf
30 |
31 | Get started
32 | -----------
33 |
34 | 1. Install the font files you want to use
35 |
36 | 2. Use your app's font picker to view the font family and all the
37 | available styles
38 |
39 | Learn more about variable fonts
40 | -------------------------------
41 |
42 | https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts
43 | https://variablefonts.typenetwork.com
44 | https://medium.com/variable-fonts
45 |
46 | In desktop apps
47 |
48 | https://theblog.adobe.com/can-variable-fonts-illustrator-cc
49 | https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts
50 |
51 | Online
52 |
53 | https://developers.google.com/fonts/docs/getting_started
54 | https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide
55 | https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts
56 |
57 | Installing fonts
58 |
59 | MacOS: https://support.apple.com/en-us/HT201749
60 | Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux
61 | Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows
62 |
63 | Android Apps
64 |
65 | https://developers.google.com/fonts/docs/android
66 | https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts
67 |
68 | License
69 | -------
70 | Please read the full license text (LICENSE.txt) to understand the permissions,
71 | restrictions and requirements for usage, redistribution, and modification.
72 |
73 | You can use them freely in your products & projects - print or digital,
74 | commercial or otherwise. However, you can't sell the fonts on their own.
75 |
76 | This isn't legal advice, please consider consulting a lawyer and see the full
77 | license for all details.
78 |
--------------------------------------------------------------------------------
/src/components/TextInput.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import styled from 'styled-components';
3 |
4 | type Props = {
5 | id?: string,
6 | placeholder: string,
7 | handleEnter?: (string) => void,
8 | onChange: (value: string) => void,
9 | value: string,
10 | style?: Object,
11 | label?: string,
12 | };
13 |
14 | const Label = styled.div`
15 | display: flex;
16 | flex: 1;
17 | min-width: 40px;
18 | background-color: ${props => props.theme.color.grey30};
19 | align-items: center;
20 | justify-content: center;
21 | border-radius: 5px 0px 0px 5px;
22 | border-width: 1px 0px 1px 1px;
23 | border-style: solid;
24 | border-color: ${props => props.theme.color.primary};
25 | `;
26 |
27 | const TextInputWrapper = styled.input`
28 | font-family: 'Roboto Variable';
29 | padding: 0 8px;
30 | height: 40px;
31 | width: 100%;
32 | display: flex;
33 | justify-content: center;
34 | align-items: center;
35 | border-radius: 5px;
36 | border-width: 1px;
37 | border-style: solid;
38 | border-color: ${props => props.theme.color.primary};
39 | font-variation-settings: 'wght' 500;
40 | `;
41 |
42 | const InputDivWrapper = styled.div`
43 | display: flex;
44 | flex-direction: row;
45 | height: 40px;
46 | width: 100%;
47 | margin-bottom: 10px;
48 | `;
49 |
50 | const TextInputWithLabelWrapper = styled.input`
51 | font-family: 'Roboto Variable';
52 | padding: 0 8px;
53 | display: flex;
54 | justify-content: center;
55 | align-items: center;
56 | border-radius: 0px 5px 5px 0px;
57 | border-width: 1px 1px 1px 0px;
58 | border-style: solid;
59 | border-color: ${props => props.theme.color.primary};
60 | font-variation-settings: 'wght' 500;
61 | flex: 5;
62 | `;
63 |
64 |
65 | function TextInput (props: Props) {
66 | const detectEnter = (e: any) => {
67 | if (e.key === 'Enter' && props.handleEnter) {
68 | props.handleEnter(e.target.value);
69 | }
70 | };
71 |
72 | return (
73 | <>
74 | {props.label ?
75 |
76 |
77 | props.onChange(e.target.value)}
81 | onKeyPress={detectEnter}
82 | placeholder={props.placeholder}
83 | value={props.value}
84 | />
85 |
86 | :
87 |
88 | props.onChange(e.target.value)}
92 | onKeyPress={detectEnter}
93 | placeholder={props.placeholder}
94 | value={props.value}
95 | />
96 |
97 | }
98 | >
99 | );
100 | }
101 |
102 | export default TextInput;
103 |
--------------------------------------------------------------------------------
/public/contracts/Getters.json:
--------------------------------------------------------------------------------
1 | {"address":"0xc5a5C42992dECbae36851359345FE25997F5C42d","abi":[{"inputs":[{"internalType":"address","name":"_coreContractAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getCiphertext","outputs":[{"internalType":"uint256[2]","name":"","type":"uint256[2]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContents","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"string","name":"url","type":"string"},{"internalType":"string","name":"property","type":"string"},{"internalType":"uint256","name":"keyHash","type":"uint256"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"string","name":"zk","type":"string"}],"internalType":"struct ContractStorage.Content[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getCreator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getHashSalt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProperties","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getProperty","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"string","name":"zk","type":"string"}],"name":"getPublicKey","outputs":[{"internalType":"uint256[2]","name":"publicKey","type":"uint256[2]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getToken","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"contentId","type":"uint256"},{"internalType":"uint256","name":"ciphertext1","type":"uint256"},{"internalType":"uint256","name":"ciphertext2","type":"uint256"},{"internalType":"bool","name":"redeemed","type":"bool"}],"internalType":"struct ContractStorage.Token","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"contentId","type":"uint256"}],"name":"getTokens","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"contentId","type":"uint256"},{"internalType":"uint256","name":"ciphertext1","type":"uint256"},{"internalType":"uint256","name":"ciphertext2","type":"uint256"},{"internalType":"bool","name":"redeemed","type":"bool"}],"internalType":"struct ContractStorage.Token[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"}]}
--------------------------------------------------------------------------------
/public/contracts/prod/Getters.json:
--------------------------------------------------------------------------------
1 | {"abi":[{"inputs":[{"internalType":"address","name":"_coreContractAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getCiphertext","outputs":[{"internalType":"uint256[2]","name":"","type":"uint256[2]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getContents","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"string","name":"url","type":"string"},{"internalType":"string","name":"property","type":"string"},{"internalType":"uint256","name":"keyHash","type":"uint256"},{"internalType":"address","name":"creator","type":"address"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"string","name":"zk","type":"string"}],"internalType":"struct ContractStorage.Content[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getCreator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getHashSalt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getProperties","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getProperty","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"string","name":"zk","type":"string"}],"name":"getPublicKey","outputs":[{"internalType":"uint256[2]","name":"publicKey","type":"uint256[2]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getToken","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"contentId","type":"uint256"},{"internalType":"uint256","name":"ciphertext1","type":"uint256"},{"internalType":"uint256","name":"ciphertext2","type":"uint256"},{"internalType":"bool","name":"redeemed","type":"bool"}],"internalType":"struct ContractStorage.Token","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"contentId","type":"uint256"}],"name":"getTokens","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"contentId","type":"uint256"},{"internalType":"uint256","name":"ciphertext1","type":"uint256"},{"internalType":"uint256","name":"ciphertext2","type":"uint256"},{"internalType":"bool","name":"redeemed","type":"bool"}],"internalType":"struct ContractStorage.Token[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"}],"address":"0x5251893f3621392e04576a4b7849ebC39ec90d9D"}
--------------------------------------------------------------------------------
/src/utils/signature.ts:
--------------------------------------------------------------------------------
1 | import BN from 'bn.js';
2 | import hash from 'hash.js';
3 | import { curves as eCurves, ec as EllipticCurve } from 'elliptic';
4 | import assert from 'assert';
5 | import constantPointsHex from './constant_points.json';
6 |
7 | // Equals 2**251 + 17 * 2**192 + 1.
8 | const prime = new BN('800000000000011000000000000000000000000000000000000000000000001', 16);
9 | // Equals 2**251. This value limits msgHash and the signature parts.
10 | const maxEcdsaVal =
11 | new BN('800000000000000000000000000000000000000000000000000000000000000', 16);
12 |
13 | // Generate BN of used constants.
14 | const zeroBn = new BN('0', 16);
15 | const oneBn = new BN('1', 16);
16 | const twoBn = new BN('2', 16);
17 | const twoPow22Bn = new BN('400000', 16);
18 | const twoPow31Bn = new BN('80000000', 16);
19 | const twoPow63Bn = new BN('8000000000000000', 16);
20 |
21 | // Create a curve with stark curve parameters.
22 | const starkEc = new EllipticCurve(
23 | new eCurves.PresetCurve({
24 | type: 'short',
25 | prime: null,
26 | p: prime,
27 | a: '00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001',
28 | b: '06f21413 efbe40de 150e596d 72f7a8c5 609ad26c 15c915c1 f4cdfcb9 9cee9e89',
29 | n: '08000000 00000010 ffffffff ffffffff b781126d cae7b232 1e66a241 adc64d2f',
30 | hash: hash.sha256,
31 | gRed: false,
32 | g: constantPointsHex[1]
33 | })
34 | );
35 |
36 | const constantPoints = constantPointsHex.map(coords => (
37 | starkEc.curve.point(new BN(coords[0], 16), new BN(coords[1], 16))));
38 | const shiftPoint = constantPoints[0];
39 |
40 |
41 | const EC_ORDER = 3618502788666131213697322783095070105526743751716087489154079457884512865583;
42 |
43 | function getRandomPrivateKey() {
44 | return BigInt(Math.random() * (EC_ORDER - 1));
45 | }
46 |
47 | function privateKeyToECPointOnStarkCurve(privateKey) {
48 | return constantPoints[1].mul(new BN(privateKey, 10));
49 | }
50 |
51 | export function genKeypair() {
52 | const privKey = getRandomPrivateKey();
53 | const pubKey = privateKeyToECPointOnStarkCurve(privKey);
54 | return { privKey, pubKey };
55 | }
56 |
57 | export function genSharedKey() {
58 | const key1 = genKeypair();
59 | const key2 = genKeypair();
60 | return computeSharedKey(key1.privKey, key2.pubKey);
61 | }
62 |
63 | export function computeSharedKey(privateKey, publicKey) {
64 | const publicKeyPoint = starkEc.curve.point(new BN(publicKey[0], 10), new BN(publicKey[1], 10))
65 | return publicKeyPoint.mul(new BN(privateKey, 10)).getX().toString(10);
66 | }
67 |
68 | export function pedersen(input) {
69 | let point = shiftPoint;
70 | for (let i = 0; i < input.length; i++) {
71 | let x = new BN(input[i], 16);
72 | assert(x.gte(zeroBn) && x.lt(prime), 'Invalid input: ' + input[i]);
73 | for (let j = 0; j < 252; j++) {
74 | const pt = constantPoints[2 + i * 252 + j];
75 | assert(!point.getX().eq(pt.getX()));
76 | if (x.and(oneBn).toNumber() !== 0) {
77 | point = point.add(pt);
78 | }
79 | x = x.shrn(1);
80 | }
81 | }
82 | return point.getX().toString(16);
83 | }
84 |
--------------------------------------------------------------------------------
/public/circuits/verification_keys/SharedKey.json:
--------------------------------------------------------------------------------
1 | {
2 | "protocol": "groth16",
3 | "curve": "bn128",
4 | "nPublic": 1,
5 | "vk_alpha_1": [
6 | "19642524115522290447760970021746675789341356000653265441069630957431566301675",
7 | "15809037446102219312954435152879098683824559980020626143453387822004586242317",
8 | "1"
9 | ],
10 | "vk_beta_2": [
11 | [
12 | "3306678135584565297353192801602995509515651571902196852074598261262327790404",
13 | "6402738102853475583969787773506197858266321704623454181848954418090577674938"
14 | ],
15 | [
16 | "4983765881427969364617654516554524254158908221590807345159959200407712579883",
17 | "15158588411628049902562758796812667714664232742372443470614751812018801551665"
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 | "2528491300866434509699704412642731178102268865012248785813458721505586631446",
41 | "11078114351411396302492606863995638386506537365844689646898417550998267219414"
42 | ],
43 | [
44 | "17448560587075395769884970409122010185777125947946128673908172602768905142360",
45 | "7646900014588577959937375249841784560277351960820231527167492175864420231155"
46 | ],
47 | [
48 | "1",
49 | "0"
50 | ]
51 | ],
52 | "vk_alphabeta_12": [
53 | [
54 | [
55 | "5990981426838611487817331801723298853689232371402636505882752025826717861263",
56 | "6471600557194756298005957410208198947034348214534657394165503369790309076215"
57 | ],
58 | [
59 | "15002700749801870140343913307313851505416165248926784119266834715141460279528",
60 | "3830910611342760800353177932876565223705290639657811356514431363408808083245"
61 | ],
62 | [
63 | "16213272029928492311641815345584648151738099578429924053941653329679116056011",
64 | "11521059852145391195901894023171250860281638548552692281491114389569775909273"
65 | ]
66 | ],
67 | [
68 | [
69 | "21473208233673181545713372461262158409524966660539444635240255266528451743613",
70 | "12831374732506919217314780439582796881729424911714976211545279975915712437524"
71 | ],
72 | [
73 | "6384272187442204077342066657702496903903539015888454871400719146512483196930",
74 | "11896033867460826226898768849934024947887432723445089197160889467704536005586"
75 | ],
76 | [
77 | "4320872437228236846208766625647342285071164667482133950438695528545836489222",
78 | "13210525034366360416090582915961576197528924758377030567364985602065069567971"
79 | ]
80 | ]
81 | ],
82 | "IC": [
83 | [
84 | "16463174501805780021089853501376060963515156895898693392073063915686087047275",
85 | "13414674582095658163460475026964050547254898204628732893702194359321219522701",
86 | "1"
87 | ],
88 | [
89 | "13266294820635328754624242943449864774638145789973957978478542841176910167529",
90 | "3018470127095380838034414633037279244203248256028953869896205416849246480481",
91 | "1"
92 | ]
93 | ]
94 | }
--------------------------------------------------------------------------------
/hardhat.config.ts:
--------------------------------------------------------------------------------
1 | import "@nomiclabs/hardhat-waffle";
2 | import "@typechain/hardhat";
3 | import "hardhat-gas-reporter";
4 | import "solidity-coverage";
5 | import "@nomiclabs/hardhat-ethers";
6 | import "@nomiclabs/hardhat-etherscan";
7 |
8 | import { config as dotenvConfig } from "dotenv";
9 | import { HardhatUserConfig } from "hardhat/config";
10 | import { NetworkUserConfig } from "hardhat/types";
11 | import { resolve } from "path";
12 |
13 | import "./scripts/deploy";
14 |
15 | dotenvConfig({ path: resolve(__dirname, "./.env") });
16 |
17 | const chainIds = {
18 | goerli: 5,
19 | hardhat: 31337,
20 | kovan: 42,
21 | mainnet: 1,
22 | rinkeby: 4,
23 | ropsten: 3,
24 | };
25 |
26 | // Ensure that we have all the environment variables we need.
27 | const mnemonic: string | undefined = process.env.MNEMONIC;
28 | if (!mnemonic) {
29 | throw new Error("Please set your MNEMONIC in a .env file");
30 | }
31 |
32 | const infuraApiKey: string | undefined = process.env.INFURA_API_KEY;
33 | if (!infuraApiKey) {
34 | throw new Error("Please set your INFURA_API_KEY in a .env file");
35 | }
36 |
37 | function getChainConfig(network: keyof typeof chainIds): NetworkUserConfig {
38 | const url: string = `https://${network}.infura.io/v3/${infuraApiKey}`;
39 | return {
40 | accounts: {
41 | count: 10,
42 | mnemonic,
43 | path: "m/44'/60'/0'/0",
44 | },
45 | chainId: chainIds[network],
46 | url,
47 | };
48 | }
49 |
50 | const config: HardhatUserConfig = {
51 | defaultNetwork: "hardhat",
52 | networks: {
53 | // hardhat: {
54 | // accounts: {
55 | // mnemonic,
56 | // },
57 | // chainId: chainIds.hardhat,
58 | // },
59 | goerli: getChainConfig("goerli"),
60 | ropsten: getChainConfig("ropsten"),
61 | localhost: {
62 | url: "http://127.0.0.1:8545",
63 | },
64 | },
65 | paths: {
66 | artifacts: "./artifacts",
67 | cache: "./cache",
68 | sources: "./contracts",
69 | tests: "./test",
70 | },
71 | solidity: {
72 | compilers: [
73 | {
74 | version: "0.8.3",
75 | settings: {
76 | metadata: {
77 | // Not including the metadata hash
78 | // https://github.com/paulrberg/solidity-template/issues/31
79 | bytecodeHash: "none",
80 | },
81 | // Disable the optimizer when debugging
82 | // https://hardhat.org/hardhat-network/#solidity-optimizer-support
83 | optimizer: {
84 | enabled: true,
85 | runs: 800,
86 | },
87 | },
88 | },
89 | {
90 | version: "0.6.11",
91 | settings: {
92 | metadata: {
93 | // Not including the metadata hash
94 | // https://github.com/paulrberg/solidity-template/issues/31
95 | bytecodeHash: "none",
96 | },
97 | // Disable the optimizer when debugging
98 | // https://hardhat.org/hardhat-network/#solidity-optimizer-support
99 | optimizer: {
100 | enabled: true,
101 | runs: 800,
102 | },
103 | },
104 | },
105 | ],
106 | },
107 | /*
108 | typechain: {
109 | outDir: "typechain",
110 | target: "ethers-v5",
111 | },
112 | */
113 | etherscan: {
114 | apiKey: process.env.ETHERSCAN_API_KEY,
115 | },
116 | };
117 |
118 | export default config;
119 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const HtmlWebpackPlugin = require('html-webpack-plugin');
4 | const { CleanWebpackPlugin } = require('clean-webpack-plugin');
5 | const CopyPlugin = require('copy-webpack-plugin');
6 |
7 | //const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
8 |
9 | const createStyledComponentsTransformer = require('typescript-plugin-styled-components')
10 | .default;
11 | const styledComponentsTransformer = createStyledComponentsTransformer();
12 |
13 | module.exports = {
14 | mode: 'production',
15 | entry: {
16 | 'bundle.js': __dirname + '/src/index.tsx',
17 | },
18 | output: {
19 | path: path.join(__dirname, 'dist'),
20 | filename: 'bundle.min.js',
21 | publicPath: '/',
22 | },
23 |
24 | // Enable sourcemaps for debugging webpack's output.
25 | devtool: 'source-map',
26 | devServer: {
27 | port: 5000,
28 | historyApiFallback: true,
29 | publicPath: '/',
30 | },
31 |
32 | resolve: {
33 | // Add '.ts' and '.tsx' as resolvable extensions.
34 | extensions: ['.ts', '.tsx', '.js', '.jsx'],
35 | // we need this to reference files in the symlinked src/circuits directory
36 | symlinks: false,
37 | },
38 |
39 | module: {
40 | rules: [
41 | {
42 | test: /\.ts(x?)$/,
43 | exclude: [
44 | /node_modules/,
45 | /snarkjs.min.js/
46 | ],
47 | loader: 'ts-loader',
48 | options: {
49 | getCustomTransformers: () => ({
50 | before: [styledComponentsTransformer],
51 | }),
52 | },
53 | },
54 | {
55 | test: /\.css$/,
56 | use: ['style-loader', 'css-loader'],
57 | },
58 | {
59 | test: /\.(woff(2)?|ttf|eot|svg)$/,
60 | use: [
61 | {
62 | loader: 'file-loader',
63 | options: {
64 | name: '[name].[ext]',
65 | outputPath: 'fonts/'
66 | }
67 | }
68 | ]
69 | },
70 | {
71 | test: /snarkjs.min.js/,
72 | use: [
73 | {
74 | loader: 'file-loader',
75 | }
76 | ]
77 | },
78 | {
79 | test: /\.(js|jsx)$/,
80 | exclude: [
81 | /node_modules/,
82 | /snarkjs.min.js/
83 | ],
84 | use: {
85 | loader: "babel-loader",
86 | options: {
87 | presets: ["@babel/preset-env"]
88 | }
89 | }
90 | },
91 | {
92 | enforce: 'pre',
93 | test: /\.js$/,
94 | exclude: [
95 | /@ethersproject/
96 | ],
97 | loader: 'source-map-loader',
98 | },
99 | ],
100 | },
101 | plugins: [
102 | new CleanWebpackPlugin(),
103 | new CopyPlugin({
104 | patterns: [
105 | { from: 'public', to: '' },
106 | { from: 'circuits', to: 'circuits' }
107 | ]
108 | }),
109 | ],
110 |
111 | // When importing a module whose path matches one of the following, just
112 | // assume a corresponding global variable exists and use that instead.
113 | // This is important because it allows us to avoid bundling all of our
114 | // dependencies, which allows browsers to cache those libraries between builds.
115 | externals: {
116 | },
117 | node: {
118 | fs: "empty",
119 | tls: "empty"
120 | }
121 | };
122 |
--------------------------------------------------------------------------------
/src/app/App.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useCallback } from 'react';
2 | import { HashRouter, Switch } from 'react-router-dom';
3 | import Web3Modal from 'web3modal';
4 | import WalletConnectProvider from '@walletconnect/web3-provider';
5 | import { providers } from 'ethers';
6 |
7 | import config from '../../config';
8 |
9 | import Page from './Page';
10 |
11 | import NewToken from '../pages/NewToken';
12 | import Token from '../pages/Token';
13 | import Tokens from '../pages/Tokens';
14 | import ChooseUser from '../pages/ChooseUser';
15 |
16 | import eth from '../utils/ethAPI';
17 |
18 | const INFURA_ID = config.infuraId;
19 | const chain = config.chain;
20 |
21 | const web3Modal = new Web3Modal({
22 | network: chain,
23 | cacheProvider: true, // optional
24 | theme: 'light', // optional. Change to "dark" for a dark theme.
25 | providerOptions: {
26 | },
27 | });
28 |
29 | const App = () => {
30 | const [signer, setSigner] = useState();
31 |
32 | const logoutOfWeb3Modal = async () => {
33 | await web3Modal.clearCachedProvider();
34 | if (eth.provider &&
35 | eth.provider['provider'] &&
36 | typeof eth.provider['provider'].disconnect == 'function') {
37 | await eth.provider['provider'].disconnect();
38 | }
39 | setTimeout(() => {
40 | window.location.reload();
41 | }, 1);
42 | };
43 |
44 | const loadWeb3Modal = useCallback(async () => {
45 | const provider = await web3Modal.connect();
46 | const injectedProvider = new providers.Web3Provider(provider);
47 | eth.setProvider(injectedProvider, setSigner);
48 |
49 | provider.on('chainChanged', chainId => {
50 | console.log(`chain changed to ${chainId}! updating providers`);
51 | });
52 |
53 | provider.on('accountsChanged', () => {
54 | console.log('account changed!');
55 | eth.setProvider(injectedProvider, setSigner);
56 | });
57 |
58 | provider.on('disconnect', (code, reason) => {
59 | console.log(code, reason);
60 | logoutOfWeb3Modal();
61 | });
62 | }, []);
63 |
64 | useEffect(() => {
65 | const { env } = config;
66 | let provider;
67 | if (env === 'production') {
68 | loadWeb3Modal();
69 | } else {
70 | const network_url = 'http://localhost:8545';
71 | provider = new providers.JsonRpcProvider(network_url);
72 | eth.setProvider(provider, setSigner);
73 | }
74 | }, []);
75 |
76 | return (
77 |
78 |
79 |
86 |
93 |
100 |
107 |
114 |
115 |
116 | );
117 | };
118 |
119 | export default App;
120 |
--------------------------------------------------------------------------------
/contracts/Getters.sol:
--------------------------------------------------------------------------------
1 | pragma solidity >=0.7.6;
2 | pragma experimental ABIEncoderV2;
3 |
4 | import "./Core.sol";
5 | import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
6 | import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
7 | import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
8 |
9 |
10 | interface ICore {
11 | function getPublicKey(address _address, string calldata zk) view external returns (uint256[2] memory publicKey);
12 |
13 | function getContent(uint256 contentId) view external returns (ContractStorage.Content memory);
14 |
15 | function contentCount() view external returns (uint256);
16 |
17 | function getToken(uint id) view external returns (ContractStorage.Token memory);
18 |
19 | function getTokenIds(uint256 contentId) view external returns (uint256[] memory);
20 |
21 | function getNumOfProperties() view external returns (uint256 length);
22 |
23 | function getProperty(uint256 id) view external returns (string memory);
24 | }
25 |
26 | contract Getters {
27 |
28 | ICore coreContract;
29 |
30 | constructor(
31 | address _coreContractAddress
32 | ) public {
33 | coreContract = ICore(_coreContractAddress);
34 | }
35 |
36 | function getPublicKey(address _address, string calldata zk) public view returns (uint256[2] memory publicKey) {
37 | return coreContract.getPublicKey(_address, zk);
38 | }
39 |
40 | function getContents() public view returns (ContractStorage.Content[] memory) {
41 | ContractStorage.Content[] memory ret =
42 | new ContractStorage.Content[](coreContract.contentCount());
43 |
44 | for (uint256 i = 0; i < coreContract.contentCount(); i++) {
45 | ret[i] = coreContract.getContent(i);
46 | }
47 |
48 | return ret;
49 | }
50 |
51 | function getCreator(uint256 id) public view returns (address) {
52 | return coreContract.getContent(id).creator;
53 | }
54 |
55 | function getCiphertext(uint256 tokenId) public view returns (uint256[2] memory) {
56 | ContractStorage.Token memory token = coreContract.getToken(tokenId);
57 | require(token.redeemed == true, 'DataMarketplaceCore/ciphertext-not-posted');
58 | uint256[2] memory ciphertext;
59 | ciphertext[0] = token.ciphertext1;
60 | ciphertext[1] = token.ciphertext2;
61 | return ciphertext;
62 | }
63 |
64 | function getProperty(uint256 id) public view returns (string memory) {
65 | return coreContract.getContent(id).property;
66 | }
67 |
68 | function getProperties() public view returns (string[] memory) {
69 | uint256 length = coreContract.getNumOfProperties();
70 | string[] memory _properties = new string[](length);
71 | for (uint i=1; i<=length; i++) {
72 | _properties[i-1] = coreContract.getProperty(i);
73 | }
74 | return _properties;
75 | }
76 |
77 | function getToken(uint256 tokenId) public view returns (ContractStorage.Token memory) {
78 | return coreContract.getToken(tokenId);
79 | }
80 |
81 | function getTokens(uint256 contentId) public view returns (ContractStorage.Token[] memory) {
82 | uint256[] memory tokenIds = coreContract.getTokenIds(contentId);
83 | uint tokenCount = tokenIds.length;
84 | ContractStorage.Token[] memory ret =
85 | new ContractStorage.Token[](tokenCount);
86 |
87 | for (uint256 i = 0; i < tokenCount; i++) {
88 | ret[i] = coreContract.getToken(tokenIds[i]);
89 | }
90 |
91 | return ret;
92 | }
93 |
94 | function getHashSalt() public view returns (uint256) {
95 | // DarkForestCore.SnarkConstants memory s = darkForestCore.snarkConstants();
96 | return 0;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/pages/content/Hash.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import styled from 'styled-components';
3 | import assert from 'assert';
4 |
5 | import TextInput from '../../components/TextInput';
6 | import { Large } from '../../components/text';
7 | import Resize from '../../components/Resize';
8 |
9 | import {
10 | ZKFunctions,
11 | stringToNum,
12 | } from '../../utils/crypto';
13 |
14 | import { InputProps } from '../../types/content';
15 | import { ZKTypes } from '../../types';
16 |
17 |
18 | const HashWrapper = styled.div`
19 | padding: 20px;
20 | width: 100%;
21 | box-sizing: border-box;
22 | `;
23 |
24 | const HashText = styled(Large)`
25 | font-size: 18px;
26 | `;
27 |
28 | type HashProps = {
29 | property: BigInt;
30 | message?: string;
31 | }
32 |
33 | const Hash = (props: HashProps) => {
34 | const hashString = props.property.toString();
35 | const [display, setDisplay] = useState(null);
36 | const [containerRef, setContainerRef] = useState(null);
37 | const [contentRef, setContentRef] = useState(null);
38 |
39 | useEffect(() => {
40 | const _display = props.message ? props.message : hashString;
41 | setDisplay(_display);
42 | }, [props]);
43 |
44 | const sliceFunction = (size) => {
45 | const hashArray = hashString.split('');
46 |
47 | const halfSize = Math.floor((size-3) / 2);
48 | const hashFirstHalf = hashArray.slice(0, halfSize).join('');
49 | const hashLastHalf = hashArray.slice(hashArray.length - halfSize).join('');
50 | return `${hashFirstHalf}...${hashLastHalf}`;
51 | };
52 |
53 | return (
54 |
60 |
61 | {display}
62 |
63 |
64 | );
65 | };
66 |
67 | const HashInput = (props: InputProps) => {
68 |
69 | useEffect(() => {
70 | props.setPreimage('');
71 | }, []);
72 |
73 | return (
74 |
79 | );
80 | };
81 |
82 | const isCiphertext = (value) => {
83 | return typeof value.iv === 'bigint' &&
84 | (Array.isArray(value.data) && typeof value.data[0] === 'bigint');
85 | };
86 |
87 | const assertContent = (content) => {
88 | assert(isCiphertext(content.cipher));
89 | assert(typeof content.property === 'bigint');
90 | };
91 |
92 | const assertMessage = (message) => assert(typeof message === 'string');
93 |
94 | const computeProperty = (preimage): any[] => {
95 | const numPreimage = stringToNum(preimage);
96 | const salt = BigInt('0');
97 | return [numPreimage, salt];
98 | };
99 |
100 | const assertProofInputs = (args: any[]) => {
101 | assert(args.length === 3);
102 | assert(typeof args[0] === 'bigint');
103 | assert(typeof args[1] === 'bigint');
104 | assert(typeof args[2] === 'bigint');
105 | };
106 |
107 | const json = {
108 | input: HashInput,
109 | display: Hash,
110 | list: Hash,
111 | decrypt: (zk, ...args) =>
112 | ZKFunctions[zk].decryptMessageCiphertext(...args),
113 | computeProperty,
114 | prover: {
115 | [ZKTypes.SNARK]: ZKFunctions[ZKTypes.SNARK].provers.hash,
116 | [ZKTypes.STARK]: ZKFunctions[ZKTypes.STARK].provers.hash,
117 | },
118 | verifier: {
119 | [ZKTypes.SNARK]: ZKFunctions[ZKTypes.SNARK].verifiers.hash,
120 | [ZKTypes.STARK]: ZKFunctions[ZKTypes.STARK].verifiers.hash,
121 | },
122 | assertProofInputs,
123 | assertContent,
124 | assertMessage,
125 | };
126 | export default json;
127 |
--------------------------------------------------------------------------------
/src/pages/Tokens.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import styled from 'styled-components';
3 |
4 | import { Button } from '../components/Button';
5 | import { Header } from '../components/text';
6 |
7 | import PropertyToggle from '../app/PropertyToggle';
8 | import { ContentElements } from './Content';
9 |
10 | import eth from '../utils/ethAPI';
11 | import ipfs from '../utils/ipfs';
12 | import { Parsers } from '../utils/parsers';
13 | import {
14 | ContentProperties,
15 | Snark,
16 | Stark,
17 | ZKTypes,
18 | } from '../types';
19 |
20 | const TokensWrapper = styled.div`
21 | display: flex;
22 | flex-direction: column;
23 | align-items: center;
24 | margin-top: 10%;
25 | margin-bottom: 10px;
26 | margin-left: 15%;
27 | margin-right: 15%;
28 | `;
29 |
30 | const TokenWrapper = styled.div`
31 | display: flex;
32 | flex-direction: row;
33 | width: calc(452px - 22px);
34 | height: ${props => props.theme.spacing(6)};
35 | background-color: ${props => props.theme.color.white};
36 | border: ${props => `1px solid ${props.theme.color.grey30}`};
37 | margin-bottom: 10px;
38 | border-radius: 4px;
39 | padding: 11px;
40 | cursor: pointer;
41 | align-items: center;
42 | :hover {
43 | background-color: ${props => props.theme.color.grey10};
44 | }
45 | `;
46 |
47 | const PostsWrapper = styled.div`
48 | display: flex;
49 | flex-direction: column;
50 | flex: 1;
51 | width: calc(100% - 100px);
52 | padding-left: 50px;
53 | padding-right: 50px;
54 | padding-top: 10px;
55 | align-items: center;
56 | `;
57 |
58 | type TokenProps = {
59 | url: string;
60 | zk: ZKTypes;
61 | property: ContentProperties;
62 | onClick: () => void;
63 | };
64 |
65 | const Token = (props: TokenProps) => {
66 | const [property, setProperty] = useState(null);
67 | const [loading, setLoading] = useState(true);
68 |
69 | useEffect(() => {
70 | ipfs.getProof(props.url, props.zk).then(proof => {
71 | // @ts-ignore
72 | const { contentProperty } = Parsers[props.zk][props.property](proof);
73 | setProperty(contentProperty);
74 | setLoading(false);
75 | });
76 | }, []);
77 |
78 | const PropertyListElement = ContentElements[props.property].list;
79 |
80 | return (
81 |
82 | {!loading ?
83 |
84 | : null}
85 |
86 | );
87 | };
88 |
89 | const Tokens = (props) => {
90 | const [tokens, setTokens] = useState([]);
91 | const [property, setProperty] =
92 | useState(ContentProperties.HASH);
93 |
94 | useEffect(() => {
95 | if (props.signer) {
96 | eth.api.getContents().then(contents => {
97 | setTokens(contents);
98 | });
99 | }
100 | }, [props.signer, property]);
101 |
102 | const sendToToken = (contentId) => () => {
103 | props.history.push(`/tokens/${contentId}`);
104 | };
105 |
106 | const sendToNewToken = () => {
107 | props.history.push('/tokens/new');
108 | };
109 |
110 | return (
111 | <>
112 |
113 |
114 |
115 |
118 |
119 |
120 | {tokens.filter(_ => _.property === property).map(_ => )}
127 |
128 | >
129 | );
130 | };
131 |
132 | export default Tokens;
133 |
--------------------------------------------------------------------------------
/src/pages/NewToken.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import styled from 'styled-components';
3 |
4 | import { Button } from '../components/Button';
5 | import { Large } from '../components/text';
6 | import Spinner from '../components/Spinner';
7 | import TextInput from '../components/TextInput';
8 | import Toggle from '../components/Toggle';
9 | import PropertyToggle from '../app/PropertyToggle';
10 | import { ContentInput, ContentElements } from './Content';
11 | import {
12 | setKey,
13 | ZKFunctions,
14 | } from '../utils/crypto';
15 | import eth from '../utils/ethAPI';
16 | import ipfs from '../utils/ipfs';
17 |
18 | import {
19 | ContentProperties,
20 | ZKTypes,
21 | IpfsResponse,
22 | Snark,
23 | Stark,
24 | } from '../types';
25 |
26 |
27 | const Title = styled(Large)`
28 | margin-bottom: 10px;
29 | `;
30 |
31 | const NewTokenWrapper = styled.div`
32 | display: flex;
33 | flex-direction: column;
34 | align-items: center;
35 | margin-left: 20%;
36 | margin-right: 20%;
37 | margin-top: 10%;
38 | height: 100%;
39 | `;
40 |
41 | const NewToken = (props) => {
42 | const [preimage, setPreimage] = useState('');
43 | const [property, setProperty] =
44 | useState(ContentProperties.HASH);
45 | const [zk, setZK] =
46 | useState(ZKTypes.SNARK);
47 | const [price, setPrice] = useState(BigInt(0));
48 | const [loading, setLoading] = useState(false);
49 | const [loadingMessage, setLoadingMessage] = useState('');
50 |
51 | const sendToTokens = () => {
52 | props.history.push('/tokens');
53 | };
54 |
55 | const onSell = async () => {
56 | setLoading(true);
57 |
58 | const commitProof = (proof: Snark | Stark) => {
59 | ipfs.addProof(proof, zk).then((result: IpfsResponse) => {
60 | let url = result.path;
61 |
62 | setKey(url, sharedKey);
63 |
64 | eth.api.postUrl(url, keyHash, property, price, zk)
65 | .then(() => {
66 | sendToTokens();
67 | setLoading(false);
68 | })
69 | .catch(error => {
70 | setLoading(false);
71 | alert(error.message);
72 | });
73 | localStorage.setItem(url, preimage);
74 | });
75 | };
76 |
77 | const sharedKey = await ZKFunctions[zk].genSharedKey();
78 | const keyHash = await ZKFunctions[zk].hash(sharedKey, BigInt(0));
79 |
80 | setLoadingMessage('generating proof');
81 | const {
82 | prover,
83 | computeProperty,
84 | assertProofInputs,
85 | } = ContentElements[property];
86 | const values = await computeProperty(preimage, sharedKey);
87 | const proofInputs = [sharedKey, ...values];
88 | assertProofInputs(proofInputs);
89 | prover[zk](proofInputs).then(commitProof);
90 | };
91 |
92 | const setPriceBigInt = (value: string) => {
93 | if (parseInt(value)) {
94 | setPrice(BigInt(value));
95 | }
96 | };
97 |
98 | return (
99 | <>
100 | {loading ?
101 |
102 | :
103 |
104 | Sell your Token
105 |
106 |
111 |
116 |
122 |
125 |
126 | }
127 | >
128 | );
129 | };
130 |
131 | export default NewToken;
132 |
--------------------------------------------------------------------------------
/src/app/NavigationBar.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import styled from 'styled-components';
3 | import { Link } from 'react-router-dom';
4 |
5 | import { Button } from '../components/Button';
6 | import { Large } from '../components/text';
7 | import Ipfs from './Ipfs';
8 | import { selfTheme as theme } from '../styles/theme';
9 |
10 |
11 | interface NavBarElementProps {
12 | active: boolean;
13 | }
14 |
15 | const color = theme.color.darkText;
16 | const NavBarElementWrapper = styled.div`
17 | border-bottom: ${props => (props.active ?
18 | `3px solid ${color}` : 'none')};
19 | :hover {
20 | border-bottom: ${() => `3px solid ${color}`};
21 | div {
22 | color: ${color};
23 | }
24 | }
25 | display: flex;
26 | align-items: center;
27 | div {
28 | color: ${props => (props.active ? color : 'default')};
29 | }
30 | `;
31 |
32 | type NavigationBarElementProps = {
33 | path: string;
34 | title: string;
35 | icon?: string;
36 | activeTab: string;
37 | };
38 |
39 | const NavigationBarElement = (props: NavigationBarElementProps) => {
40 | return (
41 |
42 |
43 | {props.title}
44 |
45 |
46 | );
47 | };
48 |
49 | const NavigationBarWrapper = styled.div`
50 | width: 100%;
51 | height: 60px;
52 | display: flex;
53 | align-items: center;
54 | flex-direction: row;
55 | background-color: ${props => props.theme.color.white};
56 | border-bottom: ${props => `1px solid ${props.theme.color.grey30}`};
57 | a {
58 | text-decoration: none;
59 | }
60 | position: fixed;
61 | `;
62 |
63 | const ElementsWrapper = styled.div`
64 | flex: 2;
65 | height: 100%;
66 | display: flex;
67 | flex-direction: row;
68 | justify-content: space-around;
69 | `;
70 |
71 | const SidebarWrapper = styled.div`
72 | display: flex;
73 | justify-content: space-around;
74 | flex: 1;
75 | align-items: center;
76 | `;
77 |
78 | const LogoutButton = styled(Button)`
79 | display: flex;
80 | margin-right: 10px;
81 | padding: 10px;
82 | flex: 1;
83 | `;
84 |
85 | const Title = styled(Large)`
86 | margin-right: 20px;
87 | color: ${color};
88 | `;
89 |
90 | type NavigationBarProps = {
91 | activeTab: string;
92 | history: any;
93 | signer: any;
94 | web3: any;
95 | }
96 |
97 | const NavigationBar = (props: NavigationBarProps) => {
98 | const [address, setAddress] = useState('');
99 | const [addresses, setAddresses] = useState([]);
100 |
101 | useEffect(() => {
102 | if (props.signer) {
103 | props.signer.getAddress().then(add => {
104 | setAddress(add);
105 | });
106 | props.signer.provider.listAccounts().then(setAddresses);
107 | }
108 | }, [props.signer]);
109 |
110 | const sendToChooseUser = () => {
111 | props.history.push('/choose-user');
112 | };
113 |
114 | return (
115 |
116 |
117 |
122 |
123 | {addresses.length > 1 ?
124 |
125 | Choose Address
126 |
127 | : null}
128 | {address ?
129 |
130 | {address.slice(0,6)}
131 |
132 |
133 | Logout
134 |
135 |
136 | :
137 |
138 |
139 | {}}>
140 | Login
141 |
142 |
143 | }
144 |
145 | );
146 | };
147 |
148 | export default NavigationBar;
149 |
--------------------------------------------------------------------------------
/crypto/babyjub.js:
--------------------------------------------------------------------------------
1 | const F1Field = require('ffjavascript').F1Field;
2 | const Scalar = require('ffjavascript').Scalar;
3 | const utils = require('ffjavascript').utils;
4 |
5 | exports.addPoint = addPoint;
6 | exports.mulPointEscalar = mulPointEscalar;
7 | exports.inCurve = inCurve;
8 | exports.inSubgroup = inSubgroup;
9 | exports.packPoint = packPoint;
10 | exports.unpackPoint = unpackPoint;
11 |
12 |
13 | exports.p = Scalar.fromString('3618502788666131213697322783095070105623107215331596699973092056135872020481');
14 | const F = new F1Field(exports.p);
15 | exports.F = F;
16 |
17 | exports.Generator = [
18 | F.e('874739451078007766457464989774322083649278607533249481151382481072868806602'),
19 | F.e('152666792071518830868575557812948353041420400780739481342941381225525861407')
20 | ];
21 |
22 | exports.beta = F.e('3141592653589793238462643383279502884197169399375105820974944592307816406665');
23 | exports.Base8 = [
24 | F.e('5299619240641551281634865583518297030282874472190772894086521144482721001553'),
25 | F.e('16950150798460657717958625567821834550301663161624707787222815936182638968203')
26 | ];
27 | exports.order = Scalar.fromString('3618502788666131213697322783095070105623107215331596699973092056135872020481');
28 | exports.subOrder = Scalar.shiftRight(exports.order, 3);
29 | exports.A = F.e('168700');
30 | exports.D = F.e('168696');
31 |
32 |
33 | function addPoint(a,b) {
34 |
35 | const res = [];
36 |
37 | /* does the equivalent of:
38 | res[0] = bigInt((a[0]*b[1] + b[0]*a[1]) * bigInt(bigInt('1') + d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q);
39 | res[1] = bigInt((a[1]*b[1] - cta*a[0]*b[0]) * bigInt(bigInt('1') - d*a[0]*b[0]*a[1]*b[1]).inverse(q)).affine(q);
40 | */
41 |
42 | const beta = F.mul(a[0],b[1]);
43 | const gamma = F.mul(a[1],b[0]);
44 | const delta = F.mul(
45 | F.sub(a[1], F.mul(exports.A, a[0])),
46 | F.add(b[0], b[1])
47 | );
48 | const tau = F.mul(beta, gamma);
49 | const dtau = F.mul(exports.D, tau);
50 |
51 | res[0] = F.div(
52 | F.add(beta, gamma),
53 | F.add(F.one, dtau)
54 | );
55 |
56 | res[1] = F.div(
57 | F.add(delta, F.sub(F.mul(exports.A,beta), gamma)),
58 | F.sub(F.one, dtau)
59 | );
60 |
61 | return res;
62 | }
63 |
64 | function mulPointEscalar(base, e) {
65 | let res = [F.e('0'),F.e('1')];
66 | let rem = e;
67 | let exp = base;
68 |
69 | while (! Scalar.isZero(rem)) {
70 | if (Scalar.isOdd(rem)) {
71 | res = addPoint(res, exp);
72 | }
73 | exp = addPoint(exp, exp);
74 | rem = Scalar.shiftRight(rem, 1);
75 | }
76 |
77 | return res;
78 | }
79 |
80 | function inSubgroup(P) {
81 | if (!inCurve(P)) return false;
82 | const res= mulPointEscalar(P, exports.subOrder);
83 | return (F.isZero(res[0]) && F.eq(res[1], F.one));
84 | }
85 |
86 | function inCurve(P) {
87 |
88 | const x2 = F.square(P[0]);
89 | const y2 = F.square(P[1]);
90 |
91 | if (!F.eq(
92 | F.add(F.mul(exports.A, x2), y2),
93 | F.add(F.one, F.mul(F.mul(x2, y2), exports.D)))) return false;
94 |
95 | return true;
96 | }
97 |
98 | function packPoint(P) {
99 | const buff = utils.leInt2Buff(P[1], 32);
100 | if (F.lt(P[0], F.zero)) {
101 | buff[31] = buff[31] | 0x80;
102 | }
103 | return buff;
104 | }
105 |
106 | function unpackPoint(_buff) {
107 | const buff = Buffer.from(_buff);
108 | let sign = false;
109 | const P = new Array(2);
110 | if (buff[31] & 0x80) {
111 | sign = true;
112 | buff[31] = buff[31] & 0x7F;
113 | }
114 | P[1] = utils.leBuff2int(buff);
115 | if (Scalar.gt(P[1], exports.p)) return null;
116 |
117 | const y2 = F.square(P[1]);
118 |
119 | let x = F.sqrt(F.div(
120 | F.sub(F.one, y2),
121 | F.sub(exports.A, F.mul(exports.D, y2))));
122 |
123 | if (x == null) return null;
124 |
125 | if (sign) x = F.neg(x);
126 |
127 | P[0] = x;
128 |
129 | return P;
130 | }
131 |
--------------------------------------------------------------------------------
/artifacts/contracts/DarkForestCore.sol/DarkForestCore.json:
--------------------------------------------------------------------------------
1 | {
2 | "_format": "hh-sol-artifact-1",
3 | "contractName": "DarkForestCore",
4 | "sourceName": "contracts/DarkForestCore.sol",
5 | "abi": [
6 | {
7 | "inputs": [],
8 | "stateMutability": "nonpayable",
9 | "type": "constructor"
10 | },
11 | {
12 | "inputs": [
13 | {
14 | "internalType": "uint256",
15 | "name": "key",
16 | "type": "uint256"
17 | }
18 | ],
19 | "name": "planets",
20 | "outputs": [
21 | {
22 | "components": [
23 | {
24 | "internalType": "address",
25 | "name": "owner",
26 | "type": "address"
27 | },
28 | {
29 | "internalType": "bool",
30 | "name": "isHomePlanet",
31 | "type": "bool"
32 | }
33 | ],
34 | "internalType": "struct DarkForestUtils.Planet",
35 | "name": "",
36 | "type": "tuple"
37 | }
38 | ],
39 | "stateMutability": "view",
40 | "type": "function"
41 | },
42 | {
43 | "inputs": [],
44 | "name": "s",
45 | "outputs": [
46 | {
47 | "components": [
48 | {
49 | "internalType": "uint256",
50 | "name": "PLANETHASH_KEY",
51 | "type": "uint256"
52 | }
53 | ],
54 | "internalType": "struct DarkForestUtils.SnarkConstants",
55 | "name": "snarkConstants",
56 | "type": "tuple"
57 | }
58 | ],
59 | "stateMutability": "view",
60 | "type": "function"
61 | },
62 | {
63 | "inputs": [],
64 | "name": "snarkConstants",
65 | "outputs": [
66 | {
67 | "components": [
68 | {
69 | "internalType": "uint256",
70 | "name": "PLANETHASH_KEY",
71 | "type": "uint256"
72 | }
73 | ],
74 | "internalType": "struct DarkForestUtils.SnarkConstants",
75 | "name": "",
76 | "type": "tuple"
77 | }
78 | ],
79 | "stateMutability": "view",
80 | "type": "function"
81 | }
82 | ],
83 | "bytecode": "0x608060405234801561001057600080fd5b50604080518082018252338152600160208083018281527f0b8f3e5cb1e0519c520b88073ab3be1313af840e2f2682ba2e77c948b27bcb8a6000908152825292517f190130b61c65d0bc84a5bab3064c7d963327e80b54c17dbf4714f663cc5f2678805494511515600160a01b026001600160a81b03199095166001600160a01b0392909216919091179390931790925582519182019092527f04c06f1329eb7d8e37e558c329a5ffc2b896718ab7dd897b7d45feae09a285d7908190529055610160806100df6000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806326c1e7501461004657806351baf19e146100f757806386b714e214610124575b600080fd5b6100bf61005436600461013b565b6040805180820190915260008082526020820152506000908152602081815260409182902082518084019093525473ffffffffffffffffffffffffffffffffffffffff8116835274010000000000000000000000000000000000000000900460ff1615159082015290565b60408051825173ffffffffffffffffffffffffffffffffffffffff168152602092830151151592810192909252015b60405180910390f35b60408051602080820183526000909152815190810190915260015481525b604051905181526020016100ee565b604080516020810190915260015481526101159081565b60006020828403121561014c578081fd5b503591905056fea164736f6c6343000803000a",
84 | "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100415760003560e01c806326c1e7501461004657806351baf19e146100f757806386b714e214610124575b600080fd5b6100bf61005436600461013b565b6040805180820190915260008082526020820152506000908152602081815260409182902082518084019093525473ffffffffffffffffffffffffffffffffffffffff8116835274010000000000000000000000000000000000000000900460ff1615159082015290565b60408051825173ffffffffffffffffffffffffffffffffffffffff168152602092830151151592810192909252015b60405180910390f35b60408051602080820183526000909152815190810190915260015481525b604051905181526020016100ee565b604080516020810190915260015481526101159081565b60006020828403121561014c578081fd5b503591905056fea164736f6c6343000803000a",
85 | "linkReferences": {},
86 | "deployedLinkReferences": {}
87 | }
88 |
--------------------------------------------------------------------------------
/scripts/solbuilder.ts:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 |
3 | import { execSync } from 'child_process';
4 | import fs from 'fs';
5 | import path from 'path';
6 | import { camelCase, upperCase } from './utils';
7 |
8 | const cwd = process.cwd();
9 | const compiledCircuitsDirectory = path.resolve(`${cwd}/compiledCircuits`);
10 | const outputDirectory = path.resolve(`${cwd}/contracts`);
11 |
12 | try {
13 | const header =
14 | `pragma solidity >=0.7.6;\n` +
15 | `pragma abicoder v2;\n` +
16 | `import "./Pairing.sol";\n`;
17 | const verify = `
18 | using Pairing for *;
19 | struct VerifyingKey {
20 | Pairing.G1Point alfa1;
21 | Pairing.G2Point beta2;
22 | Pairing.G2Point gamma2;
23 | Pairing.G2Point delta2;
24 | Pairing.G1Point[] IC;
25 | }
26 | struct Proof {
27 | Pairing.G1Point A;
28 | Pairing.G2Point B;
29 | Pairing.G1Point C;
30 | }
31 | function verify(
32 | uint[] memory input,
33 | Proof memory proof,
34 | VerifyingKey memory vk
35 | ) internal view returns (uint) {
36 | uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
37 | require(input.length + 1 == vk.IC.length,"verifier-bad-input");
38 | // Compute the linear combination vk_x
39 | Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0);
40 | for (uint i = 0; i < input.length; i++) {
41 | require(input[i] < snark_scalar_field,"verifier-gte-snark-scalar-field");
42 | vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i]));
43 | }
44 | vk_x = Pairing.addition(vk_x, vk.IC[0]);
45 | if (!Pairing.pairingProd4(
46 | Pairing.negate(proof.A), proof.B,
47 | vk.alfa1, vk.beta2,
48 | vk_x, vk.gamma2,
49 | proof.C, vk.delta2
50 | )) return 1;
51 | return 0;
52 | }
53 | function verifyProof(
54 | uint[2] memory a,
55 | uint[2][2] memory b,
56 | uint[2] memory c,
57 | uint[] memory input,
58 | VerifyingKey memory vk
59 | ) public view returns (bool) {
60 | Proof memory proof;
61 | proof.A = Pairing.G1Point(a[0], a[1]);
62 | proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
63 | proof.C = Pairing.G1Point(c[0], c[1]);
64 | if (verify(input, proof, vk) == 0) {
65 | return true;
66 | } else {
67 | return false;
68 | }
69 | }`;
70 | const circuits = fs.readdirSync(`${compiledCircuitsDirectory}`);
71 | const verifiers = circuits.map(circuit => buildVerifier(circuit.split('.')[0])).join('\n');
72 | const contract =
73 | `${header}
74 | library Verifier {
75 | ${verify}
76 |
77 | ${verifiers}}`;
78 | fs.writeFileSync(`${outputDirectory}/Verifier.sol`, contract);
79 | } catch (error) {
80 | console.log(error);
81 | process.exit(1);
82 | }
83 |
84 | function buildVerifier(circuitName) {
85 | execSync(`npx snarkjs zkey export solidityverifier ${compiledCircuitsDirectory}/${circuitName}/circuit.zkey verifier.sol`, {
86 | stdio: 'inherit',
87 | });
88 | const data = fs.readFileSync('verifier.sol').toString();
89 | execSync('rm ' + 'verifier.sol', { stdio: 'inherit' });
90 | const strList = data.match('(?<=VerifyingKey memory vk.*{\n )(.*\n)*(?=\n* }\n.*function)');
91 | const pairings = strList[0];
92 |
93 | const numInputs = parseInt(pairings.match('(?<=vk.IC = new Pairing\.G1Point[\[\]]).*(?=;)')[0].match('\(([^()]+)\)')[0]) - 1;
94 | const body =
95 | `function ${camelCase(circuitName)}VerifyingKey() internal pure returns (VerifyingKey memory vk) {
96 | ${pairings}
97 | }
98 | function verify${upperCase(circuitName)}Proof(
99 | uint256[2] memory a,
100 | uint256[2][2] memory b,
101 | uint256[2] memory c,
102 | uint256[${numInputs}] memory input
103 | ) public view returns (bool) {
104 | uint256[] memory inputValues = new uint256[](input.length);
105 | for (uint256 i = 0; i < input.length; i++) {
106 | inputValues[i] = input[i];
107 | }
108 | return verifyProof(a, b, c, inputValues, ${camelCase(circuitName)}VerifyingKey());
109 | }\n`;
110 |
111 | return body;
112 | }
113 |
--------------------------------------------------------------------------------
/src/utils/prover.ts:
--------------------------------------------------------------------------------
1 | import { post } from './api';
2 | import { Snark, Stark, ZKTypes } from '../types';
3 | import config from '../../config';
4 | const STARKWARE_APP = config.starkwareApp;
5 |
6 | const wasmPath = '/circuits/wasm/';
7 | const keyPath = '/circuits/keys/';
8 | const verificationKeyPath = '/circuits/verification_keys/';
9 |
10 | function camelCase(str) {
11 | return str.split('-').map(_ => {
12 | return _[0].toUpperCase() + _.slice(1);
13 | }).join('');
14 | }
15 |
16 | // HELPERS
17 | async function proveSnark(circuit, inputs): Promise {
18 | // @ts-ignore
19 | const { proof, publicSignals } = await snarkjs.groth16.fullProve(
20 | inputs,
21 | wasmPath + camelCase(circuit) + '.wasm',
22 | keyPath + camelCase(circuit) + '.zkey',
23 | );
24 |
25 | return { proof, publicSignals };
26 | }
27 |
28 | async function proveStark(circuit, inputs): Promise {
29 | return new Promise((resolve, reject) => {
30 | post(`${STARKWARE_APP}/prove`, { circuit, inputs }).then(res => {
31 | const proof = {
32 | fact: res.res.fact,
33 | programOutputs: res.res.programOutputs.map(BigInt),
34 | };
35 | resolve(proof);
36 | }).catch(err => {
37 | reject(err);
38 | });
39 | });
40 | }
41 |
42 | async function prove(circuit, inputs, zk: ZKTypes): Promise {
43 | const prover = zk === 'snark' ? proveSnark : proveStark;
44 | return prover(circuit, inputs);
45 | }
46 |
47 | async function verifyStark(
48 | circuit: string,
49 | proof: Snark & Stark,
50 | ): Promise {
51 | // send to sharp
52 | if ('programOutputs' in proof) {
53 | return new Promise(resolve => resolve(true));
54 | } else {
55 | throw new Error('proof is not a STARK');
56 | }
57 | }
58 |
59 | async function verifySnark(
60 | circuit: string,
61 | proof: Snark & Stark,
62 | ): Promise {
63 | if ('publicSignals' in proof) {
64 | const vKey = await fetch(verificationKeyPath + camelCase(circuit) + '.json')
65 | .then(res => {
66 | return res.json();
67 | });
68 |
69 | // @ts-ignore
70 | const res = await snarkjs.groth16.verify(
71 | vKey,
72 | proof.publicSignals,
73 | proof.proof,
74 | );
75 | return res;
76 | } else {
77 | throw new Error('proof is not a SNARK');
78 | }
79 | }
80 |
81 | async function verify(
82 | circuit: string,
83 | proof: Snark & Stark,
84 | zk: ZKTypes,
85 | ): Promise {
86 | const verifier = zk === 'snark' ? verifySnark : verifyStark;
87 | return verifier(circuit, proof);
88 | }
89 |
90 | // PROVERS
91 | export async function proveEncryption(
92 | zk: ZKTypes,
93 | args,
94 | ) {
95 | return prove('encryption', {
96 | key: args[0].toString(),
97 | seller_private_key: zk === ZKTypes.SNARK ? args[1].asCircuitInputs() : args[1].rawPrivKey.toString(),
98 | buyer_public_key: args[2].asCircuitInputs(),
99 | }, zk);
100 | }
101 |
102 | export async function proveHash(zk: ZKTypes, args) {
103 | return prove('hash', {
104 | preimage: args[1].toString(),
105 | key: args[0].toString(),
106 | salt: args[2].toString(),
107 | }, zk);
108 | }
109 |
110 | export async function proveBlur(zk: ZKTypes, args) {
111 | return prove('blur-image', {
112 | preimage: args[1].map(_ => _.toString()),
113 | key: args[0].toString(),
114 | blurred_image: args[2].map(_ => _.toString()),
115 | }, zk);
116 | }
117 |
118 | export async function proveDarkForest(zk: ZKTypes, args) {
119 | return prove('dark-forest', {
120 | x: args[1].toString(),
121 | y: args[2].toString(),
122 | key: args[0].toString(),
123 | hash: args[3].toString(),
124 | salt: args[4],
125 | }, zk);
126 | }
127 |
128 | // VERIFIERS
129 | export const verifyEncryption = async (zk: ZKTypes, proof) => verify('encryption', proof, zk);
130 | export const verifyHash = async (zk: ZKTypes, proof) => verify('hash', proof, zk);
131 | export const verifyBlur = async (zk: ZKTypes, proof) => verify('blur', proof, zk);
132 | export const verifyDarkForest = async (zk: ZKTypes, proof) => verify('dark-forest', proof, zk);
133 |
--------------------------------------------------------------------------------
/src/pages/content/Blur.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import styled from 'styled-components';
3 | import assert from 'assert';
4 |
5 | import {
6 | blurImage,
7 | ZKFunctions,
8 | } from '../../utils/crypto';
9 |
10 | import {
11 | InputProps,
12 | } from '../../types/content';
13 | import {
14 | ZKTypes,
15 | } from '../../types';
16 |
17 |
18 | type PixelProps = {
19 | bit: number;
20 | }
21 |
22 | const Pixel = styled.div`
23 | display: flex;
24 | flex: 1;
25 | height: 100%;
26 | background-color: ${props => (props.bit === 0 ?
27 | 'black' : 'white')};
28 | `;
29 |
30 | type ImageWrapperProps = {
31 | height: string;
32 | }
33 |
34 | const ImageWrapper = styled.div`
35 | justify-content: space-between;
36 | border: 1px solid black;
37 | display: flex;
38 | flex-direction: row;
39 | height: ${props => props.height};
40 | width: 100%;
41 | align-items: center;
42 | box-sizing: border-box;
43 | `;
44 |
45 | type ImageProps = {
46 | property: number[];
47 | height: string;
48 | message?: number[];
49 | }
50 |
51 | const Image = (props: ImageProps) => {
52 | const bits = props.message ? props.message : props.property;
53 |
54 | return (
55 |
56 | {bits.map((bit, index) => (
57 |
58 | ))}
59 |
60 | );
61 | };
62 |
63 | type ImageLargeProps = {
64 | property: number[];
65 | message?: number[];
66 | }
67 |
68 | const ImageLarge = (props: ImageLargeProps) => {
69 | return (
70 |
71 | );
72 | };
73 |
74 | const ImageSmall = (props: ImageLargeProps) => {
75 | return (
76 |
77 | );
78 | };
79 | const ImageInput = (props: InputProps) => {
80 |
81 | useEffect(() => {
82 | props.setPreimage('0000000000000000');
83 | }, []);
84 |
85 | const onChange = (index: number) => () => {
86 | let preimageArray = props.preimage.split('').map(Number);
87 | preimageArray[index] = (preimageArray[index] + 1) % 2;
88 | const newPreimage = preimageArray.join('');
89 | props.setPreimage(newPreimage);
90 | };
91 |
92 | return (
93 | <>
94 |
95 | {props.preimage.split('').map((bit, index) => {
96 | return (
97 |
102 | );
103 | })}
104 |
105 |
106 | >
107 | );
108 | };
109 |
110 | const isNumberArray = (value) => {
111 | return Array.isArray(value) &&
112 | typeof value[0] === 'number';
113 | };
114 |
115 | const assertContent = (content) => {
116 | assert(isNumberArray(content.cipher));
117 | assert(isNumberArray(content.property));
118 | };
119 |
120 | const assertMessage = isNumberArray;
121 |
122 | const computeProperty = (preimage, key) => {
123 | const preimageArray = preimage.split('').map(Number);
124 | const blurredImage = blurImage(preimageArray, key);
125 | return [preimageArray, blurredImage];
126 | };
127 |
128 | const assertProofInputs = (args: any[]) => {
129 | assert(args.length === 3);
130 | assert(typeof args[0] === 'bigint');
131 | assert(isNumberArray(args[1]));
132 | assert(isNumberArray(args[2]));
133 | };
134 |
135 | const json = {
136 | input: ImageInput,
137 | display: ImageLarge,
138 | list: ImageSmall,
139 | decrypt: (zk, a, b) => blurImage(a, b),
140 | computeProperty,
141 | prover: {
142 | [ZKTypes.SNARK]: ZKFunctions[ZKTypes.SNARK].provers.blur,
143 | [ZKTypes.STARK]: ZKFunctions[ZKTypes.STARK].provers.blur,
144 | },
145 | verifier: {
146 | [ZKTypes.SNARK]: ZKFunctions[ZKTypes.SNARK].verifiers.blur,
147 | [ZKTypes.STARK]: ZKFunctions[ZKTypes.STARK].verifiers.blur,
148 | },
149 | assertProofInputs,
150 | assertContent,
151 | assertMessage,
152 | };
153 | export default json;
154 |
--------------------------------------------------------------------------------
/public/circuits/verification_keys/Hash.json:
--------------------------------------------------------------------------------
1 | {
2 | "protocol": "groth16",
3 | "curve": "bn128",
4 | "nPublic": 5,
5 | "vk_alpha_1": [
6 | "19642524115522290447760970021746675789341356000653265441069630957431566301675",
7 | "15809037446102219312954435152879098683824559980020626143453387822004586242317",
8 | "1"
9 | ],
10 | "vk_beta_2": [
11 | [
12 | "3306678135584565297353192801602995509515651571902196852074598261262327790404",
13 | "6402738102853475583969787773506197858266321704623454181848954418090577674938"
14 | ],
15 | [
16 | "4983765881427969364617654516554524254158908221590807345159959200407712579883",
17 | "15158588411628049902562758796812667714664232742372443470614751812018801551665"
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 | "2528491300866434509699704412642731178102268865012248785813458721505586631446",
41 | "11078114351411396302492606863995638386506537365844689646898417550998267219414"
42 | ],
43 | [
44 | "17448560587075395769884970409122010185777125947946128673908172602768905142360",
45 | "7646900014588577959937375249841784560277351960820231527167492175864420231155"
46 | ],
47 | [
48 | "1",
49 | "0"
50 | ]
51 | ],
52 | "vk_alphabeta_12": [
53 | [
54 | [
55 | "5990981426838611487817331801723298853689232371402636505882752025826717861263",
56 | "6471600557194756298005957410208198947034348214534657394165503369790309076215"
57 | ],
58 | [
59 | "15002700749801870140343913307313851505416165248926784119266834715141460279528",
60 | "3830910611342760800353177932876565223705290639657811356514431363408808083245"
61 | ],
62 | [
63 | "16213272029928492311641815345584648151738099578429924053941653329679116056011",
64 | "11521059852145391195901894023171250860281638548552692281491114389569775909273"
65 | ]
66 | ],
67 | [
68 | [
69 | "21473208233673181545713372461262158409524966660539444635240255266528451743613",
70 | "12831374732506919217314780439582796881729424911714976211545279975915712437524"
71 | ],
72 | [
73 | "6384272187442204077342066657702496903903539015888454871400719146512483196930",
74 | "11896033867460826226898768849934024947887432723445089197160889467704536005586"
75 | ],
76 | [
77 | "4320872437228236846208766625647342285071164667482133950438695528545836489222",
78 | "13210525034366360416090582915961576197528924758377030567364985602065069567971"
79 | ]
80 | ]
81 | ],
82 | "IC": [
83 | [
84 | "6649706228940092214024537715615750974782507177962522143585713102098252140507",
85 | "8600012682628506602820352378092933216847589691662499915982120618606494269693",
86 | "1"
87 | ],
88 | [
89 | "11890359990516516306620937012547994802495225911011046267065388026614930788971",
90 | "7640518447137566552605716762042533071088153492924720917575059134719958960794",
91 | "1"
92 | ],
93 | [
94 | "13240033539492298308581903484700265342341622504201213204034038067339035592231",
95 | "2085478624939869822204404203546372376628476589570140288168203331015267633255",
96 | "1"
97 | ],
98 | [
99 | "17074828529152127823096532362911641732470042415519965643143486759850463393976",
100 | "19176684664061417791363598996003389146087993907369817080564093102545749703925",
101 | "1"
102 | ],
103 | [
104 | "3487870124006761499757286140356040193039885261060458946754054319861912246688",
105 | "14227488130452521732880752674651927713352840101996664468289157682022926222454",
106 | "1"
107 | ],
108 | [
109 | "17243644912270822364454898995391259659202910174472139797545967979755313574588",
110 | "18321263016295783859814954531795102538581144887377749037991635164191301750260",
111 | "1"
112 | ]
113 | ]
114 | }
--------------------------------------------------------------------------------
/public/circuits/verification_keys/Encryption.json:
--------------------------------------------------------------------------------
1 | {
2 | "protocol": "groth16",
3 | "curve": "bn128",
4 | "nPublic": 5,
5 | "vk_alpha_1": [
6 | "19642524115522290447760970021746675789341356000653265441069630957431566301675",
7 | "15809037446102219312954435152879098683824559980020626143453387822004586242317",
8 | "1"
9 | ],
10 | "vk_beta_2": [
11 | [
12 | "3306678135584565297353192801602995509515651571902196852074598261262327790404",
13 | "6402738102853475583969787773506197858266321704623454181848954418090577674938"
14 | ],
15 | [
16 | "4983765881427969364617654516554524254158908221590807345159959200407712579883",
17 | "15158588411628049902562758796812667714664232742372443470614751812018801551665"
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 | "2528491300866434509699704412642731178102268865012248785813458721505586631446",
41 | "11078114351411396302492606863995638386506537365844689646898417550998267219414"
42 | ],
43 | [
44 | "17448560587075395769884970409122010185777125947946128673908172602768905142360",
45 | "7646900014588577959937375249841784560277351960820231527167492175864420231155"
46 | ],
47 | [
48 | "1",
49 | "0"
50 | ]
51 | ],
52 | "vk_alphabeta_12": [
53 | [
54 | [
55 | "5990981426838611487817331801723298853689232371402636505882752025826717861263",
56 | "6471600557194756298005957410208198947034348214534657394165503369790309076215"
57 | ],
58 | [
59 | "15002700749801870140343913307313851505416165248926784119266834715141460279528",
60 | "3830910611342760800353177932876565223705290639657811356514431363408808083245"
61 | ],
62 | [
63 | "16213272029928492311641815345584648151738099578429924053941653329679116056011",
64 | "11521059852145391195901894023171250860281638548552692281491114389569775909273"
65 | ]
66 | ],
67 | [
68 | [
69 | "21473208233673181545713372461262158409524966660539444635240255266528451743613",
70 | "12831374732506919217314780439582796881729424911714976211545279975915712437524"
71 | ],
72 | [
73 | "6384272187442204077342066657702496903903539015888454871400719146512483196930",
74 | "11896033867460826226898768849934024947887432723445089197160889467704536005586"
75 | ],
76 | [
77 | "4320872437228236846208766625647342285071164667482133950438695528545836489222",
78 | "13210525034366360416090582915961576197528924758377030567364985602065069567971"
79 | ]
80 | ]
81 | ],
82 | "IC": [
83 | [
84 | "6696830915188811222805337860434242118015796195504552362503772065564241004793",
85 | "14168315932310402745458233483865755546062824270218045859290041083862651822454",
86 | "1"
87 | ],
88 | [
89 | "21797365513790993772188867392601402947083186120404804982493953694003686130098",
90 | "10894181459181605005323314653042322574935689496365271983143352198223111959228",
91 | "1"
92 | ],
93 | [
94 | "13956123995938546240142728085826425531645707098551729463962137646146316756078",
95 | "1015579278733704732152149441790371937618646964903561859133106159079756082705",
96 | "1"
97 | ],
98 | [
99 | "1406513136486938335399692418160257047861625989046073447629101086191159002553",
100 | "5501588824195265410437141777891417923446988980418639101973843701710315702890",
101 | "1"
102 | ],
103 | [
104 | "13116752893921034560348126282679915303501261626202282210808233325523938302596",
105 | "8014465560771828168190678410134247897388632687630536200036146352367517129204",
106 | "1"
107 | ],
108 | [
109 | "6268772482625100927397258823484197390170769634851849637235756810655726976365",
110 | "18548977206527417647915185397219583535313858552278826900129808792864343191398",
111 | "1"
112 | ]
113 | ]
114 | }
--------------------------------------------------------------------------------
/scripts/builder.ts:
--------------------------------------------------------------------------------
1 | require('dotenv').config();
2 |
3 | import { execSync } from 'child_process';
4 | import fs from 'fs';
5 | import path from 'path';
6 | import { upperCase } from './utils';
7 |
8 | const wasmOutPath = 'wasm';
9 | const zkeyOutPath = 'keys';
10 | const verificationOutPath = 'verification_keys';
11 | const deterministic = process.argv[2] === 'true';
12 | const circuitsList = process.argv[3];
13 | let potFile = process.argv[4];
14 |
15 | // TODO: add an option to generate with entropy for production keys
16 |
17 | if (process.argv.length !== 5) {
18 | console.log('usage');
19 | console.log(
20 | 'builder comma,seperated,list,of,circuits wasm_out_path zkey_out_path [`true` if deterministic / `false` if not] pot_size \n for example, $ node circuits/builder.js . . false sig-check 20'
21 | );
22 | process.exit(1);
23 | }
24 |
25 | if (!potFile) {
26 | potFile = '15';
27 | }
28 |
29 | const cwd = process.cwd();
30 | const circuitsDirectory = path.resolve(`${cwd}/circuits`);
31 | const outputDirectory = path.resolve(`${cwd}/compiledCircuits`);
32 |
33 | if (!fs.existsSync(`${outputDirectory}`)) {
34 | fs.mkdirSync(`${outputDirectory}`);
35 | }
36 |
37 | for (let circuitName of circuitsList.split(',')) {
38 | if (deterministic && !process.env['beacon']) {
39 | console.log("ERROR! Can't find a sourced .env with a beacon variable");
40 | process.exit(1);
41 | }
42 |
43 | if (!fs.existsSync(`${outputDirectory}/${circuitName}`)) {
44 | fs.mkdirSync(`${outputDirectory}/${circuitName}`);
45 | }
46 | process.chdir(`${circuitsDirectory}/${circuitName}`);
47 |
48 | try {
49 | execSync('npx circom circuit.circom --r1cs --wasm --sym', {
50 | stdio: 'inherit',
51 | });
52 | execSync('npx snarkjs r1cs info circuit.r1cs', { stdio: 'inherit' });
53 | execSync(
54 | "npx snarkjs zkey new circuit.r1cs '" +
55 | circuitsDirectory +
56 | '/pots/pot' +
57 | potFile +
58 | "_final.ptau' circuit_" +
59 | circuitName +
60 | '.zkey',
61 | { stdio: 'inherit' }
62 | );
63 | if (deterministic) {
64 | execSync(
65 | 'npx snarkjs zkey beacon circuit_' +
66 | circuitName +
67 | '.zkey circuit.zkey ' +
68 | process.env['beacon'] +
69 | ' 10',
70 | { stdio: 'inherit' }
71 | );
72 | } else {
73 | execSync(
74 | 'npx snarkjs zkey contribute circuit_' +
75 | circuitName +
76 | '.zkey circuit.zkey ' +
77 | `-e='${Date.now()}'`,
78 | { stdio: 'inherit' }
79 | );
80 | }
81 | execSync(
82 | 'npx snarkjs zkey export verificationkey circuit.zkey verification_key.json',
83 | { stdio: 'inherit' }
84 | );
85 | execSync(
86 | 'npx snarkjs wtns calculate circuit.wasm input.json witness.wtns',
87 | {
88 | stdio: 'inherit',
89 | }
90 | );
91 | execSync(
92 | 'npx snarkjs groth16 prove circuit.zkey witness.wtns proof.json public.json',
93 | { stdio: 'inherit' }
94 | );
95 | execSync(
96 | 'npx snarkjs groth16 verify verification_key.json public.json proof.json',
97 | { stdio: 'inherit' }
98 | );
99 | fs.copyFileSync(
100 | 'circuit.wasm',
101 | `${outputDirectory}/${circuitName}/circuit.wasm`
102 | );
103 | fs.copyFileSync(
104 | 'circuit.zkey',
105 | `${outputDirectory}/${circuitName}/circuit.zkey`
106 | );
107 | fs.copyFileSync(
108 | 'verification_key.json',
109 | `${outputDirectory}/${circuitName}/verification_key.json`
110 | );
111 | execSync('rm circuit.wasm', { stdio: 'inherit' });
112 | execSync('rm circuit.zkey', { stdio: 'inherit' });
113 | execSync(`rm circuit_${circuitName}.zkey`, { stdio: 'inherit' });
114 | execSync('rm verification_key.json', { stdio: 'inherit' });
115 | execSync('rm witness.wtns', { stdio: 'inherit' });
116 | execSync('rm circuit.r1cs', { stdio: 'inherit' });
117 | execSync('rm circuit.sym', { stdio: 'inherit' });
118 | execSync('rm proof.json', { stdio: 'inherit' });
119 | } catch (error) {
120 | console.log(error);
121 | process.exit(1);
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # EthDataMarketplace
2 |
3 | ## How it works
4 |
5 | 1. Creator generates a [Property Proof](#property-proofs) which:
6 | - asserts they have some content which satisfies a particular property (`f(data) = property`)
7 | - outputs the encryption of the data with a randomly generated key (`Enc(data, key)`)
8 | - outputs the hash of the randomly generated key (`H(key)`)
9 | 2. The creator publishes the proof on IPFS and registers the IPFS URI and the key hash on a smart contract
10 | 3. Using the IPFS URI on the contract, the buyer sees the property and verifies that:
11 | - the [Property Proof](#property-proofs) is valid
12 | - the output key hash in the proof matches the key hash stored on the contract (if this is unchecked the creator could maliciously submit two different keys to the smart contract and the [Property Proof](#property-proofs), so the buyer won't be able to successfully retrieve the content)
13 | 4. if valid, the buyer will purchase the token and lock ETH in the contract
14 | 5. the creator will generate an [Encryption Proof](#encryption-proof) which:
15 | - asserts that they have the preimage to the key hash stored on the contract (`H(preimage) = H(key)`)
16 | - outputs the encryption of the preimage with the buyer's public key (`Enc(preimage, pk)`)
17 | if the proof is valid, the ETH is redeemed from the contract
18 |
19 | 6. the buyer retrieves the encrypted key (`Enc(key, pk)`) from the contract computes
20 | - `Dec(Enc(key, pk), sk) => key`
21 | - `Dec(Enc(data, key), key) => data`
22 |
23 | ## Circuits
24 |
25 | The circuits are divided into two types [Encryption Proofs](#encryption-proof) and [Property Proofs](#property-proofs). The *Encryption Proof* is the proof sent over the contract by the seller to verify the decryption key exchange. The *Property Proofs* are the proofs published on IPFS by the seller to commit to the property of the content.
26 |
27 | ### Encryption Proof
28 |
29 | The proof sent by the seller in step 5, which
30 | - asserts that they have the preimage to the key hash stored on the contract (`H(preimage) = H(key)`)
31 | - outputs the encryption of the preimage with the buyer's public key (`Enc(preimage, pk)`)
32 |
33 | #### encryption
34 |
35 | ##### Inputs
36 | | signal | private | type | description |
37 | |-|-|-|-|
38 | | key | true | BigInt | |
39 | | private_key | true | BigInt | |
40 | | hash | false | BigInt | |
41 | | public_key | false | Array[2] | |
42 |
43 | ##### Outputs
44 | | signal | type | description |
45 | |-|-|-|
46 | | out | Array[2] | |
47 |
48 | ### Property Proofs
49 |
50 | The proof published by the seller on IPFS in step 1-2, which
51 | - asserts they have some content which satisfies a particular property (`f(data) = property`)
52 | - outputs the encryption of the data with a randomly generated key (`Enc(key, pk)`)
53 | - outputs the hash of the randomly generated key (`H(key)`)
54 |
55 | Below are possible properties that can be committed and verified.
56 |
57 | #### hash
58 |
59 | Commits the MiMC hash of the content.
60 | ```f(data) = H(data)```
61 |
62 | ##### Inputs
63 | | signal | private | type | description |
64 | |-|-|-|-|
65 | | preimage | true | BigInt | |
66 | | key | true | BigInt | |
67 | | hash | false | BigInt | |
68 | | salt | false | BigInt | |
69 |
70 | ##### Outputs
71 | | signal | type | description |
72 | |-|-|-|
73 | | key_hash | BigInt | |
74 | | ciphertext | Array[2] | |
75 |
76 | #### dark-forest
77 |
78 | Commits the MiMC hash of the `x` and `y` coordinates of a Dark Forest planet.
79 |
80 | ##### Inputs
81 | | signal | private | type | description |
82 | |-|-|-|-|
83 | | x | true | BigInt | |
84 | | y | true | BigInt | |
85 | | key | true | BigInt | |
86 | | hash | false | BigInt | |
87 | | salt | false | BigInt | |
88 |
89 | ##### Outputs
90 | | signal | type | description |
91 | |-|-|-|
92 | | key_hash | BigInt | |
93 | | ciphertext | Array[3] | |
94 |
95 | #### blur-image
96 |
97 | Commits the XOR of a bitmap with a `key`.
98 |
99 | > Note: Obviously, this means the property is nothing more than a random bitmap that is non-unique to the content and doesn't give any indication to the buyer of what they are purchasing. This was made as a quick example of another property and an early attempt at proving a property of an image. Hopefully, this can be improved in the future to be more applicable.
100 |
101 | ##### Inputs
102 | | signal | private | type | description |
103 | |-|-|-|-|
104 | | preimage | true | Array[N] | |
105 | | key | true | BigInt | |
106 | | blurred_image | false | Array[N] | |
107 |
108 | ##### Outputs
109 | | signal | type | description |
110 | |-|-|-|
111 | | hash | BigInt | |
112 | | computed_image | Array[N] | |
113 |
--------------------------------------------------------------------------------
/src/app/Ipfs.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import styled from 'styled-components';
3 |
4 | import Modal from '../components/Modal';
5 | import TextInput from '../components/TextInput';
6 | import Toggle from '../components/Toggle';
7 | import { Header } from '../components/text';
8 | import ipfs from '../utils/ipfs';
9 | import config from '../../config';
10 |
11 |
12 | type IconProps = {
13 | connected: boolean;
14 | }
15 |
16 | const ConnectedIcon = styled.div`
17 | border-radius: ${props => props.theme.borderRadii.circle};
18 | width: 10px;
19 | height: 10px;
20 | background-color: ${props => props.connected ? 'green' : 'yellow'};
21 | border: 1px solid black;
22 | margin-right: auto;
23 | `;
24 |
25 | const IpfsLabel = styled.div`
26 | margin-right: auto;
27 | `;
28 |
29 | const IpfsIcon = styled.div`
30 | display: flex;
31 | border: ${props => `1px solid ${props.theme.color.grey30}`};
32 | height: ${props => props.theme.spacing(5)};
33 | padding: 0px 10px;
34 | align-items: center;
35 | border-radius: ${props => props.theme.borderRadii.curvy};
36 | :hover {
37 | cursor: pointer;
38 | background-color: ${props => props.theme.color.grey10};
39 | }
40 | flex: 1;
41 | margin-right: 10px;
42 | box-sizing: border-box;
43 | `;
44 |
45 | const ModalHeader = styled(Header)`
46 | margin-top: auto;
47 | margin-bottom: auto;
48 | `;
49 |
50 | enum Providers {
51 | HOST = 'host',
52 | INFURA = 'infura',
53 | LOCAL = 'local',
54 | }
55 |
56 | export default function Ipfs() {
57 | const [modalShow, setModalShow] = useState(false);
58 | const [provider, setProvider] = useState(Providers.INFURA);
59 | const [host, setHost] = useState(ipfs.host);
60 | const [protocol, setProtocol] = useState(ipfs.protocol);
61 | const [infuraProjectId, setInfuraProjectId] =
62 | useState(ipfs.infuraProjectId);
63 | const [infuraProjectSecret, setInfuraProjectSecret] =
64 | useState(ipfs.infuraProjectSecret);
65 | const [connected, setConnected] = useState(false);
66 | const [didMount, setDidMount] = useState(false);
67 |
68 | useEffect(() => {
69 | switch (ipfs.host) {
70 | case 'host':
71 | setProvider(Providers.HOST);
72 | break;
73 | case 'infura':
74 | setProvider(Providers.INFURA);
75 | break;
76 | case 'localhost':
77 | setProvider(Providers.LOCAL);
78 | break;
79 | }
80 | }, []);
81 |
82 | useEffect(() => {
83 | ipfs.checkConnection().then(setConnected);
84 | setDidMount(true);
85 | return () => setDidMount(false);
86 | }, [provider]);
87 |
88 | const onShow = () => {
89 | setModalShow(true);
90 | };
91 |
92 | const onClose = () => {
93 | onEnter();
94 | setModalShow(false);
95 | };
96 |
97 | const onEnter = () => {
98 | ipfs.updateSettings(host, protocol, infuraProjectId, infuraProjectSecret);
99 | };
100 |
101 | const onSetProvider = (_provider: Providers) => {
102 | setProvider(_provider);
103 | switch(_provider) {
104 | case Providers.LOCAL:
105 | setHost('localhost');
106 | setProtocol('http');
107 | break;
108 | case Providers.INFURA:
109 | setHost('ipfs.infura.io');
110 | setProtocol('https');
111 | break;
112 | case Providers.HOST:
113 | setHost(config.ipfsHost);
114 | setProtocol('http');
115 | break;
116 | }
117 | };
118 |
119 | return (
120 | <>
121 |
122 |
123 |
124 | IPFS
125 |
126 |
127 |
128 | Change IPFS Settings
129 |
134 | {provider === Providers.HOST ?
135 | null :
136 | <>
137 |
143 |
149 |
150 | {provider === Providers.INFURA ?
151 | <>
152 |
158 |
164 | >
165 | : null}
166 | >
167 | }
168 |
169 | >
170 | );
171 | }
172 |
--------------------------------------------------------------------------------