├── .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> + Send + 'a, 43 | { 44 | self.tasks.lock().await.push(executor.spawn(future)) 45 | } 46 | 47 | /// Waits for a stop signal, then closes all tasks. Insures that all tasks 48 | /// are stopped when a channel closes. Called in start(). 49 | async fn handle_stop(self: Arc) { 50 | let stop_sub = self.channel.clone().subscribe_stop().await; 51 | 52 | // Wait for the stop signal 53 | // Not interested in the exact error 54 | let _ = stop_sub.receive().await; 55 | 56 | self.close_all_tasks().await 57 | } 58 | 59 | /// Closes all open tasks. Takes all the tasks from the internal queue and 60 | /// closes them. 61 | async fn close_all_tasks(self: Arc) { 62 | debug!(target: "net", 63 | "ProtocolJobsManager::close_all_tasks() [START, name={}, addr={}]", 64 | self.name, 65 | self.channel.address() 66 | ); 67 | // Take all the tasks from our internal queue... 68 | let tasks = std::mem::take(&mut *self.tasks.lock().await); 69 | for task in tasks { 70 | // ... and cancel them 71 | let _ = task.cancel().await; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/net/protocols/protocol_seed.rs: -------------------------------------------------------------------------------- 1 | use log::*; 2 | use smol::Executor; 3 | use std::sync::Arc; 4 | 5 | use crate::net::error::NetResult; 6 | use crate::net::messages; 7 | use crate::net::{ChannelPtr, HostsPtr, SettingsPtr}; 8 | 9 | /// Implements the seed protocol. 10 | pub struct ProtocolSeed { 11 | channel: ChannelPtr, 12 | hosts: HostsPtr, 13 | settings: SettingsPtr, 14 | } 15 | 16 | impl ProtocolSeed { 17 | /// Create a new seed protocol. 18 | pub fn new(channel: ChannelPtr, hosts: HostsPtr, settings: SettingsPtr) -> Arc { 19 | Arc::new(Self { 20 | channel, 21 | hosts, 22 | settings, 23 | }) 24 | } 25 | 26 | /// Starts the seed protocol. Creates a subscription to the address message, 27 | /// then sends our address to the seed server. Sends a get-address 28 | /// message and receives an address message. 29 | pub async fn start(self: Arc, _executor: Arc>) -> NetResult<()> { 30 | debug!(target: "net", "ProtocolSeed::start() [START]"); 31 | // Create a subscription to address message. 32 | let addr_sub = self 33 | .channel 34 | .clone() 35 | .subscribe_msg::() 36 | .await 37 | .expect("Missing addrs dispatcher!"); 38 | 39 | // Send own address to the seed server. 40 | self.send_self_address().await?; 41 | 42 | // Send get address message. 43 | let get_addr = messages::GetAddrsMessage {}; 44 | self.channel.clone().send(get_addr).await?; 45 | 46 | // Receive addresses. 47 | let addrs_msg = addr_sub.receive().await?; 48 | debug!(target: "net", "ProtocolSeed::start() received {} addrs", addrs_msg.addrs.len()); 49 | self.hosts.store(addrs_msg.addrs.clone()).await; 50 | 51 | debug!(target: "net", "ProtocolSeed::start() [END]"); 52 | Ok(()) 53 | } 54 | 55 | /// Sends own external address over a channel. Imports own external address 56 | /// from settings, then adds that address to an address message and 57 | /// sends it out over the channel. 58 | pub async fn send_self_address(&self) -> NetResult<()> { 59 | match self.settings.external_addr { 60 | Some(addr) => { 61 | debug!(target: "net", "ProtocolSeed::send_own_address() addr={}", addr); 62 | let addr = messages::AddrsMessage { addrs: vec![addr] }; 63 | self.channel.clone().send(addr).await?; 64 | } 65 | None => { 66 | // Do nothing if external address is not configured 67 | } 68 | } 69 | Ok(()) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/net/protocols/protocol_version.rs: -------------------------------------------------------------------------------- 1 | use futures::FutureExt; 2 | use log::*; 3 | use smol::Executor; 4 | use std::sync::Arc; 5 | 6 | use crate::net::error::{NetError, NetResult}; 7 | use crate::net::message_subscriber::MessageSubscription; 8 | use crate::net::messages; 9 | use crate::net::utility::sleep; 10 | use crate::net::{ChannelPtr, SettingsPtr}; 11 | 12 | /// Implements the protocol version handshake sent out by nodes at the beginning 13 | /// of a connection. 14 | pub struct ProtocolVersion { 15 | channel: ChannelPtr, 16 | version_sub: MessageSubscription, 17 | verack_sub: MessageSubscription, 18 | settings: SettingsPtr, 19 | } 20 | 21 | impl ProtocolVersion { 22 | /// Create a new version protocol. Makes a version and version 23 | /// acknowledgement subscription, then adds them to a version protocol 24 | /// instance. 25 | pub async fn new(channel: ChannelPtr, settings: SettingsPtr) -> Arc { 26 | // Creates a version subscription. 27 | let version_sub = channel 28 | .clone() 29 | .subscribe_msg::() 30 | .await 31 | .expect("Missing version dispatcher!"); 32 | 33 | // Creates a version acknowledgement subscription. 34 | let verack_sub = channel 35 | .clone() 36 | .subscribe_msg::() 37 | .await 38 | .expect("Missing verack dispatcher!"); 39 | 40 | Arc::new(Self { 41 | channel, 42 | version_sub, 43 | verack_sub, 44 | settings, 45 | }) 46 | } 47 | /// Start version information exchange. Start the timer. Send version info 48 | /// and wait for version acknowledgement. Wait for version info and send 49 | /// version acknowledgement. 50 | pub async fn run(self: Arc, executor: Arc>) -> NetResult<()> { 51 | debug!(target: "net", "ProtocolVersion::run() [START]"); 52 | // Start timer 53 | // Send version, wait for verack 54 | // Wait for version, send verack 55 | // Fin. 56 | let result = futures::select! { 57 | _ = self.clone().exchange_versions(executor).fuse() => Ok(()), 58 | _ = sleep(self.settings.channel_handshake_seconds).fuse() => Err(NetError::ChannelTimeout) 59 | }; 60 | debug!(target: "net", "ProtocolVersion::run() [END]"); 61 | result 62 | } 63 | /// Send and recieve version information. 64 | async fn exchange_versions(self: Arc, executor: Arc>) -> NetResult<()> { 65 | debug!(target: "net", "ProtocolVersion::exchange_versions() [START]"); 66 | 67 | let send = executor.spawn(self.clone().send_version()); 68 | let recv = executor.spawn(self.recv_version()); 69 | 70 | send.await.and(recv.await)?; 71 | debug!(target: "net", "ProtocolVersion::exchange_versions() [END]"); 72 | Ok(()) 73 | } 74 | /// Send version info and wait for version acknowledgement. 75 | async fn send_version(self: Arc) -> NetResult<()> { 76 | debug!(target: "net", "ProtocolVersion::send_version() [START]"); 77 | let version = messages::VersionMessage {}; 78 | self.channel.clone().send(version).await?; 79 | 80 | // Wait for version acknowledgement 81 | let _verack_msg = self.verack_sub.receive().await?; 82 | 83 | debug!(target: "net", "ProtocolVersion::send_version() [END]"); 84 | Ok(()) 85 | } 86 | /// Recieve version info, check the message is okay and send version 87 | /// acknowledgement. 88 | async fn recv_version(self: Arc) -> NetResult<()> { 89 | debug!(target: "net", "ProtocolVersion::recv_version() [START]"); 90 | // Rec 91 | let _version_msg = self.version_sub.receive().await?; 92 | 93 | // Check the message is OK 94 | 95 | // Send version acknowledgement 96 | let verack = messages::VerackMessage {}; 97 | self.channel.clone().send(verack).await?; 98 | 99 | debug!(target: "net", "ProtocolVersion::recv_version() [END]"); 100 | Ok(()) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/net/sessions/mod.rs: -------------------------------------------------------------------------------- 1 | /// Inbound connections session. Manages the creation of inbound sessions. Used 2 | /// to create an inbound session and start and stop the session. 3 | /// 4 | /// Class consists of 3 pointers: a weak pointer to the peer-to-peer class, an 5 | /// acceptor pointer, and a stoppable task pointer. Using a weak pointer to P2P 6 | /// allows us to avoid circular dependencies. 7 | pub mod inbound_session; 8 | 9 | /// Outbound connections session. Manages the creation of outbound sessions. 10 | /// Used to create an outbound session and stop and start the session. 11 | /// 12 | /// Class consists of a weak pointer to the peer-to-peer interface and a vector 13 | /// of outbound connection slots. Using a weak pointer to p2p allows us to avoid 14 | /// circular dependencies. The vector of slots is wrapped in a mutex lock. This 15 | /// is switched on everytime we instantiate a connection slot and insures that 16 | /// no other part of the program uses the slots at the same time. 17 | pub mod outbound_session; 18 | 19 | /// Seed connections session. Manages the creation of seed sessions. Used on 20 | /// first time connecting to the network. The seed node stores a list of other 21 | /// nodes in the network. 22 | pub mod seed_session; 23 | 24 | /// Defines methods that are used across sessions. Implements registering the 25 | /// channel and initializing the channel by performing a network handshake. 26 | pub mod session; 27 | 28 | pub use inbound_session::InboundSession; 29 | pub use outbound_session::OutboundSession; 30 | pub use seed_session::SeedSession; 31 | pub use session::Session; 32 | -------------------------------------------------------------------------------- /src/net/sessions/session.rs: -------------------------------------------------------------------------------- 1 | use async_trait::async_trait; 2 | use log::*; 3 | use smol::Executor; 4 | use std::sync::Arc; 5 | 6 | use crate::net::error::NetResult; 7 | use crate::net::p2p::P2pPtr; 8 | use crate::net::protocols::ProtocolVersion; 9 | use crate::net::ChannelPtr; 10 | 11 | /// Removes channel from the list of connected channels when a stop signal is 12 | /// received. 13 | async fn remove_sub_on_stop(p2p: P2pPtr, channel: ChannelPtr) { 14 | debug!(target: "net", "remove_sub_on_stop() [START]"); 15 | // Subscribe to stop events 16 | let stop_sub = channel.clone().subscribe_stop().await; 17 | // Wait for a stop event 18 | let _ = stop_sub.receive().await; 19 | debug!(target: "net", 20 | "remove_sub_on_stop(): received stop event. Removing channel {}", 21 | channel.address() 22 | ); 23 | // Remove channel from p2p 24 | p2p.remove(channel).await; 25 | debug!(target: "net", "remove_sub_on_stop() [END]"); 26 | } 27 | 28 | #[async_trait] 29 | /// Session trait. 30 | pub trait Session: Sync { 31 | /// Registers a new channel with the session. Performs a network handshake 32 | /// and starts the channel. 33 | async fn register_channel( 34 | self: Arc, 35 | channel: ChannelPtr, 36 | executor: Arc>, 37 | ) -> NetResult<()> { 38 | debug!(target: "net", "Session::register_channel() [START]"); 39 | 40 | let protocol_version = ProtocolVersion::new(channel.clone(), self.p2p().settings()).await; 41 | let handshake_task = 42 | self.perform_handshake_protocols(protocol_version, channel.clone(), executor.clone()); 43 | 44 | // start channel 45 | channel.start(executor); 46 | 47 | handshake_task.await?; 48 | 49 | debug!(target: "net", "Session::register_channel() [END]"); 50 | Ok(()) 51 | } 52 | 53 | /// Performs network handshake to initialize channel. Adds the channel to 54 | /// the list of connected channels, and prepares to remove the channel 55 | /// when a stop signal is received. 56 | async fn perform_handshake_protocols( 57 | &self, 58 | protocol_version: Arc, 59 | channel: ChannelPtr, 60 | executor: Arc>, 61 | ) -> NetResult<()> { 62 | // Perform handshake 63 | protocol_version.run(executor.clone()).await?; 64 | 65 | // Channel is now initialized 66 | 67 | // Add channel to p2p 68 | self.p2p().store(channel.clone()).await; 69 | 70 | // Subscribe to stop, so can remove from p2p 71 | executor 72 | .spawn(remove_sub_on_stop(self.p2p(), channel)) 73 | .detach(); 74 | 75 | // Channel is ready for use 76 | Ok(()) 77 | } 78 | 79 | /// Returns a pointer to the p2p network interface. 80 | fn p2p(&self) -> P2pPtr; 81 | } 82 | -------------------------------------------------------------------------------- /src/net/settings.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | use std::sync::Arc; 3 | 4 | /// Atomic pointer to network settings. 5 | pub type SettingsPtr = Arc; 6 | 7 | /// Defines the network settings. 8 | #[derive(Clone)] 9 | pub struct Settings { 10 | pub inbound: Option, 11 | pub outbound_connections: u32, 12 | 13 | pub seed_query_timeout_seconds: u32, 14 | pub connect_timeout_seconds: u32, 15 | pub channel_handshake_seconds: u32, 16 | pub channel_heartbeat_seconds: u32, 17 | 18 | pub external_addr: Option, 19 | pub peers: Vec, 20 | pub seeds: Vec, 21 | } 22 | 23 | impl Default for Settings { 24 | fn default() -> Self { 25 | Self { 26 | inbound: None, 27 | outbound_connections: 0, 28 | seed_query_timeout_seconds: 8, 29 | connect_timeout_seconds: 10, 30 | channel_handshake_seconds: 4, 31 | channel_heartbeat_seconds: 10, 32 | external_addr: None, 33 | peers: Vec::new(), 34 | seeds: Vec::new(), 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/net/utility.rs: -------------------------------------------------------------------------------- 1 | use smol::Timer; 2 | use std::time::Duration; 3 | 4 | /// Sleep for any number of seconds. 5 | pub async fn sleep(seconds: u32) { 6 | Timer::after(Duration::from_secs(seconds.into())).await; 7 | } 8 | -------------------------------------------------------------------------------- /src/old/basic_minimal.rs: -------------------------------------------------------------------------------- 1 | use bellman::{ 2 | gadgets::{ 3 | Assignment, 4 | }, 5 | groth16, Circuit, ConstraintSystem, SynthesisError, 6 | }; 7 | use bls12_381::Bls12; 8 | 9 | use ff::{Field}; 10 | 11 | use rand::rngs::OsRng; 12 | 13 | 14 | pub const CRH_IVK_PERSONALIZATION: &[u8; 8] = b"Zcashivk"; 15 | 16 | struct MyCircuit { 17 | aux: Vec>, 18 | } 19 | 20 | impl Circuit for MyCircuit { 21 | fn synthesize>( 22 | self, 23 | cs: &mut CS, 24 | ) -> Result<(), SynthesisError> { 25 | //let x = num::AllocatedNum::alloc(cs.namespace(|| "conditional anchor"), || { 26 | // Ok(*self.aux_values[0].get()?) 27 | //})?; 28 | 29 | //let x2 = x.mul(cs.namespace(|| "x2"), &x)?; 30 | //let x3 = x.mul(cs.namespace(|| "x2"), &x2)?; 31 | //x3.inputize(cs.namespace(|| "pubx2"))?; 32 | 33 | // ------------------ 34 | 35 | // x 36 | let x_var = cs.alloc(|| "num", || Ok(*self.aux[0].get()?))?; 37 | 38 | // x2 = x * x 39 | 40 | let x2_var = cs.alloc(|| "product num", || Ok(*self.aux[1].get()?))?; 41 | 42 | let x3_var = cs.alloc(|| "product num", || Ok(*self.aux[2].get()?))?; 43 | 44 | let input = cs.alloc_input(|| "input variable", || Ok(*self.aux[2].get()?))?; 45 | 46 | let coeff = bls12_381::Scalar::one(); 47 | let lc0 = bellman::LinearCombination::zero() + (coeff, x_var); 48 | let lc1 = bellman::LinearCombination::zero() + (coeff, x_var); 49 | let lc2 = bellman::LinearCombination::zero() + (coeff, x2_var); 50 | 51 | cs.enforce(|| "multiplication constraint", |_| lc0, |_| lc1, |_| lc2); 52 | 53 | // x3 = x2 * x 54 | 55 | let coeff = bls12_381::Scalar::one(); 56 | let lc0 = bellman::LinearCombination::zero() + (coeff, x2_var); 57 | let lc1 = bellman::LinearCombination::zero() + (coeff, x_var); 58 | let lc2 = bellman::LinearCombination::zero() + (coeff, x3_var); 59 | 60 | cs.enforce(|| "multiplication constraint", |_| lc0, |_| lc1, |_| lc2); 61 | 62 | // inputize values 63 | 64 | let coeff = bls12_381::Scalar::one(); 65 | let lc0 = bellman::LinearCombination::zero() + (coeff, input); 66 | let lc1 = bellman::LinearCombination::zero() + (coeff, CS::one()); 67 | let lc2 = bellman::LinearCombination::zero() + (coeff, x3_var); 68 | 69 | cs.enforce(|| "enforce input is correct", |_| lc0, |_| lc1, |_| lc2); 70 | 71 | Ok(()) 72 | } 73 | } 74 | 75 | fn main() { 76 | use std::time::Instant; 77 | 78 | let start = Instant::now(); 79 | // Create parameters for our circuit. In a production deployment these would 80 | // be generated securely using a multiparty computation. 81 | let params = { 82 | let c = MyCircuit { aux: vec![None] }; 83 | groth16::generate_random_parameters::(c, &mut OsRng).unwrap() 84 | }; 85 | println!("Setup: [{:?}]", start.elapsed()); 86 | 87 | // Prepare the verification key (for proof verification). 88 | let pvk = groth16::prepare_verifying_key(¶ms.vk); 89 | 90 | // Pick a preimage and compute its hash. 91 | let quantity = bls12_381::Scalar::from(3); 92 | 93 | // Create an instance of our circuit (with the preimage as a witness). 94 | let c = MyCircuit { 95 | aux: vec![ 96 | Some(quantity), 97 | Some(quantity * quantity), 98 | Some(quantity * quantity * quantity), 99 | ], 100 | }; 101 | 102 | let start = Instant::now(); 103 | // Create a Groth16 proof with our parameters. 104 | let proof = groth16::create_random_proof(c, ¶ms, &mut OsRng).unwrap(); 105 | println!("Prove: [{:?}]", start.elapsed()); 106 | 107 | let public_input = vec![bls12_381::Scalar::from(27)]; 108 | 109 | let start = Instant::now(); 110 | // Check the proof! 111 | assert!(groth16::verify_proof(&pvk, &proof, &public_input).is_ok()); 112 | println!("Verify: [{:?}]", start.elapsed()); 113 | } 114 | -------------------------------------------------------------------------------- /src/old/bits.rs: -------------------------------------------------------------------------------- 1 | use bls12_381::Scalar; 2 | 3 | mod bits_contract; 4 | mod vm; 5 | use bits_contract::load_zkvm; 6 | 7 | fn main() -> std::result::Result<(), vm::ZKVMError> { 8 | let mut vm = load_zkvm(); 9 | 10 | vm.setup(); 11 | 12 | let params = vec![( 13 | 0, 14 | Scalar::from_raw([ 15 | 0xb981_9dc8_2d90_607e, 16 | 0xa361_ee3f_d48f_df77, 17 | 0x52a3_5a8c_1908_dd87, 18 | 0x15a3_6d1f_0f39_0d88, 19 | ]), 20 | )]; 21 | vm.initialize(¶ms)?; 22 | 23 | let proof = vm.prove(); 24 | 25 | let public = vm.public(); 26 | 27 | assert_eq!(public.len(), 0); 28 | 29 | assert!(vm.verify(&proof, &public)); 30 | Ok(()) 31 | } 32 | -------------------------------------------------------------------------------- /src/old/jubjub.rs: -------------------------------------------------------------------------------- 1 | use bls12_381::Scalar; 2 | use ff::PrimeField; 3 | use group::Group; 4 | use jubjub::SubgroupPoint; 5 | 6 | const EDWARDS_D: Scalar = Scalar::from_raw([ 7 | 0x0106_5fd6_d634_3eb1, 8 | 0x292d_7f6d_3757_9d26, 9 | 0xf5fd_9207_e6bd_7fd4, 10 | 0x2a93_18e7_4bfa_2b48, 11 | ]); 12 | 13 | fn print_generators() { 14 | use group::{Curve, Group, GroupEncoding}; 15 | use zcash_primitives::constants::*; 16 | 17 | let x = jubjub::ExtendedPoint::from(VALUE_COMMITMENT_RANDOMNESS_GENERATOR.clone()).to_affine(); 18 | println!("G_VCR: {:?}", x); 19 | let x = jubjub::ExtendedPoint::from(VALUE_COMMITMENT_VALUE_GENERATOR.clone()).to_affine(); 20 | println!("G_VCV: {:?}", x); 21 | } 22 | 23 | fn main() { 24 | print_generators(); 25 | 26 | let g = SubgroupPoint::from_raw_unchecked( 27 | bls12_381::Scalar::from_raw([ 28 | 0xb981_9dc8_2d90_607e, 29 | 0xa361_ee3f_d48f_df77, 30 | 0x52a3_5a8c_1908_dd87, 31 | 0x15a3_6d1f_0f39_0d88, 32 | ]), 33 | bls12_381::Scalar::from_raw([ 34 | 0x7b0d_c53c_4ebf_1891, 35 | 0x1f3a_beeb_98fa_d3e8, 36 | 0xf789_1142_c001_d925, 37 | 0x015d_8c7f_5b43_fe33, 38 | ]), 39 | ); 40 | let x = g + g; 41 | let x = jubjub::AffinePoint::from(jubjub::ExtendedPoint::from(x)); 42 | println!("{:?}", x); 43 | 44 | let one = Scalar::from_bytes(&[ 45 | 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 47 | 0x00, 0x00, 48 | ]) 49 | .unwrap(); 50 | assert_eq!(Scalar::one(), one); 51 | 52 | // Scalar stuff 53 | println!("-Scalar::one: {:?}", -Scalar::one()); 54 | let bits = (-Scalar::one()).to_le_bits(); 55 | for b in bits.iter() { 56 | print!("{}", if *b { 1 } else { 0 }); 57 | } 58 | println!(""); 59 | 60 | println!("Edwards d: {:?}", EDWARDS_D); 61 | } 62 | -------------------------------------------------------------------------------- /src/old/mint2.rs: -------------------------------------------------------------------------------- 1 | use bls12_381::Scalar; 2 | use ff::{Field, PrimeField}; 3 | use group::{Curve, Group, GroupEncoding}; 4 | 5 | mod mint2_contract; 6 | mod vm; 7 | use mint2_contract::{load_params, load_zkvm}; 8 | 9 | fn unpack(value: F) -> Vec { 10 | let mut bits = Vec::new(); 11 | print!("Unpack: "); 12 | for (i, bit) in value.to_le_bits().into_iter().cloned().enumerate() { 13 | match bit { 14 | true => bits.push(Scalar::one()), 15 | false => bits.push(Scalar::zero()), 16 | } 17 | print!("{}", if bit { 1 } else { 0 }); 18 | } 19 | println!(""); 20 | bits 21 | } 22 | 23 | fn unpack_u64(value: u64) -> Vec { 24 | let mut result = Vec::with_capacity(64); 25 | 26 | for i in 0..64 { 27 | if (value >> i) & 1 == 1 { 28 | result.push(Scalar::one()); 29 | } else { 30 | result.push(Scalar::zero()); 31 | } 32 | } 33 | 34 | result 35 | } 36 | 37 | fn do_vcr_test(value: &jubjub::Fr) { 38 | let mut curbase = zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR; 39 | let mut result = jubjub::SubgroupPoint::identity(); 40 | //let value = jubjub::Fr::from(7); 41 | for (i, bit) in value.to_le_bits().into_iter().cloned().enumerate() { 42 | let thisbase = if bit { 43 | curbase.clone() 44 | } else { 45 | jubjub::SubgroupPoint::identity() 46 | }; 47 | result += thisbase; 48 | curbase = curbase.double(); 49 | print!("{}", if bit { 1 } else { 0 }); 50 | } 51 | println!(""); 52 | let result = jubjub::ExtendedPoint::from(result).to_affine(); 53 | println!("cvr1: {:?}", result); 54 | let randomness_commit = 55 | zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR * value; 56 | let randomness_commit = jubjub::ExtendedPoint::from(randomness_commit).to_affine(); 57 | println!("cvr2: {:?}", randomness_commit); 58 | } 59 | 60 | fn main() -> std::result::Result<(), vm::ZKVMError> { 61 | use rand::rngs::OsRng; 62 | let public_point = jubjub::ExtendedPoint::from(jubjub::SubgroupPoint::random(&mut OsRng)); 63 | let public_affine = public_point.to_affine(); 64 | 65 | let value = 110; 66 | let randomness_value: jubjub::Fr = jubjub::Fr::random(&mut OsRng); 67 | //let randomness_value = jubjub::Fr::from(7); 68 | let value_commit = (zcash_primitives::constants::VALUE_COMMITMENT_VALUE_GENERATOR 69 | * jubjub::Fr::from(value)) 70 | + (zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR * randomness_value); 71 | 72 | ///// 73 | let randomness_commit = 74 | zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR * randomness_value; 75 | ///// 76 | do_vcr_test(&randomness_value); 77 | 78 | let mut vm = load_zkvm(); 79 | 80 | vm.setup(); 81 | 82 | let mut params = vec![public_affine.get_u(), public_affine.get_v()]; 83 | for x in unpack(randomness_value) { 84 | params.push(x); 85 | } 86 | let params = load_params(params); 87 | println!("Size of params: {}", params.len()); 88 | vm.initialize(¶ms)?; 89 | 90 | let proof = vm.prove(); 91 | 92 | let public = vm.public(); 93 | 94 | assert_eq!(public.len(), 2); 95 | 96 | // Use this code for testing point doubling 97 | let dbl = public_point.double().to_affine(); 98 | println!("{:?}", dbl.get_u()); 99 | println!("{:?}", public[0]); 100 | println!("{:?}", dbl.get_v()); 101 | println!("{:?}", public[1]); 102 | //assert_eq!(public.len(), 2); 103 | //assert_eq!(public[0], dbl.get_u()); 104 | //assert_eq!(public[1], dbl.get_v()); 105 | 106 | assert!(vm.verify(&proof, &public)); 107 | Ok(()) 108 | } 109 | -------------------------------------------------------------------------------- /src/old/simple.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 | mod simple_circuit; 9 | use simple_circuit::InputSpend; 10 | 11 | fn main() { 12 | use rand::rngs::OsRng; 13 | 14 | let ak = jubjub::SubgroupPoint::random(&mut OsRng); 15 | 16 | let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng); 17 | let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret + ak; 18 | 19 | let params = { 20 | let c = InputSpend { 21 | secret: None, 22 | ak: None, 23 | value: None, 24 | is_cool: None, 25 | path: None, 26 | }; 27 | groth16::generate_random_parameters::(c, &mut OsRng).unwrap() 28 | }; 29 | let pvk = groth16::prepare_verifying_key(¶ms.vk); 30 | 31 | let c = InputSpend { 32 | secret: Some(secret), 33 | ak: Some(ak), 34 | value: Some(110), 35 | is_cool: Some(true), 36 | path: Some(bls12_381::Scalar::one()), 37 | }; 38 | 39 | let proof = groth16::create_random_proof(c, ¶ms, &mut OsRng).unwrap(); 40 | 41 | let mut public_input = [bls12_381::Scalar::zero(); 4]; 42 | { 43 | let result = jubjub::ExtendedPoint::from(public); 44 | let affine = result.to_affine(); 45 | //let (u, v) = (affine.get_u(), affine.get_v()); 46 | let u = affine.get_u(); 47 | let v = affine.get_v(); 48 | public_input[0] = u; 49 | public_input[1] = v; 50 | } 51 | 52 | { 53 | const CRH_IVK_PERSONALIZATION: &[u8; 8] = b"Zcashivk"; 54 | let preimage = [42; 80]; 55 | let hash_result = { 56 | let mut hash = [0; 32]; 57 | hash.copy_from_slice( 58 | Blake2sParams::new() 59 | .hash_length(32) 60 | .personal(CRH_IVK_PERSONALIZATION) 61 | .to_state() 62 | .update(&ak.to_bytes()) 63 | .finalize() 64 | .as_bytes(), 65 | ); 66 | hash 67 | }; 68 | 69 | // Pack the hash as inputs for proof verification. 70 | let hash = multipack::bytes_to_bits_le(&hash_result); 71 | let hash = multipack::compute_multipacking(&hash); 72 | 73 | // There are 2 chunks for a blake hash 74 | assert_eq!(hash.len(), 2); 75 | 76 | public_input[2] = hash[0]; 77 | public_input[3] = hash[1]; 78 | } 79 | 80 | assert!(groth16::verify_proof(&pvk, &proof, &public_input).is_ok()); 81 | } 82 | -------------------------------------------------------------------------------- /src/old/vmtest.rs: -------------------------------------------------------------------------------- 1 | use bls12_381::Scalar; 2 | 3 | mod vm; 4 | mod vm_load; 5 | use vm_load::load_zkvm; 6 | 7 | fn main() { 8 | let mut vm = load_zkvm(); 9 | 10 | vm.setup(); 11 | 12 | let params = vec![ 13 | ( 14 | 0, 15 | Scalar::from_raw([ 16 | 0xb981_9dc8_2d90_607e, 17 | 0xa361_ee3f_d48f_df77, 18 | 0x52a3_5a8c_1908_dd87, 19 | 0x15a3_6d1f_0f39_0d88, 20 | ]), 21 | ), 22 | ( 23 | 1, 24 | Scalar::from_raw([ 25 | 0x7b0d_c53c_4ebf_1891, 26 | 0x1f3a_beeb_98fa_d3e8, 27 | 0xf789_1142_c001_d925, 28 | 0x015d_8c7f_5b43_fe33, 29 | ]), 30 | ), 31 | ( 32 | 2, 33 | Scalar::from_raw([ 34 | 0xb981_9dc8_2d90_607e, 35 | 0xa361_ee3f_d48f_df77, 36 | 0x52a3_5a8c_1908_dd87, 37 | 0x15a3_6d1f_0f39_0d88, 38 | ]), 39 | ), 40 | ( 41 | 3, 42 | Scalar::from_raw([ 43 | 0x7b0d_c53c_4ebf_1891, 44 | 0x1f3a_beeb_98fa_d3e8, 45 | 0xf789_1142_c001_d925, 46 | 0x015d_8c7f_5b43_fe33, 47 | ]), 48 | ), 49 | ]; 50 | vm.initialize(¶ms); 51 | 52 | let proof = vm.prove(); 53 | 54 | let public = vm.public(); 55 | 56 | assert_eq!(public.len(), 2); 57 | // 0x66ced46f14e5616d12b993f60a6e66558d6b6afe4c321ed212e0b9cfbd81061a 58 | // 0x4731570fdd57cf280eadc8946fa00df81112502e44e497e794ab9a221f1bcca 59 | println!("u = {:?}", public[0]); 60 | println!("v = {:?}", public[1]); 61 | 62 | assert!(vm.verify(&proof, &public)); 63 | } 64 | -------------------------------------------------------------------------------- /src/old/zkmimc.rs: -------------------------------------------------------------------------------- 1 | use bls12_381::Scalar; 2 | use ff::{Field, PrimeField}; 3 | use std::ops::{Add, AddAssign, MulAssign, Neg, SubAssign}; 4 | 5 | mod vm; 6 | mod zkmimc_contract; 7 | use zkmimc_contract::load_zkvm; 8 | mod mimc_constants; 9 | use mimc_constants::mimc_constants; 10 | 11 | const MIMC_ROUNDS: usize = 322; 12 | 13 | fn mimc(mut xl: Scalar, mut xr: Scalar, constants: &[Scalar]) -> Scalar { 14 | assert_eq!(constants.len(), MIMC_ROUNDS); 15 | 16 | for i in 0..MIMC_ROUNDS { 17 | let mut tmp1 = xl; 18 | tmp1.add_assign(&constants[i]); 19 | let mut tmp2 = tmp1.square(); 20 | tmp2.mul_assign(&tmp1); 21 | tmp2.add_assign(&xr); 22 | xr = xl; 23 | xl = tmp2; 24 | } 25 | 26 | xl 27 | } 28 | 29 | macro_rules! from_slice { 30 | ($data:expr, $len:literal) => {{ 31 | let mut array = [0; $len]; 32 | // panics if not enough data 33 | let bytes = &$data[..array.len()]; 34 | assert_eq!(bytes.len(), array.len()); 35 | for (a, b) in array.iter_mut().rev().zip(bytes.iter()) { 36 | *a = *b; 37 | } 38 | //array.copy_from_slice(bytes.iter().rev()); 39 | array 40 | }}; 41 | } 42 | 43 | fn main() -> std::result::Result<(), vm::ZKVMError> { 44 | use rand::rngs::OsRng; 45 | 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 | let mut vm = load_zkvm(); 59 | 60 | vm.setup(); 61 | 62 | let params = vec![ 63 | ( 64 | 0, 65 | Scalar::from_raw([ 66 | 0xb981_9dc8_2d90_607e, 67 | 0xa361_ee3f_d48f_df77, 68 | 0x52a3_5a8c_1908_dd87, 69 | 0x15a3_6d1f_0f39_0d88, 70 | ]), 71 | ), 72 | ( 73 | 1, 74 | Scalar::from_raw([ 75 | 0x7b0d_c53c_4ebf_1891, 76 | 0x1f3a_beeb_98fa_d3e8, 77 | 0xf789_1142_c001_d925, 78 | 0x015d_8c7f_5b43_fe33, 79 | ]), 80 | ), 81 | ]; 82 | vm.initialize(¶ms)?; 83 | 84 | let proof = vm.prove(); 85 | 86 | let public = vm.public(); 87 | 88 | let mimc_hash = mimc(params[0].1.clone(), params[1].1.clone(), &constants); 89 | assert_eq!(public.len(), 1); 90 | assert_eq!(public[0], mimc_hash); 91 | 92 | assert!(vm.verify(&proof, &public)); 93 | Ok(()) 94 | } 95 | -------------------------------------------------------------------------------- /src/rpc/__init__.py: -------------------------------------------------------------------------------- 1 | from rpc import jsonclient 2 | from .jsonclient import RpcClient 3 | -------------------------------------------------------------------------------- /src/rpc/adapter.rs: -------------------------------------------------------------------------------- 1 | // Adapter class goes here 2 | // 3 | -------------------------------------------------------------------------------- /src/rpc/jsonclient.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | # TODO: generate random ID (4 byte unsigned int) (rand range 0 - max size uint32) 4 | # TODO: make functions async 5 | # TODO: parse json replies into something more legible 6 | 7 | class RpcClient: 8 | def __init__(self): 9 | self.url = "http://localhost:8000/" 10 | self.payload = { 11 | "method": [], 12 | "params": [], 13 | "jsonrpc": [], 14 | "id": [], 15 | } 16 | 17 | def key_gen(self, payload): 18 | payload['method'] = "key_gen" 19 | payload['jsonrpc'] = "2.0" 20 | payload['id'] = "0" 21 | key = self.__request(payload) 22 | print(key) 23 | 24 | def get_info(self, payload): 25 | payload['method'] = "get_info" 26 | payload['jsonrpc'] = "2.0" 27 | payload['id'] = "0" 28 | info = self.__request(payload) 29 | print(info) 30 | 31 | def stop(self, payload): 32 | payload['method'] = "stop" 33 | payload['jsonrpc'] = "2.0" 34 | payload['id'] = "0" 35 | stop = self.__request(payload) 36 | print(stop) 37 | 38 | def say_hello(self, payload): 39 | payload['method'] = "say_hello" 40 | payload['jsonrpc'] = "2.0" 41 | payload['id'] = "0" 42 | hello = self.__request(payload) 43 | print(hello) 44 | 45 | def __request(self, payload): 46 | response = requests.post(self.url, json=payload).json() 47 | print(response) 48 | assert response["jsonrpc"] 49 | 50 | 51 | if __name__ == "__main__": 52 | client = RpcClient() 53 | 54 | -------------------------------------------------------------------------------- /src/rpc/jsonserver.rs: -------------------------------------------------------------------------------- 1 | use async_executor::Executor; 2 | use async_native_tls::TlsAcceptor; 3 | use async_std::sync::Mutex; 4 | use easy_parallel::Parallel; 5 | use ff::Field; 6 | use http_types::{Request, Response, StatusCode}; 7 | use log::*; 8 | use rand::rngs::OsRng; 9 | use serde_json::json; 10 | use smol::Async; 11 | use std::fs::File; 12 | use std::io::prelude::*; 13 | use std::io::BufReader; 14 | use std::net::SocketAddr; 15 | use std::net::TcpListener; 16 | use std::sync::Arc; 17 | use rusqlite::Connection; 18 | use crate::{net, serial, Result, Error}; 19 | 20 | // json RPC server goes here 21 | pub struct RpcInterface { 22 | p2p: Arc, 23 | pub started: Mutex, 24 | stop_send: async_channel::Sender<()>, 25 | stop_recv: async_channel::Receiver<()>, 26 | } 27 | 28 | impl RpcInterface { 29 | pub fn new(p2p: Arc) -> Arc { 30 | let (stop_send, stop_recv) = async_channel::unbounded::<()>(); 31 | 32 | Arc::new(Self { 33 | p2p, 34 | started: Mutex::new(false), 35 | stop_send, 36 | stop_recv, 37 | }) 38 | } 39 | 40 | async fn db_connect() -> Connection { 41 | let path = dirs::home_dir() 42 | .expect("Cannot find home directory.") 43 | .as_path() 44 | .join(".config/darkfi/wallet.db"); 45 | let connector = Connection::open(&path); 46 | connector.expect("Failed to connect to database.") 47 | } 48 | 49 | async fn generate_key() -> (Vec, Vec) { 50 | let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng); 51 | let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret; 52 | let pubkey = serial::serialize(&public); 53 | let privkey = serial::serialize(&secret); 54 | (privkey, pubkey) 55 | } 56 | 57 | // TODO: fix this 58 | async fn store_key(conn: &Connection, pubkey: Vec, privkey: Vec) -> Result<()> { 59 | let mut db_file = File::open("wallet.sql")?; 60 | let mut contents = String::new(); 61 | db_file.read_to_string(&mut contents)?; 62 | Ok(conn.execute_batch(&mut contents)?) 63 | } 64 | 65 | // add new methods to handle wallet commands 66 | pub async fn serve(self: Arc, mut req: Request) -> http_types::Result { 67 | info!("RPC serving {}", req.url()); 68 | 69 | let request = req.body_string().await?; 70 | 71 | let mut io = jsonrpc_core::IoHandler::new(); 72 | io.add_sync_method("say_hello", |_| { 73 | Ok(jsonrpc_core::Value::String("Hello World!".into())) 74 | }); 75 | 76 | let self2 = self.clone(); 77 | io.add_method("get_info", move |_| { 78 | let self2 = self2.clone(); 79 | async move { 80 | Ok(json!({ 81 | "started": *self2.started.lock().await, 82 | "connections": self2.p2p.connections_count().await 83 | })) 84 | } 85 | }); 86 | 87 | let stop_send = self.stop_send.clone(); 88 | io.add_method("stop", move |_| { 89 | let stop_send = stop_send.clone(); 90 | async move { 91 | let _ = stop_send.send(()).await; 92 | Ok(jsonrpc_core::Value::Null) 93 | } 94 | }); 95 | io.add_method("key_gen", move |_| async move { 96 | RpcInterface::db_connect().await; 97 | let (pubkey, privkey) = RpcInterface::generate_key().await; 98 | //println!("{}", pubkey, "{}", privkey); 99 | Ok(jsonrpc_core::Value::Null) 100 | }); 101 | 102 | let response = io 103 | .handle_request_sync(&request) 104 | .ok_or(Error::BadOperationType)?; 105 | 106 | let mut res = Response::new(StatusCode::Ok); 107 | res.insert_header("Content-Type", "text/plain"); 108 | res.set_body(response); 109 | Ok(res) 110 | } 111 | 112 | pub async fn wait_for_quit(self: Arc) -> Result<()> { 113 | Ok(self.stop_recv.recv().await?) 114 | } 115 | } 116 | 117 | -------------------------------------------------------------------------------- /src/rpc/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod test; 2 | pub mod jsonserver; 3 | 4 | -------------------------------------------------------------------------------- /src/rpc/test.rs: -------------------------------------------------------------------------------- 1 | fn foo() { 2 | } 3 | 4 | -------------------------------------------------------------------------------- /src/service/gateway.rs: -------------------------------------------------------------------------------- 1 | use image::EncodableLayout; 2 | 3 | use super::reqrep::{Reply, Request}; 4 | use crate::serial::{deserialize, serialize}; 5 | use crate::Result; 6 | 7 | use async_executor::Executor; 8 | use async_std::sync::Arc; 9 | use async_zmq; 10 | use futures::FutureExt; 11 | 12 | pub struct GatewayService; 13 | 14 | enum NetEvent { 15 | RECEIVE(async_zmq::Multipart), 16 | SEND(async_zmq::Multipart), 17 | } 18 | 19 | impl GatewayService { 20 | pub async fn start(executor: Arc>) { 21 | let mut worker = async_zmq::reply("tcp://127.0.0.1:4444") 22 | .unwrap() 23 | .connect() 24 | .unwrap(); 25 | 26 | let (send_queue_s, send_queue_r) = async_channel::unbounded::(); 27 | 28 | let ex2 = executor.clone(); 29 | loop { 30 | let event = futures::select! { 31 | request = worker.recv().fuse() => NetEvent::RECEIVE(request.unwrap()), 32 | reply = send_queue_r.recv().fuse() => NetEvent::SEND(reply.unwrap()) 33 | }; 34 | 35 | match event { 36 | NetEvent::RECEIVE(request) => { 37 | ex2.spawn(Self::handle_request(send_queue_s.clone(), request)) 38 | .detach(); 39 | } 40 | NetEvent::SEND(reply) => { 41 | worker.send(reply).await.unwrap(); 42 | } 43 | } 44 | } 45 | } 46 | 47 | async fn handle_request( 48 | send_queue: async_channel::Sender, 49 | request: async_zmq::Multipart, 50 | ) -> Result<()> { 51 | let mut messages = vec![]; 52 | for req in request.iter() { 53 | let req = req.as_bytes(); 54 | let req: Request = deserialize(req).unwrap(); 55 | 56 | // TODO 57 | // do things 58 | 59 | println!("Gateway service received a msg {:?}", req); 60 | 61 | let rep = Reply::from(&req, 0, "text".as_bytes().to_vec()); 62 | let rep = serialize(&rep); 63 | let msg = async_zmq::Message::from(rep); 64 | messages.push(msg); 65 | } 66 | send_queue.send(messages).await?; 67 | Ok(()) 68 | } 69 | } 70 | 71 | struct GatewayClient; 72 | 73 | #[repr(u8)] 74 | enum GatewayCommand { 75 | PUTSLAB, 76 | GETSLAB, 77 | GETLASTINDEX, 78 | } 79 | -------------------------------------------------------------------------------- /src/service/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod gateway; 2 | pub mod reqrep; 3 | -------------------------------------------------------------------------------- /src/system/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod stoppable_task; 2 | pub mod subscriber; 3 | pub mod types; 4 | 5 | pub use stoppable_task::{StoppableTask, StoppableTaskPtr}; 6 | pub use subscriber::{Subscriber, SubscriberPtr, Subscription}; 7 | pub use types::ExecutorPtr; 8 | -------------------------------------------------------------------------------- /src/system/stoppable_task.rs: -------------------------------------------------------------------------------- 1 | use async_executor::Executor; 2 | use futures::Future; 3 | use futures::FutureExt; 4 | use std::sync::Arc; 5 | 6 | pub type StoppableTaskPtr = Arc; 7 | 8 | pub struct StoppableTask { 9 | stop_send: async_channel::Sender<()>, 10 | stop_recv: async_channel::Receiver<()>, 11 | } 12 | 13 | impl StoppableTask { 14 | pub fn new() -> Arc { 15 | let (stop_send, stop_recv) = async_channel::unbounded(); 16 | Arc::new(Self { 17 | stop_send, 18 | stop_recv, 19 | }) 20 | } 21 | 22 | pub async fn stop(&self) { 23 | // Ignore any errors from this send 24 | let _ = self.stop_send.send(()).await; 25 | } 26 | 27 | pub fn start<'a, MainFut, StopFut, StopFn, Error>( 28 | self: Arc, 29 | main: MainFut, 30 | stop_handler: StopFn, 31 | stop_value: Error, 32 | executor: Arc>, 33 | ) where 34 | MainFut: Future> + Send + 'a, 35 | StopFut: Future + Send, 36 | StopFn: FnOnce(std::result::Result<(), Error>) -> StopFut + Send + 'a, 37 | Error: std::error::Error + Send + 'a, 38 | { 39 | executor 40 | .spawn(async move { 41 | let result = futures::select! { 42 | _ = self.stop_recv.recv().fuse() => Err(stop_value), 43 | result = main.fuse() => result 44 | }; 45 | 46 | stop_handler(result).await; 47 | }) 48 | .detach(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/system/subscriber.rs: -------------------------------------------------------------------------------- 1 | use async_std::sync::Mutex; 2 | use rand::Rng; 3 | use std::collections::HashMap; 4 | use std::sync::Arc; 5 | 6 | pub type SubscriberPtr = Arc>; 7 | 8 | pub type SubscriptionID = u64; 9 | 10 | pub struct Subscription { 11 | id: SubscriptionID, 12 | recv_queue: async_channel::Receiver, 13 | parent: Arc>, 14 | } 15 | 16 | impl Subscription { 17 | pub async fn receive(&self) -> T { 18 | let message_result = self.recv_queue.recv().await; 19 | 20 | match message_result { 21 | Ok(message_result) => message_result, 22 | Err(err) => { 23 | panic!("MessageSubscription::receive() recv_queue failed! {}", err); 24 | } 25 | } 26 | } 27 | 28 | // Must be called manually since async Drop is not possible in Rust 29 | pub async fn unsubscribe(&self) { 30 | self.parent.clone().unsubscribe(self.id).await 31 | } 32 | } 33 | 34 | // Simple broadcast (publish-subscribe) class 35 | pub struct Subscriber { 36 | subs: Mutex>>, 37 | } 38 | 39 | impl Subscriber { 40 | pub fn new() -> Arc { 41 | Arc::new(Self { 42 | subs: Mutex::new(HashMap::new()), 43 | }) 44 | } 45 | 46 | fn random_id() -> SubscriptionID { 47 | let mut rng = rand::thread_rng(); 48 | rng.gen() 49 | } 50 | 51 | pub async fn subscribe(self: Arc) -> Subscription { 52 | let (sender, recvr) = async_channel::unbounded(); 53 | 54 | let sub_id = Self::random_id(); 55 | 56 | self.subs.lock().await.insert(sub_id, sender); 57 | 58 | Subscription { 59 | id: sub_id, 60 | recv_queue: recvr, 61 | parent: self.clone(), 62 | } 63 | } 64 | 65 | async fn unsubscribe(self: Arc, sub_id: SubscriptionID) { 66 | self.subs.lock().await.remove(&sub_id); 67 | } 68 | 69 | pub async fn notify(&self, message_result: T) { 70 | for sub in (*self.subs.lock().await).values() { 71 | match sub.send(message_result.clone()).await { 72 | Ok(()) => {} 73 | Err(err) => { 74 | panic!("Error returned sending message in notify() call! {}", err); 75 | } 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/system/types.rs: -------------------------------------------------------------------------------- 1 | use smol::Executor; 2 | use std::sync::Arc; 3 | 4 | pub type ExecutorPtr<'a> = Arc>; 5 | -------------------------------------------------------------------------------- /src/wallet/mod.rs: -------------------------------------------------------------------------------- 1 | // Empty mod.rs file for now 2 | -------------------------------------------------------------------------------- /src/wallet/schema.sql: -------------------------------------------------------------------------------- 1 | ATTACH DATABASE 'wallet.db' AS wallet KEY 'testkey'; 2 | SELECT sqlcipher_export('wallet'); 3 | CREATE TABLE IF NOT EXISTS keys( 4 | key_id INT PRIMARY KEY NOT NULL, 5 | key_public BLOB NOT NULL, 6 | key_private BLOB NOT NULL 7 | ); 8 | CREATE INDEX IF NOT EXISTS key_public on keys(key_public); 9 | 10 | -------------------------------------------------------------------------------- /zkvm.md: -------------------------------------------------------------------------------- 1 | # do the setup for mint.zcd, save the params in mint.params 2 | zkvm setup mint.zcd mint.setup 3 | # make the proof 4 | zkvm prove mint.zcd mint.setup mint-params.json proof.dat 5 | # verify the proof 6 | zkvm verify mint.zcd mint.setup proof.dat 7 | # show public values in proof 8 | zkvm public proof.dat 9 | 10 | --------------------------------------------------------------------------------