├── .github
└── workflows
│ └── matrix-commit-message.yml
├── .gitignore
├── Cargo.toml
├── README.md
├── TODO.md
├── darkcli.py
├── doc
├── mint.pseudo
├── rangeproof.pseudo
└── spend.pseudo
├── lisp
├── README.md
├── TODO.md
├── core.rs
├── env.rs
├── examples
│ ├── jubjub-add-macro.lisp
│ ├── jubjub.lisp
│ ├── macro-test.lisp
│ ├── mimc-constants.lisp
│ ├── mint2.lisp
│ └── util.lisp
├── lisp.rs
├── printer.rs
├── racket
│ ├── jj.rkt
│ └── zk.rkt
├── reader.rs
├── run.sh
└── types.rs
├── proofs
├── bits.psm
├── jubjub.params
├── jubjub.psm
├── mimc.psm
├── mimc_constants.psm
├── mint.pism
├── mint2.psm
├── old
│ ├── mint.aux
│ ├── sapling.pism
│ ├── sapling.prf
│ ├── sapling2.prf
│ ├── sapling3.prf
│ ├── saplingb.prf
│ ├── simple.aux
│ ├── simple.pism
│ ├── simple.prf
│ ├── test.pism
│ └── working.pism
├── spend.pism
└── vm.pism
├── res
├── font
│ └── PressStart2P-Regular.ttf
├── img
│ ├── absolutely-proprietary.png
│ └── absolutely-proprietary2.png
├── model
│ ├── earth.blend
│ ├── earth.jpg
│ ├── earth.mtl
│ └── earth.obj
└── shader
│ ├── light.frag
│ ├── light.frag.spv
│ ├── light.vert
│ ├── light.vert.spv
│ ├── phong.frag
│ ├── phong.frag.spv
│ ├── shader.frag
│ ├── shader.frag.spv
│ ├── shader.vert
│ ├── shader.vert.spv
│ ├── ui_shader.frag
│ ├── ui_shader.frag.spv
│ ├── ui_shader.vert
│ └── ui_shader.vert.spv
├── run_jubjub.sh
├── run_jubjub2.sh
├── run_mimc.sh
├── run_mimc2.sh
├── run_mint.sh
├── run_network.sh
├── rustfmt.toml
├── scripts
├── codegen.py
├── compile.py
├── compile_export_rust.py
├── compile_export_supervisor.py
├── finite_fields
│ ├── README.md
│ ├── euclidean-test.py
│ ├── euclidean.py
│ ├── finitefield-test.py
│ ├── finitefield.py
│ ├── modp-test.py
│ ├── modp.py
│ ├── numbertype.py
│ ├── polynomial-test.py
│ ├── polynomial.py
│ ├── test.py
│ └── typecast-test.py
├── jsonrpc_client.py
├── jubjub.py
├── modp.py
├── monitor-p2p.py
├── old
│ ├── compile.sh
│ ├── compile_and_run.sh
│ ├── run_bits.sh
│ ├── run_mimc.sh
│ ├── run_mint2.sh
│ ├── run_mint_contract.sh
│ ├── run_spend_contract.sh
│ └── run_vmtest.sh
├── parser.py
├── pism.py
├── pism.vim
├── preprocess.py
├── reorder-logs.py
├── sapvi.vim
├── to_html.sh
└── zk
│ ├── 3.3-encrypted-polynomial.py
│ ├── 3.4-restricted-polynomial.py
│ ├── 3.5-zero-knowledge.py
│ ├── 3.6-trusted-setup.py
│ ├── 4.4-proof-of-operation.py
│ ├── 4.5.1-polynomial-interpolation.py
│ ├── 4.5.2-multi-operation-polynomials.py
│ ├── 4.6.2-multi-variable-operand-polynomial.py
│ ├── 4.8-example-computation.py
│ └── qap.py
├── src
├── async_serial.rs
├── bin
│ ├── compile-shaders.rs
│ ├── demowallet.rs
│ ├── dfg.rs
│ ├── dfi.rs
│ ├── jubjub.rs
│ ├── mimc.rs
│ ├── mimc_constants.rs
│ ├── mint-classic.rs
│ ├── mint.rs
│ ├── services.rs
│ ├── spend-classic.rs
│ ├── tx.rs
│ └── zkvm.rs
├── bls_extensions.rs
├── circuit
│ ├── mint_contract.rs
│ ├── mod.rs
│ └── spend_contract.rs
├── crypto
│ ├── coin.rs
│ ├── diffie_hellman.rs
│ ├── fr_serial.rs
│ ├── merkle.rs
│ ├── mint_proof.rs
│ ├── mod.rs
│ ├── note.rs
│ ├── schnorr.rs
│ ├── spend_proof.rs
│ └── util.rs
├── endian.rs
├── error.rs
├── gfx
│ ├── camera.rs
│ ├── mod.rs
│ ├── model.rs
│ └── texture.rs
├── gui
│ ├── mod.rs
│ └── texture.rs
├── lib.rs
├── net
│ ├── acceptor.rs
│ ├── channel.rs
│ ├── connector.rs
│ ├── error.rs
│ ├── hosts.rs
│ ├── message_subscriber.rs
│ ├── messages.rs
│ ├── mod.rs
│ ├── p2p.rs
│ ├── protocols
│ │ ├── mod.rs
│ │ ├── protocol_address.rs
│ │ ├── protocol_jobs_manager.rs
│ │ ├── protocol_ping.rs
│ │ ├── protocol_seed.rs
│ │ └── protocol_version.rs
│ ├── sessions
│ │ ├── inbound_session.rs
│ │ ├── mod.rs
│ │ ├── outbound_session.rs
│ │ ├── seed_session.rs
│ │ └── session.rs
│ ├── settings.rs
│ └── utility.rs
├── old
│ ├── basic_minimal.rs
│ ├── bits.rs
│ ├── blake.rs
│ ├── eq.rs
│ ├── jubjub.rs
│ ├── mimc.rs
│ ├── mint2.rs
│ ├── pedersen_hash.rs
│ ├── sha256.rs
│ ├── simple.rs
│ ├── vmtest.rs
│ ├── zec.rs
│ └── zkmimc.rs
├── rpc
│ ├── __init__.py
│ ├── adapter.rs
│ ├── jsonclient.py
│ ├── jsonserver.rs
│ ├── mod.rs
│ └── test.rs
├── serial.rs
├── service
│ ├── gateway.rs
│ ├── mod.rs
│ └── reqrep.rs
├── system
│ ├── mod.rs
│ ├── stoppable_task.rs
│ ├── subscriber.rs
│ └── types.rs
├── tx.rs
├── vm.rs
├── vm_serial.rs
└── wallet
│ ├── mod.rs
│ └── schema.sql
└── zkvm.md
/.github/workflows/matrix-commit-message.yml:
--------------------------------------------------------------------------------
1 | on: [push]
2 |
3 | jobs:
4 | send-message:
5 | runs-on: ubuntu-latest
6 | name: Send message via Matrix
7 | steps:
8 | - name: checkout
9 | uses: actions/checkout@v2
10 | with:
11 | fetch-depth: 0
12 | - run: |
13 | ALL_MSGS=""
14 | for i in ${{ join(github.event.commits.*.id, ' ') }}; do
15 | MSG=$(git --no-pager show -s --format='%h %an: %s' $i)
16 | ALL_MSGS="$ALL_MSGS$MSG
"
17 | done
18 | echo "::set-output name=COMMIT_MESSAGE::$ALL_MSGS"
19 | id: commit-message
20 | - uses: narodnik/matrix-action@main
21 | with:
22 | server: 'matrix.dark.fi'
23 | room-id: '!MODZOZydPqCRdulXmR:dark.fi'
24 | #access_token: ${{ secrets.MATRIX_TOKEN }}
25 | status: 'OK'
26 | user: 'b1-66er'
27 | password: ${{ secrets.MATRIX_PASSWORD }}
28 | message: '${{ steps.commit-message.outputs.COMMIT_MESSAGE }}'
29 | #- name: Send message to test channel
30 | # id: matrix-chat-message
31 | # uses: fadenb/matrix-chat-message@v0.0.6
32 | # with:
33 | # homeserver: 'dark.fi'
34 | # token: ${{ secrets.MATRIX_TOKEN }}
35 | # channel: '!MODZOZydPqCRdulXmR:dark.fi'
36 | # message: |
37 | # This is an *example message* using **markdown** for formatting.\
38 | # Use a `\` character at the end of a line to cause a linebreak (the whole message is treated as markdown).\
39 | # You can use variables like ${{ github.sha }} anywhere.
40 |
41 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | Cargo.lock
2 | .gitignore
3 | /target
4 | scripts/__pycache__/
5 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "sapvi"
3 | version = "0.1.0"
4 | authors = ["narodnik "]
5 | edition = "2018"
6 |
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8 |
9 | [lib]
10 | name = "sapvi"
11 |
12 | [dependencies]
13 | ff = "0.8"
14 | group = "0.8"
15 | bellman = { version = "0.8", default-features = false, features = ["groth16"] }
16 | bls12_381 = "0.3.1"
17 | jubjub = "0.5.1"
18 |
19 | zcash_primitives = "0.5.0"
20 | zcash_proofs = "0.5.0"
21 | # zcash_primitives = { git = "https://github.com/zcash/librustzcash" }
22 | #zcash_proofs = { git = "https://github.com/zcash/librustzcash" }
23 | #zcash_proofs = { git = "https://github.com/narodnik/librustzcash" }
24 | #bench-utils = { git = "https://github.com/scipr-lab/zexe", features = ["print-trace"]}
25 | rand = "0.7.3"
26 | rand_core = "0.5.1"
27 | sha2 = "0.9.1"
28 | rand_xorshift = "0.2"
29 | blake2s_simd = "0.5"
30 | blake2b_simd = "0.5.11"
31 | crypto_api_chachapoly = "0.4"
32 | bitvec = "0.18"
33 | bimap = "0.5.2"
34 | async-trait = "0.1.42"
35 | multimap = "0.8.2"
36 |
37 | hex = "0.4.2"
38 | num_enum = "0.5.0"
39 |
40 | lazy_static = "1.4.0"
41 | itertools = "0.8.0"
42 | #fnv = "1.0.6"
43 | regex = "1"
44 |
45 | simplelog = "0.7.4"
46 | clap = "3.0.0-beta.1"
47 | failure = "0.1.8"
48 | failure_derive = "0.1.8"
49 | log = "0.4"
50 | ctrlc = "3.1.7"
51 | serde_json = "1.0.61"
52 | owning_ref = "0.4.1"
53 |
54 | smol = "1.2.4"
55 | futures = "0.3.5"
56 | async-channel = "1.4.2"
57 | async-executor = "1.4.0"
58 | async-dup = "1.1.0"
59 | async-std = "1.6.2"
60 | easy-parallel = "3.1.0"
61 |
62 | jsonrpc-core = "16.0.0"
63 | http-types = "2.9.0"
64 | async-h1 = "2.3.0"
65 | async-native-tls = "0.3.3"
66 |
67 | # GUI deps
68 | anyhow = "1.0"
69 | bytemuck = { version = "1.4", features = [ "derive" ] }
70 | image = "0.23"
71 | winit = "0.23"
72 | shaderc = "0.7"
73 | cgmath = "0.17"
74 | env_logger = "0.7"
75 | wgpu = "0.7"
76 | wgpu_glyph = "0.11"
77 | tobj = "2.0.4"
78 |
79 | # used by compile-shaders
80 | fs_extra = "1.2"
81 | glob = "0.3"
82 |
83 | async_zmq = "0.3.2"
84 |
85 | # wallet deps
86 | rocksdb = "0.16.0"
87 | dirs = "2.0.2"
88 | [dependencies.rusqlite]
89 | version = "0.25.1"
90 | features = ["bundled", "sqlcipher"]
91 |
92 | [[bin]]
93 | name = "lisp"
94 | path = "lisp/lisp.rs"
95 |
96 | [[bin]]
97 | name = "zkvm"
98 | path = "src/bin/zkvm.rs"
99 |
100 | [[bin]]
101 | name = "dfi"
102 | path = "src/bin/dfi.rs"
103 |
104 | [[bin]]
105 | name = "mimc"
106 | path = "src/old/mimc.rs"
107 |
108 | [[bin]]
109 | name = "mint-classic"
110 | path = "src/bin/mint-classic.rs"
111 |
112 | [[bin]]
113 | name = "spend-classic"
114 | path = "src/bin/spend-classic.rs"
115 |
116 | [[bin]]
117 | name = "tx"
118 | path = "src/bin/tx.rs"
119 |
120 | [[bin]]
121 | name = "dfg"
122 | path = "src/bin/dfg.rs"
123 |
124 | [[bin]]
125 | name = "compile-shaders"
126 | path = "src/bin/compile-shaders.rs"
127 |
128 | [[bin]]
129 | name = "services"
130 | path = "src/bin/services.rs"
131 |
132 | [[bin]]
133 | name = "demowallet"
134 | path = "src/bin/demowallet.rs"
135 |
136 | [profile.release]
137 | debug = 1
138 |
139 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ```
2 | ./run_jubjub2.sh
3 | ```
4 |
5 |
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 | * Transaction API
2 | * Merkle tree API
3 | * src/old/spend.rs for merkle_hash() function
4 | * Look at zcash_primitives::merkle_tree::CommitmentTree class
5 | * Higher level language:
6 | * Lisp / Racket
7 | * PyPEG
8 | * lark-parser has a Python3 grammar
9 | * Pyparsing
10 | * tokenize
11 | * Finish mint and spend contracts in new ZK language
12 | * Save/load setup parameters using zcash API
13 | * How big are the params?
14 | * See zec.rs
15 | * Command line tool to use VM
16 | * Take params in as a json
17 | * Poseidon hash
18 | * PoS spec
19 |
20 |
--------------------------------------------------------------------------------
/darkcli.py:
--------------------------------------------------------------------------------
1 | import argparse
2 | import requests
3 | import json
4 |
5 | def arg_parser(client):
6 | parser = argparse.ArgumentParser(prog='dark',
7 | usage='%(prog)s [commands]',
8 | description="""DarkFi wallet
9 | command-line tool""")
10 | parser.add_argument("-k", "--key", action='store_true', help="Generate a new keypair")
11 | parser.add_argument("-i", "--info", action='store_true', help="Request info from daemon")
12 | parser.add_argument("-s", "--stop", action='store_true', help="Send a stop signal to the daemon")
13 | parser.add_argument("-hi", "--hello", action='store_true', help="Say hello")
14 | args = parser.parse_args()
15 |
16 | if args.key:
17 | try:
18 | print("Attemping to generate a new key pair...")
19 | client.key_gen(client.payload)
20 | except Exception:
21 | raise
22 |
23 | if args.info:
24 | try:
25 | print("Info was entered")
26 | client.get_info(client.payload)
27 | print("Requesting daemon info...")
28 | except Exception:
29 | raise
30 |
31 | if args.stop:
32 | try:
33 | print("Stop was entered")
34 | client.stop(client.payload)
35 | print("Sending a stop signal...")
36 | except Exception:
37 | raise
38 |
39 | if args.hello:
40 | try:
41 | print("Hello was entered")
42 | client.say_hello(client.payload)
43 | except Exception:
44 | raise
45 |
46 |
47 | class DarkClient:
48 | # TODO: generate random ID (4 byte unsigned int) (rand range 0 - max size
49 | # uint32
50 | def __init__(self):
51 | self.url = "http://localhost:8000/"
52 | self.payload = {
53 | "method": [],
54 | "params": [],
55 | "jsonrpc": [],
56 | "id": [],
57 | }
58 |
59 | def key_gen(self, payload):
60 | payload['method'] = "key_gen"
61 | payload['jsonrpc'] = "2.0"
62 | payload['id'] = "0"
63 | key = self.__request(payload)
64 | print(key)
65 |
66 | def get_info(self, payload):
67 | payload['method'] = "get_info"
68 | payload['jsonrpc'] = "2.0"
69 | payload['id'] = "0"
70 | info = self.__request(payload)
71 | print(info)
72 |
73 | def stop(self, payload):
74 | payload['method'] = "stop"
75 | payload['jsonrpc'] = "2.0"
76 | payload['id'] = "0"
77 | stop = self.__request(payload)
78 | print(stop)
79 |
80 | def say_hello(self, payload):
81 | payload['method'] = "say_hello"
82 | payload['jsonrpc'] = "2.0"
83 | payload['id'] = "0"
84 | hello = self.__request(payload)
85 | print(hello)
86 |
87 | def __request(self, payload):
88 | response = requests.post(self.url, json=payload).json()
89 | # print something better
90 | # parse into data structure
91 | print(response)
92 | assert response["jsonrpc"]
93 |
94 |
95 | if __name__ == "__main__":
96 | client = DarkClient()
97 | arg_parser(client)
98 |
99 | #rpc()
100 | ## Example echo method
101 | #payload = {
102 | # #"method:": args,
103 | # #"method": "stop",
104 | # "method": "get_info",
105 | # #"method": "say_hello",
106 | # #"params": [],
107 | # "jsonrpc": "2.0",
108 | # "id": 0,
109 | #}
110 | #response = requests.post(url, json=payload).json()
111 |
112 | #print(response)
113 | #assert response["result"] == "Hello World!"
114 | #assert response["jsonrpc"]
115 |
--------------------------------------------------------------------------------
/doc/mint.pseudo:
--------------------------------------------------------------------------------
1 | param public_u
2 | param public_v
3 | param value
4 | param serial
5 | param randomness_coin
6 | param randomness_value
7 | constant generator_coin
8 | constant generator_value_commit_value
9 | constant generator_value_commit_random
10 |
11 | public coin = mimc_hash(public_u, public_v, value, serial, randomness_coin)
12 |
13 | private value_digits = unpack(value)
14 | rangeproof_assert(value, value_digits)
15 | public value_commit = jj_add(
16 | jj_mul(value, generator_value_commit_value),
17 | jj_mul(randomness_value, generator_value_commit_random)
18 | )
19 |
20 |
--------------------------------------------------------------------------------
/doc/rangeproof.pseudo:
--------------------------------------------------------------------------------
1 | param value
2 |
3 | private value_bits[] = unpack(value)
4 |
5 | digit = 1
6 | linear_combo = []
7 | for bit in value_bits:
8 | enforce (bit) * (1 - bit) == 0
9 |
10 | linear_combo.append((digit bit))
11 |
12 | digit = digit.double()
13 |
14 | enforce (linear_combo) * (~one) == value
15 |
16 |
--------------------------------------------------------------------------------
/doc/spend.pseudo:
--------------------------------------------------------------------------------
1 | param secret
2 | param serial
3 | param coin_merkle_branch[4]
4 | param coin_merkle_is_right[4]
5 | constant generator_coin
6 | constant generator_value_commit_value
7 | constant generator_value_commit_random
8 |
9 | public nullifier = mimc_hash(secret, serial)
10 |
11 | private (public_u, public_v) = jj_mul(secret, generator_coin)
12 | public coin = mimc_hash(public_u, public_v, value, serial, randomness_coin)
13 |
14 | let current = coin
15 | for i in range(4):
16 | branch = coin_merkle_branch[i]
17 | is_right = coin_merkle_is_right[i]
18 |
19 | # reverse(a, b, condition) = if condition (b, a) else (a, b)
20 | private left, right = conditionally_reverse(current, branch, is_right)
21 |
22 | # Only the last one is public
23 | if i == 3:
24 | current = public mimc_hash(left, right)
25 | else:
26 | current = private mimc_hash(left, right)
27 |
28 | private value_digits = unpack(value)
29 | rangeproof_assert(value, value_digits)
30 | public value_commit = jj_add(
31 | jj_mul(value, generator_value_commit_value),
32 | jj_mul(randomness_value, generator_value_commit_random)
33 | )
34 |
35 |
--------------------------------------------------------------------------------
/lisp/README.md:
--------------------------------------------------------------------------------
1 | ## zklisp
2 |
3 | This is a DSL for ZKVMCircuit from sapvi language.
4 |
5 | It uses the mal (lisp) version of rust with some modifications to interact with bellman backend and also sapvi vm.
6 |
7 | ## run
8 |
9 |
10 | ```
11 | cargo run --bin lisp load new.lisp
12 | ```
13 |
--------------------------------------------------------------------------------
/lisp/TODO.md:
--------------------------------------------------------------------------------
1 | ## TODO
2 |
3 | - Document the language
4 | - Integrate with zkvm command line
5 | - Integrate with ZKVMCircuit: allocs and constraints
6 | - Added CryptoOperation such double and square to core.rs
7 | - Adapt ZKContract to use lisp to read contract and execute
8 |
--------------------------------------------------------------------------------
/lisp/env.rs:
--------------------------------------------------------------------------------
1 | use std::cell::RefCell;
2 | use std::collections::HashMap;
3 | use std::rc::Rc;
4 | // use fnv::FnvHashMap;
5 |
6 | use crate::types::MalErr::ErrString;
7 | use crate::types::MalVal::{List, Nil, Sym, Vector};
8 | use crate::types::{error, MalErr, MalRet, MalVal};
9 |
10 | #[derive(Debug)]
11 | pub struct EnvStruct {
12 | data: RefCell>,
13 | pub outer: Option,
14 | }
15 |
16 | pub type Env = Rc;
17 |
18 | // TODO: it would be nice to use impl here but it doesn't work on
19 | // a deftype (i.e. Env)
20 |
21 | pub fn env_new(outer: Option) -> Env {
22 | Rc::new(EnvStruct {
23 | data: RefCell::new(HashMap::default()),
24 | outer: outer,
25 | })
26 | }
27 |
28 | // TODO: mbinds and exprs as & types
29 | pub fn env_bind(outer: Option, mbinds: MalVal, exprs: Vec) -> Result {
30 | let env = env_new(outer);
31 | match mbinds {
32 | List(binds, _) | Vector(binds, _) => {
33 | for (i, b) in binds.iter().enumerate() {
34 | match b {
35 | Sym(s) if s == "&" => {
36 | env_set(&env, binds[i + 1].clone(), list!(exprs[i..].to_vec()))?;
37 | break;
38 | }
39 | _ => {
40 | env_set(&env, b.clone(), exprs[i].clone())?;
41 | }
42 | }
43 | }
44 | Ok(env)
45 | }
46 | _ => Err(ErrString("env_bind binds not List/Vector".to_string())),
47 | }
48 | }
49 |
50 | pub fn env_find(env: &Env, key: &str) -> Option {
51 | match (env.data.borrow().contains_key(key), env.outer.clone()) {
52 | (true, _) => Some(env.clone()),
53 | (false, Some(o)) => env_find(&o, key),
54 | _ => None,
55 | }
56 | }
57 |
58 | pub fn env_get(env: &Env, key: &MalVal) -> MalRet {
59 | match key {
60 | Sym(ref s) => match env_find(env, s) {
61 | Some(e) => Ok(e
62 | .data
63 | .borrow()
64 | .get(s)
65 | .ok_or(ErrString(format!("'{}' not found", s)))?
66 | .clone()),
67 | _ => error(&format!("'{}' not found", s)),
68 | },
69 | _ => error("Env.get called with non-Str"),
70 | }
71 | }
72 |
73 | pub fn env_set(env: &Env, key: MalVal, val: MalVal) -> MalRet {
74 | match key {
75 | Sym(ref s) => {
76 | env.data.borrow_mut().insert(s.to_string(), val.clone());
77 | Ok(val)
78 | }
79 | _ => error("Env.set called with non-Str"),
80 | }
81 | }
82 |
83 | pub fn env_sets(env: &Env, key: &str, val: MalVal) {
84 | env.data.borrow_mut().insert(key.to_string(), val);
85 | }
86 |
--------------------------------------------------------------------------------
/lisp/examples/jubjub-add-macro.lisp:
--------------------------------------------------------------------------------
1 | (println "jubjub-add-macro.lisp")
2 | (load-file "util.lisp")
3 |
4 | (defmacro! jubjub-add (fn* [param1 param2 param3 param4]
5 | (let* [u1 (gensym) v1 (gensym) u2 (gensym) v2 (gensym)
6 | EDWARDS_D (gensym) U (gensym) A (gensym) B (gensym)
7 | C (gensym) u3 (gensym) v3 (gensym)] (
8 | `(def! ~u1 (alloc ~u1 param1))
9 | `(def! ~v1 (alloc ~v1 param2))
10 | `(def! ~u2 (alloc ~u2 param3))
11 | `(def! ~v2 (alloc ~v2 param4))
12 | `(def! ~EDWARDS_D (alloc-const ~EDWARDS_D (scalar "2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1")))
13 | `(def! ~U (alloc ~U (* (+ ~u1 ~v1) (+ ~u2 ~v2))))
14 | `(def! ~A (alloc ~A (* ~v2 ~u1)))
15 | `(def! ~B (alloc ~B (* ~u2 ~v1)))
16 | `(def! ~C (alloc ~C (* ~EDWARDS_D (* ~A ~B))))
17 | `(def! ~u3 (alloc-input ~u3 (/ (+ ~A ~B) (+ scalar::one ~C))))
18 | `(def! ~v3 (alloc-input ~v3 (/ (- (- ~U ~A) ~B) (- scalar::one ~C))))
19 | `(enforce
20 | ((scalar::one ~u1) (scalar::one ~v1))
21 | ((scalar::one ~u2) (scalar::one ~v2))
22 | (scalar::one ~U)
23 | )
24 | `(enforce
25 | (~EDWARDS_D ~A)
26 | (scalar::one ~B)
27 | (scalar::one ~C)
28 | )
29 | `(enforce
30 | ((scalar::one cs::one)(scalar::one ~C))
31 | (scalar::one ~u3)
32 | ((scalar::one ~A) (scalar::one ~B))
33 | )
34 | `(enforce
35 | ((scalar::one cs::one) (scalar::one::neg ~C))
36 | (scalar::one ~v3)
37 | ((scalar::one ~U) (scalar::one::neg ~A) (scalar::one::neg ~B))
38 | )
39 | )
40 | ;; improve return values
41 | )
42 | ))
43 |
44 | (def! param4 (scalar "015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891"))
45 | (def! param3 (scalar "15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e"))
46 | (def! param2 (scalar "015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891"))
47 | (def! param1 (scalar "15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e"))
48 |
49 | (prove (
50 | (def! result1 (jubjub-add param1 param2 param3 param4))
51 | (println 'jubjub-result result1)
52 | ))
--------------------------------------------------------------------------------
/lisp/examples/jubjub.lisp:
--------------------------------------------------------------------------------
1 | (println "jubjub-add.lisp")
2 | (load-file "util.lisp")
3 |
4 | (defmacro! zk-square (fn* [var] (
5 | (let* [v1 (gensym)
6 | v2 (gensym)] (
7 | `(alloc ~v1 ~var)
8 | `(alloc ~v2 (square ~var))
9 | `(enforce
10 | (scalar::one ~v1)
11 | (scalar::one ~v1)
12 | (scalar::one ~v2)
13 | )
14 | )
15 | ))
16 | ))
17 |
18 | ;; -u^2 + v^2 = 1 + du^2v^2
19 | (defmacro! zk-witness (fn* [val1 val2] (
20 | (let* [v (gensym)
21 | u (gensym)
22 | u2v2 (gensym)] (
23 | `(alloc ~v1 ~var)
24 | `(alloc ~v2 (square ~var))
25 | `(enforce
26 | (scalar::one ~v1)
27 | (scalar::one ~v1)
28 | (scalar::one ~v2)
29 | )
30 | )
31 | ))
32 | ))
33 |
34 | (defmacro! jubjub-add (fn* [param1 param2 param3 param4]
35 | (let* [u1 (gensym) v1 (gensym) u2 (gensym) v2 (gensym)
36 | EDWARDS_D (gensym) U (gensym) A (gensym) B (gensym)
37 | C (gensym) u3 (gensym) v3 (gensym)] (
38 | `(def! ~u1 (alloc ~u1 param1))
39 | `(def! ~v1 (alloc ~v1 param2))
40 | `(def! ~u2 (alloc ~u2 param3))
41 | `(def! ~v2 (alloc ~v2 param4))
42 | `(def! ~EDWARDS_D (alloc-const ~EDWARDS_D (scalar "2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1")))
43 | `(def! ~U (alloc ~U (* (+ ~u1 ~v1) (+ ~u2 ~v2))))
44 | `(def! ~A (alloc ~A (* ~v2 ~u1)))
45 | `(def! ~B (alloc ~B (* ~u2 ~v1)))
46 | `(def! ~C (alloc ~C (* ~EDWARDS_D (* ~A ~B))))
47 | `(def! ~u3 (alloc-input ~u3 (/ (+ ~A ~B) (+ scalar::one ~C))))
48 | `(def! ~v3 (alloc-input ~v3 (/ (- (- ~U ~A) ~B) (- scalar::one ~C))))
49 | `(enforce
50 | ((scalar::one ~u1) (scalar::one ~v1))
51 | ((scalar::one ~u2) (scalar::one ~v2))
52 | (scalar::one ~U)
53 | )
54 | `(enforce
55 | (~EDWARDS_D ~A)
56 | (scalar::one ~B)
57 | (scalar::one ~C)
58 | )
59 | `(enforce
60 | ((scalar::one cs::one)(scalar::one ~C))
61 | (scalar::one ~u3)
62 | ((scalar::one ~A) (scalar::one ~B))
63 | )
64 | `(enforce
65 | ((scalar::one cs::one) (scalar::one::neg ~C))
66 | (scalar::one ~v3)
67 | ((scalar::one ~U) (scalar::one::neg ~A) (scalar::one::neg ~B))
68 | )
69 | )
70 | ;; improve return values
71 | )
72 | ))
73 |
74 | (prove
75 | (
76 | (def! result-witness (zk-witness param1 param2))
77 | (println 'result-witness (nth (nth result-witness 0) 1))
78 | )
79 | )
--------------------------------------------------------------------------------
/lisp/examples/util.lisp:
--------------------------------------------------------------------------------
1 | (def! inc (fn* [a] (i+ a 1)))
2 | (def! gensym
3 | (let* [counter (atom 0)]
4 | (fn* []
5 | (symbol (str "G__" (swap! counter inc))))))
6 |
7 | (def! gensym2
8 | (let* [counter (atom 0)]
9 | (fn* [name]
10 | (symbol (str name "__" (swap! counter inc))))))
11 | ;; Like load-file, but will never load the same path twice.
12 |
13 | ;; This file is normally loaded with `load-file`, so it needs a
14 | ;; different mechanism to neutralize multiple inclusions of
15 | ;; itself. Moreover, the file list should never be reset.
16 |
17 | (def! load-file-once
18 | (try*
19 | load-file-once
20 | (catch* _
21 | (let* [seen (atom {"../lib/util.mal" nil})]
22 | (fn* [filename]
23 | (if (not (contains? @seen filename))
24 | (do
25 | (swap! seen assoc filename nil)
26 | (load-file filename))))))))
27 |
--------------------------------------------------------------------------------
/lisp/printer.rs:
--------------------------------------------------------------------------------
1 | use crate::types::MalVal;
2 | use crate::types::MalVal::{Atom, Bool, Func, Hash, Int, List, MalFunc, Nil, Str, Sym, Vector};
3 |
4 | fn escape_str(s: &str) -> String {
5 | s.chars()
6 | .map(|c| match c {
7 | '"' => "\\\"".to_string(),
8 | '\n' => "\\n".to_string(),
9 | '\\' => "\\\\".to_string(),
10 | _ => c.to_string(),
11 | })
12 | .collect::>()
13 | .join("")
14 | }
15 |
16 | impl MalVal {
17 | pub fn pr_str(&self, print_readably: bool) -> String {
18 | match self {
19 | Nil => String::from("nil"),
20 | Bool(true) => String::from("true"),
21 | Bool(false) => String::from("false"),
22 | Int(i) => format!("{}", i),
23 | //Float(f) => format!("{}", f),
24 | Str(s) => {
25 | if s.starts_with("\u{29e}") {
26 | format!(":{}", &s[2..])
27 | } else if print_readably {
28 | format!("\"{}\"", escape_str(s))
29 | } else {
30 | s.clone()
31 | }
32 | }
33 | Sym(s) => s.clone(),
34 | List(l, _) => pr_seq(&**l, print_readably, "(", ")", " "),
35 | Vector(l, _) => pr_seq(&**l, print_readably, "[", "]", " "),
36 | Hash(hm, _) => {
37 | let l: Vec = hm
38 | .iter()
39 | .flat_map(|(k, v)| vec![Str(k.to_string()), v.clone()])
40 | .collect();
41 | pr_seq(&l, print_readably, "{", "}", " ")
42 | }
43 | Func(f, _) => format!("#", f),
44 | MalFunc {
45 | ast: a, params: p, ..
46 | } => format!("(fn* {} {})", p.pr_str(true), a.pr_str(true)),
47 | Atom(a) => format!("(atom {})", a.borrow().pr_str(true)),
48 | MalVal::ZKScalar(a) => format!("{:?}", a),
49 | i => format!("{:?}", i.pr_str(true)),
50 | }
51 | }
52 | }
53 |
54 | pub fn pr_seq(
55 | seq: &Vec,
56 | print_readably: bool,
57 | start: &str,
58 | end: &str,
59 | join: &str,
60 | ) -> String {
61 | let strs: Vec = seq.iter().map(|x| x.pr_str(print_readably)).collect();
62 | format!("{}{}{}", start, strs.join(join), end)
63 | }
64 |
--------------------------------------------------------------------------------
/lisp/racket/jj.rkt:
--------------------------------------------------------------------------------
1 | #lang racket
2 |
3 | (require "zk.rkt")
4 |
5 | (struct jj_point
6 | (u v)
7 | )
8 |
9 | (define (create_jj_param_point name)
10 | (jj_point
11 | (zk_param (string-append name "_u"))
12 | (zk_param (string-append name "_v"))
13 | )
14 | )
15 | (define (create_jj_public_point name)
16 | (jj_point
17 | (zk_public (string-append name "_u"))
18 | (zk_public (string-append name "_v"))
19 | )
20 | )
21 |
22 | (define (zk_jj_add namespace result a b)
23 | (zk_comment "call jj_add()")
24 | (let* ([namespace (append namespace (list "_jj_add"))]
25 | [U (zk_private namespace 'U)]
26 | [A (zk_private namespace 'A)]
27 | [B (zk_private namespace 'B)]
28 | [C (zk_private namespace 'C)]
29 | [tmp (zk_local namespace 'tmp)])
30 | (zk_comment "Compute U = (x1 + y1) * (y2 - EDWARDS_A*x2)")
31 | (zk_comment " = (x1 + y1) * (x2 + y2)")
32 | (zk_set U (jj_point-u a))
33 | (zk_add U (jj_point-v a))
34 |
35 | (zk_set tmp (jj_point-u b))
36 | (zk_add tmp (jj_point-v b))
37 |
38 | (zk_mul U tmp)
39 |
40 | (zk_comment "assert (x1 + y1) * (x2 + y2) == U")
41 | (zk_lc0_add (jj_point-u a))
42 | (zk_lc0_add (jj_point-v a))
43 | (zk_lc1_add (jj_point-u b))
44 | (zk_lc1_add (jj_point-v b))
45 | (zk_lc2_add U)
46 | (zk_enforce)
47 |
48 | (zk_comment "Compute A = y2 * x1")
49 | (zk_set A (jj_point-v b))
50 | (zk_mul A (jj_point-u a))
51 | (zk_comment "Compute B = x2 * y1")
52 | (zk_set B (jj_point-u b))
53 | (zk_mul B (jj_point-v a))
54 | (zk_comment "Compute C = d*A*B")
55 | (zk_load C const_d)
56 | (zk_mul C A)
57 | (zk_mul C B)
58 |
59 | (zk_comment "assert (d * A) * (B) == C")
60 | (zk_lc0_add_coeff const_d A)
61 | (zk_lc1_add B)
62 | (zk_lc2_add C)
63 | (zk_enforce)
64 |
65 | (zk_comment "Compute P.x = (A + B) / (1 + C)")
66 | (zk_set (jj_point-u result) A)
67 | (zk_add (jj_point-u result) B)
68 | ; Re-use the tmp variable from earlier here
69 | (zk_load tmp const_one)
70 | (zk_add tmp C)
71 | (zk_divide (jj_point-u result) tmp)
72 |
73 | (zk_lc0_add_one)
74 | (zk_lc0_add C)
75 | (zk_lc1_add (jj_point-u result))
76 | (zk_lc2_add A)
77 | (zk_lc2_add B)
78 | (zk_enforce)
79 |
80 | (zk_comment "Compute P.y = (U - A - B) / (1 - C)")
81 | (zk_set (jj_point-v result) U)
82 | (zk_sub (jj_point-v result) A)
83 | (zk_sub (jj_point-v result) B)
84 | ; Re-use the tmp variable from earlier here
85 | (zk_load tmp const_one)
86 | (zk_sub tmp C)
87 | (zk_divide (jj_point-v result) tmp)
88 |
89 | (zk_lc0_add_one)
90 | (zk_lc0_sub C)
91 | (zk_lc1_add (jj_point-v result))
92 | (zk_lc2_add U)
93 | (zk_lc2_sub A)
94 | (zk_lc2_sub B)
95 | (zk_enforce)
96 | )
97 | )
98 |
99 | (create_zk_output "jj.psm")
100 |
101 | (define const_d (zk_constant
102 | "d" "0x2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1"))
103 | (define const_one (zk_constant
104 | "one" "0x0000000000000000000000000000000000000000000000000000000000000001"))
105 |
106 | (zk_contract_begin "foo")
107 | (define namespace (list "_"))
108 | (define a (create_jj_param_point "a"))
109 | (define b (create_jj_param_point "b"))
110 | (define result (create_jj_public_point "result"))
111 | (zk_jj_add namespace result a b)
112 | (zk_contract_end)
113 |
114 |
--------------------------------------------------------------------------------
/lisp/racket/zk.rkt:
--------------------------------------------------------------------------------
1 | #lang racket
2 |
3 | (provide zk_variable)
4 | (provide zk_constant)
5 | (provide zk_param)
6 | (provide zk_public)
7 | (provide zk_local)
8 | (provide zk_private)
9 | (provide zk_comment)
10 | (provide zk_set)
11 | (provide zk_add)
12 | (provide zk_sub)
13 | (provide zk_mul)
14 | (provide zk_divide)
15 | (provide zk_load)
16 | (provide zk_lc0_add)
17 | (provide zk_lc1_add)
18 | (provide zk_lc2_add)
19 | (provide zk_lc0_sub)
20 | (provide zk_lc1_sub)
21 | (provide zk_lc2_sub)
22 | (provide zk_lc0_add_coeff)
23 | (provide zk_lc1_add_coeff)
24 | (provide zk_lc2_add_coeff)
25 | (provide zk_lc0_add_one)
26 | (provide zk_lc1_add_one)
27 | (provide zk_lc2_add_one)
28 | (provide zk_enforce)
29 |
30 | (provide create_zk_output)
31 | (provide zk_contract_begin)
32 | (provide zk_contract_end)
33 |
34 | (define out '0)
35 | (define (create_zk_output filename)
36 | (set! out (open-output-file "jj.psm" #:exists 'truncate))
37 | )
38 |
39 | (struct zk_variable
40 | (name type)
41 | )
42 |
43 | (define (zk_constant name hex_value)
44 | (fprintf out "constant ~a ~a\n" name hex_value)
45 | name
46 | )
47 |
48 | (define (zk_contract_begin contract_name)
49 | (fprintf out "contract ~a\n" contract_name)
50 | )
51 | (define (zk_contract_end)
52 | (fprintf out "end\n")
53 | )
54 |
55 | (define (zk_param name)
56 | (fprintf out "param ~a\n" name)
57 | (zk_variable name 'param)
58 | )
59 |
60 | (define (zk_public name)
61 | (fprintf out "public ~a\n" name)
62 | (zk_variable name 'public)
63 | )
64 |
65 | (define (strings->string sts)
66 | (apply string-append sts))
67 |
68 | (define (apply_ns namespace name)
69 | (strings->string
70 | (append namespace
71 | (list "__" (symbol->string name))
72 | )))
73 |
74 | (define (zk_local namespace name)
75 | (let ([name (apply_ns namespace name)])
76 | (fprintf out "local ~a\n" name)
77 | (zk_variable name 'local)
78 | )
79 | )
80 |
81 | (define (zk_private namespace name)
82 | (let ([name (apply_ns namespace name)])
83 | (fprintf out "private ~a\n" name)
84 | (zk_variable name 'private)
85 | )
86 | )
87 |
88 | (define (zk_comment str)
89 | (fprintf out "# ~a\n" str)
90 | )
91 |
92 | (define (zk_set self other)
93 | (fprintf out "set ~a ~a\n" (zk_variable-name self) (zk_variable-name other))
94 | )
95 | (define (zk_add self other)
96 | (fprintf out "add ~a ~a\n" (zk_variable-name self) (zk_variable-name other))
97 | )
98 | (define (zk_sub self other)
99 | (fprintf out "sub ~a ~a\n" (zk_variable-name self) (zk_variable-name other))
100 | )
101 | (define (zk_mul self other)
102 | (fprintf out "mul ~a ~a\n" (zk_variable-name self) (zk_variable-name other))
103 | )
104 | (define (zk_divide self other)
105 | (fprintf out "divide ~a ~a\n"
106 | (zk_variable-name self) (zk_variable-name other))
107 | )
108 |
109 | (define (zk_load self constant)
110 | (fprintf out "load ~a ~a\n" (zk_variable-name self) constant)
111 | )
112 |
113 | (define (zk_lc0_add self)
114 | (fprintf out "lc0_add ~a\n" (zk_variable-name self)))
115 | (define (zk_lc1_add self)
116 | (fprintf out "lc1_add ~a\n" (zk_variable-name self)))
117 | (define (zk_lc2_add self)
118 | (fprintf out "lc2_add ~a\n" (zk_variable-name self)))
119 | (define (zk_lc0_sub self)
120 | (fprintf out "lc0_sub ~a\n" (zk_variable-name self)))
121 | (define (zk_lc1_sub self)
122 | (fprintf out "lc1_sub ~a\n" (zk_variable-name self)))
123 | (define (zk_lc2_sub self)
124 | (fprintf out "lc2_sub ~a\n" (zk_variable-name self)))
125 | (define (zk_lc0_add_coeff constant self)
126 | (fprintf out "lc0_add_coeff ~a ~a\n" constant (zk_variable-name self)))
127 | (define (zk_lc1_add_coeff constant self)
128 | (fprintf out "lc1_add_coeff ~a ~a\n" constant (zk_variable-name self)))
129 | (define (zk_lc2_add_coeff constant self)
130 | (fprintf out "lc2_add_coeff ~a ~a\n" constant (zk_variable-name self)))
131 | (define (zk_lc0_add_one)
132 | (fprintf out "lc0_add_one\n"))
133 | (define (zk_lc1_add_one)
134 | (fprintf out "lc1_add_one\n"))
135 | (define (zk_lc2_add_one)
136 | (fprintf out "lc2_add_one\n"))
137 | (define (zk_enforce)
138 | (fprintf out "enforce\n")
139 | )
140 |
141 |
142 |
--------------------------------------------------------------------------------
/lisp/run.sh:
--------------------------------------------------------------------------------
1 | export RUST_BACKTRACE=full
2 | cargo run --bin lisp load mint2.lisp
3 | #cargo run --bin lisp load jubjub-mul.lisp
4 | #cargo run --bin lisp load new-cs.lisp
5 |
--------------------------------------------------------------------------------
/proofs/bits.psm:
--------------------------------------------------------------------------------
1 | contract bits_decomposition
2 | param x
3 | {% for i in range(256) %}
4 | private b_{{i}}
5 | {% endfor %}
6 |
7 | # x is unpacked into little endian order
8 | unpack_bits x b_0 b_255
9 |
10 | {% for i in range(256) %}
11 | # (1 - b) * b == 0
12 | lc0_add_one
13 | lc0_sub b_{{i}}
14 |
15 | lc1_add b_{{i}}
16 |
17 | enforce
18 | {% endfor %}
19 |
20 | {% for i in range(256) %}
21 | lc0_add b_{{i}}
22 | lc_coeff_double
23 | {% endfor %}
24 | lc_coeff_reset
25 | lc0_sub x
26 | lc1_add_one
27 | enforce
28 | end
29 |
30 |
--------------------------------------------------------------------------------
/proofs/jubjub.params:
--------------------------------------------------------------------------------
1 | a_u 15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e
2 | a_v 015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891
3 | b_u 15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e
4 | b_v 015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891
5 |
--------------------------------------------------------------------------------
/proofs/jubjub.psm:
--------------------------------------------------------------------------------
1 | constant a 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000
2 | constant d 0x2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1
3 | constant one 0x0000000000000000000000000000000000000000000000000000000000000001
4 |
5 | {% macro jubjub_add(P, x1, y1, x2, y2) -%}
6 | # Compute U = (x1 + y1) * (y2 - EDWARDS_A*x2)
7 | # = (x1 + y1) * (x2 + y2)
8 | private {{P}}_U
9 | set {{P}}_U {{ x1 }}
10 | add {{P}}_U {{ y1 }}
11 | local {{P}}_tmp
12 | set {{P}}_tmp {{ x2 }}
13 | add {{P}}_tmp {{ y2 }}
14 | mul {{P}}_U {{P}}_tmp
15 |
16 | # assert (x1 + y1) * (x2 + y2) == U
17 | lc0_add {{ x1 }}
18 | lc0_add {{ y1 }}
19 | lc1_add {{ x2 }}
20 | lc1_add {{ y2 }}
21 | lc2_add {{P}}_U
22 | enforce
23 |
24 | # Compute A = y2 * x1
25 | private {{P}}_A
26 | set {{P}}_A {{ y2 }}
27 | mul {{P}}_A {{ x1 }}
28 | # Compute B = x2 * y1
29 | private {{P}}_B
30 | set {{P}}_B {{ x2 }}
31 | mul {{P}}_B {{ y1 }}
32 | # Compute C = d*A*B
33 | private {{P}}_C
34 | load {{P}}_C d
35 | mul {{P}}_C {{P}}_A
36 | mul {{P}}_C {{P}}_B
37 |
38 | # assert (d * A) * (B) == C
39 | lc0_add_coeff d {{P}}_A
40 | lc1_add {{P}}_B
41 | lc2_add {{P}}_C
42 | enforce
43 |
44 | # Compute P.x = (A + B) / (1 + C)
45 | private {{P}}_x
46 | set {{P}}_x {{P}}_A
47 | add {{P}}_x {{P}}_B
48 | local {{P}}_x_denom
49 | load {{P}}_x_denom one
50 | add {{P}}_x_denom {{P}}_C
51 | divide {{P}}_x {{P}}_x_denom
52 |
53 | lc0_add_one
54 | lc0_add {{P}}_C
55 | lc1_add {{P}}_x
56 | lc2_add {{P}}_A
57 | lc2_add {{P}}_B
58 | enforce
59 |
60 | # Compute P.y = (U - A - B) / (1 - C)
61 | private {{P}}_y
62 | set {{P}}_y {{P}}_U
63 | sub {{P}}_y {{P}}_A
64 | sub {{P}}_y {{P}}_B
65 | local {{P}}_y_denom
66 | load {{P}}_y_denom one
67 | sub {{P}}_y_denom {{P}}_C
68 | divide {{P}}_y {{P}}_y_denom
69 |
70 | lc0_add_one
71 | lc0_sub {{P}}_C
72 | lc1_add {{P}}_y
73 | lc2_add {{P}}_U
74 | lc2_sub {{P}}_A
75 | lc2_sub {{P}}_B
76 | enforce
77 | {%- endmacro %}
78 |
79 | contract input_spend
80 | param x1
81 | param y1
82 |
83 | param x2
84 | param y2
85 |
86 | {{ jubjub_add("P", "x1", "y1", "x2", "y2") }}
87 |
88 | public x3
89 | set x3 P_x
90 | public y3
91 | set y3 P_y
92 |
93 | lc0_add x3
94 | lc1_add_one
95 | lc2_add P_x
96 | enforce
97 |
98 | lc0_add y3
99 | lc1_add_one
100 | lc2_add P_y
101 | enforce
102 | end
103 |
104 |
--------------------------------------------------------------------------------
/proofs/mimc.psm:
--------------------------------------------------------------------------------
1 | {% include 'mimc_constants.psm' %}
2 |
3 | contract mimc
4 | param left_0
5 | param right
6 |
7 | {# Jinja cannot set variables inside loops so use this hack #}
8 | {% set ns = namespace(right="right") %}
9 |
10 | {% for i in range(322) %}
11 | # Each round perform these steps:
12 | # xL, xR := xR + (xL + Ci)^3, xL
13 |
14 | local mimc_const
15 | load mimc_const mimc_constant_{{i}}
16 |
17 | private tmp_{{i}}
18 | set tmp_{{i}} left_{{i}}
19 | add tmp_{{i}} mimc_const
20 | square tmp_{{i}}
21 |
22 | lc0_add left_{{i}}
23 | lc0_add_constant mimc_constant_{{i}}
24 | lc1_add left_{{i}}
25 | lc1_add_constant mimc_constant_{{i}}
26 | lc2_add tmp_{{i}}
27 | enforce
28 |
29 | # new_xL = xR + (xL + Ci)^3
30 | # new_xL = xR + tmp * (xL + Ci)
31 | # new_xL - xR = tmp * (xL + Ci)
32 | private left_{{i+1}}
33 | set left_{{i+1}} left_{{i}}
34 | add left_{{i+1}} mimc_const
35 | mul left_{{i+1}} tmp_{{i}}
36 | add left_{{i+1}} {{ns.right}}
37 |
38 | lc0_add tmp_{{i}}
39 | lc1_add left_{{i}}
40 | lc1_add_constant mimc_constant_{{i}}
41 | lc2_add left_{{i+1}}
42 | lc2_sub {{ns.right}}
43 | enforce
44 |
45 | # xR = xL
46 | # right_{{i+1}} = left_{{i}}
47 | {% set ns.right = "left_" + i|string %}
48 |
49 | # xL = new_xL
50 | {% endfor %}
51 |
52 | public hash_result
53 | set hash_result left_322
54 |
55 | lc0_add left_322
56 | lc1_add_one
57 | lc2_add hash_result
58 | enforce
59 | end
60 |
61 |
--------------------------------------------------------------------------------
/proofs/mint.pism:
--------------------------------------------------------------------------------
1 | # :set syntax=pism
2 | # :source ../scripts/pism.vim
3 | constant G_VCV FixedGenerator
4 | constant G_VCR FixedGenerator
5 | constant CRH_IVK BlakePersonalization
6 | #constant JUBJUB_FR_CAPACITY BinarySize
7 | #constant NOTE_COMMIT PedersenPersonalization
8 |
9 | contract mint_contract
10 | # Value commitment
11 | param value U64
12 | param randomness_value Fr
13 |
14 | param serial Fr
15 | param randomness_coin Fr
16 | param public Point
17 | start
18 | # Witness input values
19 | u64_as_binary_le value param:value
20 | fr_as_binary_le randomness_value param:randomness_value
21 | fr_as_binary_le serial param:serial
22 | fr_as_binary_le randomness_coin param:randomness_coin
23 |
24 | witness public param:public
25 | assert_not_small_order public
26 |
27 | # Make value commitment
28 | # V = v * G_VCV + r * G_VCR
29 |
30 | ec_mul_const vcv value G_VCV
31 | ec_mul_const rcv randomness_value G_VCR
32 | ec_add cv vcv rcv
33 | # emit cv
34 | emit_ec cv
35 |
36 | # Make the coin
37 | # C = Hash(public_key, value, serial, randomness_coin)
38 |
39 | # Build the preimage to hash
40 | alloc_binary preimage
41 |
42 | # public_key
43 | ec_repr repr_public public
44 | binary_extend preimage repr_public
45 |
46 | # value
47 | binary_extend preimage value
48 |
49 | # Fr values are 252 bits so we need to pad it with extra 0s
50 | # to match the Rust values which are 256 bits
51 | {% macro binary_put_fr(binary, var) -%}
52 | binary_extend {{ binary }} {{ var }}
53 | {% for n in range(4) %}
54 | alloc_const_bit zero_bit false
55 | binary_push {{ binary }} zero_bit
56 | {% endfor %}
57 | {%- endmacro %}
58 |
59 | # serial
60 | {{ binary_put_fr("preimage", "serial") }}
61 |
62 | # randomness_coin
63 | {{ binary_put_fr("preimage", "randomness_coin") }}
64 |
65 | # Public key: SubgroupPoint = 256 bits
66 | # Value: u64 = 64 bits
67 | # Serial: Fr = 252 + 4 bits padding
68 | # Randomness coin Fr = 252 + 4 bits padding
69 | # TOTAL: 832 bits for preimage
70 | static_assert_binary_size preimage 832
71 | blake2s coin preimage CRH_IVK
72 | emit_binary coin
73 | end
74 |
75 |
--------------------------------------------------------------------------------
/proofs/old/mint.aux:
--------------------------------------------------------------------------------
1 | {
2 | "constants": {
3 | "G_SPEND": {
4 | "maps_to": "zcash_proofs::constants::SPENDING_KEY_GENERATOR"
5 | },
6 | "G_PROOF": {
7 | "maps_to": "zcash_proofs::constants::PROOF_GENERATION_KEY_GENERATOR"
8 | },
9 | "CRH_IVK": {
10 | "maps_to": "zcash_primitives::constants::CRH_IVK_PERSONALIZATION"
11 | },
12 | "PRF_NF": {
13 | "maps_to": "zcash_primitives::constants::PRF_NF_PERSONALIZATION"
14 | },
15 | "G_VCV": {
16 | "maps_to": "zcash_proofs::constants::VALUE_COMMITMENT_VALUE_GENERATOR"
17 | },
18 | "G_VCR": {
19 | "maps_to": "zcash_proofs::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR"
20 | },
21 | "JUBJUB_FR_CAPACITY": {
22 | "maps_to": "jubjub::Fr::CAPACITY as usize"
23 | },
24 | "NOTE_COMMIT": {
25 | "maps_to": "pedersen_hash::Personalization::NoteCommitment"
26 | },
27 | "MERKLE_0": {
28 | "maps_to": "pedersen_hash::Personalization::MerkleTree(0)"
29 | },
30 | "MERKLE_1": {
31 | "maps_to": "pedersen_hash::Personalization::MerkleTree(1)"
32 | },
33 | "MERKLE_2": {
34 | "maps_to": "pedersen_hash::Personalization::MerkleTree(2)"
35 | },
36 | "MERKLE_3": {
37 | "maps_to": "pedersen_hash::Personalization::MerkleTree(3)"
38 | }
39 | }
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/proofs/old/saplingb.prf:
--------------------------------------------------------------------------------
1 | # :set syntax=sapvi
2 | # :source ../scripts/sapvi.vim
3 | const:
4 | G_VCV: SubgroupPoint
5 | G_VCR: SubgroupPoint
6 | G_SPEND: SubgroupPoint
7 | G_PROOF: SubgroupPoint
8 | G_NOTE_COMMIT_R: SubgroupPoint
9 | G_NULL: SubgroupPoint
10 |
11 | CRH_IVK: Blake2sPersonalization
12 | NOTE_COMMIT: PedersenPersonalization
13 | MERKLE: list
14 | PRF_NF: Blake2sPersonalization
15 |
16 | contract input_spend(
17 | value: U64 -> BinaryNumber
18 | randomness: Fr -> BinaryNumber
19 | ak: Point
20 | ar: Fr -> BinaryNumber
21 | nsk: Fr -> BinaryNumber
22 | g_d: Point
23 | commitment_randomness: Fr -> BinaryNumber
24 | auth_path: [(Scalar, Bool)]
25 | anchor: Scalar
26 | ) -> (Point, Point, Scalar, BinaryNumber):
27 | let rk: Point = ak + ar * G_SPEND
28 | emit rk
29 |
30 | let nk: Point = nsk * G_PROOF
31 |
32 | let mut ivk_preimage: BinaryNumber = []
33 | ivk_preimage.put(ak)
34 |
35 | let mut nf_preimage: BinaryNumber = []
36 |
37 | ivk_preimage.put(nk)
38 | nf_preimage.put(nk)
39 |
40 | assert ivk_preimage.len() == 512
41 | assert nf_preimage.len() == 256
42 |
43 | let mut ivk = blake2s(ivk_preimage, CRH_IVK)
44 | ivk.truncate(JUBJUB_FR_CAPACITY)
45 | # This will error if ivk.len() != 256
46 | #let ivk: Fr = ivk as Fr
47 | let pk_d: Point = ivk * g_d
48 |
49 | let cv: Point = value * G_VCV + rcv * G_VCR
50 | emit cv
51 |
52 | let mut note_contents: BinaryNumber = []
53 | note_contents.put(value)
54 | note_contents.put(g_d)
55 | note_contents.put(p_k)
56 | assert note_contents.len() == 64 + 256 + 256
57 |
58 | let mut cm = pedersen_hash(note_contents, NOTE_COMMIT)
59 | cm += commitment_randomness * G_NOTE_COMMIT_R
60 |
61 | let mut position = []
62 | let mut cur: Scalar = cm.u
63 |
64 | for i in range(auth_path.size()):
65 | let (node: Scalar, is_right: Bool) = auth_path[i]
66 |
67 | position.push(is_right)
68 |
69 | # Scalar -> AllocatedNum
70 | let (left: Scalar, right: Scalar) = swap_if(is_right, cur, node)
71 |
72 | let mut preimage: BinaryNumber = []
73 | preimage.put(left)
74 | preimage.put(right)
75 |
76 | cur = pedersen_hash(MERKLE_TREE[i], preimage).u
77 |
78 | enforce cur == rt
79 | emit rt
80 |
81 | let rho: Point = rho + position * G_NULL
82 |
83 | nf_preimage.put(rho)
84 | assert nf_preimage.len() == 512
85 |
86 | let nf: BinaryNumber = blake2s(nf_preimage, PRF_NF)
87 | emit nf
88 |
89 | contract output_mint(
90 | value: U64 -> BinaryNumber
91 | randomness: Fr -> BinaryNumber
92 | g_d: Point
93 | esk: Fr -> BinaryNumber
94 | pk_d: Point
95 | commitment_randomness: Fr -> BinaryNumber
96 | ) -> (Point, Point, Scalar):
97 | let cv: Point = value * G_VCV + rcv * G_VCR
98 | emit cv
99 |
100 | let mut note_contents: Binary = []
101 | note_contents.put(value)
102 |
103 | let epk: Point = esk * g_d
104 | emit epk
105 |
106 | let v_contents: Scalar = pk_d.v
107 | let sign_bit: Bool = pk_d.u.is_odd()
108 |
109 | note_contents.put(v_contents)
110 | note_contents.put(sign_bit)
111 |
112 | assert len(note_contents) == 64 + 256 + 256
113 |
114 | let mut cm: Point = pedersen_hash(note_contents, NOTE_COMMIT)
115 | let rcm: Point = commitment_randomness * G_NOTE_COMMIT_R
116 | cm += rcm
117 |
118 | let cmu: Scalar = cm.u
119 | emit cmu
120 |
121 |
--------------------------------------------------------------------------------
/proofs/old/simple.aux:
--------------------------------------------------------------------------------
1 | {
2 | "constants": {
3 | "G_SPEND": {
4 | "maps_to": "zcash_proofs::constants::SPENDING_KEY_GENERATOR"
5 | },
6 | "G_VCV": {
7 | "maps_to": "zcash_proofs::constants::VALUE_COMMITMENT_VALUE_GENERATOR"
8 | },
9 | "G_VCR": {
10 | "maps_to": "zcash_proofs::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR"
11 | },
12 | "CRH_IVK": {
13 | "maps_to": "zcash_primitives::constants::CRH_IVK_PERSONALIZATION"
14 | },
15 | "JUBJUB_FR_CAPACITY": {
16 | "maps_to": "jubjub::Fr::CAPACITY as usize"
17 | },
18 | "NOTE_COMMIT": {
19 | "maps_to": "pedersen_hash::Personalization::NoteCommitment"
20 | }
21 | }
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/proofs/old/simple.pism:
--------------------------------------------------------------------------------
1 | # :set syntax=pism
2 | # :source ../scripts/pism.vim
3 | constant G_SPEND FixedGenerator
4 | constant CRH_IVK BlakePersonalization
5 | constant JUBJUB_FR_CAPACITY BinarySize
6 | constant NOTE_COMMIT PedersenPersonalization
7 |
8 | contract input_spend
9 | param secret Fr
10 | param ak Point
11 | param value U64
12 | param is_cool Bool
13 | param path Scalar
14 | start
15 | # Compute P = xG + A
16 | witness ak param:ak
17 | assert_not_small_order ak
18 | fr_as_binary_le secret param:secret
19 |
20 | ec_mul_const public secret G_SPEND
21 |
22 | ec_add public public ak
23 | emit_ec public
24 |
25 | # Make some a blake2s hash
26 | alloc_binary preimage
27 | ec_repr repr_ak ak
28 | binary_extend preimage repr_ak
29 | static_assert_binary_size preimage 256
30 | blake2s ivk preimage CRH_IVK
31 | emit_binary ivk
32 |
33 | # Below lines are random garbage
34 | # Uncomment them to test
35 |
36 | #binary_clone ivk2 ivk
37 | #binary_truncate ivk2 JUBJUB_FR_CAPACITY
38 | #u64_as_binary_le value_bits param:value
39 | #ec_mul pk_d value_bits public
40 |
41 | #pedersen_hash cm ivk NOTE_COMMIT
42 | #ec_get_u cur cm
43 | #
44 | #alloc_bit is_cool param:is_cool
45 | #clone_bit is_cool2 is_cool
46 | #binary_push ivk is_cool2
47 |
48 | #alloc_scalar path param:path
49 | #conditionally_reverse ul ur cur path is_cool
50 |
51 | #scalar_as_binary ul_bin ul
52 | #binary_extend preimage ul_bin
53 |
54 | #scalar_enforce_equal ur ul
55 | #emit_scalar ur
56 | end
57 |
58 |
--------------------------------------------------------------------------------
/proofs/old/simple.prf:
--------------------------------------------------------------------------------
1 | const G_SPEND: SubgroupPoint
2 |
3 | contract input_spend(
4 | secret: Fr -> BinaryNumber
5 | ) -> Point:
6 | let public: Point = secret * G_SPEND
7 | emit public
8 |
9 |
--------------------------------------------------------------------------------
/proofs/old/test.pism:
--------------------------------------------------------------------------------
1 | # :set syntax=pism
2 | # :source ../scripts/pism.vim
3 | constant G_SPEND FixedGenerator
4 | constant CRH_IVK BlakePersonalization
5 | constant JUBJUB_FR_CAPACITY BinarySize
6 | constant NOTE_COMMIT PedersenPersonalization
7 |
8 | contract input_spend
9 | param secret Fr
10 | param ak Point
11 | param value U64
12 | param is_cool Bool
13 | param path Scalar
14 | {% for n in range(10) %}
15 | param path_{{ n }} Scalar
16 | param is_right_{{ n }} Bool
17 | {% endfor %}
18 | start
19 | # Compute P = xG + A
20 | witness ak param:ak
21 | assert_not_small_order ak
22 | fr_as_binary_le secret param:secret
23 |
24 | ec_mul_const public secret G_SPEND
25 |
26 | ec_add public public ak
27 | emit_ec public
28 |
29 | # Make some a blake2s hash
30 | alloc_binary preimage
31 | ec_repr repr_ak ak
32 | binary_extend preimage repr_ak
33 | static_assert_binary_size preimage 256
34 | blake2s ivk preimage CRH_IVK
35 | emit_binary ivk
36 |
37 | ############
38 | # For loop 10 times
39 | {% for n in range(10) %}
40 | alloc_bit is_right param:is_right_{{ n }}
41 | alloc_scalar path param:path_{{ n }}
42 | {% endfor %}
43 | ############
44 |
45 | # Below lines are random garbage
46 | # Uncomment them to test
47 |
48 | #binary_clone ivk2 ivk
49 | #binary_truncate ivk2 JUBJUB_FR_CAPACITY
50 | #u64_as_binary_le value_bits param:value
51 | #ec_mul pk_d value_bits public
52 |
53 | #pedersen_hash cm ivk NOTE_COMMIT
54 | #ec_get_u cur cm
55 | #
56 | #alloc_bit is_cool param:is_cool
57 | #clone_bit is_cool2 is_cool
58 | #binary_push ivk is_cool2
59 |
60 | #alloc_scalar path param:path
61 | #conditionally_reverse ul ur cur path is_cool
62 |
63 | #scalar_as_binary ul_bin ul
64 | #binary_extend preimage ul_bin
65 |
66 | #scalar_enforce_equal ur ul
67 | #emit_scalar ur
68 | end
69 |
70 |
--------------------------------------------------------------------------------
/proofs/spend.pism:
--------------------------------------------------------------------------------
1 | constant G_VCV FixedGenerator
2 | constant G_VCR FixedGenerator
3 | constant G_SPEND FixedGenerator
4 | constant PRF_NF BlakePersonalization
5 | constant CRH_IVK BlakePersonalization
6 | constant NOTE_COMMIT PedersenPersonalization
7 | {% for i in range(4) %}
8 | constant MERKLE_{{ i }} PedersenPersonalization
9 | {% endfor %}
10 |
11 | contract spend_contract
12 | # Value commitment
13 | param value U64
14 | param randomness_value Fr
15 |
16 | param serial Fr
17 | param randomness_coin Fr
18 | param secret Fr
19 |
20 | {% for i in range(4) %}
21 | param branch_{{ i }} Scalar
22 | param is_right_{{ i }} Bool
23 | {% endfor %}
24 | start
25 | # Witness input values
26 | u64_as_binary_le value param:value
27 | fr_as_binary_le randomness_value param:randomness_value
28 |
29 | # Make value commitment
30 | # V = v * G_VCV + r * G_VCR
31 |
32 | ec_mul_const vcv value G_VCV
33 | ec_mul_const rcv randomness_value G_VCR
34 | ec_add cv vcv rcv
35 | # emit cv
36 | emit_ec cv
37 |
38 | # Make the nullifier
39 | # N = Hash(secret, serial)
40 | fr_as_binary_le serial param:serial
41 | fr_as_binary_le secret param:secret
42 |
43 | alloc_binary nf_preimage
44 |
45 | # Fr values are 252 bits so we need to pad it with extra 0s
46 | # to match the Rust values which are 256 bits
47 | {% macro binary_put_fr(binary, var) -%}
48 | binary_extend {{ binary }} {{ var }}
49 | {% for n in range(4) %}
50 | alloc_const_bit zero_bit false
51 | binary_push {{ binary }} zero_bit
52 | {% endfor %}
53 | {%- endmacro %}
54 |
55 | # secret
56 | binary_clone secret2 secret
57 | {{ binary_put_fr("nf_preimage", "secret2") }}
58 |
59 | # serial
60 | binary_clone serial2 serial
61 | {{ binary_put_fr("nf_preimage", "serial2") }}
62 |
63 | # Secret: Fr = 252 + 4 bits padding
64 | # Serial: Fr = 252 + 4 bits padding
65 | # TOTAL: 512 bits for preimage
66 | static_assert_binary_size nf_preimage 512
67 | blake2s nf nf_preimage PRF_NF
68 | emit_binary nf
69 |
70 | # Derive the public key
71 | # P = secret * G
72 | ec_mul_const public secret G_SPEND
73 |
74 | # Make the coin (same as mint contract)
75 | # C = Hash(public_key, value, serial, randomness_coin)
76 | fr_as_binary_le randomness_coin param:randomness_coin
77 |
78 | # Build the preimage to hash
79 | alloc_binary preimage
80 |
81 | # public_key
82 | ec_repr repr_public public
83 | binary_extend preimage repr_public
84 |
85 | # value
86 | binary_extend preimage value
87 |
88 | # serial
89 | {{ binary_put_fr("preimage", "serial") }}
90 |
91 | # randomness_coin
92 | {{ binary_put_fr("preimage", "randomness_coin") }}
93 |
94 | # Public key: SubgroupPoint = 256 bits
95 | # Value: u64 = 64 bits
96 | # Serial: Fr = 252 + 4 bits padding
97 | # Randomness coin Fr = 252 + 4 bits padding
98 | # TOTAL: 832 bits for preimage
99 | static_assert_binary_size preimage 832
100 | blake2s coin preimage CRH_IVK
101 | # Debug stuff. Normally we don't reveal the coin in the spend proof.
102 | #binary_clone coin2 coin
103 | #emit_binary coin2
104 |
105 | # coin_commit = PedersenHash(coin)
106 | pedersen_hash cm coin NOTE_COMMIT
107 | # left = coin_commit.u
108 | ec_get_u current cm
109 |
110 | # Our merkle tree has a height of 4
111 | {% for i in range(4) %}
112 | # left = current
113 | # right = branch[{{ i }}]
114 | alloc_scalar branch param:branch_{{ i }}
115 |
116 | # is_right = is_right[{{ i }}]
117 | alloc_bit is_right param:is_right_{{ i }}
118 |
119 | # reverse(a, b, condition) = if condition (b, a) else (a, b)
120 | conditionally_reverse left right current branch is_right
121 |
122 | # coin_commit = PedersenHash(left || right)
123 | scalar_as_binary left left
124 | scalar_as_binary right right
125 | alloc_binary preimage
126 | binary_extend preimage left
127 | binary_extend preimage right
128 | pedersen_hash cm preimage MERKLE_{{ i }}
129 | # current = coin_commit.u
130 | ec_get_u current cm
131 | {% endfor %}
132 | # Reveal the merkle root
133 | emit_scalar current
134 | end
135 |
136 |
--------------------------------------------------------------------------------
/proofs/vm.pism:
--------------------------------------------------------------------------------
1 | constant v 123
2 |
3 | contract input_spend
4 | param x
5 | private x2
6 | set x2 x
7 | mul x2 x
8 |
9 | lc0_add x
10 | lc1_add x
11 | lc2_add x2
12 | enforce
13 |
14 | private x3
15 | set x3 x2
16 | mul x3 x
17 |
18 | lc0_add x2
19 | lc1_add x
20 | lc2_add x3
21 | enforce
22 |
23 | public input
24 | set input x3
25 |
26 | lc0_add input
27 | lc1_add_one
28 | lc2_add x3
29 | enforce
30 | end
31 |
32 |
--------------------------------------------------------------------------------
/res/font/PressStart2P-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/narodnik/sapvi/10f00058d30eef274e387f547dcffee8467e39b1/res/font/PressStart2P-Regular.ttf
--------------------------------------------------------------------------------
/res/img/absolutely-proprietary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/narodnik/sapvi/10f00058d30eef274e387f547dcffee8467e39b1/res/img/absolutely-proprietary.png
--------------------------------------------------------------------------------
/res/img/absolutely-proprietary2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/narodnik/sapvi/10f00058d30eef274e387f547dcffee8467e39b1/res/img/absolutely-proprietary2.png
--------------------------------------------------------------------------------
/res/model/earth.blend:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/narodnik/sapvi/10f00058d30eef274e387f547dcffee8467e39b1/res/model/earth.blend
--------------------------------------------------------------------------------
/res/model/earth.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/narodnik/sapvi/10f00058d30eef274e387f547dcffee8467e39b1/res/model/earth.jpg
--------------------------------------------------------------------------------
/res/model/earth.mtl:
--------------------------------------------------------------------------------
1 | # Blender MTL File: 'None'
2 | # Material Count: 1
3 |
4 | newmtl Material.001
5 | Ns 225.000000
6 | Ka 1.000000 1.000000 1.000000
7 | Kd 0.800000 0.800000 0.800000
8 | Ks 0.500000 0.500000 0.500000
9 | Ke 0.000000 0.000000 0.000000
10 | Ni 1.450000
11 | d 1.000000
12 | illum 2
13 | map_Kd earth.jpg
14 |
--------------------------------------------------------------------------------
/res/shader/light.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | layout(location=0) in vec3 v_color;
4 | layout(location=0) out vec4 f_color;
5 |
6 | void main() {
7 | f_color = vec4(v_color, 1.0);
8 | }
--------------------------------------------------------------------------------
/res/shader/light.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/narodnik/sapvi/10f00058d30eef274e387f547dcffee8467e39b1/res/shader/light.frag.spv
--------------------------------------------------------------------------------
/res/shader/light.vert:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | layout(location=0) in vec3 a_position;
4 |
5 | layout(location=0) out vec3 v_color;
6 |
7 | layout(set=0, binding=0)
8 | uniform Uniforms {
9 | vec3 u_view_position; // unused
10 | mat4 u_view_proj;
11 | };
12 |
13 | layout(set=1, binding=0)
14 | uniform Light {
15 | vec3 u_position;
16 | vec3 u_color;
17 | };
18 |
19 | // Let's keep our light smaller than our other objects
20 | float scale = 0.25;
21 |
22 | void main() {
23 | vec3 v_position = a_position * scale + u_position;
24 | gl_Position = u_view_proj * vec4(v_position, 1);
25 |
26 | v_color = u_color;
27 | }
--------------------------------------------------------------------------------
/res/shader/light.vert.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/narodnik/sapvi/10f00058d30eef274e387f547dcffee8467e39b1/res/shader/light.vert.spv
--------------------------------------------------------------------------------
/res/shader/phong.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | layout(location=0) in vec2 v_tex_coords;
4 | layout(location=1) in vec3 v_normal;
5 | layout(location=2) in vec3 v_position;
6 |
7 | layout(location=0) out vec4 f_color;
8 |
9 | layout(set = 0, binding = 0) uniform texture2D t_diffuse;
10 | layout(set = 0, binding = 1) uniform sampler s_diffuse;
11 |
12 | layout(set=1, binding=0)
13 | uniform Uniforms {
14 | vec3 u_view_position;
15 | mat4 u_view_proj; // unused
16 | };
17 |
18 | layout(set = 2, binding = 0) uniform Light {
19 | vec3 light_position;
20 | vec3 light_color;
21 | };
22 |
23 | void main() {
24 | vec4 object_color = texture(sampler2D(t_diffuse, s_diffuse), v_tex_coords);
25 |
26 | // We don't need (or want) much ambient light, so 0.1 is fine
27 | float ambient_strength = 0.1;
28 | vec3 ambient_color = light_color * ambient_strength;
29 |
30 | vec3 normal = normalize(v_normal);
31 | vec3 light_dir = normalize(light_position - v_position);
32 |
33 | float diffuse_strength = max(dot(normal, light_dir), 0.0);
34 | vec3 diffuse_color = light_color * diffuse_strength;
35 |
36 | vec3 view_dir = normalize(u_view_position - v_position);
37 | vec3 reflect_dir = reflect(-light_dir, normal);
38 |
39 | float specular_strength = pow(max(dot(view_dir, reflect_dir), 0.0), 32);
40 | vec3 specular_color = specular_strength * light_color;
41 |
42 | vec3 result = (ambient_color + diffuse_color + specular_color) * object_color.xyz;
43 |
44 | // Since lights don't typically (afaik) cast transparency, so we use
45 | // the alpha here at the end.
46 | f_color = vec4(result, object_color.a);
47 | }
--------------------------------------------------------------------------------
/res/shader/phong.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/narodnik/sapvi/10f00058d30eef274e387f547dcffee8467e39b1/res/shader/phong.frag.spv
--------------------------------------------------------------------------------
/res/shader/shader.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | layout(location=0) in vec2 v_tex_coords;
4 | layout(location=1) in vec3 v_normal;
5 | layout(location=2) in vec3 v_position;
6 |
7 | layout(location=0) out vec4 f_color;
8 |
9 | layout(set = 0, binding = 0) uniform texture2D t_diffuse;
10 | layout(set = 0, binding = 1) uniform sampler s_diffuse;
11 |
12 | layout(set=1, binding=0)
13 | uniform Uniforms {
14 | vec3 u_view_position;
15 | mat4 u_view_proj; // unused
16 | };
17 |
18 | layout(set=2, binding=0) uniform Light {
19 | vec3 light_position;
20 | vec3 light_color;
21 | };
22 |
23 | void main() {
24 | vec4 object_color = texture(sampler2D(t_diffuse, s_diffuse), v_tex_coords);
25 |
26 | // We don't need (or want) much ambient light, so 0.1 is fine
27 | float ambient_strength = 0.1;
28 | vec3 ambient_color = light_color * ambient_strength;
29 |
30 | vec3 normal = normalize(v_normal);
31 | vec3 light_dir = normalize(light_position - v_position);
32 |
33 | float diffuse_strength = max(dot(normal, light_dir), 0.0);
34 | vec3 diffuse_color = light_color * diffuse_strength;
35 |
36 | vec3 view_dir = normalize(u_view_position - v_position);
37 | vec3 half_dir = normalize(view_dir + light_dir);
38 |
39 | float specular_strength = pow(max(dot(normal, half_dir), 0.0), 32);
40 | vec3 specular_color = specular_strength * light_color;
41 |
42 | vec3 result = (ambient_color + diffuse_color + specular_color) * object_color.xyz;
43 |
44 | // Since lights don't typically (afaik) cast transparency, so we use
45 | // the alpha here at the end.
46 | f_color = vec4(result, object_color.a);
47 | }
48 |
--------------------------------------------------------------------------------
/res/shader/shader.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/narodnik/sapvi/10f00058d30eef274e387f547dcffee8467e39b1/res/shader/shader.frag.spv
--------------------------------------------------------------------------------
/res/shader/shader.vert:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | layout(location=0) in vec3 a_position;
4 | layout(location=1) in vec2 a_tex_coords;
5 | layout(location=2) in vec3 a_normal;
6 |
7 | layout(location=0) out vec2 v_tex_coords;
8 | layout(location=1) out vec3 v_normal;
9 | layout(location=2) out vec3 v_position;
10 |
11 | layout(set=1, binding=0)
12 | uniform Uniforms {
13 | vec3 u_view_position; // unused
14 | mat4 u_view_proj;
15 | };
16 |
17 | layout(location=5) in vec4 model_matrix_0;
18 | layout(location=6) in vec4 model_matrix_1;
19 | layout(location=7) in vec4 model_matrix_2;
20 | layout(location=8) in vec4 model_matrix_3;
21 |
22 | void main() {
23 | mat4 model_matrix = mat4(
24 | model_matrix_0,
25 | model_matrix_1,
26 | model_matrix_2,
27 | model_matrix_3
28 | );
29 | v_tex_coords = a_tex_coords;
30 | mat3 normal_matrix = mat3(transpose(inverse(model_matrix)));
31 | v_normal = normal_matrix * a_normal;
32 |
33 | vec4 model_space = model_matrix * vec4(a_position, 1.0);
34 | v_position = model_space.xyz;
35 |
36 | gl_Position = u_view_proj * model_space;
37 | }
--------------------------------------------------------------------------------
/res/shader/shader.vert.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/narodnik/sapvi/10f00058d30eef274e387f547dcffee8467e39b1/res/shader/shader.vert.spv
--------------------------------------------------------------------------------
/res/shader/ui_shader.frag:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | layout(location=0) in vec2 v_tex_coords;
4 | layout(location=0) out vec4 f_color;
5 |
6 | layout(set = 0, binding = 0) uniform texture2D t_diffuse;
7 | layout(set = 0, binding = 1) uniform sampler s_diffuse;
8 |
9 | void main() {
10 | f_color = texture(sampler2D(t_diffuse, s_diffuse), v_tex_coords);
11 | }
--------------------------------------------------------------------------------
/res/shader/ui_shader.frag.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/narodnik/sapvi/10f00058d30eef274e387f547dcffee8467e39b1/res/shader/ui_shader.frag.spv
--------------------------------------------------------------------------------
/res/shader/ui_shader.vert:
--------------------------------------------------------------------------------
1 | #version 450
2 |
3 | layout(location=0) in vec3 a_position;
4 | layout(location=1) in vec2 a_tex_coords;
5 |
6 | layout(location=0) out vec2 v_tex_coords;
7 |
8 | void main() {
9 | v_tex_coords = a_tex_coords;
10 | gl_Position = vec4(a_position, 1.0);
11 | }
--------------------------------------------------------------------------------
/res/shader/ui_shader.vert.spv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/narodnik/sapvi/10f00058d30eef274e387f547dcffee8467e39b1/res/shader/ui_shader.vert.spv
--------------------------------------------------------------------------------
/run_jubjub.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -x
2 | #python scripts/preprocess.py proofs/jubjub.psm > /tmp/jubjub.psm || exit $?
3 | racket lisp/jj.rkt || exit $?
4 | python scripts/compile.py --supervisor jj.psm --output jubjub.zcd || exit $?
5 | cargo run --release --bin jubjub
6 |
7 |
--------------------------------------------------------------------------------
/run_jubjub2.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -x
2 | racket lisp/jj.rkt || exit $?
3 | python scripts/compile.py --supervisor jj.psm --output jubjub.zcd || exit $?
4 | cargo run --release --bin zkvm -- init jubjub.zcd jubjub.zts
5 | cargo run --release --bin zkvm -- prove jubjub.zcd jubjub.zts proofs/jubjub.params jubjub.prf
6 | cargo run --release --bin zkvm -- verify jubjub.zcd jubjub.zts jubjub.prf
7 | cargo run --release --bin zkvm -- show jubjub.prf
8 |
--------------------------------------------------------------------------------
/run_mimc.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -x
2 | python3 scripts/preprocess.py proofs/mimc.psm > /tmp/mimc.psm || exit $?
3 | python3 scripts/compile.py --supervisor /tmp/mimc.psm --output mimc.zcd || exit $?
4 | cargo run --release --bin mimc
5 |
6 |
--------------------------------------------------------------------------------
/run_mimc2.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -x
2 | python3 scripts/preprocess.py proofs/mimc.psm > /tmp/mimc.psm || exit $?
3 | python3 scripts/compile.py --supervisor /tmp/mimc.psm --output mimc.zcd || exit $?
4 | cargo run --release --bin zkvm -- init mimc.zcd mimc.zts
5 | cargo run --release --bin zkvm -- prove mimc.zcd mimc.zts proofs/mimc.params mimc.prf
6 | cargo run --release --bin zkvm -- verify mimc.zcd mimc.zts mimc.prf
7 | cargo run --release --bin zkvm -- show mimc.prf
8 |
--------------------------------------------------------------------------------
/run_mint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -x
2 | python3 scripts/preprocess.py proofs/mint2.psm > /tmp/mint2.psm || exit $?
3 | python3 scripts/compile.py --supervisor /tmp/mint2.psm --output mint.zcd || exit $?
4 | cargo run --release --bin mint
5 |
6 |
--------------------------------------------------------------------------------
/run_network.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Run this script then
4 | # python scripts/monitor-p2p.py
5 | # to view the network topology
6 |
7 | declare -a arr=(
8 | # Seed node
9 | "cargo run --bin dfi -- -r 8999 --accept 127.0.0.1:9999 --log /tmp/darkfi/seed.log"
10 | # Server with no outgoing connections
11 | "cargo run --bin dfi -- -r 9000 --accept 127.0.0.1:10001 --seeds 127.0.0.1:9999 --log /tmp/darkfi/server.log"
12 | # Server/client with 2 outgoing connections
13 | "cargo run --bin dfi -- -r 9005 --accept 127.0.0.1:10002 --seeds 127.0.0.1:9999 --log /tmp/darkfi/server1.log --slots 3"
14 | # Server/client with 2 outgoing connections
15 | "cargo run --bin dfi -- -r 9006 --accept 127.0.0.1:10003 --seeds 127.0.0.1:9999 --log /tmp/darkfi/server2.log --slots 3"
16 | # Server/client with 2 outgoing connections
17 | "cargo run --bin dfi -- -r 9007 --accept 127.0.0.1:10004 --seeds 127.0.0.1:9999 --log /tmp/darkfi/server3.log --slots 3"
18 | # Server/client with 2 outgoing connections
19 | "cargo run --bin dfi -- -r 9008 --accept 127.0.0.1:10005 --seeds 127.0.0.1:9999 --log /tmp/darkfi/server4.log --slots 3"
20 | # Client with 1 outgoing connection
21 | "cargo run --bin dfi -- -r 9002 --seeds 127.0.0.1:9999 --slots 4 --log /tmp/darkfi/client.log"
22 | # Client with 1 outgoing connection
23 | "cargo run --bin dfi -- -r 9003 --seeds 127.0.0.1:9999 --slots 4 --log /tmp/darkfi/client1.log"
24 | # Client with 1 outgoing connection
25 | "cargo run --bin dfi -- -r 9004 --seeds 127.0.0.1:9999 --slots 4 --log /tmp/darkfi/client2.log"
26 | )
27 |
28 | mkdir -p /tmp/darkfi/
29 |
30 | for cmd in "${arr[@]}"; do {
31 | echo "Process \"$cmd\" started";
32 | RUST_BACKTRACE=1 $cmd & pid=$!
33 | PID_LIST+=" $pid";
34 | sleep 2;
35 | } done
36 |
37 | trap "kill $PID_LIST" SIGINT
38 |
39 | echo "Parallel processes have started";
40 |
41 | wait $PID_LIST
42 |
43 | echo
44 | echo "All processes have completed";
45 |
46 |
--------------------------------------------------------------------------------
/rustfmt.toml:
--------------------------------------------------------------------------------
1 | # Config file for cargo fmt. Uncomment line to edit the default settings.
2 |
3 | # max_width = 100
4 | # hard_tabs = false
5 | # tab_spaces = 4
6 | # newline_style = "Auto"
7 | # use_small_heuristics = "Default"
8 | # indent_style = "Block"
9 | wrap_comments = true
10 | format_code_in_doc_comments = true
11 | comment_width = 80
12 | # normalize_comments = true
13 | # normalize_doc_attributes = true
14 | # license_template_path = ""
15 | format_strings = true
16 | # format_macro_matchers = true
17 | # format_macro_bodies = true
18 | # empty_item_single_line = true
19 | # struct_lit_single_line = true
20 | # fn_single_line = false
21 | # where_single_line = false
22 | # imports_indent = "Block"
23 | # imports_layout = "Mixed"
24 | # merge_imports = false
25 | # reorder_imports = true
26 | # reorder_modules = true
27 | # reorder_impl_items = false
28 | # type_punctuation_density = "Wide"
29 | # space_before_colon = false
30 | # space_after_colon = true
31 | # spaces_around_ranges = false
32 | # binop_separator = "Front"
33 | # remove_nested_parens = true
34 | # combine_control_expr = true
35 | # overflow_delimited_expr = false
36 | # struct_field_align_threshold = 0
37 | # enum_discrim_align_threshold = 0
38 | # match_arm_blocks = true
39 | # force_multiline_blocks = false
40 | # fn_args_layout = "Tall"
41 | # brace_style = "SameLineWhere"
42 | # control_brace_style = "AlwaysSameLine"
43 | # trailing_semicolon = true
44 | # trailing_comma = "Vertical"
45 | # match_block_trailing_comma = false
46 | # blank_lines_upper_bound = 1
47 | # blank_lines_lower_bound = 0
48 | edition = "2018"
49 | # version = "One"
50 | # inline_attribute_width = 0
51 | # merge_derives = true
52 | # use_try_shorthand = false
53 | # use_field_init_shorthand = false
54 | # force_explicit_abi = true
55 | # condense_wildcard_suffixes = false
56 | # color = "Auto"
57 | # required_version = "1.4.21"
58 | # unstable_features = false
59 | # disable_all_formatting = false
60 | # skip_children = false
61 | # hide_parse_errors = false
62 | # error_on_line_overflow = false
63 | # error_on_unformatted = false
64 | # report_todo = "Never"
65 | # report_fixme = "Never"
66 | # ignore = []
67 | # emit_mode = "Files"
68 | # make_backup = false
69 |
--------------------------------------------------------------------------------
/scripts/codegen.py:
--------------------------------------------------------------------------------
1 | # Functions here are called from pism.py using getattr()
2 | # and the function name as a string.
3 |
4 | def witness(line, out, point):
5 | return \
6 | r"""let %s = ecc::EdwardsPoint::witness(
7 | cs.namespace(|| "%s"),
8 | %s.map(jubjub::ExtendedPoint::from))?;""" % (out, line, point)
9 |
10 | def assert_not_small_order(line, point):
11 | return '%s.assert_not_small_order(cs.namespace(|| "%s"))?;' % (point, line)
12 |
13 | def u64_as_binary_le(line, out, val):
14 | return \
15 | r"""let %s = boolean::u64_into_boolean_vec_le(
16 | cs.namespace(|| "%s"),
17 | %s,
18 | )?;""" % (out, line, val)
19 |
20 | def fr_as_binary_le(line, out, fr):
21 | return \
22 | r"""let %s = boolean::field_into_boolean_vec_le(
23 | cs.namespace(|| "%s"), %s)?;""" % (out, line, fr)
24 |
25 | def ec_mul_const(line, out, fr, base):
26 | return \
27 | r"""let %s = ecc::fixed_base_multiplication(
28 | cs.namespace(|| "%s"),
29 | &%s,
30 | &%s,
31 | )?;""" % (out, line, base, fr)
32 |
33 | def ec_mul(line, out, fr, base):
34 | return 'let %s = %s.mul(cs.namespace(|| "%s"), &%s)?;' % (
35 | out, base, line, fr)
36 |
37 | def ec_add(line, out, a, b):
38 | return 'let %s = %s.add(cs.namespace(|| "%s"), &%s)?;' % (out, a, line, b)
39 |
40 | def ec_repr(line, out, point):
41 | return 'let %s = %s.repr(cs.namespace(|| "%s"))?;' % (out, point, line)
42 |
43 | def ec_get_u(line, out, point):
44 | return "let mut %s = %s.get_u().clone();" % (out, point)
45 |
46 | def emit_ec(line, point):
47 | return '%s.inputize(cs.namespace(|| "%s"))?;' % (point, line)
48 |
49 | def alloc_binary(line, out):
50 | return "let mut %s = vec![];" % out
51 |
52 | def binary_clone(line, out, binary):
53 | return "let mut %s: Vec<_> = %s.iter().cloned().collect();" % (out, binary)
54 |
55 | def binary_extend(line, binary, value):
56 | return "%s.extend(%s);" % (binary, value)
57 |
58 | def binary_push(line, binary, bit):
59 | return "%s.push(%s);" % (binary, bit)
60 |
61 | def binary_truncate(line, binary, size):
62 | return "%s.truncate(%s);" % (binary, size)
63 |
64 | def static_assert_binary_size(line, binary, size):
65 | return "assert_eq!(%s.len(), %s);" % (binary, size)
66 |
67 | def blake2s(line, out, input, personalization):
68 | return \
69 | r"""let mut %s = blake2s::blake2s(
70 | cs.namespace(|| "%s"),
71 | &%s,
72 | %s,
73 | )?;""" % (out, line, input, personalization)
74 |
75 | def pedersen_hash(line, out, input, personalization):
76 | return \
77 | r"""let mut %s = pedersen_hash::pedersen_hash(
78 | cs.namespace(|| "%s"),
79 | %s,
80 | &%s,
81 | )?;""" % (out, line, personalization, input)
82 |
83 | def emit_binary(line, binary):
84 | return 'multipack::pack_into_inputs(cs.namespace(|| "%s"), &%s)?;' % (
85 | line, binary)
86 |
87 | def alloc_bit(line, out, value):
88 | return \
89 | r"""let %s = boolean::Boolean::from(boolean::AllocatedBit::alloc(
90 | cs.namespace(|| "%s"),
91 | %s
92 | )?);""" % (out, line, value)
93 |
94 | def alloc_const_bit(line, out, value):
95 | return "let %s = Boolean::constant(%s);" % (out, value)
96 |
97 | def clone_bit(line, out, value):
98 | return "let %s = %s.clone();" % (out, value)
99 |
100 | def alloc_scalar(line, out, scalar):
101 | return \
102 | r"""let %s =
103 | num::AllocatedNum::alloc(cs.namespace(|| "%s"), || Ok(*%s.get()?))?;""" % (
104 | out, line, scalar)
105 |
106 | def scalar_as_binary(line, out, scalar):
107 | return 'let %s = %s.to_bits_le(cs.namespace(|| "%s"))?;' % (out, scalar,
108 | line)
109 |
110 | def emit_scalar(line, scalar):
111 | return '%s.inputize(cs.namespace(|| "%s"))?;' % (scalar, line)
112 |
113 | def scalar_enforce_equal(line, scalar_left, scalar_right):
114 | return \
115 | r"""cs.enforce(
116 | || "%s",
117 | |lc| lc + %s.get_variable(),
118 | |lc| lc + CS::one(),
119 | |lc| lc + %s.get_variable(),
120 | );""" % (line, scalar_left, scalar_right)
121 |
122 | def conditionally_reverse(line, out_left, out_right, in_left, in_right,
123 | condition):
124 | return \
125 | r"""let (%s, %s) = num::AllocatedNum::conditionally_reverse(
126 | cs.namespace(|| "%s"),
127 | &%s,
128 | &%s,
129 | &%s,
130 | )?;""" % (out_left, out_right, line, in_left, in_right, condition)
131 |
132 |
--------------------------------------------------------------------------------
/scripts/finite_fields/README.md:
--------------------------------------------------------------------------------
1 | finite-fields
2 | =============
3 |
4 | Python code and tests for the post ["Programming with Finite Fields"](http://jeremykun.com/2014/03/13/programming-with-finite-fields/)
5 |
--------------------------------------------------------------------------------
/scripts/finite_fields/euclidean-test.py:
--------------------------------------------------------------------------------
1 | from test import test
2 | from euclidean import *
3 |
4 | test(1, gcd(7, 9))
5 | test(2, gcd(8, 18))
6 | test(-12, gcd(-12, 24))
7 | test(12, gcd(12, -24)) # gcd is only unique up to multiplication by a unit, and so sometimes we'll get negatives.
8 | test(38, gcd(4864, 3458))
9 |
10 | test((32, -45, 38), extendedEuclideanAlgorithm(4864, 3458))
11 | test((-45, 32, 38), extendedEuclideanAlgorithm(3458, 4864))
12 |
13 | from modp import *
14 |
15 | Mod2 = IntegersModP(2)
16 | test(Mod2(1), gcd(Mod2(1), Mod2(0)))
17 | test(Mod2(1), gcd(Mod2(1), Mod2(1)))
18 | test(Mod2(0), gcd(Mod2(2), Mod2(2)))
19 |
20 | Mod7 = IntegersModP(7)
21 | test(Mod7(6), gcd(Mod7(6), Mod7(14)))
22 | test(Mod7(2), gcd(Mod7(6), Mod7(9)))
23 |
24 | ModHuge = IntegersModP(9923)
25 | test(ModHuge(38), gcd(ModHuge(4864), ModHuge(3458)))
26 | test((ModHuge(32), ModHuge(-45), ModHuge(38)),
27 | extendedEuclideanAlgorithm(ModHuge(4864), ModHuge(3458)))
28 |
29 | from polynomial import *
30 |
31 | p = polynomialsOver(Mod7).factory
32 | test(p([-1, 1]), gcd(p([-1,0,1]), p([-1,0,0,1])))
33 | f = p([-1,0,1])
34 | g = p([-1,0,0,1])
35 | test((p([0,-1]), p([1]), p([-1, 1])), extendedEuclideanAlgorithm(f, g))
36 | test(p([-1,1]), f * p([0,-1]) + g * p([1]))
37 |
38 | p = polynomialsOver(Mod2).factory
39 | f = p([1,0,0,0,1,1,1,0,1,1,1]) # x^10 + x^9 + x^8 + x^6 + x^5 + x^4 + 1
40 | g = p([1,0,1,1,0,1,1,0,0,1]) # x^9 + x^6 + x^5 + x^3 + x^1 + 1
41 | theGcd = p([1,1,0,1]) # x^3 + x + 1
42 | x = p([0,0,0,0,1]) # x^4
43 | y = p([1,1,1,1,1,1]) # x^5 + x^4 + x^3 + x^2 + x + 1
44 |
45 | test((x, y, theGcd), extendedEuclideanAlgorithm(f, g))
46 |
--------------------------------------------------------------------------------
/scripts/finite_fields/euclidean.py:
--------------------------------------------------------------------------------
1 |
2 | # a general Euclidean algorithm for any number type with
3 | # a divmod and a valuation abs() whose minimum value is zero
4 | def gcd(a, b):
5 | if abs(a) < abs(b):
6 | return gcd(b, a)
7 |
8 | while abs(b) > 0:
9 | _,r = divmod(a,b)
10 | a,b = b,r
11 |
12 | return a
13 |
14 |
15 | # extendedEuclideanAlgorithm: int, int -> int, int, int
16 | # input (a,b) and output three numbers x,y,d such that ax + by = d = gcd(a,b).
17 | # Works for any number type with a divmod and a valuation abs()
18 | # whose minimum value is zero
19 | def extendedEuclideanAlgorithm(a, b):
20 | if abs(b) > abs(a):
21 | (x,y,d) = extendedEuclideanAlgorithm(b, a)
22 | return (y,x,d)
23 |
24 | if abs(b) == 0:
25 | return (1, 0, a)
26 |
27 | x1, x2, y1, y2 = 0, 1, 1, 0
28 | while abs(b) > 0:
29 | q, r = divmod(a,b)
30 | x = x2 - q*x1
31 | y = y2 - q*y1
32 | a, b, x2, x1, y2, y1 = b, r, x1, x, y1, y
33 |
34 | return (x2, y2, a)
35 |
36 |
--------------------------------------------------------------------------------
/scripts/finite_fields/finitefield-test.py:
--------------------------------------------------------------------------------
1 | from test import test
2 | from finitefield import *
3 | from polynomial import *
4 | from modp import *
5 |
6 | def p(L, q):
7 | f = IntegersModP(q)
8 | Polynomial = polynomialsOver(f).factory
9 | return Polynomial(L)
10 |
11 | test(True, isIrreducible(p([0,1], 2), 2))
12 | test(False, isIrreducible(p([1,0,1], 2), 2))
13 | test(True, isIrreducible(p([1,0,1], 3), 3))
14 |
15 | test(False, isIrreducible(p([1,0,0,1], 5), 5))
16 | test(False, isIrreducible(p([1,0,0,1], 7), 7))
17 | test(False, isIrreducible(p([1,0,0,1], 11), 11))
18 |
19 |
20 | test(True, isIrreducible(p([-2, 0, 1], 13), 13))
21 |
22 |
23 | Z5 = IntegersModP(5)
24 | Poly = polynomialsOver(Z5).factory
25 | f = Poly([3,0,1])
26 | F25 = FiniteField(5, 2, polynomialModulus=f)
27 | x = F25([2,1])
28 | test(Poly([1,2]), x.inverse())
29 |
--------------------------------------------------------------------------------
/scripts/finite_fields/modp-test.py:
--------------------------------------------------------------------------------
1 | from modp import *
2 | from test import test
3 |
4 | mod7 = IntegersModP(7)
5 |
6 | test(mod7(5), mod7(5)) # Sanity check
7 | test(mod7(5), 1 / mod7(3))
8 | test(mod7(1), mod7(3) * mod7(5))
9 | test(mod7(3), mod7(3) * 1)
10 | test(mod7(2), mod7(5) + mod7(4))
11 |
12 | test(True, mod7(0) == mod7(3) + mod7(4))
13 |
14 |
--------------------------------------------------------------------------------
/scripts/finite_fields/modp.py:
--------------------------------------------------------------------------------
1 |
2 | from .euclidean import *
3 | from .numbertype import *
4 |
5 | # so all IntegersModP are instances of the same base class
6 | class _Modular(FieldElement):
7 | pass
8 |
9 |
10 | @memoize
11 | def IntegersModP(p):
12 | # assume p is prime
13 |
14 | class IntegerModP(_Modular):
15 | def __init__(self, n):
16 | try:
17 | self.n = int(n) % IntegerModP.p
18 | except:
19 | raise TypeError("Can't cast type %s to %s in __init__" % (type(n).__name__, type(self).__name__))
20 |
21 | self.field = IntegerModP
22 |
23 | @typecheck
24 | def __add__(self, other):
25 | return IntegerModP(self.n + other.n)
26 |
27 | @typecheck
28 | def __sub__(self, other):
29 | return IntegerModP(self.n - other.n)
30 |
31 | @typecheck
32 | def __mul__(self, other):
33 | return IntegerModP(self.n * other.n)
34 |
35 | def __neg__(self):
36 | return IntegerModP(-self.n)
37 |
38 | @typecheck
39 | def __eq__(self, other):
40 | return isinstance(other, IntegerModP) and self.n == other.n
41 |
42 | @typecheck
43 | def __ne__(self, other):
44 | return isinstance(other, IntegerModP) is False or self.n != other.n
45 |
46 | @typecheck
47 | def __divmod__(self, divisor):
48 | q,r = divmod(self.n, divisor.n)
49 | return (IntegerModP(q), IntegerModP(r))
50 |
51 | def inverse(self):
52 | # need to use the division algorithm *as integers* because we're
53 | # doing it on the modulus itself (which would otherwise be zero)
54 | x,y,d = extendedEuclideanAlgorithm(self.n, self.p)
55 |
56 | if d != 1:
57 | raise Exception("Error: p is not prime in %s!" % (self.__name__))
58 |
59 | return IntegerModP(x)
60 |
61 | def __abs__(self):
62 | return abs(self.n)
63 |
64 | def __str__(self):
65 | return str(self.n)
66 |
67 | def __repr__(self):
68 | return '%d (mod %d)' % (self.n, self.p)
69 |
70 | def __int__(self):
71 | return self.n
72 |
73 | IntegerModP.p = p
74 | IntegerModP.__name__ = 'Z/%d' % (p)
75 | IntegerModP.englishName = 'IntegersMod%d' % (p)
76 | return IntegerModP
77 |
78 |
79 | if __name__ == "__main__":
80 | mod7 = IntegersModP(7)
81 |
--------------------------------------------------------------------------------
/scripts/finite_fields/numbertype.py:
--------------------------------------------------------------------------------
1 | # memoize calls to the class constructors for fields
2 | # this helps typechecking by never creating two separate
3 | # instances of a number class.
4 | def memoize(f):
5 | cache = {}
6 |
7 | def memoizedFunction(*args, **kwargs):
8 | argTuple = args + tuple(kwargs)
9 | if argTuple not in cache:
10 | cache[argTuple] = f(*args, **kwargs)
11 | return cache[argTuple]
12 |
13 | memoizedFunction.cache = cache
14 | return memoizedFunction
15 |
16 |
17 | # type check a binary operation, and silently typecast 0 or 1
18 | def typecheck(f):
19 | def newF(self, other):
20 | if (hasattr(other.__class__, 'operatorPrecedence') and
21 | other.__class__.operatorPrecedence > self.__class__.operatorPrecedence):
22 | return NotImplemented
23 |
24 | if type(self) is not type(other):
25 | try:
26 | other = self.__class__(other)
27 | except TypeError:
28 | message = 'Not able to typecast %s of type %s to type %s in function %s'
29 | raise TypeError(message % (other, type(other).__name__, type(self).__name__, f.__name__))
30 | except Exception as e:
31 | message = 'Type error on arguments %r, %r for functon %s. Reason:%s'
32 | raise TypeError(message % (self, other, f.__name__, type(other).__name__, type(self).__name__, e))
33 |
34 | return f(self, other)
35 |
36 | return newF
37 |
38 |
39 |
40 | # require a subclass to implement +-* neg and to perform typechecks on all of
41 | # the binary operations finally, the __init__ must operate when given a single
42 | # argument, provided that argument is the int zero or one
43 | class DomainElement(object):
44 | operatorPrecedence = 1
45 |
46 | # the 'r'-operators are only used when typecasting ints
47 | def __radd__(self, other): return self + other
48 | def __rsub__(self, other): return -self + other
49 | def __rmul__(self, other): return self * other
50 |
51 | # square-and-multiply algorithm for fast exponentiation
52 | def __pow__(self, n):
53 | if type(n) is not int:
54 | raise TypeError
55 |
56 | Q = self
57 | R = self if n & 1 else self.__class__(1)
58 |
59 | i = 2
60 | while i <= n:
61 | Q = (Q * Q)
62 |
63 | if n & i == i:
64 | R = (Q * R)
65 |
66 | i = i << 1
67 |
68 | return R
69 |
70 |
71 | # requires the additional % operator (i.e. a Euclidean Domain)
72 | def powmod(self, n, modulus):
73 | if type(n) is not int:
74 | raise TypeError
75 |
76 | Q = self
77 | R = self if n & 1 else self.__class__(1)
78 |
79 | i = 2
80 | while i <= n:
81 | Q = (Q * Q) % modulus
82 |
83 | if n & i == i:
84 | R = (Q * R) % modulus
85 |
86 | i = i << 1
87 |
88 | return R
89 |
90 |
91 |
92 | # additionally require inverse() on subclasses
93 | class FieldElement(DomainElement):
94 | def __truediv__(self, other): return self * other.inverse()
95 | def __rtruediv__(self, other): return self.inverse() * other
96 | def __div__(self, other): return self.__truediv__(other)
97 | def __rdiv__(self, other): return self.__rtruediv__(other)
98 |
99 |
--------------------------------------------------------------------------------
/scripts/finite_fields/polynomial-test.py:
--------------------------------------------------------------------------------
1 | from __future__ import division
2 | from test import test
3 | from fractions import Fraction
4 | from polynomial import *
5 |
6 | from modp import *
7 |
8 | Mod5 = IntegersModP(5)
9 | Mod11 = IntegersModP(11)
10 |
11 | polysOverQ = polynomialsOver(Fraction).factory
12 | polysMod5 = polynomialsOver(Mod5).factory
13 | polysMod11 = polynomialsOver(Mod11).factory
14 |
15 | for p in [polysOverQ, polysMod5, polysMod11]:
16 | # equality
17 | test(True, p([]) == p([]))
18 | test(True, p([1,2]) == p([1,2]))
19 | test(True, p([1,2,0]) == p([1,2,0,0]))
20 |
21 | # addition
22 | test(p([1,2,3]), p([1,0,3]) + p([0,2]))
23 | test(p([1,2,3]), p([1,2,3]) + p([]))
24 | test(p([5,2,3]), p([4]) + p([1,2,3]))
25 | test(p([1,2]), p([1,2,3]) + p([0,0,-3]))
26 |
27 | # subtraction
28 | test(p([1,-2,3]), p([1,0,3]) - p([0,2]))
29 | test(p([1,2,3]), p([1,2,3]) - p([]))
30 | test(p([-1,-2,-3]), p([]) - p([1,2,3]))
31 |
32 | # multiplication
33 | test(p([1,2,1]), p([1,1]) * p([1,1]))
34 | test(p([2,5,5,3]), p([2,3]) * p([1,1,1]))
35 | test(p([0,7,49]), p([0,1,7]) * p([7]))
36 |
37 | # division
38 | test(p([1,1,1,1,1,1]), p([-1,0,0,0,0,0,1]) / p([-1,1]))
39 | test(p([-1,1,-1,1,-1,1]), p([1,0,0,0,0,0,1]) / p([1,1]))
40 | test(p([]), p([]) / p([1,1]))
41 | test(p([1,1]), p([1,1]) / p([1]))
42 | test(p([1,1]), p([2,2]) / p([2]))
43 |
44 | # modulus
45 | test(p([]), p([1,7,49]) % p([7]))
46 | test(p([-7]), p([-3,10,-5,3]) % p([1,3]))
47 |
48 |
49 | test(polysOverQ([Fraction(1,7), 1, 7]), polysOverQ([1,7,49]) / polysOverQ([7]))
50 | test(polysMod5([1 / Mod5(7), 1, 7]), polysMod5([1,7,49]) / polysMod5([7]))
51 | test(polysMod11([1 / Mod11(7), 1, 7]), polysMod11([1,7,49]) / polysMod11([7]))
52 |
--------------------------------------------------------------------------------
/scripts/finite_fields/polynomial.py:
--------------------------------------------------------------------------------
1 | try:
2 | from itertools import zip_longest
3 | except ImportError:
4 | from itertools import izip_longest as zip_longest
5 | import fractions
6 |
7 | from .numbertype import *
8 |
9 | # strip all copies of elt from the end of the list
10 | def strip(L, elt):
11 | if len(L) == 0: return L
12 |
13 | i = len(L) - 1
14 | while i >= 0 and L[i] == elt:
15 | i -= 1
16 |
17 | return L[:i+1]
18 |
19 |
20 | # create a polynomial with coefficients in a field; coefficients are in
21 | # increasing order of monomial degree so that, for example, [1,2,3]
22 | # corresponds to 1 + 2x + 3x^2
23 | @memoize
24 | def polynomialsOver(field=fractions.Fraction):
25 |
26 | class Polynomial(DomainElement):
27 | operatorPrecedence = 2
28 |
29 | @classmethod
30 | def factory(cls, L):
31 | return Polynomial([cls.field(x) for x in L])
32 |
33 | def __init__(self, c):
34 | if type(c) is Polynomial:
35 | self.coefficients = c.coefficients
36 | elif isinstance(c, field):
37 | self.coefficients = [c]
38 | elif not hasattr(c, '__iter__') and not hasattr(c, 'iter'):
39 | self.coefficients = [field(c)]
40 | else:
41 | self.coefficients = c
42 |
43 | self.coefficients = strip(self.coefficients, field(0))
44 |
45 |
46 | def isZero(self): return self.coefficients == []
47 |
48 | def __repr__(self):
49 | if self.isZero():
50 | return '0'
51 |
52 | return ' + '.join(['%s x^%d' % (a,i) if i > 0 else '%s'%a
53 | for i,a in enumerate(self.coefficients)])
54 |
55 |
56 | def __abs__(self): return len(self.coefficients) # the valuation only gives 0 to the zero polynomial, i.e. 1+degree
57 | def __len__(self): return len(self.coefficients)
58 | def __sub__(self, other): return self + (-other)
59 | def __iter__(self): return iter(self.coefficients)
60 | def __neg__(self): return Polynomial([-a for a in self])
61 |
62 | def iter(self): return self.__iter__()
63 | def leadingCoefficient(self): return self.coefficients[-1]
64 | def degree(self): return abs(self) - 1
65 |
66 | @typecheck
67 | def __eq__(self, other):
68 | return self.degree() == other.degree() and all([x==y for (x,y) in zip(self, other)])
69 |
70 | @typecheck
71 | def __ne__(self, other):
72 | return self.degree() != other.degree() or any([x!=y for (x,y) in zip(self, other)])
73 |
74 | @typecheck
75 | def __add__(self, other):
76 | newCoefficients = [sum(x) for x in zip_longest(self, other, fillvalue=self.field(0))]
77 | return Polynomial(newCoefficients)
78 |
79 |
80 | @typecheck
81 | def __mul__(self, other):
82 | if self.isZero() or other.isZero():
83 | return Zero()
84 |
85 | newCoeffs = [self.field(0) for _ in range(len(self) + len(other) - 1)]
86 |
87 | for i,a in enumerate(self):
88 | for j,b in enumerate(other):
89 | newCoeffs[i+j] += a*b
90 |
91 | return Polynomial(newCoeffs)
92 |
93 |
94 | @typecheck
95 | def __divmod__(self, divisor):
96 | quotient, remainder = Zero(), self
97 | divisorDeg = divisor.degree()
98 | divisorLC = divisor.leadingCoefficient()
99 |
100 | while remainder.degree() >= divisorDeg:
101 | monomialExponent = remainder.degree() - divisorDeg
102 | monomialZeros = [self.field(0) for _ in range(monomialExponent)]
103 | monomialDivisor = Polynomial(monomialZeros + [remainder.leadingCoefficient() / divisorLC])
104 |
105 | quotient += monomialDivisor
106 | remainder -= monomialDivisor * divisor
107 |
108 | return quotient, remainder
109 |
110 |
111 | @typecheck
112 | def __truediv__(self, divisor):
113 | if divisor.isZero():
114 | raise ZeroDivisionError
115 | return divmod(self, divisor)[0]
116 |
117 |
118 | @typecheck
119 | def __mod__(self, divisor):
120 | if divisor.isZero():
121 | raise ZeroDivisionError
122 | return divmod(self, divisor)[1]
123 |
124 |
125 | def Zero():
126 | return Polynomial([])
127 |
128 |
129 | Polynomial.field = field
130 | Polynomial.__name__ = '(%s)[x]' % field.__name__
131 | Polynomial.englishName = 'Polynomials in one variable over %s' % field.__name__
132 | return Polynomial
133 |
134 |
--------------------------------------------------------------------------------
/scripts/finite_fields/test.py:
--------------------------------------------------------------------------------
1 | def test(expected, actual):
2 | if expected != actual:
3 | import sys, traceback
4 | (filename, lineno, container, code) = traceback.extract_stack()[-2]
5 | print("Test: %r failed on line %d in file %r.\nExpected %r but got %r\n" %
6 | (code, lineno, filename, expected, actual))
7 |
8 | sys.exit(1)
9 |
10 |
--------------------------------------------------------------------------------
/scripts/finite_fields/typecast-test.py:
--------------------------------------------------------------------------------
1 | from modp import *
2 | from polynomial import *
3 |
4 |
5 | mod3 = IntegersModP(3)
6 | Polynomial = polynomialsOver(mod3)
7 | x = mod3(1)
8 | p = Polynomial([1,2])
9 |
10 | x+p
11 | p+x
12 |
13 |
--------------------------------------------------------------------------------
/scripts/jsonrpc_client.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import json
3 |
4 |
5 | def main():
6 | url = "http://localhost:8000/"
7 |
8 | # Example echo method
9 | payload = {
10 | "method": "stop",
11 | #"method": "get_info",
12 | "params": [],
13 | "jsonrpc": "2.0",
14 | "id": 0,
15 | }
16 | response = requests.post(url, json=payload).json()
17 |
18 | print(response)
19 | #assert response["result"] == "Hello World!"
20 | assert response["jsonrpc"]
21 |
22 | if __name__ == "__main__":
23 | main()
24 |
25 |
--------------------------------------------------------------------------------
/scripts/jubjub.py:
--------------------------------------------------------------------------------
1 | from finite_fields.modp import IntegersModP
2 |
3 | q = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001
4 | modq = IntegersModP(q)
5 |
6 | a = modq(-1)
7 | print("a:", hex(a.n))
8 | d = -(modq(10240)/modq(10241))
9 | params = (a, d)
10 |
11 | def is_jubjub(params, x, y):
12 | a, d = params
13 |
14 | return a * x**2 + y**2 == 1 + d * x**2 * y**2
15 |
16 | def add(params, point_1, point_2):
17 | # From here: https://z.cash/technology/jubjub/
18 |
19 | a, d = params
20 |
21 | x1, y1 = point_1
22 | x2, y2 = point_2
23 |
24 | x3 = (x1 * y2 + y1 * x2) / (1 + d * x1 * x2 * y1 * y2)
25 | y3 = (y1 * y2 + x1 * x2) / (1 - d * x1 * x2 * y1 * y2)
26 |
27 | return (x3, y3)
28 |
29 | def fake_zk_add(params, point_1, point_2):
30 | # From here: https://z.cash/technology/jubjub/
31 |
32 | a, d = params
33 |
34 | x1, y1 = point_1
35 | x2, y2 = point_2
36 |
37 | # Compute U = (u1 + v1) * (v2 - EDWARDS_A*u2)
38 | # = (u1 + v1) * (u2 + v2)
39 | U = (x1 + y1) * (x2 + y2)
40 | assert (x1 + y1) * (x2 + y2) == U
41 |
42 | # Compute A = v2 * u1
43 | A = y2 * x1
44 | # Compute B = u2 * v1
45 | B = x2 * y1
46 | # Compute C = d*A*B
47 | C = d * A * B
48 | assert (d * A) * (B) == C
49 |
50 | # Compute u3 = (A + B) / (1 + C)
51 | # NOTE: make sure we check for (1 + C) has an inverse
52 | u3 = (A + B) / (1 + C)
53 | assert (1 + C) * (u3) == (A + B)
54 |
55 | # Compute v3 = (U - A - B) / (1 - C)
56 | # We will also need to check inverse here as well.
57 | v3 = (U - A - B) / (1 - C)
58 | assert (1 - C) * (v3) == (U - A - B)
59 |
60 | return u3, v3
61 |
62 | x = 0x15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e
63 | y = 0x015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891
64 |
65 | x3, y3 = add(params, (x, y), (x, y))
66 | print(hex(x3.n), hex(y3.n))
67 | u3, v3 = fake_zk_add(params, (x, y), (x, y))
68 | print(hex(u3.n), hex(v3.n))
69 |
70 | print(is_jubjub(params, x, y))
71 | print(is_jubjub(params, x3, y3))
72 |
73 | print()
74 | print("Identity (0, 1) is jubjub?", is_jubjub(params, 0, 1))
75 | print("Torsion (0, -1) is jubjub?", is_jubjub(params, 0, -1))
76 | double_torsion = add(params, (0, -1), (0, -1))
77 | print("Double torsion is:", hex(double_torsion[0].n), hex(double_torsion[1].n))
78 | dbl_ident = add(params, (0, 1), (0, 1))
79 | print("Double identity is:", hex(dbl_ident[0].n), hex(dbl_ident[1].n))
80 |
81 |
--------------------------------------------------------------------------------
/scripts/modp.py:
--------------------------------------------------------------------------------
1 | from finite_fields.modp import IntegersModP
2 |
3 | q = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001
4 | modq = IntegersModP(q)
5 |
6 | a = modq(-1)
7 | print("0x%x" % a.n)
8 | print("\n")
9 | two = modq(2)
10 | inv2 = modq(2).inverse()
11 | print("Inverse of 2 = 0x%x" % inv2.n)
12 | print((two * inv2))
13 | # This is from bellman
14 | inv2_bellman = 0x39f6d3a994cebea4199cec0404d0ec02a9ded2017fff2dff7fffffff80000001
15 | assert inv2.n == inv2_bellman
16 | assert (2 * inv2.n) % q == 1
17 |
18 | # Futures contract calculation
19 | multiplier = modq(1)
20 | quantity = modq(100)
21 | entry_price = modq(10000)
22 | exit_price = modq(15000)
23 |
24 | initial_margin = multiplier * quantity
25 | print("initial margin =", initial_margin)
26 | price_return = exit_price * entry_price.inverse()
27 | print("R =", price_return)
28 | pnl = initial_margin - (initial_margin * exit_price) * entry_price.inverse()
29 | print("PNL =", pnl)
30 |
31 |
--------------------------------------------------------------------------------
/scripts/old/compile.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | python scripts/parser.py proofs/sapling3.prf | rustfmt > proofs/sapling3.rs
3 |
--------------------------------------------------------------------------------
/scripts/old/compile_and_run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -x
2 | python scripts/pism.py proofs/simple.pism | rustfmt > src/simple_circuit.rs
3 | cargo run --release --bin simple
4 |
5 |
--------------------------------------------------------------------------------
/scripts/old/run_bits.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -x
2 | python scripts/preprocess.py proofs/bits.psm > /tmp/bits.psm
3 | python scripts/vm.py --rust /tmp/bits.psm > src/bits_contract.rs
4 | cargo run --release --bin bits
5 |
6 |
--------------------------------------------------------------------------------
/scripts/old/run_mimc.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -x
2 | python scripts/preprocess.py proofs/mimc.psm > /tmp/mimc.psm
3 | python scripts/vm.py --rust /tmp/mimc.psm > src/zkmimc_contract.rs
4 | cargo run --release --bin zkmimc
5 |
6 |
--------------------------------------------------------------------------------
/scripts/old/run_mint2.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -x
2 | python scripts/preprocess.py proofs/mint2.psm > /tmp/mint2.psm || exit $?
3 | python scripts/vm.py --rust /tmp/mint2.psm > src/mint2_contract.rs || exit $?
4 | cargo run --release --bin mint2
5 |
6 |
--------------------------------------------------------------------------------
/scripts/old/run_mint_contract.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -x
2 | python scripts/preprocess.py proofs/mint.pism > /tmp/mint.pism
3 | python scripts/pism.py /tmp/mint.pism proofs/mint.aux | rustfmt > src/mint_contract.rs
4 | cargo run --release --bin mint
5 |
--------------------------------------------------------------------------------
/scripts/old/run_spend_contract.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -x
2 | python scripts/preprocess.py proofs/spend.pism > /tmp/spend.pism
3 | python scripts/pism.py /tmp/spend.pism proofs/mint.aux | rustfmt > src/spend_contract.rs
4 | cargo run --release --bin spend
5 |
--------------------------------------------------------------------------------
/scripts/old/run_vmtest.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -x
2 | python scripts/preprocess.py proofs/jubjub.pism > /tmp/jubjub.pism
3 | python scripts/vm.py --rust /tmp/jubjub.pism > src/vm_load.rs
4 | cargo run --release --bin vmtest
5 |
6 |
--------------------------------------------------------------------------------
/scripts/pism.vim:
--------------------------------------------------------------------------------
1 | "For autoload, add this to your VIM config:
2 | " VIM: .vimrc
3 | " NeoVIM: .config/nvim/init.vim
4 | "
5 | "autocmd BufRead *.pism call SetPismOptions()
6 | "function SetPismOptions()
7 | " set syntax=pism
8 | " source /home/narodnik/src/sapvi/scripts/pism.vim
9 | "endfunction
10 |
11 | if exists('b:current_syntax')
12 | finish
13 | endif
14 |
15 | syn keyword sapviKeyword constant contract start end constraint
16 | "syn keyword sapviAttr
17 | syn keyword sapviType FixedGenerator BlakePersonalization PedersenPersonalization ByteSize U64 Fr Point Bool Scalar BinarySize
18 | syn keyword sapviFunctionKeyword enforce lc0_add_one lc1_add_one lc2_add_one lc_coeff_reset lc_coeff_double lc0_sub_one lc1_sub_one lc2_sub_one dump_alloc dump_local
19 | syn match sapviFunction "^[ ]*[a-z_0-9]* "
20 | syn match sapviComment "#.*$"
21 | syn match sapviNumber ' \zs\d\+\ze'
22 | syn match sapviHexNumber ' \zs0x[a-z0-9]\+\ze'
23 | syn match sapviConst '[A-Z_]\{2,}[A-Z0-9_]*'
24 | syn keyword sapviBoolVal true false
25 | syn match sapviPreproc "{%.*%}"
26 | syn match sapviPreproc2 "{{.*}}"
27 |
28 | hi def link sapviKeyword Statement
29 | "hi def link sapviAttr StorageClass
30 | hi def link sapviPreproc PreProc
31 | hi def link sapviPreproc2 PreProc
32 | hi def link sapviType Type
33 | hi def link sapviFunction Function
34 | hi def link sapviFunctionKeyword Function
35 | hi def link sapviComment Comment
36 | hi def link sapviNumber Constant
37 | hi def link sapviHexNumber Constant
38 | hi def link sapviConst Constant
39 | hi def link sapviBoolVal Constant
40 |
41 | let b:current_syntax = "pism"
42 |
--------------------------------------------------------------------------------
/scripts/preprocess.py:
--------------------------------------------------------------------------------
1 | import os.path
2 | import sys
3 | from jinja2 import Environment, FileSystemLoader, Template
4 |
5 | def main(argv):
6 | if len(argv) != 2:
7 | print("error: missing arg", file=sys.stderr)
8 | return -1
9 |
10 | path = argv[1]
11 | dirname, filename = os.path.dirname(path), os.path.basename(path)
12 | env = Environment(loader = FileSystemLoader([dirname]))
13 | template = env.get_template(filename)
14 | print(template.render())
15 |
16 | return 0
17 |
18 | if __name__ == "__main__":
19 | sys.exit(main(sys.argv))
20 |
21 |
--------------------------------------------------------------------------------
/scripts/reorder-logs.py:
--------------------------------------------------------------------------------
1 | import datetime as dt
2 |
3 | def isotime_to_ms(isotime):
4 | ms = dt.timedelta(microseconds=1)
5 | time = dt.time.fromisoformat(isotime)
6 | ms_time = (dt.datetime.combine(dt.date.min, time) - dt.datetime.min) / ms
7 | return ms_time
8 |
9 | def line_time(line):
10 | return isotime_to_ms(line.split()[1])
11 |
12 | lines = []
13 | filenames = {"Client": "/tmp/a.txt", "Server": "/tmp/b.txt"}
14 |
15 | for label, filename in filenames.items():
16 | with open(filename) as file:
17 | file_lines = file.read().split("\n")
18 | # Cleanup a bit
19 | file_lines = [line for line in file_lines if line and line[0].isdigit()]
20 | # Attach the label to each line
21 | file_lines = ["%s: %s" % (label, line) for line in file_lines]
22 | lines.extend(file_lines)
23 |
24 | lines.sort(key=line_time)
25 | for line in lines:
26 | # Now remove timestamps and other info we don't need
27 | line = line.split()
28 | line = line[0] + " " + " ".join(line[4:])
29 | print(line)
30 |
--------------------------------------------------------------------------------
/scripts/sapvi.vim:
--------------------------------------------------------------------------------
1 | if exists('b:current_syntax')
2 | finish
3 | endif
4 |
5 | syn keyword sapviKeyword assert enforce for in def return const as let emit contract private proof
6 | syn keyword sapviAttr mut
7 | syn keyword sapviType BinaryNumber Point Fr SubgroupPoint EdwardsPoint Scalar EncryptedNum list Bool U64 Num Binary
8 | syn match sapviFunction "\zs[a-zA-Z0-9_]*\ze("
9 | syn match sapviComment "#.*$"
10 | syn match sapviNumber '\d\+'
11 | syn match sapviConst '[A-Z_]\{2,}[A-Z0-9_]*'
12 |
13 | hi def link sapviKeyword Statement
14 | hi def link sapviAttr StorageClass
15 | hi def link sapviType Type
16 | hi def link sapviFunction Function
17 | hi def link sapviComment Comment
18 | hi def link sapviNumber Constant
19 | hi def link sapviConst Constant
20 |
21 | let b:current_syntax = "sapvi"
22 |
--------------------------------------------------------------------------------
/scripts/to_html.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #nvim -c ":TOhtml" $1
3 | sed -i "s/PreProc { color: #5fd7ff; }/PreProc { color: #8f2722; }/" $1
4 | sed -i "s/Comment { color: #00ffff; }/Comment { color: #0055ff; }/" $1
5 |
6 |
--------------------------------------------------------------------------------
/scripts/zk/3.3-encrypted-polynomial.py:
--------------------------------------------------------------------------------
1 | from bls_py import bls12381
2 | from bls_py import pairing
3 | from bls_py import ec
4 | from bls_py.fields import Fq, Fq2, Fq6, Fq12, bls12381_q as Q
5 | import random
6 | import numpy as np
7 |
8 | # Section 3.3.4 from "Why and How zk-SNARK Works"
9 |
10 | def rand_scalar():
11 | return random.randrange(1, bls12381.q)
12 |
13 | #x = rand_scalar()
14 | #y = ec.y_for_x(x)
15 |
16 | g1 = ec.generator_Fq(bls12381)
17 | g2 = ec.generator_Fq2(bls12381)
18 |
19 | null = ec.AffinePoint(Fq(Q, 0), Fq(Q, 1), True, bls12381)
20 | assert g1 + null == g1
21 |
22 | #################################
23 | # Verifier (trusted setup)
24 | #################################
25 |
26 | # samples a random value (a secret)
27 | s = rand_scalar()
28 |
29 | # calculates encryptions of s for all powers i in 0 to d
30 | # E(s^i) = g^s^i
31 | d = 10
32 | encrypted_powers = [
33 | g1 * (s**i) for i in range(d)
34 | ]
35 |
36 | # evaluates unencrypted target polynomial with s: t(s)
37 | target = (s - 1) * (s - 2)
38 |
39 | # encrypted values of s provided to the prover
40 | # Actual values of s are toxic waste and discarded
41 |
42 | #################################
43 | # Prover
44 | #################################
45 |
46 | # E(p(s)) = p(s)G
47 | # = c_d s^d G + ... + c_1 s^1 G + c_0 s^0 G
48 | # = s^3 G - 3 s^2 G + 2 s G
49 | # E(h(s)) = sG
50 | # t(s) = s^2 - 3s + 2
51 | # E(h(s)) t(s) = s^3 G - 3 s^2 G + 2 s G
52 |
53 | # Lets test these manually:
54 |
55 | e_s = encrypted_powers
56 | e_p_s = e_s[3] - 3 * e_s[2] + 2 * e_s[1]
57 | e_h_s = e_s[1]
58 | t_s = s**2 - 3*s + 2
59 | assert t_s == target
60 | assert e_p_s == e_h_s * t_s
61 |
62 | #############################
63 |
64 | # x^3 - 3x^2 + 2x
65 | main_poly = np.poly1d([1, -3, 2, 0])
66 | # (x - 1)(x - 2)
67 | target_poly = np.poly1d([1, -1]) * np.poly1d([1, -2])
68 |
69 | # Calculates polynomial h(x) = p(x) / t(x)
70 | cofactor, remainder = main_poly / target_poly
71 | assert remainder == np.poly1d([0])
72 |
73 | # Using encrypted powers and coefficients, evaluates
74 | # E(p(s)) and E(h(s))
75 | def evaluate(poly, encrypted_powers):
76 | coeffs = list(poly.coef)[::-1]
77 | result = null
78 | for power, coeff in zip(encrypted_powers, coeffs):
79 | #print(coeff, power)
80 | coeff = int(coeff)
81 | # I have to do this for some strange reason
82 | # Because if coeff is negative and I do += power * coeff
83 | # then it gives me a different result than what I expect
84 | if coeff < 0:
85 | result -= power * (-coeff)
86 | else:
87 | result += power * coeff
88 | return result
89 |
90 | encrypted_poly = evaluate(main_poly, encrypted_powers)
91 | assert encrypted_poly == e_p_s
92 | encrypted_cofactor = evaluate(cofactor, encrypted_powers)
93 |
94 | # resulting g^p and g^h are provided to the verifier
95 |
96 | #################################
97 | # Verifier
98 | #################################
99 |
100 | # Last check that p = t(s) h
101 |
102 | assert encrypted_poly == encrypted_cofactor * target
103 |
104 |
--------------------------------------------------------------------------------
/scripts/zk/3.4-restricted-polynomial.py:
--------------------------------------------------------------------------------
1 | from bls_py import bls12381
2 | from bls_py import pairing
3 | from bls_py import ec
4 | from bls_py.fields import Fq, Fq2, Fq6, Fq12, bls12381_q as Q
5 | import random
6 | import numpy as np
7 |
8 | # Section 3.4 from "Why and How zk-SNARK Works"
9 |
10 | def rand_scalar():
11 | return random.randrange(1, bls12381.q)
12 |
13 | #x = rand_scalar()
14 | #y = ec.y_for_x(x)
15 |
16 | g1 = ec.generator_Fq(bls12381)
17 | g2 = ec.generator_Fq2(bls12381)
18 |
19 | null = ec.AffinePoint(Fq(Q, 0), Fq(Q, 1), True, bls12381)
20 | assert g1 + null == g1
21 |
22 | #################################
23 | # Verifier (trusted setup)
24 | #################################
25 |
26 | # samples a random value (a secret)
27 | s = rand_scalar()
28 |
29 | # calculate the shift
30 | a = rand_scalar()
31 |
32 | # calculates encryptions of s for all powers i in 0 to d
33 | # E(s^i) = g^s^i
34 | d = 10
35 | encrypted_powers = [
36 | g1 * (s**i) for i in range(d)
37 | ]
38 | encrypted_shifted_powers = [
39 | g1 * (a * s**i) for i in range(d)
40 | ]
41 |
42 | # evaluates unencrypted target polynomial with s: t(s)
43 | target = (s - 1) * (s - 2)
44 |
45 | # encrypted values of s provided to the prover
46 | # Actual values of s are toxic waste and discarded
47 |
48 | #################################
49 | # Prover
50 | #################################
51 |
52 | # E(p(s)) = p(s)G
53 | # = c_d s^d G + ... + c_1 s^1 G + c_0 s^0 G
54 | # = s^3 G - 3 s^2 G + 2 s G
55 | # E(h(s)) = sG
56 | # t(s) = s^2 - 3s + 2
57 | # E(h(s)) t(s) = s^3 G - 3 s^2 G + 2 s G
58 |
59 | # Lets test these manually:
60 |
61 | e_s = encrypted_powers
62 | e_p_s = e_s[3] - 3 * e_s[2] + 2 * e_s[1]
63 | e_h_s = e_s[1]
64 | t_s = s**2 - 3*s + 2
65 | assert t_s == target
66 | assert e_p_s == e_h_s * t_s
67 |
68 | e_as = encrypted_shifted_powers
69 | e_p_as = e_as[3] - 3 * e_as[2] + 2 * e_as[1]
70 | assert e_p_s * a == e_p_as
71 |
72 | #############################
73 |
74 | # x^3 - 3x^2 + 2x
75 | main_poly = np.poly1d([1, -3, 2, 0])
76 | # (x - 1)(x - 2)
77 | target_poly = np.poly1d([1, -1]) * np.poly1d([1, -2])
78 |
79 | # Calculates polynomial h(x) = p(x) / t(x)
80 | cofactor, remainder = main_poly / target_poly
81 | assert remainder == np.poly1d([0])
82 |
83 | # Using encrypted powers and coefficients, evaluates
84 | # E(p(s)) and E(h(s))
85 | def evaluate(poly, encrypted_powers):
86 | coeffs = list(poly.coef)[::-1]
87 | result = null
88 | for power, coeff in zip(encrypted_powers, coeffs):
89 | #print(coeff, power)
90 | coeff = int(coeff)
91 | # I have to do this for some strange reason
92 | # Because if coeff is negative and I do += power * coeff
93 | # then it gives me a different result than what I expect
94 | if coeff < 0:
95 | result -= power * (-coeff)
96 | else:
97 | result += power * coeff
98 | return result
99 |
100 | encrypted_poly = evaluate(main_poly, encrypted_powers)
101 | assert encrypted_poly == e_p_s
102 | encrypted_cofactor = evaluate(cofactor, encrypted_powers)
103 |
104 | # Alpha shifted powers
105 | encrypted_shift_poly = evaluate(main_poly, encrypted_shifted_powers)
106 |
107 | # resulting g^p and g^h are provided to the verifier
108 |
109 | #################################
110 | # Verifier
111 | #################################
112 |
113 | # Last check that p = t(s) h
114 |
115 | assert encrypted_poly == encrypted_cofactor * target
116 |
117 | # Verify (g^p)^a == g^p'
118 |
119 | assert encrypted_poly * a == encrypted_shift_poly
120 |
--------------------------------------------------------------------------------
/scripts/zk/3.5-zero-knowledge.py:
--------------------------------------------------------------------------------
1 | from bls_py import bls12381
2 | from bls_py import pairing
3 | from bls_py import ec
4 | from bls_py.fields import Fq, Fq2, Fq6, Fq12, bls12381_q as Q
5 | import random
6 | import numpy as np
7 |
8 | # Section 3.5 from "Why and How zk-SNARK Works"
9 |
10 | def rand_scalar():
11 | return random.randrange(1, bls12381.q)
12 |
13 | #x = rand_scalar()
14 | #y = ec.y_for_x(x)
15 |
16 | g1 = ec.generator_Fq(bls12381)
17 | g2 = ec.generator_Fq2(bls12381)
18 |
19 | null = ec.AffinePoint(Fq(Q, 0), Fq(Q, 1), True, bls12381)
20 | assert g1 + null == g1
21 |
22 | #################################
23 | # Verifier (trusted setup)
24 | #################################
25 |
26 | # samples a random value (a secret)
27 | s = rand_scalar()
28 |
29 | # calculate the shift
30 | a = rand_scalar()
31 |
32 | # calculates encryptions of s for all powers i in 0 to d
33 | # E(s^i) = g^s^i
34 | d = 10
35 | encrypted_powers = [
36 | g1 * (s**i) for i in range(d)
37 | ]
38 | encrypted_shifted_powers = [
39 | g1 * (a * s**i) for i in range(d)
40 | ]
41 |
42 | # evaluates unencrypted target polynomial with s: t(s)
43 | target = (s - 1) * (s - 2)
44 |
45 | # encrypted values of s provided to the prover
46 | # Actual values of s are toxic waste and discarded
47 |
48 | #################################
49 | # Prover
50 | #################################
51 |
52 | # delta shift
53 | delta = rand_scalar()
54 |
55 | # E(p(s)) = p(s)G
56 | # = c_d s^d G + ... + c_1 s^1 G + c_0 s^0 G
57 | # = s^3 G - 3 s^2 G + 2 s G
58 | # E(h(s)) = sG
59 | # t(s) = s^2 - 3s + 2
60 | # E(h(s)) t(s) = s^3 G - 3 s^2 G + 2 s G
61 |
62 | # Lets test these manually:
63 |
64 | e_s = encrypted_powers
65 | e_p_s = e_s[3] - 3 * e_s[2] + 2 * e_s[1]
66 | e_h_s = e_s[1]
67 | t_s = s**2 - 3*s + 2
68 | # exponentiate with delta
69 | e_p_s *= delta
70 | e_h_s *= delta
71 | assert t_s == target
72 | assert e_p_s == e_h_s * t_s
73 |
74 | e_as = encrypted_shifted_powers
75 | e_p_as = e_as[3] - 3 * e_as[2] + 2 * e_as[1]
76 | # exponentiate with delta
77 | e_p_as *= delta
78 | assert e_p_s * a == e_p_as
79 |
80 | #############################
81 |
82 | # x^3 - 3x^2 + 2x
83 | main_poly = np.poly1d([1, -3, 2, 0])
84 | # (x - 1)(x - 2)
85 | target_poly = np.poly1d([1, -1]) * np.poly1d([1, -2])
86 |
87 | # Calculates polynomial h(x) = p(x) / t(x)
88 | cofactor, remainder = main_poly / target_poly
89 | assert remainder == np.poly1d([0])
90 |
91 | # Using encrypted powers and coefficients, evaluates
92 | # E(p(s)) and E(h(s))
93 | def evaluate(poly, encrypted_powers):
94 | coeffs = list(poly.coef)[::-1]
95 | result = null
96 | for power, coeff in zip(encrypted_powers, coeffs):
97 | #print(coeff, power)
98 | coeff = int(coeff)
99 | # I have to do this for some strange reason
100 | # Because if coeff is negative and I do += power * coeff
101 | # then it gives me a different result than what I expect
102 | if coeff < 0:
103 | result -= power * (-coeff)
104 | else:
105 | result += power * coeff
106 | # Add delta to the result
107 | # Free extra obfuscation to the polynomial
108 | return result * delta
109 |
110 | encrypted_poly = evaluate(main_poly, encrypted_powers)
111 | assert encrypted_poly == e_p_s
112 | encrypted_cofactor = evaluate(cofactor, encrypted_powers)
113 |
114 | # Alpha shifted powers
115 | encrypted_shift_poly = evaluate(main_poly, encrypted_shifted_powers)
116 |
117 | # resulting g^p and g^h are provided to the verifier
118 |
119 | #################################
120 | # Verifier
121 | #################################
122 |
123 | # Last check that p = t(s) h
124 |
125 | assert encrypted_poly == encrypted_cofactor * target
126 |
127 | # Verify (g^p)^a == g^p'
128 |
129 | assert encrypted_poly * a == encrypted_shift_poly
130 |
--------------------------------------------------------------------------------
/scripts/zk/4.5.1-polynomial-interpolation.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 |
3 | def lagrange(points):
4 | result = np.poly1d([0])
5 | for i, (x_i, y_i) in enumerate(points):
6 | poly = np.poly1d([y_i])
7 | for j, (x_j, y_j) in enumerate(points):
8 | if i == j:
9 | continue
10 | poly *= np.poly1d([1, -x_j]) / (x_i - x_j)
11 | #print(poly)
12 | #print(poly(1), poly(2), poly(3))
13 | result += poly
14 | return result
15 |
16 | left = lagrange([
17 | (1, 2), (2, 2), (3, 6)
18 | ])
19 | print(left)
20 |
21 | right = lagrange([
22 | (1, 1), (2, 3), (3, 2)
23 | ])
24 | print(right)
25 |
26 | out = lagrange([
27 | (1, 2), (2, 6), (3, 12)
28 | ])
29 | print(out)
30 |
31 |
--------------------------------------------------------------------------------
/scripts/zk/4.6.2-multi-variable-operand-polynomial.py:
--------------------------------------------------------------------------------
1 | from bls_py import bls12381
2 | from bls_py import pairing
3 | from bls_py import ec
4 | from bls_py.fields import Fq, Fq2, Fq6, Fq12, bls12381_q as Q
5 | from finite_fields.modp import IntegersModP
6 | from finite_fields.polynomial import polynomialsOver
7 | import random
8 |
9 | n = bls12381.n
10 |
11 | g1 = ec.generator_Fq(bls12381)
12 | g2 = ec.generator_Fq2(bls12381)
13 |
14 | mod_field = IntegersModP(n)
15 | poly = polynomialsOver(mod_field).factory
16 |
17 | def lagrange(points):
18 | result = poly([0])
19 | for i, (x_i, y_i) in enumerate(points):
20 | p = poly([y_i])
21 | for j, (x_j, y_j) in enumerate(points):
22 | if i == j:
23 | continue
24 | p *= poly([-x_j, 1]) / (x_i - x_j)
25 | #print(poly)
26 | #print(poly(1), poly(2), poly(3))
27 | result += p
28 | return result
29 |
30 | l_a_points = [
31 | (1, 1), (2, 1), (3, 0)
32 | ]
33 | l_a = lagrange(l_a_points)
34 | #print(l_a)
35 |
36 | l_d_points = [
37 | (1, 0), (2, 0), (3, 1)
38 | ]
39 | l_d = lagrange(l_d_points)
40 | #print(l_d)
41 |
42 | # a x b = r_1
43 | # a x c = r_2
44 | # d x c = r_3
45 |
46 | # a = 3
47 | # d = 2
48 | L = 3*l_a + 2*l_d
49 | #print(L)
50 |
51 | def poly_call(poly, x):
52 | result = mod_field(0)
53 | for degree, coeff in enumerate(poly):
54 | result += coeff * (x**degree)
55 | return result.n
56 |
57 | assert poly_call(L, 1) == 3
58 | assert poly_call(L, 2) == 3
59 | assert poly_call(L, 3) == 2
60 |
61 | def rand_scalar():
62 | return random.randrange(1, bls12381.q)
63 |
64 | #################################
65 | # Verifier (trusted setup)
66 | #################################
67 |
68 | # samples a random value (a secret)
69 | toxic_scalar = rand_scalar()
70 | # calculate the shift
71 | alpha_shift = rand_scalar()
72 |
73 | l_a_s = poly_call(l_a, toxic_scalar)
74 | l_d_s = poly_call(l_d, toxic_scalar)
75 |
76 | enc_a_s = g1 * l_a_s
77 | enc_a_s_alpha = enc_a_s * alpha_shift
78 |
79 | enc_d_s = g1 * l_d_s
80 | enc_d_s_alpha = enc_d_s * alpha_shift
81 |
82 | # Proving key is enc_* values above
83 |
84 | # Actual values of s are toxic waste and discarded
85 |
86 | verify_key = g2 * alpha_shift
87 |
88 | #################################
89 | # Prover
90 | #################################
91 |
92 | a = 3
93 | d = 2
94 | assigned_a = enc_a_s * a
95 | assigned_d = enc_d_s * d
96 |
97 | assigned_a_shift = enc_a_s_alpha * a
98 | assigned_d_shift = enc_d_s_alpha * d
99 |
100 | operand = assigned_a + assigned_d
101 | operand_shift = assigned_a_shift + assigned_d_shift
102 |
103 | # proof = operand, operand_shift
104 |
105 | #################################
106 | # Verifier
107 | #################################
108 |
109 | e = pairing.ate_pairing
110 | assert e(operand_shift, g2) == e(operand, verify_key)
111 |
112 |
--------------------------------------------------------------------------------
/scripts/zk/4.8-example-computation.py:
--------------------------------------------------------------------------------
1 | # Algorithm:
2 | # if w { a * b } else { a + b }
3 |
4 | # Equation:
5 | # f(w, a, b) = w(ab) + (1 - w)(a + b) = v
6 |
7 | # w(ab) + a + b - w(ab) = v
8 | # w(ab - a - b) = v - a - b
9 |
10 | # Constraints:
11 | # 1: [1 a] [1 b] [1 m]
12 | # 2: [1 w] [1 m, -1 a, -1 b] = [1 v, -1 a, -1 b]
13 | # 3: [1 w] [1 w] [1 w]
14 |
15 | # f(1, 4, 2) = 8
16 |
17 | from bls_py import bls12381
18 | from bls_py import pairing
19 | from bls_py import ec
20 | from bls_py.fields import Fq, Fq2, Fq6, Fq12, bls12381_q as Q
21 | from finite_fields.modp import IntegersModP
22 | from finite_fields.polynomial import polynomialsOver
23 | import random
24 |
25 | n = bls12381.n
26 |
27 | g1 = ec.generator_Fq(bls12381)
28 | g2 = ec.generator_Fq2(bls12381)
29 |
30 | mod_field = IntegersModP(n)
31 | poly = polynomialsOver(mod_field).factory
32 |
33 | def lagrange(points):
34 | result = poly([0])
35 | for i, (x_i, y_i) in enumerate(points):
36 | p = poly([y_i])
37 | for j, (x_j, y_j) in enumerate(points):
38 | if i == j:
39 | continue
40 | p *= poly([-x_j, 1]) / (x_i - x_j)
41 | #print(poly)
42 | #print(poly(1), poly(2), poly(3))
43 | result += p
44 | return result
45 |
46 | left_variables = {
47 | "a": lagrange([
48 | (1, 1), (2, 0), (3, 0)
49 | ]),
50 | "w": lagrange([
51 | (1, 0), (2, 1), (3, 1)
52 | ])
53 | }
54 |
55 | right_variables = {
56 | "m": lagrange([
57 | (1, 0), (2, 1), (3, 0)
58 | ]),
59 | "a": lagrange([
60 | (1, 0), (2, -1), (3, 0)
61 | ]),
62 | "b": lagrange([
63 | (1, 1), (2, -1), (3, 0)
64 | ]),
65 | "w": lagrange([
66 | (1, 0), (2, 0), (3, 1)
67 | ]),
68 | }
69 |
70 | out_variables = {
71 | "m": lagrange([
72 | (1, 1), (2, 0), (3, 0)
73 | ]),
74 | "v": lagrange([
75 | (1, 0), (2, 1), (3, 0)
76 | ]),
77 | "a": lagrange([
78 | (1, 0), (2, -1), (3, 0)
79 | ]),
80 | "b": lagrange([
81 | (1, 0), (2, -1), (3, 0)
82 | ]),
83 | "w": lagrange([
84 | (1, 0), (2, 0), (3, 1)
85 | ]),
86 | }
87 |
88 | private_inputs = {
89 | "w": 1,
90 | "a": 3,
91 | "b": 2
92 | }
93 |
94 | private_inputs["m"] = private_inputs["a"] * private_inputs["b"]
95 | private_inputs["v"] = \
96 | private_inputs["w"] * (
97 | private_inputs["m"] - private_inputs["a"] - private_inputs["b"]) \
98 | + private_inputs["a"] + private_inputs["b"]
99 | assert private_inputs["v"] == 6
100 |
101 | left_variable_poly = (
102 | private_inputs["a"] * left_variables["a"]
103 | + private_inputs["w"] * left_variables["w"]
104 | )
105 | right_variable_poly = (
106 | private_inputs["m"] * right_variables["m"]
107 | + private_inputs["a"] * right_variables["a"]
108 | + private_inputs["b"] * right_variables["b"]
109 | + private_inputs["w"] * right_variables["w"]
110 | )
111 | out_variable_poly = (
112 | private_inputs["m"] * out_variables["m"]
113 | + private_inputs["v"] * out_variables["v"]
114 | + private_inputs["a"] * out_variables["a"]
115 | + private_inputs["b"] * out_variables["b"]
116 | + private_inputs["w"] * out_variables["w"]
117 | )
118 |
119 | # (x - 1)(x - 2)(x - 3)
120 | target_poly = poly([-1, 1]) * poly([-2, 1]) * poly([-3, 1])
121 |
122 | def poly_call(poly, x):
123 | result = mod_field(0)
124 | for degree, coeff in enumerate(poly):
125 | result += coeff * (x**degree)
126 | return result.n
127 |
128 | assert poly_call(target_poly, 1) == 0
129 | assert poly_call(target_poly, 2) == 0
130 | assert poly_call(target_poly, 3) == 0
131 |
132 | main_poly = left_variable_poly * right_variable_poly - out_variable_poly
133 | cofactor_poly = main_poly / target_poly
134 |
135 | assert (
136 | left_variable_poly * right_variable_poly == \
137 | cofactor_poly * target_poly + out_variable_poly
138 | )
139 |
140 |
--------------------------------------------------------------------------------
/scripts/zk/qap.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 |
3 | # Lets prove we know the answer to x**3 + x + 5 == 35 (x = 5)
4 |
5 | # We break it down into these statements:
6 |
7 | # L1: s1 = x * x
8 | # L2: y = s1 * x
9 | # L3: s2 = y + x
10 | # L4: out = s2 + 5
11 |
12 | # Statements are of the form:
13 | # a * b = c
14 |
15 | # s1 = x * x
16 | # OR a * b = c, where a = x, b = x and c = s1
17 | L1 = np.array([
18 | # a b c
19 | [0, 0, 0], # 1
20 | [1, 1, 0], # x
21 | [0, 0, 0], # out
22 | [0, 0, 1], # s1
23 | [0, 0, 0], # y
24 | [0, 0, 0] # s2
25 | ])
26 |
27 | # y = s1 * x
28 | L2 = np.array([
29 | # a b c
30 | [0, 0, 0], # 1
31 | [0, 1, 0], # x
32 | [0, 0, 0], # out
33 | [1, 0, 0], # s1
34 | [0, 0, 1], # y
35 | [0, 0, 0] # s2
36 | ])
37 |
38 | # s2 = y + x
39 | L3 = np.array([
40 | # a b c
41 | [0, 1, 0], # 1
42 | [1, 0, 0], # x
43 | [0, 0, 0], # out
44 | [0, 0, 0], # s1
45 | [1, 0, 0], # y
46 | [0, 0, 1] # s2
47 | ])
48 |
49 | # out = s2 + 5
50 | L4 = np.array([
51 | # a b c
52 | [5, 1, 0], # 1
53 | [0, 0, 0], # x
54 | [0, 0, 1], # out
55 | [0, 0, 0], # s1
56 | [0, 0, 0], # y
57 | [1, 0, 0] # s2
58 | ])
59 |
60 | a = np.array([L.transpose()[0] for L in (L1, L2, L3, L4)])
61 | b = np.array([L.transpose()[1] for L in (L1, L2, L3, L4)])
62 | c = np.array([L.transpose()[2] for L in (L1, L2, L3, L4)])
63 | print("A")
64 | print(a)
65 | print("B")
66 | print(b)
67 | print("C")
68 | print(c)
69 |
70 | # The witness
71 | s = np.array([
72 | 1,
73 | 3,
74 | 35,
75 | 9,
76 | 27,
77 | 30
78 | ])
79 | print()
80 |
81 | #print(s * a * s * b - s * c)
82 | for a_i, b_i, c_i in zip(a, b, c):
83 | assert sum(s * a_i) * sum(s * b_i) - sum(s * c_i) == 0
84 |
85 | print("R1CS done.")
86 | print()
87 |
88 | def factorial(x):
89 | r = 1
90 | for x_i in range(2, x + 1):
91 | r *= x_i
92 | return r
93 |
94 | def combinations(n, r):
95 | return factorial(n) / (factorial(n - r) * factorial(r))
96 |
97 | def lagrange(points):
98 | result = np.poly1d([0])
99 | for i, (x_i, y_i) in enumerate(points):
100 | poly = np.poly1d([y_i])
101 | for j, (x_j, y_j) in enumerate(points):
102 | if i == j:
103 | continue
104 | poly *= np.poly1d([1, -x_j]) / (x_i - x_j)
105 | #print(poly)
106 | #print(poly(1), poly(2), poly(3))
107 | result += poly
108 | return result
109 |
110 | # 1.5, -5.5, 7
111 | #poly = lagrange([(1, 3), (2, 2), (3, 4)])
112 | #print(poly)
113 |
114 | def make_qap(a):
115 | a_qap = []
116 | a_polys = []
117 | for a_i in a.transpose():
118 | poly = lagrange(list(enumerate(a_i, start=1)))
119 | coeffs = poly.c.tolist()
120 | if len(coeffs) < 4:
121 | coeffs = [0] * (4 - len(coeffs)) + coeffs
122 | a_qap.append(coeffs)
123 | a_polys.append(poly)
124 | a_qap = np.array(a_qap)
125 | print(a_qap)
126 | return a_polys
127 |
128 | print("A")
129 | a_polys = make_qap(a)
130 | print("B")
131 | b_polys = make_qap(b)
132 | print("C")
133 | c_polys = make_qap(c)
134 |
135 | def check(polys, x):
136 | results = []
137 | for poly in polys:
138 | results.append(int(poly(x)))
139 | return results
140 |
141 | print()
142 | print("A results at x", check(a_polys, 1))
143 | print()
144 | print("B results at x", check(b_polys, 1))
145 | print()
146 | print("C results at x", check(c_polys, 1))
147 |
148 | def combine_polys(polys):
149 | r = np.poly1d([0])
150 | for s_i, p_i in zip(s, polys):
151 | r += s_i * p_i
152 | return r
153 |
154 | print()
155 | print()
156 | A = combine_polys(a_polys)
157 | print("A =")
158 | print(A)
159 | B = combine_polys(b_polys)
160 | print("B =")
161 | print(B)
162 | C = combine_polys(c_polys)
163 | print("C =")
164 | print(C)
165 | print()
166 | t = A * B - C
167 | print("t =")
168 | print(t)
169 |
170 | # 4 statements in our R1CS: L1, L2, L3, L4
171 | divisor_poly = np.poly1d([1])
172 | for x in range(1, 4 + 1):
173 | divisor_poly *= np.poly1d([1, -x])
174 |
175 | quot, remainder = np.polydiv(t, divisor_poly)
176 | assert len(remainder.c) == 1
177 | print()
178 | print("Result of QAP:")
179 | print(int(remainder.c[0]))
180 |
--------------------------------------------------------------------------------
/src/async_serial.rs:
--------------------------------------------------------------------------------
1 | use futures::prelude::*;
2 |
3 | use crate::endian;
4 | use crate::error::{Error, Result};
5 | use crate::serial::VarInt;
6 |
7 | impl VarInt {
8 | pub async fn encode_async(&self, stream: &mut W) -> Result {
9 | match self.0 {
10 | 0..=0xFC => {
11 | AsyncWriteExt::write_u8(stream, self.0 as u8).await?;
12 | Ok(1)
13 | }
14 | 0xFD..=0xFFFF => {
15 | AsyncWriteExt::write_u8(stream, 0xFD).await?;
16 | AsyncWriteExt::write_u16(stream, self.0 as u16).await?;
17 | Ok(3)
18 | }
19 | 0x10000..=0xFFFFFFFF => {
20 | AsyncWriteExt::write_u8(stream, 0xFE).await?;
21 | AsyncWriteExt::write_u32(stream, self.0 as u32).await?;
22 | Ok(5)
23 | }
24 | _ => {
25 | AsyncWriteExt::write_u8(stream, 0xFF).await?;
26 | AsyncWriteExt::write_u64(stream, self.0 as u64).await?;
27 | Ok(9)
28 | }
29 | }
30 | }
31 |
32 | pub async fn decode_async(stream: &mut R) -> Result {
33 | let n = AsyncReadExt::read_u8(stream).await?;
34 | match n {
35 | 0xFF => {
36 | let x = AsyncReadExt::read_u64(stream).await?;
37 | if x < 0x100000000 {
38 | Err(Error::NonMinimalVarInt)
39 | } else {
40 | Ok(VarInt(x))
41 | }
42 | }
43 | 0xFE => {
44 | let x = AsyncReadExt::read_u32(stream).await?;
45 | if x < 0x10000 {
46 | Err(Error::NonMinimalVarInt)
47 | } else {
48 | Ok(VarInt(x as u64))
49 | }
50 | }
51 | 0xFD => {
52 | let x = AsyncReadExt::read_u16(stream).await?;
53 | if x < 0xFD {
54 | Err(Error::NonMinimalVarInt)
55 | } else {
56 | Ok(VarInt(x as u64))
57 | }
58 | }
59 | n => Ok(VarInt(n as u64)),
60 | }
61 | }
62 | }
63 |
64 | macro_rules! async_encoder_fn {
65 | ($name:ident, $val_type:ty, $writefn:ident) => {
66 | #[inline]
67 | pub async fn $name(stream: &mut W, v: $val_type) -> Result<()> {
68 | stream
69 | .write_all(&endian::$writefn(v))
70 | .await
71 | .map_err(Error::Io)
72 | }
73 | };
74 | }
75 |
76 | macro_rules! async_decoder_fn {
77 | ($name:ident, $val_type:ty, $readfn:ident, $byte_len: expr) => {
78 | pub async fn $name(stream: &mut R) -> Result<$val_type> {
79 | assert_eq!(::std::mem::size_of::<$val_type>(), $byte_len); // size_of isn't a constfn in 1.22
80 | let mut val = [0; $byte_len];
81 | stream.read_exact(&mut val[..]).await.map_err(Error::Io)?;
82 | Ok(endian::$readfn(&val))
83 | }
84 | };
85 | }
86 |
87 | pub struct AsyncReadExt {}
88 |
89 | impl AsyncReadExt {
90 | async_decoder_fn!(read_u64, u64, slice_to_u64_le, 8);
91 | async_decoder_fn!(read_u32, u32, slice_to_u32_le, 4);
92 | async_decoder_fn!(read_u16, u16, slice_to_u16_le, 2);
93 |
94 | pub async fn read_u8(stream: &mut R) -> Result {
95 | let mut slice = [0u8; 1];
96 | stream.read_exact(&mut slice).await?;
97 | Ok(slice[0])
98 | }
99 | }
100 |
101 | pub struct AsyncWriteExt {}
102 |
103 | impl AsyncWriteExt {
104 | async_encoder_fn!(write_u64, u64, u64_to_array_le);
105 | async_encoder_fn!(write_u32, u32, u32_to_array_le);
106 | async_encoder_fn!(write_u16, u16, u16_to_array_le);
107 |
108 | pub async fn write_u8(stream: &mut W, v: u8) -> Result<()> {
109 | stream.write_all(&[v]).await.map_err(Error::Io)
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/bin/compile-shaders.rs:
--------------------------------------------------------------------------------
1 | use anyhow::*;
2 | use fs_extra::copy_items;
3 | use fs_extra::dir::CopyOptions;
4 | use glob::glob;
5 | use std::env;
6 | use std::fs::{read_to_string, write};
7 | use std::path::PathBuf;
8 |
9 | struct ShaderData {
10 | src: String,
11 | src_path: PathBuf,
12 | spv_path: PathBuf,
13 | kind: shaderc::ShaderKind,
14 | }
15 |
16 | impl ShaderData {
17 | pub fn load(src_path: PathBuf) -> Result {
18 | let extension = src_path
19 | .extension()
20 | .context("File has no extension")?
21 | .to_str()
22 | .context("Extension cannot be converted to &str")?;
23 | let kind = match extension {
24 | "vert" => shaderc::ShaderKind::Vertex,
25 | "frag" => shaderc::ShaderKind::Fragment,
26 | "comp" => shaderc::ShaderKind::Compute,
27 | _ => bail!("Unsupported shader: {}", src_path.display()),
28 | };
29 |
30 | let src = read_to_string(src_path.clone())?;
31 | let spv_path = src_path.with_extension(format!("{}.spv", extension));
32 |
33 | Ok(Self {
34 | src,
35 | src_path,
36 | spv_path,
37 | kind,
38 | })
39 | }
40 | }
41 |
42 | fn main() -> Result<()> {
43 | // Collect all shaders recursively within /src/
44 | let mut shader_paths = [
45 | glob("./res/shader/**/*.vert")?,
46 | glob("./res/shader/**/*.frag")?,
47 | glob("./res/shader/**/*.comp")?,
48 | ];
49 |
50 | // This could be parallelized
51 | let shaders = shader_paths
52 | .iter_mut()
53 | .flatten()
54 | .map(|glob_result| ShaderData::load(glob_result?))
55 | .collect::>>()
56 | .into_iter()
57 | .collect::>>()?;
58 |
59 | let mut compiler = shaderc::Compiler::new().context("Unable to create shader compiler")?;
60 |
61 | // This can't be parallelized. The [shaderc::Compiler] is not
62 | // thread safe. Also, it creates a lot of resources. You could
63 | // spawn multiple processes to handle this, but it would probably
64 | // be better just to only compile shaders that have been changed
65 | // recently.
66 | for shader in shaders {
67 | // This tells cargo to rerun this script if something in /src/ changes.
68 | println!(
69 | "cargo:rerun-if-changed={}",
70 | shader.src_path.as_os_str().to_str().unwrap()
71 | );
72 |
73 | let compiled = compiler.compile_into_spirv(
74 | &shader.src,
75 | shader.kind,
76 | &shader.src_path.to_str().unwrap(),
77 | "main",
78 | None,
79 | )?;
80 | write(shader.spv_path, compiled.as_binary_u8())?;
81 | }
82 |
83 | // This tells cargo to rerun this script if something in /res/ changes.
84 | println!("cargo:rerun-if-changed=res/*");
85 |
86 | //let out_dir = env::var("OUT_DIR")?;
87 | //let mut copy_options = CopyOptions::new();
88 | //copy_options.overwrite = true;
89 | //let mut paths_to_copy = Vec::new();
90 | //paths_to_copy.push("res/");
91 | //copy_items(&paths_to_copy, out_dir, ©_options)?;
92 |
93 | Ok(())
94 | }
95 |
--------------------------------------------------------------------------------
/src/bin/demowallet.rs:
--------------------------------------------------------------------------------
1 | //! cargo run --example request --features="rt-tokio" --no-default-features
2 |
3 | use async_zmq::zmq;
4 | use sapvi::serial;
5 | use sapvi::service::reqrep::{Reply, Request};
6 |
7 | fn connect() {
8 | let context = zmq::Context::new();
9 | let requester = context.socket(zmq::REQ).unwrap();
10 | requester
11 | .connect("tcp://127.0.0.1:3333")
12 | .expect("failed to connect requester");
13 |
14 | for request_nbr in 0..10 {
15 | let req = Request::new(0, "test".as_bytes().to_vec());
16 | let req = serial::serialize(&req);
17 | requester.send(req, 0).unwrap();
18 | let message = requester.recv_msg(0).unwrap();
19 | let rep: Reply = serial::deserialize(&message).unwrap();
20 | println!("Received reply {:?} {:?}", request_nbr, rep);
21 | }
22 | }
23 | fn main() {
24 | let mut thread_pools = vec![];
25 | for _ in 0..20 {
26 | let t = std::thread::spawn(connect);
27 | thread_pools.push(t);
28 | }
29 |
30 | for t in thread_pools {
31 | t.join().unwrap();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/bin/jubjub.rs:
--------------------------------------------------------------------------------
1 | use bls12_381::Scalar;
2 | use sapvi::{BlsStringConversion, Decodable, Encodable, ZKContract, ZKProof};
3 | use std::fs::File;
4 | use std::time::Instant;
5 |
6 | type Result = std::result::Result;
7 |
8 | fn main() -> Result<()> {
9 | {
10 | // Load the contract from file
11 |
12 | let start = Instant::now();
13 | let file = File::open("jubjub.zcd")?;
14 | let mut contract = ZKContract::decode(file)?;
15 | println!(
16 | "Loaded contract '{}': [{:?}]",
17 | contract.name,
18 | start.elapsed()
19 | );
20 |
21 | println!("Stats:");
22 | println!(" Constants: {}", contract.vm.constants.len());
23 | println!(" Alloc: {}", contract.vm.alloc.len());
24 | println!(" Operations: {}", contract.vm.ops.len());
25 | println!(
26 | " Constraint Instructions: {}",
27 | contract.vm.constraints.len()
28 | );
29 |
30 | // Do the trusted setup
31 |
32 | contract.setup("jubjub.zts")?;
33 | }
34 |
35 | // Load the contract from file
36 |
37 | let start = Instant::now();
38 | let file = File::open("jubjub.zcd")?;
39 | let mut contract = ZKContract::decode(file)?;
40 | println!(
41 | "Loaded contract '{}': [{:?}]",
42 | contract.name,
43 | start.elapsed()
44 | );
45 |
46 | contract.load_setup("jubjub.zts")?;
47 |
48 | {
49 | // Put in our input parameters
50 |
51 | contract.set_param(
52 | "a_u",
53 | Scalar::from_string("15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e"),
54 | )?;
55 | contract.set_param(
56 | "a_v",
57 | Scalar::from_string("015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891"),
58 | )?;
59 | contract.set_param(
60 | "b_u",
61 | Scalar::from_string("15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e"),
62 | )?;
63 | contract.set_param(
64 | "b_v",
65 | Scalar::from_string("015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891"),
66 | )?;
67 |
68 | // Generate the ZK proof
69 |
70 | let proof = contract.prove()?;
71 |
72 | // Test and show our output values
73 |
74 | assert_eq!(proof.public.len(), 2);
75 | // 0x66ced46f14e5616d12b993f60a6e66558d6b6afe4c321ed212e0b9cfbd81061a
76 | assert_eq!(
77 | *proof.public.get("result_u").unwrap(),
78 | Scalar::from_string("66ced46f14e5616d12b993f60a6e66558d6b6afe4c321ed212e0b9cfbd81061a")
79 | );
80 | // 0x4731570fdd57cf280eadc8946fa00df81112502e44e497e794ab9a221f1bcca
81 | assert_eq!(
82 | *proof.public.get("result_v").unwrap(),
83 | Scalar::from_string("04731570fdd57cf280eadc8946fa00df81112502e44e497e794ab9a221f1bcca")
84 | );
85 | println!("u = {:?}", proof.public.get("result_u").unwrap());
86 | println!("v = {:?}", proof.public.get("result_v").unwrap());
87 |
88 | let mut file = File::create("jubjub.prf")?;
89 | proof.encode(&mut file)?;
90 | }
91 |
92 | // Verify the proof
93 |
94 | let file = File::open("jubjub.prf")?;
95 | let proof = ZKProof::decode(file)?;
96 | assert!(contract.verify(&proof));
97 |
98 | Ok(())
99 | }
100 |
--------------------------------------------------------------------------------
/src/bin/mimc.rs:
--------------------------------------------------------------------------------
1 | use bls12_381::Scalar;
2 | use ff::Field;
3 | use sapvi::{Decodable, ZKContract};
4 | use std::fs::File;
5 | use std::ops::{Add, AddAssign, MulAssign, Neg, SubAssign};
6 | use std::time::Instant;
7 |
8 | type Result = std::result::Result;
9 |
10 | mod mimc_constants;
11 | use mimc_constants::mimc_constants;
12 |
13 | const MIMC_ROUNDS: usize = 322;
14 |
15 | fn mimc(mut xl: Scalar, mut xr: Scalar, constants: &[Scalar]) -> Scalar {
16 | assert_eq!(constants.len(), MIMC_ROUNDS);
17 |
18 | for i in 0..MIMC_ROUNDS {
19 | let mut tmp1 = xl;
20 | tmp1.add_assign(&constants[i]);
21 | let mut tmp2 = tmp1.square();
22 | tmp2.mul_assign(&tmp1);
23 | tmp2.add_assign(&xr);
24 | xr = xl;
25 | xl = tmp2;
26 | }
27 |
28 | xl
29 | }
30 |
31 | macro_rules! from_slice {
32 | ($data:expr, $len:literal) => {{
33 | let mut array = [0; $len];
34 | // panics if not enough data
35 | let bytes = &$data[..array.len()];
36 | assert_eq!(bytes.len(), array.len());
37 | for (a, b) in array.iter_mut().rev().zip(bytes.iter()) {
38 | *a = *b;
39 | }
40 | //array.copy_from_slice(bytes.iter().rev());
41 | array
42 | }};
43 | }
44 |
45 | fn main() -> Result<()> {
46 | /////////////////////////////////
47 | // Initialize our MiMC constants
48 | let mut constants = Vec::new();
49 | for const_str in mimc_constants() {
50 | let bytes = from_slice!(&hex::decode(const_str).unwrap(), 32);
51 | assert_eq!(bytes.len(), 32);
52 | let constant = Scalar::from_bytes(&bytes).unwrap();
53 |
54 | constants.push(constant);
55 | }
56 | /////////////////////////////////
57 |
58 | // Load the contract from file
59 |
60 | let start = Instant::now();
61 | let file = File::open("mimc.zcd")?;
62 | let mut contract = ZKContract::decode(file)?;
63 | println!(
64 | "Loaded contract '{}': [{:?}]",
65 | contract.name,
66 | start.elapsed()
67 | );
68 |
69 | println!("Stats:");
70 | println!(" Constants: {}", contract.vm.constants.len());
71 | println!(" Alloc: {}", contract.vm.alloc.len());
72 | println!(" Operations: {}", contract.vm.ops.len());
73 | println!(
74 | " Constraint Instructions: {}",
75 | contract.vm.constraints.len()
76 | );
77 |
78 | // Do the trusted setup
79 |
80 | contract.setup("mimc.zts");
81 |
82 | // Put in our input parameters
83 |
84 | let left = Scalar::from_raw([
85 | 0xb981_9dc8_2d90_607e,
86 | 0xa361_ee3f_d48f_df77,
87 | 0x52a3_5a8c_1908_dd87,
88 | 0x15a3_6d1f_0f39_0d88,
89 | ]);
90 | let right = Scalar::from_raw([
91 | 0x7b0d_c53c_4ebf_1891,
92 | 0x1f3a_beeb_98fa_d3e8,
93 | 0xf789_1142_c001_d925,
94 | 0x015d_8c7f_5b43_fe33,
95 | ]);
96 |
97 | println!("----> {:?}", left);
98 | println!("----> {:?}", right);
99 |
100 | contract.set_param("left_0", left.clone())?;
101 | contract.set_param("right", right.clone())?;
102 |
103 | // Generate the ZK proof
104 |
105 | let proof = contract.prove()?;
106 |
107 | // Test and show our output values
108 |
109 | let mimc_hash = mimc(left, right, &constants);
110 | assert_eq!(proof.public.len(), 1);
111 | // 0x66ced46f14e5616d12b993f60a6e66558d6b6afe4c321ed212e0b9cfbd81061a
112 | assert_eq!(*proof.public.get("hash_result").unwrap(), mimc_hash);
113 | println!(
114 | "hash result = {:?}",
115 | proof.public.get("hash_result").unwrap()
116 | );
117 |
118 | // Verify the proof
119 |
120 | assert!(contract.verify(&proof));
121 |
122 | Ok(())
123 | }
124 |
--------------------------------------------------------------------------------
/src/bin/mint-classic.rs:
--------------------------------------------------------------------------------
1 | use bellman::gadgets::multipack;
2 | use bellman::groth16;
3 | use blake2s_simd::Params as Blake2sParams;
4 | use bls12_381::Bls12;
5 | use ff::Field;
6 | use group::{Curve, Group, GroupEncoding};
7 |
8 | use sapvi::crypto::{
9 | create_mint_proof, load_params, save_params, setup_mint_prover, verify_mint_proof,
10 | };
11 |
12 | fn main() {
13 | use rand::rngs::OsRng;
14 | use std::time::Instant;
15 |
16 | let public = jubjub::SubgroupPoint::random(&mut OsRng);
17 |
18 | let value = 110;
19 | let randomness_value: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
20 |
21 | let serial: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
22 | let randomness_coin: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
23 |
24 | {
25 | let params = setup_mint_prover();
26 | save_params("mint.params", ¶ms);
27 | }
28 | let (params, pvk) = load_params("mint.params").expect("params should load");
29 |
30 | let (proof, revealed) = create_mint_proof(
31 | ¶ms,
32 | value,
33 | randomness_value,
34 | serial,
35 | randomness_coin,
36 | public,
37 | );
38 |
39 | assert!(verify_mint_proof(&pvk, &proof, &revealed));
40 | }
41 |
--------------------------------------------------------------------------------
/src/bin/mint.rs:
--------------------------------------------------------------------------------
1 | use sapvi::{Decodable, ZKContract};
2 | use std::fs::File;
3 | use std::time::Instant;
4 |
5 | use bls12_381::Scalar;
6 | use ff::{Field, PrimeField};
7 | use group::{Curve, Group};
8 | use rand::rngs::OsRng;
9 |
10 | type Result = std::result::Result;
11 |
12 | // Unpack a value (such as jubjub::Fr) into 256 Scalar binary digits
13 | fn unpack(value: F) -> Vec {
14 | let mut bits = Vec::new();
15 | print!("Unpack: ");
16 | for (_i, bit) in value.to_le_bits().into_iter().cloned().enumerate() {
17 | match bit {
18 | true => bits.push(Scalar::one()),
19 | false => bits.push(Scalar::zero()),
20 | }
21 | print!("{}", if bit { 1 } else { 0 });
22 | }
23 | println!("");
24 | bits
25 | }
26 |
27 | // Unpack a u64 value in 64 Scalar binary digits
28 | fn unpack_u64(value: u64) -> Vec {
29 | let mut result = Vec::with_capacity(64);
30 |
31 | for i in 0..64 {
32 | if (value >> i) & 1 == 1 {
33 | result.push(Scalar::one());
34 | } else {
35 | result.push(Scalar::zero());
36 | }
37 | }
38 |
39 | result
40 | }
41 |
42 | fn main() -> Result<()> {
43 | let start = Instant::now();
44 | let file = File::open("mint.zcd")?;
45 | let mut visor = ZKContract::decode(file)?;
46 | println!("{}", visor.name);
47 | //ZKContract::load_contract(bytes);
48 | println!("Loaded contract: [{:?}]", start.elapsed());
49 |
50 | println!("Stats:");
51 | println!(" Constants: {}", visor.vm.constants.len());
52 | println!(" Alloc: {}", visor.vm.alloc.len());
53 | println!(" Operations: {}", visor.vm.ops.len());
54 | println!(
55 | " Constraint Instructions: {}",
56 | visor.vm.constraints.len()
57 | );
58 |
59 | visor.setup("mint.zts");
60 |
61 | // We use the ExtendedPoint in calculations because it's faster
62 | let public_point = jubjub::ExtendedPoint::from(jubjub::SubgroupPoint::random(&mut OsRng));
63 | // But to serialize we need to convert to affine (which has the (u, v) values)
64 | let public_affine = public_point.to_affine();
65 |
66 | let randomness_value: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
67 |
68 | for param in visor.param_names() {
69 | println!("Param name: {}", param);
70 | }
71 |
72 | visor.set_param("public_u", public_affine.get_u())?;
73 | visor.set_param("public_v", public_affine.get_v())?;
74 | for (i, param_bit) in unpack(randomness_value).into_iter().enumerate() {
75 | visor.set_param(&format!("vc_randomness_{}", i), param_bit)?;
76 | }
77 |
78 | let proof = visor.prove()?;
79 |
80 | assert_eq!(proof.public.len(), 2);
81 | for (name, value) in &proof.public {
82 | println!("Public {} = {:?}", name, value);
83 | }
84 |
85 | assert!(visor.verify(&proof));
86 |
87 | Ok(())
88 | }
89 |
--------------------------------------------------------------------------------
/src/bin/services.rs:
--------------------------------------------------------------------------------
1 | use async_executor::Executor;
2 | use easy_parallel::Parallel;
3 | use std::sync::Arc;
4 |
5 | use sapvi::Result;
6 |
7 | use sapvi::service::{gateway, reqrep};
8 |
9 | async fn start(executor: Arc>) -> Result<()> {
10 | executor.clone().spawn(reqrep::ReqRepAPI::start()).detach();
11 |
12 | gateway::GatewayService::start(executor.clone()).await;
13 | Ok(())
14 | }
15 |
16 | fn main() -> Result<()> {
17 | let ex = Arc::new(Executor::new());
18 | let (signal, shutdown) = async_channel::unbounded::<()>();
19 | let ex2 = ex.clone();
20 |
21 | let (_, result) = Parallel::new()
22 | // Run four executor threads.
23 | .each(0..3, |_| smol::future::block_on(ex.run(shutdown.recv())))
24 | // Run the main future on the current thread.
25 | .finish(|| {
26 | smol::future::block_on(async move {
27 | start(ex2).await?;
28 | drop(signal);
29 | Ok::<(), sapvi::Error>(())
30 | })
31 | });
32 |
33 | result
34 | }
35 |
--------------------------------------------------------------------------------
/src/bls_extensions.rs:
--------------------------------------------------------------------------------
1 | use bls12_381 as bls;
2 | use std::io;
3 |
4 | use crate::error::{Error, Result};
5 | use crate::serial::{Decodable, Encodable, ReadExt, WriteExt};
6 |
7 | macro_rules! from_slice {
8 | ($data:expr, $len:literal) => {{
9 | let mut array = [0; $len];
10 | // panics if not enough data
11 | let bytes = &$data[..array.len()];
12 | array.copy_from_slice(bytes);
13 | array
14 | }};
15 | }
16 |
17 | pub trait BlsStringConversion {
18 | fn to_string(&self) -> String;
19 | fn from_string(object: &str) -> Self;
20 | }
21 |
22 | impl BlsStringConversion for bls::Scalar {
23 | fn to_string(&self) -> String {
24 | let mut bytes = self.to_bytes();
25 | bytes.reverse();
26 | hex::encode(bytes)
27 | }
28 | fn from_string(object: &str) -> Self {
29 | let mut bytes = from_slice!(&hex::decode(object).unwrap(), 32);
30 | bytes.reverse();
31 | bls::Scalar::from_bytes(&bytes).unwrap()
32 | }
33 | }
34 |
35 | macro_rules! serialization_bls {
36 | ($type:ty, $to_x:ident, $from_x:ident, $size:literal) => {
37 | impl Encodable for $type {
38 | fn encode(&self, mut s: S) -> Result {
39 | let data = self.$to_x();
40 | assert_eq!(data.len(), $size);
41 | s.write_slice(&data)?;
42 | Ok(data.len())
43 | }
44 | }
45 |
46 | impl Decodable for $type {
47 | fn decode(mut d: D) -> Result {
48 | let mut slice = [0u8; $size];
49 | d.read_slice(&mut slice)?;
50 | let result = Self::$from_x(&slice);
51 | if bool::from(result.is_none()) {
52 | return Err(Error::ParseFailed("$t conversion from slice failed"));
53 | }
54 | Ok(result.unwrap())
55 | }
56 | }
57 | };
58 | }
59 |
60 | serialization_bls!(bls::Scalar, to_bytes, from_bytes, 32);
61 |
62 | macro_rules! make_serialize_deserialize_test {
63 | ($name:ident, $type:ty, $default_func:ident) => {
64 | #[test]
65 | fn $name() {
66 | let point = <$type>::$default_func();
67 |
68 | let mut data: Vec = vec![];
69 | let result = point.encode(&mut data);
70 | assert!(result.is_ok());
71 |
72 | let point2 = <$type>::decode(&data[..]);
73 | assert!(point2.is_ok());
74 | let point2 = point2.unwrap();
75 |
76 | assert_eq!(point, point2);
77 | }
78 | };
79 | }
80 |
81 | make_serialize_deserialize_test!(serial_test_scalar, bls::Scalar, zero);
82 |
--------------------------------------------------------------------------------
/src/circuit/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod mint_contract;
2 | pub mod spend_contract;
3 |
--------------------------------------------------------------------------------
/src/crypto/coin.rs:
--------------------------------------------------------------------------------
1 | use bitvec::{order::Lsb0, view::AsBits};
2 | use ff::PrimeField;
3 | use group::Curve;
4 | use lazy_static::lazy_static;
5 | use std::io;
6 |
7 | use super::merkle::Hashable;
8 |
9 | pub const SAPLING_COMMITMENT_TREE_DEPTH: usize = 4;
10 |
11 | /// Compute a parent node in the Sapling commitment tree given its two children.
12 | pub fn merkle_hash(depth: usize, lhs: &[u8; 32], rhs: &[u8; 32]) -> bls12_381::Scalar {
13 | // This thing is nasty lol
14 | let lhs = {
15 | let mut tmp = [false; 256];
16 | for (a, b) in tmp.iter_mut().zip(lhs.as_bits::()) {
17 | *a = *b;
18 | }
19 | tmp
20 | };
21 |
22 | let rhs = {
23 | let mut tmp = [false; 256];
24 | for (a, b) in tmp.iter_mut().zip(rhs.as_bits::()) {
25 | *a = *b;
26 | }
27 | tmp
28 | };
29 |
30 | jubjub::ExtendedPoint::from(zcash_primitives::pedersen_hash::pedersen_hash(
31 | zcash_primitives::pedersen_hash::Personalization::MerkleTree(depth),
32 | lhs.iter()
33 | .copied()
34 | .take(bls12_381::Scalar::NUM_BITS as usize)
35 | .chain(
36 | rhs.iter()
37 | .copied()
38 | .take(bls12_381::Scalar::NUM_BITS as usize),
39 | ),
40 | ))
41 | .to_affine()
42 | .get_u()
43 | }
44 |
45 | /// A node within the Sapling commitment tree.
46 | #[derive(Clone, Copy, Debug, PartialEq)]
47 | pub struct Coin {
48 | repr: [u8; 32],
49 | }
50 |
51 | impl Coin {
52 | pub fn new(repr: [u8; 32]) -> Self {
53 | Coin { repr }
54 | }
55 | }
56 |
57 | impl Hashable for Coin {
58 | fn read(mut reader: R) -> io::Result {
59 | let mut repr = [0u8; 32];
60 | reader.read_exact(&mut repr)?;
61 | Ok(Coin::new(repr))
62 | }
63 |
64 | fn write(&self, mut writer: W) -> io::Result<()> {
65 | writer.write_all(self.repr.as_ref())
66 | }
67 |
68 | fn combine(depth: usize, lhs: &Self, rhs: &Self) -> Self {
69 | Coin {
70 | repr: merkle_hash(depth, &lhs.repr, &rhs.repr).to_repr(),
71 | }
72 | }
73 |
74 | fn blank() -> Self {
75 | // The smallest u-coordinate that is not on the curve
76 | // is one.
77 | let uncommitted_note = bls12_381::Scalar::one();
78 | Coin {
79 | repr: uncommitted_note.to_repr(),
80 | }
81 | }
82 |
83 | fn empty_root(depth: usize) -> Self {
84 | EMPTY_ROOTS[depth]
85 | }
86 | }
87 |
88 | impl From for bls12_381::Scalar {
89 | fn from(coin: Coin) -> Self {
90 | bls12_381::Scalar::from_repr(coin.repr).expect("Tree nodes should be in the prime field")
91 | }
92 | }
93 |
94 | lazy_static! {
95 | static ref EMPTY_ROOTS: Vec = {
96 | let mut v = vec![Coin::blank()];
97 | for d in 0..SAPLING_COMMITMENT_TREE_DEPTH {
98 | let next = Coin::combine(d, &v[d], &v[d]);
99 | v.push(next);
100 | }
101 | v
102 | };
103 | }
104 |
--------------------------------------------------------------------------------
/src/crypto/diffie_hellman.rs:
--------------------------------------------------------------------------------
1 | use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
2 | use group::{cofactor::CofactorGroup, GroupEncoding};
3 |
4 | pub const KDF_SAPLING_PERSONALIZATION: &[u8; 16] = b"DarkFiSaplingKDF";
5 |
6 | /// Functions used for encrypting the note in transaction outputs.
7 |
8 | /// Sapling key agreement for note encryption.
9 | ///
10 | /// Implements section 5.4.4.3 of the Zcash Protocol Specification.
11 | pub fn sapling_ka_agree(esk: &jubjub::Fr, pk_d: &jubjub::ExtendedPoint) -> jubjub::SubgroupPoint {
12 | // [8 esk] pk_d
13 | // ::clear_cofactor is implemented using
14 | // ExtendedPoint::mul_by_cofactor in the jubjub crate.
15 |
16 | // ExtendedPoint::multiply currently just implements double-and-add,
17 | // so using wNAF is a concrete speed improvement (as it operates over a window of bits
18 | // instead of individual bits).
19 | // We want that to be fast because it's in the hot path for trial decryption of notes on chain.
20 | let mut wnaf = group::Wnaf::new();
21 | wnaf.scalar(esk).base(*pk_d).clear_cofactor()
22 | }
23 |
24 | /// Sapling KDF for note encryption.
25 | ///
26 | /// Implements section 5.4.4.4 of the Zcash Protocol Specification.
27 | pub fn kdf_sapling(dhsecret: jubjub::SubgroupPoint, epk: &jubjub::ExtendedPoint) -> Blake2bHash {
28 | Blake2bParams::new()
29 | .hash_length(32)
30 | .personal(KDF_SAPLING_PERSONALIZATION)
31 | .to_state()
32 | .update(&dhsecret.to_bytes())
33 | .update(&epk.to_bytes())
34 | .finalize()
35 | }
36 |
--------------------------------------------------------------------------------
/src/crypto/fr_serial.rs:
--------------------------------------------------------------------------------
1 | use group::GroupEncoding;
2 | use std::io;
3 |
4 | use crate::error::{Error, Result};
5 | use crate::serial::{Decodable, Encodable, ReadExt, WriteExt};
6 |
7 | impl Encodable for jubjub::Fr {
8 | fn encode(&self, mut s: S) -> Result {
9 | s.write_slice(&self.to_bytes()[..])?;
10 | Ok(32)
11 | }
12 | }
13 |
14 | impl Decodable for jubjub::Fr {
15 | fn decode(mut d: D) -> Result {
16 | let mut bytes = [0u8; 32];
17 | d.read_slice(&mut bytes)?;
18 | let result = Self::from_bytes(&bytes);
19 | if result.is_some().into() {
20 | Ok(result.unwrap())
21 | } else {
22 | Err(Error::BadOperationType)
23 | }
24 | }
25 | }
26 |
27 | impl Encodable for jubjub::SubgroupPoint {
28 | fn encode(&self, mut s: S) -> Result {
29 | s.write_slice(&self.to_bytes()[..])?;
30 | Ok(32)
31 | }
32 | }
33 |
34 | impl Decodable for jubjub::SubgroupPoint {
35 | fn decode(mut d: D) -> Result {
36 | let mut bytes = [0u8; 32];
37 | d.read_slice(&mut bytes)?;
38 | let result = Self::from_bytes(&bytes);
39 | if result.is_some().into() {
40 | Ok(result.unwrap())
41 | } else {
42 | Err(Error::BadOperationType)
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/crypto/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod coin;
2 | pub mod diffie_hellman;
3 | pub mod fr_serial;
4 | pub mod merkle;
5 | pub mod mint_proof;
6 | pub mod note;
7 | pub mod schnorr;
8 | pub mod spend_proof;
9 | pub mod util;
10 |
11 | use bellman::groth16;
12 | use bls12_381::Bls12;
13 |
14 | use crate::error::Result;
15 | pub use mint_proof::{create_mint_proof, setup_mint_prover, verify_mint_proof, MintRevealedValues};
16 | pub use spend_proof::{
17 | create_spend_proof, setup_spend_prover, verify_spend_proof, SpendRevealedValues,
18 | };
19 |
20 | pub fn save_params(filename: &str, params: &groth16::Parameters) -> Result<()> {
21 | let buffer = std::fs::File::create(filename)?;
22 | params.write(buffer)?;
23 | Ok(())
24 | }
25 |
26 | pub fn load_params(
27 | filename: &str,
28 | ) -> Result<(
29 | groth16::Parameters,
30 | groth16::PreparedVerifyingKey,
31 | )> {
32 | let buffer = std::fs::File::open(filename)?;
33 | let params = groth16::Parameters::::read(buffer, false)?;
34 | let pvk = groth16::prepare_verifying_key(¶ms.vk);
35 | Ok((params, pvk))
36 | }
37 |
--------------------------------------------------------------------------------
/src/crypto/schnorr.rs:
--------------------------------------------------------------------------------
1 | use ff::Field;
2 | use group::{Group, GroupEncoding};
3 | use rand::rngs::OsRng;
4 | use std::io;
5 |
6 | use super::util::hash_to_scalar;
7 | use crate::error::{Error, Result};
8 | use crate::serial::{Decodable, Encodable};
9 |
10 | pub struct SecretKey(pub jubjub::Fr);
11 |
12 | impl SecretKey {
13 | pub fn random() -> Self {
14 | Self(jubjub::Fr::random(&mut OsRng))
15 | }
16 |
17 | pub fn sign(&self, message: &[u8]) -> Signature {
18 | let mask = jubjub::Fr::random(&mut OsRng);
19 | let commit = zcash_primitives::constants::SPENDING_KEY_GENERATOR * mask;
20 |
21 | let challenge = hash_to_scalar(b"DarkFi_Schnorr", &commit.to_bytes(), message);
22 |
23 | let response = mask + challenge * self.0;
24 |
25 | Signature { commit, response }
26 | }
27 |
28 | pub fn public_key(&self) -> PublicKey {
29 | let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * self.0;
30 | PublicKey(public)
31 | }
32 | }
33 |
34 | pub struct PublicKey(pub jubjub::SubgroupPoint);
35 |
36 | pub struct Signature {
37 | commit: jubjub::SubgroupPoint,
38 | response: jubjub::Fr,
39 | }
40 |
41 | impl Encodable for Signature {
42 | fn encode(&self, mut s: S) -> Result {
43 | let mut len = 0;
44 | len += self.commit.encode(&mut s)?;
45 | len += self.response.encode(s)?;
46 | Ok(len)
47 | }
48 | }
49 |
50 | impl Decodable for Signature {
51 | fn decode(mut d: D) -> Result {
52 | Ok(Self {
53 | commit: Decodable::decode(&mut d)?,
54 | response: Decodable::decode(d)?,
55 | })
56 | }
57 | }
58 |
59 | impl PublicKey {
60 | pub fn verify(&self, message: &[u8], signature: &Signature) -> bool {
61 | let challenge = hash_to_scalar(b"DarkFi_Schnorr", &signature.commit.to_bytes(), message);
62 | zcash_primitives::constants::SPENDING_KEY_GENERATOR * signature.response
63 | - self.0 * challenge
64 | == signature.commit
65 | }
66 | }
67 |
68 | #[test]
69 | fn test_schnorr() {
70 | let secret = SecretKey::random();
71 | let message = b"Foo bar";
72 | let signature = secret.sign(&message[..]);
73 | let public = secret.public_key();
74 | assert!(public.verify(&message[..], &signature));
75 | }
76 |
--------------------------------------------------------------------------------
/src/crypto/util.rs:
--------------------------------------------------------------------------------
1 | use blake2b_simd::Params;
2 |
3 | pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> jubjub::Fr {
4 | let mut hasher = Params::new().hash_length(64).personal(persona).to_state();
5 | hasher.update(a);
6 | hasher.update(b);
7 | let ret = hasher.finalize();
8 | jubjub::Fr::from_bytes_wide(ret.as_array())
9 | }
10 |
--------------------------------------------------------------------------------
/src/gfx/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod camera;
2 | pub mod model;
3 | pub mod texture;
4 |
--------------------------------------------------------------------------------
/src/gui/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod texture;
2 |
--------------------------------------------------------------------------------
/src/gui/texture.rs:
--------------------------------------------------------------------------------
1 | use anyhow::*;
2 | use image::GenericImageView;
3 |
4 | pub struct Texture {
5 | pub texture: wgpu::Texture,
6 | pub view: wgpu::TextureView,
7 | pub sampler: wgpu::Sampler,
8 | }
9 |
10 | impl Texture {
11 | pub fn from_bytes(
12 | device: &wgpu::Device,
13 | queue: &wgpu::Queue,
14 | bytes: &[u8],
15 | label: &str,
16 | ) -> Result {
17 | let img = image::load_from_memory(bytes)?;
18 | Self::from_image(device, queue, &img, Some(label))
19 | }
20 |
21 | pub fn from_image(
22 | device: &wgpu::Device,
23 | queue: &wgpu::Queue,
24 | img: &image::DynamicImage,
25 | label: Option<&str>,
26 | ) -> Result {
27 | let rgba = img.as_rgba8().unwrap();
28 | let dimensions = img.dimensions();
29 |
30 | let size = wgpu::Extent3d {
31 | width: dimensions.0,
32 | height: dimensions.1,
33 | depth: 1,
34 | };
35 | let texture = device.create_texture(&wgpu::TextureDescriptor {
36 | label,
37 | size,
38 | mip_level_count: 1,
39 | sample_count: 1,
40 | dimension: wgpu::TextureDimension::D2,
41 | format: wgpu::TextureFormat::Rgba8UnormSrgb,
42 | usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST,
43 | });
44 |
45 | queue.write_texture(
46 | wgpu::TextureCopyView {
47 | texture: &texture,
48 | mip_level: 0,
49 | origin: wgpu::Origin3d::ZERO,
50 | },
51 | rgba,
52 | wgpu::TextureDataLayout {
53 | offset: 0,
54 | bytes_per_row: 4 * dimensions.0,
55 | rows_per_image: dimensions.1,
56 | },
57 | size,
58 | );
59 |
60 | let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
61 | let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
62 | address_mode_u: wgpu::AddressMode::ClampToEdge,
63 | address_mode_v: wgpu::AddressMode::ClampToEdge,
64 | address_mode_w: wgpu::AddressMode::ClampToEdge,
65 | mag_filter: wgpu::FilterMode::Linear,
66 | min_filter: wgpu::FilterMode::Nearest,
67 | mipmap_filter: wgpu::FilterMode::Nearest,
68 | ..Default::default()
69 | });
70 |
71 | Ok(Self {
72 | texture,
73 | view,
74 | sampler,
75 | })
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/lib.rs:
--------------------------------------------------------------------------------
1 | #[macro_use] extern crate clap;
2 | use bellman::groth16;
3 | use bls12_381::{Bls12, Scalar};
4 | use std::collections::{HashMap, HashSet};
5 |
6 | pub mod async_serial;
7 | pub mod bls_extensions;
8 | pub mod circuit;
9 | pub mod crypto;
10 | pub mod endian;
11 | pub mod error;
12 | pub mod gfx;
13 | pub mod gui;
14 | pub mod net;
15 | pub mod rpc;
16 | pub mod serial;
17 | pub mod service;
18 | pub mod system;
19 | pub mod tx;
20 | pub mod vm;
21 | pub mod vm_serial;
22 |
23 | pub use crate::bls_extensions::BlsStringConversion;
24 | pub use crate::error::{Error, Result};
25 | pub use crate::net::p2p::P2p;
26 | pub use crate::serial::{Decodable, Encodable};
27 | pub use crate::vm::{
28 | AllocType, ConstraintInstruction, CryptoOperation, VariableIndex, VariableRef, ZKVMCircuit,
29 | ZKVirtualMachine,
30 | };
31 |
32 | pub type Bytes = Vec;
33 |
34 | pub struct ZKContract {
35 | pub name: String,
36 | pub vm: ZKVirtualMachine,
37 | params_map: HashMap,
38 | pub params: HashMap,
39 | public_map: bimap::BiMap,
40 | }
41 |
42 | pub struct ZKProof {
43 | pub public: HashMap,
44 | pub proof: groth16::Proof,
45 | }
46 |
47 | impl ZKContract {
48 | // Just have a load() and save()
49 | // Load the contract, do the setup, save it...
50 |
51 | pub fn setup(&mut self, filename: &str) -> Result<()> {
52 | self.vm.setup()?;
53 |
54 | let buffer = std::fs::File::create(filename)?;
55 | self.vm.params.as_ref().unwrap().write(buffer)?;
56 | Ok(())
57 | }
58 |
59 | pub fn load_setup(&mut self, filename: &str) -> Result<()> {
60 | let buffer = std::fs::File::open(filename)?;
61 | let setup = groth16::Parameters::::read(buffer, false)?;
62 | let vk = groth16::prepare_verifying_key(&setup.vk);
63 | self.vm.params = Some(setup);
64 | self.vm.verifying_key = Some(vk);
65 | Ok(())
66 | }
67 |
68 | pub fn param_names(&self) -> Vec {
69 | self.params_map.keys().cloned().collect()
70 | }
71 | pub fn set_param(&mut self, name: &str, value: Scalar) -> Result<()> {
72 | match self.params_map.get(name) {
73 | Some(index) => {
74 | self.params.insert(*index, value);
75 | Ok(())
76 | }
77 | None => Err(Error::InvalidParamName),
78 | }
79 | }
80 |
81 | pub fn prove(&mut self) -> Result {
82 | // Error if params not all set
83 | let user_params: HashSet<_> = self.params.keys().collect();
84 | let req_params: HashSet<_> = self.params_map.values().collect();
85 | if user_params != req_params {
86 | return Err(Error::MissingParams);
87 | }
88 |
89 | // execute
90 | let params = std::mem::replace(&mut self.params, HashMap::default());
91 | self.vm.initialize(¶ms.into_iter().collect())?;
92 |
93 | // prove
94 | let proof = self.vm.prove();
95 |
96 | let mut public = HashMap::new();
97 | for (index, value) in self.vm.public() {
98 | match self.public_map.get_by_right(&index) {
99 | Some(name) => {
100 | public.insert(name.clone(), value);
101 | }
102 | None => return Err(Error::BadContract),
103 | }
104 | }
105 |
106 | // return proof and public values (Hashmap string -> scalars)
107 | Ok(ZKProof { public, proof })
108 | }
109 | pub fn verify(&self, proof: &ZKProof) -> bool {
110 | let mut public = vec![];
111 | for (name, value) in &proof.public {
112 | match self.public_map.get_by_left(name) {
113 | Some(index) => {
114 | public.push((index, value.clone()));
115 | }
116 | None => return false,
117 | }
118 | }
119 | public.sort_by(|a, b| a.0.partial_cmp(b.0).unwrap());
120 | let (_, public): (Vec, Vec) = public.into_iter().unzip();
121 |
122 | // Takes proof and public values
123 | self.vm.verify(&proof.proof, &public)
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/src/net/connector.rs:
--------------------------------------------------------------------------------
1 | use futures::FutureExt;
2 | use smol::Async;
3 | use std::net::{SocketAddr, TcpStream};
4 |
5 | use crate::net::error::{NetError, NetResult};
6 | use crate::net::utility::sleep;
7 | use crate::net::{Channel, ChannelPtr, SettingsPtr};
8 |
9 | /// Create outbound socket connections.
10 | pub struct Connector {
11 | settings: SettingsPtr,
12 | }
13 |
14 | impl Connector {
15 | /// Create a new connector with default network settings.
16 | pub fn new(settings: SettingsPtr) -> Self {
17 | Self { settings }
18 | }
19 |
20 | /// Establish an outbound connection.
21 | pub async fn connect(&self, hostaddr: SocketAddr) -> NetResult {
22 | futures::select! {
23 | stream_result = Async::::connect(hostaddr).fuse() => {
24 | match stream_result {
25 | Ok(stream) => Ok(Channel::new(stream, hostaddr).await),
26 | Err(_) => Err(NetError::ConnectFailed)
27 | }
28 | }
29 | _ = sleep(self.settings.connect_timeout_seconds).fuse() => Err(NetError::ConnectTimeout)
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/net/error.rs:
--------------------------------------------------------------------------------
1 | use std::fmt;
2 |
3 | /// Returns the relevant network error if a program fails.
4 | pub type NetResult = std::result::Result;
5 |
6 | /// An enum representing the main network errors.
7 | #[derive(Debug, Copy, Clone)]
8 | pub enum NetError {
9 | OperationFailed,
10 | ConnectFailed,
11 | ConnectTimeout,
12 | ChannelStopped,
13 | ChannelTimeout,
14 | ServiceStopped,
15 | }
16 |
17 | impl std::error::Error for NetError {}
18 |
19 | impl fmt::Display for NetError {
20 | fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
21 | match *self {
22 | NetError::OperationFailed => f.write_str("Operation failed"),
23 | NetError::ConnectFailed => f.write_str("Connection failed"),
24 | NetError::ConnectTimeout => f.write_str("Connection timed out"),
25 | NetError::ChannelStopped => f.write_str("Channel stopped"),
26 | NetError::ChannelTimeout => f.write_str("Channel timed out"),
27 | NetError::ServiceStopped => f.write_str("Service stopped"),
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/net/hosts.rs:
--------------------------------------------------------------------------------
1 | use async_std::sync::Mutex;
2 | use rand::seq::SliceRandom;
3 | use std::collections::HashSet;
4 | use std::net::SocketAddr;
5 | use std::sync::Arc;
6 |
7 | /// Pointer to hosts class.
8 | pub type HostsPtr = Arc;
9 |
10 | /// Manages a store of network addresses.
11 | pub struct Hosts {
12 | addrs: Mutex>,
13 | }
14 |
15 | impl Hosts {
16 | /// Create a new host list.
17 | pub fn new() -> Arc {
18 | Arc::new(Self {
19 | addrs: Mutex::new(Vec::new()),
20 | })
21 | }
22 |
23 | /// Checks if a host address is in the host list.
24 | async fn contains(&self, addrs: &Vec) -> bool {
25 | let a_set: HashSet<_> = addrs.iter().copied().collect();
26 | self.addrs
27 | .lock()
28 | .await
29 | .iter()
30 | .any(|item| a_set.contains(item))
31 | }
32 |
33 | /// Add a new host to the host list.
34 | pub async fn store(&self, addrs: Vec) {
35 | if !self.contains(&addrs).await {
36 | self.addrs.lock().await.extend(addrs)
37 | }
38 | }
39 |
40 | /// Return a single host address.
41 | pub async fn load_single(&self) -> Option {
42 | self.addrs
43 | .lock()
44 | .await
45 | .choose(&mut rand::thread_rng())
46 | .cloned()
47 | }
48 |
49 | /// Return the list of hosts.
50 | pub async fn load_all(&self) -> Vec {
51 | self.addrs.lock().await.clone()
52 | }
53 |
54 | /// Check if the host list is empty.
55 | pub async fn is_empty(&self) -> bool {
56 | self.addrs.lock().await.is_empty()
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/net/protocols/mod.rs:
--------------------------------------------------------------------------------
1 | /// Protocol for address and get-address messages. Implements how nodes exchange
2 | /// connection information about other nodes on the network. Address and
3 | /// get-address messages are exchanged continually alongside ping-pong messages
4 | /// as part of a network connection.
5 | ///
6 | /// Protocol starts by creating a subscription to address and get address
7 | /// messages. Then the protocol sends out a get address message and waits for an
8 | /// address message. Upon receiving an address messages, nodes add the
9 | /// address information to their local store.
10 | pub mod protocol_address;
11 |
12 | /// Manages the tasks for the network protocol. Used by other connection
13 | /// protocols to handle asynchronous task execution across the network. Runs all
14 | /// tasks that are handed to it on an executor that has stopping functionality.
15 | pub mod protocol_jobs_manager;
16 |
17 | /// Protocol for ping-pong keep-alive messages. Implements ping message and pong
18 | /// response. These messages are like the network heartbeat- they are sent
19 | /// continually between nodes, to ensure each node is still alive and active.
20 | /// Ping-pong messages ensure that the network doesn't
21 | /// time out.
22 | ///
23 | /// Protocol starts by creating a subscription to ping and pong messages. Then
24 | /// it starts a loop with a timer and runs ping-pong in the task manager. It
25 | /// sends out a ping and waits for pong reply. Then waits for ping and replies
26 | /// with a pong.
27 | pub mod protocol_ping;
28 |
29 | /// Seed server protocol. Seed server is used when connecting to the network for
30 | /// the first time. Returns a list of IP addresses that nodes can connect to.
31 | ///
32 | /// To start the seed protocol, we create a subscription to the address message,
33 | /// and send our address to the seed server. Then we send a get-address message
34 | /// and receive an address message. We add these addresses to our internal
35 | /// store.
36 | pub mod protocol_seed;
37 |
38 | /// Protocol for version information handshake between nodes at the start of a
39 | /// connection. Implements the process for exchanging version information
40 | /// between nodes. This is the first step when establishing a p2p connection.
41 | ///
42 | /// The version protocol starts of by instantiating the protocol and creating a
43 | /// new subscription to version and version acknowledgement messages. Then we
44 | /// run the protocol. Nodes send a version message and wait for a version
45 | /// acknowledgement, while asynchronously waiting for version info from the
46 | /// other node and sending the version acknowledgement.
47 | pub mod protocol_version;
48 |
49 | pub use protocol_address::ProtocolAddress;
50 | pub use protocol_jobs_manager::{ProtocolJobsManager, ProtocolJobsManagerPtr};
51 | pub use protocol_ping::ProtocolPing;
52 | pub use protocol_seed::ProtocolSeed;
53 | pub use protocol_version::ProtocolVersion;
54 |
--------------------------------------------------------------------------------
/src/net/protocols/protocol_jobs_manager.rs:
--------------------------------------------------------------------------------
1 | use async_std::sync::Mutex;
2 | use futures::Future;
3 | use log::*;
4 | use smol::Task;
5 | use std::sync::Arc;
6 |
7 | use crate::net::error::NetResult;
8 | use crate::net::ChannelPtr;
9 | use crate::system::ExecutorPtr;
10 |
11 | /// Pointer to protocol jobs manager.
12 | pub type ProtocolJobsManagerPtr = Arc;
13 |
14 | /// Manages the tasks for the network protocol. Used by other connection
15 | /// protocols to handle asynchronous task execution across the network. Runs all
16 | /// tasks that are handed to it on an executor that has stopping functionality.
17 | pub struct ProtocolJobsManager {
18 | name: &'static str,
19 | channel: ChannelPtr,
20 | tasks: Mutex>>>,
21 | }
22 |
23 | impl ProtocolJobsManager {
24 | /// Create a new protocol jobs manager.
25 | pub fn new(name: &'static str, channel: ChannelPtr) -> Arc {
26 | Arc::new(Self {
27 | name,
28 | channel,
29 | tasks: Mutex::new(Vec::new()),
30 | })
31 | }
32 |
33 | /// Runs the task on an executor. Prepares to stop all tasks when the
34 | /// channel is closed.
35 | pub fn start(self: Arc, executor: ExecutorPtr<'_>) {
36 | executor.spawn(self.handle_stop()).detach()
37 | }
38 |
39 | /// Spawns a new task and adds it to the internal queue.
40 | pub async fn spawn<'a, F>(&self, future: F, executor: ExecutorPtr<'a>)
41 | where
42 | F: Future