diff --git a/example/config/cashierd.toml b/example/config/cashierd.toml new file mode 100644 index 000000000..5bdf4c979 --- /dev/null +++ b/example/config/cashierd.toml @@ -0,0 +1,10 @@ +accept_url = "127.0.0.1:7777" +rpc_url = "http://127.0.0.1:8000" +client_database_path = "cashier_client_database.db" +btc_endpoint = "tcp://electrum.blockstream.info:50001" +gateway_url = "127.0.0.1:3333" +log_path = "/tmp/cashierd.log" +cashierdb_path = "~/.config/darkfi/cashier.db" +client_walletdb_path = "~/.config/darkfi/cashier_client_walletdb.db" +password = "TEST_PASSWORD" +client_password = "TEST_PASSWORD" diff --git a/example/config/darkfid.toml b/example/config/darkfid.toml new file mode 100644 index 000000000..b9eb9d9b7 --- /dev/null +++ b/example/config/darkfid.toml @@ -0,0 +1,8 @@ +connect_url = "127.0.0.1:3333" +subscriber_url = "127.0.0.1:4444" +cashier_url = "127.0.0.1:7777" +rpc_url = "127.0.0.1:8000" +database_path = "~/.config/darkfi/database_client.db" +walletdb_path = "~/.config/darkfi/walletdb.db" +log_path = "/tmp/darkfid_service_daemon.log" +password = "TEST_PASSWORD" diff --git a/example/config/drk.toml b/example/config/drk.toml new file mode 100644 index 000000000..9fba336b9 --- /dev/null +++ b/example/config/drk.toml @@ -0,0 +1,2 @@ +rpc_url = "http://127.0.0.1:8000" +log_path = "/tmp/drk_cli.log" diff --git a/example/config/gatewayd.toml b/example/config/gatewayd.toml new file mode 100644 index 000000000..743a6b6fb --- /dev/null +++ b/example/config/gatewayd.toml @@ -0,0 +1,4 @@ +connect_url = "127.0.0.1:3333" +publisher_url = "127.0.0.1:4444" +database_path = "gatewayd.db" +log_path = "/tmp/gatewayd.log" diff --git a/example/halo2/Cargo.lock b/example/halo2/Cargo.lock new file mode 100644 index 000000000..33ea1fb1a --- /dev/null +++ b/example/halo2/Cargo.lock @@ -0,0 +1,791 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aes" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" +dependencies = [ + "aes-soft", + "aesni", + "cipher", +] + +[[package]] +name = "aes-soft" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" +dependencies = [ + "cipher", + "opaque-debug", +] + +[[package]] +name = "aesni" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" +dependencies = [ + "cipher", + "opaque-debug", +] + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "arrayvec" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4dc07131ffa69b8072d35f5007352af944213cde02545e2103680baed38fcd" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bigint" +version = "4.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0e8c8a600052b52482eff2cf4d810e462fdff1f656ac1ecb6232132a1ed7def" +dependencies = [ + "byteorder", + "crunchy", +] + +[[package]] +name = "bitvec" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5237f00a8c86130a0cc317830e558b966dd7850d48a953d998c813f01a41b527" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2b_simd" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" +dependencies = [ + "arrayref", + "arrayvec 0.5.2", + "constant_time_eq", +] + +[[package]] +name = "block-modes" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a0e8073e8baa88212fb5823574c02ebccb395136ba9a164ab89379ec6072f0" +dependencies = [ + "block-padding", + "cipher", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "bls12_381" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54757888b09a69be70b5ec303e382a74227392086ba808cb01eeca29233a2397" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "crunchy" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" + +[[package]] +name = "crypto_api" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f855e87e75a4799e18b8529178adcde6fd4f97c1449ff4821e747ff728bb102" + +[[package]] +name = "crypto_api_chachapoly" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d930b6a026ce9d358a17f9c9046c55d90b14bb847f36b6ebb6b19365d4feffb8" +dependencies = [ + "crypto_api", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "ff" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" +dependencies = [ + "bitvec", + "rand_core", + "subtle", +] + +[[package]] +name = "fpe" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a25080721bbcd2cd4d765b7d607ea350425fa087ce53cd3e31afcacdab850352" +dependencies = [ + "aes", + "block-modes", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "funty" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e" + +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "group" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912" +dependencies = [ + "byteorder", + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "halo2" +version = "0.0.1" +source = "git+https://github.com/zcash/halo2.git?rev=27c4187673a9c6ade13fbdbd4f20955530c22d7f#27c4187673a9c6ade13fbdbd4f20955530c22d7f" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "pasta_curves", + "rand", + "rayon", +] + +[[package]] +name = "halo2_ecc" +version = "0.0.0" +source = "git+https://github.com/parazyd/orchard.git?rev=f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9#f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9" +dependencies = [ + "arrayvec 0.7.1", + "bigint", + "ff", + "group", + "halo2", + "halo2_utilities", + "lazy_static", + "pasta_curves", + "rand", +] + +[[package]] +name = "halo2_examples" +version = "0.1.0" +dependencies = [ + "arrayvec 0.7.1", + "bigint", + "bitvec", + "ff", + "group", + "halo2", + "halo2_ecc", + "halo2_poseidon", + "halo2_utilities", + "lazy_static", + "orchard", + "pasta_curves", + "rand", + "sinsemilla", + "subtle", +] + +[[package]] +name = "halo2_poseidon" +version = "0.0.0" +source = "git+https://github.com/parazyd/orchard.git?rev=f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9#f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9" +dependencies = [ + "bitvec", + "ff", + "halo2", + "halo2_utilities", + "pasta_curves", +] + +[[package]] +name = "halo2_utilities" +version = "0.0.0" +source = "git+https://github.com/parazyd/orchard.git?rev=f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9#f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9" +dependencies = [ + "bigint", + "ff", + "halo2", + "pasta_curves", + "rand", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "incrementalmerkletree" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d75fb342984cc8cea665a9ef5607b4956569839ca098172082fa1b19bdaf02" +dependencies = [ + "serde", +] + +[[package]] +name = "jubjub" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "593fc4726ca80edb47ee18ab4d826719e25c2096991a79308b44fb915c6014ef" +dependencies = [ + "bitvec", + "bls12_381", + "ff", + "group", + "rand_core", + "subtle", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1fa8cddc8fbbee11227ef194b5317ed014b8acbf15139bd716a18ad3fe99ec5" + +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + +[[package]] +name = "nonempty" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7" + +[[package]] +name = "num-bigint" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d0a3d5e207573f948a9e5376662aa743a2ea13f7c50a554d7af443a73fbfeba" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "orchard" +version = "0.0.0" +source = "git+https://github.com/parazyd/orchard.git?rev=f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9#f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9" +dependencies = [ + "aes", + "arrayvec 0.7.1", + "bigint", + "bitvec", + "blake2b_simd", + "ff", + "fpe", + "group", + "halo2", + "halo2_ecc", + "halo2_poseidon", + "halo2_utilities", + "incrementalmerkletree", + "lazy_static", + "nonempty", + "pasta_curves", + "rand", + "reddsa", + "serde", + "sinsemilla", + "subtle", + "zcash_note_encryption", +] + +[[package]] +name = "pasta_curves" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a21914ddc589b74e7638091c8e91a4e8b083ee5e1d0066d64407131b7570799" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "lazy_static", + "rand", + "static_assertions", + "subtle", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "proc-macro2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" + +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rayon" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "reddsa" +version = "0.0.0" +source = "git+https://github.com/str4d/redjubjub.git?rev=d5d8c5f3bb704bad8ae88fe4a29ae1f744774cb2#d5d8c5f3bb704bad8ae88fe4a29ae1f744774cb2" +dependencies = [ + "blake2b_simd", + "byteorder", + "digest", + "group", + "jubjub", + "pasta_curves", + "rand_core", + "serde", + "thiserror", + "zeroize", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1056a0db1978e9dbf0f6e4fca677f6f9143dc1c19de346f22cac23e422196834" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13af2fbb8b60a8950d6c72a56d2095c28870367cc8e10c55e9745bac4995a2c4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sinsemilla" +version = "0.0.0" +source = "git+https://github.com/parazyd/orchard.git?rev=f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9#f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9" +dependencies = [ + "ff", + "group", + "halo2", + "halo2_ecc", + "halo2_utilities", + "pasta_curves", + "rand", + "subtle", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "synstructure" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typenum" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "wyz" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "129e027ad65ce1453680623c3fb5163cbf7107bfe1aa32257e7d0e63f9ced188" +dependencies = [ + "tap", +] + +[[package]] +name = "zcash_note_encryption" +version = "0.0.0" +source = "git+https://github.com/zcash/librustzcash.git?rev=13b023387bafdc7b5712c933dc0e16ee94b96a6a#13b023387bafdc7b5712c933dc0e16ee94b96a6a" +dependencies = [ + "blake2b_simd", + "byteorder", + "crypto_api_chachapoly", + "ff", + "group", + "rand_core", + "subtle", +] + +[[package]] +name = "zeroize" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "377db0846015f7ae377174787dd452e1c5f5a9050bc6f954911d01f116daa0cd" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2c1e130bebaeab2f23886bf9acbaca14b092408c452543c857f66399cd6dab1" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] diff --git a/example/halo2/Cargo.toml b/example/halo2/Cargo.toml new file mode 100644 index 000000000..69b6bcb51 --- /dev/null +++ b/example/halo2/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "halo2_examples" +version = "0.1.0" +authors = ["narodnik "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ff = "0.10" +group = "0.10" +pasta_curves = "0.1.2" +bitvec = "0.22" +rand = "0.8.4" +arrayvec = "0.7.0" +lazy_static = "1" +bigint = "4" +subtle = "2.3" +halo2 = "0.0" + +[patch.crates-io] +halo2 = { git = "https://github.com/zcash/halo2.git", rev = "27c4187673a9c6ade13fbdbd4f20955530c22d7f" } + +[dependencies.halo2_poseidon] +git = "https://github.com/parazyd/orchard.git" +#rev = "0d14f2390734e4710fc24a976f037dae3a6e7ac8" +rev = "f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9" +features = ["halo2"] + +[dependencies.halo2_utilities] +git = "https://github.com/parazyd/orchard.git" +#rev = "0d14f2390734e4710fc24a976f037dae3a6e7ac8" +rev = "f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9" + +[dependencies.halo2_ecc] +git = "https://github.com/parazyd/orchard.git" +#rev = "0d14f2390734e4710fc24a976f037dae3a6e7ac8" +rev = "f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9" + +[dependencies.sinsemilla] +git = "https://github.com/parazyd/orchard.git" +#rev = "0d14f2390734e4710fc24a976f037dae3a6e7ac8" +rev = "f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9" + + [dependencies.orchard] +git = "https://github.com/parazyd/orchard.git" +rev = "f9cc01c21010b31988129f9cbc2ca8c0bdbf2ee9" diff --git a/example/halo2/README.md b/example/halo2/README.md new file mode 100644 index 000000000..1e2fbb2a6 --- /dev/null +++ b/example/halo2/README.md @@ -0,0 +1,6 @@ +Always use the --release flag otherwise it's too slow: + +``` +cargo run --release --bin simple3 +``` + diff --git a/example/halo2/src/bin/burn.rs b/example/halo2/src/bin/burn.rs new file mode 100644 index 000000000..ea027dad4 --- /dev/null +++ b/example/halo2/src/bin/burn.rs @@ -0,0 +1,73 @@ +use std::iter; + +use group::{ff::PrimeFieldBits, Curve}; +use halo2::{ + arithmetic::{CurveAffine, Field, FieldExt}, + pasta::{Fp, Fq}, +}; +use halo2_ecc::gadget::FixedPoints; +use halo2_poseidon::primitive::{ConstantLength, Hash, P128Pow5T3 as OrchardNullifier}; +use orchard::constants::{fixed_bases::OrchardFixedBases, sinsemilla::MERKLE_CRH_PERSONALIZATION}; +use rand::rngs::OsRng; +use sinsemilla::primitive::{CommitDomain, HashDomain}; + +use halo2_examples::pedersen_commitment; + +fn main() { + let secret_key = Fq::random(&mut OsRng); + let serial = Fp::random(&mut OsRng); + + // Sinsemilla hash + let domain = HashDomain::new(MERKLE_CRH_PERSONALIZATION); + let nullifier = domain + .hash( + iter::empty() + .chain(secret_key.to_le_bits().iter().by_val()) + .chain(serial.to_le_bits().iter().by_val()), + ) + .unwrap(); + + let public_key = OrchardFixedBases::SpendAuthG.generator() * secret_key; + let coords = public_key.to_affine().coordinates().unwrap(); + + let value = 110; + let asset = 1; + + let value_blind = Fq::random(&mut OsRng); + let asset_blind = Fq::random(&mut OsRng); + + let coin_blind = Fp::random(&mut OsRng); + + // FIXME: + let messages = [ + [*coords.x(), *coords.y()], + [Fp::from(value), Fp::from(asset)], + [serial, coin_blind], + ]; + let mut coin = Fp::zero(); + for msg in messages.iter() { + coin += Hash::init(OrchardNullifier, ConstantLength::<2>).hash(*msg); + } + + // TODO: Merkle + + let value_commit = pedersen_commitment(value, value_blind); + let asset_commit = pedersen_commitment(asset, asset_blind); + let value_coords = value_commit.to_affine().coordinates().unwrap(); + let asset_coords = value_commit.to_affine().coordinates().unwrap(); + + let sig_secret = Fq::random(&mut OsRng); + let sig_pubkey = OrchardFixedBases::SpendAuthG.generator() * sig_secret; + let sig_pk_coords = sig_pubkey.to_affine().coordinates().unwrap(); + + let mut public_inputs = vec![ + nullifier, + *value_coords.x(), + *value_coords.y(), + *asset_coords.x(), + *asset_coords.y(), + // merkle_root, + *sig_pk_coords.x(), + *sig_pk_coords.y(), + ]; +} diff --git a/example/halo2/src/bin/mint.rs b/example/halo2/src/bin/mint.rs new file mode 100644 index 000000000..41380daf4 --- /dev/null +++ b/example/halo2/src/bin/mint.rs @@ -0,0 +1,439 @@ +use std::{convert::TryInto, time::Instant}; + +use group::{ff::Field, Curve, Group}; +use halo2::{ + arithmetic::CurveAffine, + circuit::{floor_planner, Layouter}, + dev::MockProver, + pasta::{vesta, Ep, Fp, Fq}, + plonk, + plonk::{Circuit, ConstraintSystem, Error}, + poly::commitment, + transcript::{Blake2bRead, Blake2bWrite}, +}; +use halo2_ecc::{chip::EccChip, gadget::FixedPoint}; +use halo2_poseidon::{ + gadget::{Hash as PoseidonHash, Word}, + pow5t3::{Pow5T3Chip as PoseidonChip, StateWord}, + primitive::{ConstantLength, Hash, P128Pow5T3 as OrchardNullifier}, +}; +use halo2_utilities::{ + lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions, Var, +}; +use orchard::constants::fixed_bases::OrchardFixedBases; +use rand::rngs::OsRng; + +use halo2_examples::{circuit::Config, pedersen_commitment}; + +const K: u32 = 9; + +#[derive(Default, Debug)] +struct MintCircuit { + pub_x: Option, // x coordinate for pubkey + pub_y: Option, // y coordinate for pubkey + value: Option, // The value of this coin + asset: Option, // The asset ID + serial: Option, // Unique serial number corresponding to this coin + coin_blind: Option, // Random blinding factor for coin + value_blind: Option, // Random blinding factor for value commitment + asset_blind: Option, // Random blinding factor for the asset ID +} + +impl UtilitiesInstructions for MintCircuit { + type Var = CellValue; +} + +impl Circuit for MintCircuit { + type Config = Config; + type FloorPlanner = floor_planner::V1; + //type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let advices = [ + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + ]; + + let q_add = meta.selector(); + + let table_idx = meta.lookup_table_column(); + + // let lookup = ( + // table_idx, + // meta.lookup_table_column(), + // meta.lookup_table_column(), + // ); + + let primary = meta.instance_column(); + + meta.enable_equality(primary.into()); + + for advice in advices.iter() { + meta.enable_equality((*advice).into()); + } + + let lagrange_coeffs = [ + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + ]; + + let rc_a = lagrange_coeffs[2..5].try_into().unwrap(); + let rc_b = lagrange_coeffs[5..8].try_into().unwrap(); + + meta.enable_constant(lagrange_coeffs[0]); + + let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx); + + let ecc_config = EccChip::::configure( + meta, + advices, + lagrange_coeffs, + range_check.clone(), + ); + + let poseidon_config = PoseidonChip::configure( + meta, + OrchardNullifier, + advices[6..9].try_into().unwrap(), + advices[5], + rc_a, + rc_b, + ); + + Config { + primary, + q_add, + advices, + ecc_config, + poseidon_config, + } + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + // Construct the ECC chip. + let ecc_chip = EccChip::construct(config.ecc_config.clone()); + + let pub_x = self.load_private( + layouter.namespace(|| "load pubkey x"), + config.advices[0], + self.pub_x, + )?; + let pub_y = self.load_private( + layouter.namespace(|| "load pubkey y"), + config.advices[0], + self.pub_y, + )?; + let value = self.load_private( + layouter.namespace(|| "load value"), + config.advices[0], + self.value, + )?; + let asset = self.load_private( + layouter.namespace(|| "load asset"), + config.advices[0], + self.asset, + )?; + let serial = self.load_private( + layouter.namespace(|| "load serial"), + config.advices[0], + self.serial, + )?; + let coin_blind = self.load_private( + layouter.namespace(|| "load coin_blind"), + config.advices[0], + self.coin_blind, + )?; + + // ============= + // = Coin hash = + // ============= + + // TODO: This is a hack until issue is resolved in poseidon gadget + let mut coin = Fp::zero(); + let messages = [[pub_x, pub_y], [value, asset], [serial, coin_blind]]; + //let messages = [[pub_x, pub_y], [value, asset]]; + //let messages = [[pub_x, pub_y]]; + for msg in messages.iter() { + let poseidon_message = layouter.assign_region( + || "load message", + |mut region| { + let mut message_word = |i: usize| { + let val = msg[i].value(); + let var = region.assign_advice( + || format!("load message_{}", i), + config.poseidon_config.state()[i], + 0, + || val.ok_or(Error::SynthesisError), + )?; + region.constrain_equal(var, msg[i].cell())?; + Ok(Word::<_, _, OrchardNullifier, 3, 2>::from_inner( + StateWord::new(var, val), + )) + }; + Ok([message_word(0)?, message_word(1)?]) + }, + )?; + + let poseidon_hasher = PoseidonHash::init( + PoseidonChip::construct(config.poseidon_config.clone()), + layouter.namespace(|| "Poseidon init"), + ConstantLength::<2>, + )?; + + let poseidon_output = + poseidon_hasher.hash(layouter.namespace(|| "Poseidon hash"), poseidon_message)?; + + let poseidon_output: CellValue = poseidon_output.inner().into(); + + if !poseidon_output.value().is_none() { + coin += poseidon_output.value().unwrap(); + } + } + + // if coin != Fp::zero() { + // println!("circuit hash: {:?}", coin); + // } + + let hash = self.load_private( + layouter.namespace(|| "load hash"), + config.advices[0], + Some(coin), + )?; + + // Constrain the coin C; index in public values is 0 + layouter.constrain_instance(hash.cell(), config.primary, 0)?; + + // ==================== + // = Value commitment = + // ==================== + + // This constant one is used for multiplication + let one = self.load_constant( + layouter.namespace(|| "constant one"), + config.advices[0], + Fp::one(), + )?; + + // v*G_1 + let (commitment, _) = { + let value_commit_v = OrchardFixedBases::ValueCommitV; + let value_commit_v = FixedPoint::from_inner(ecc_chip.clone(), value_commit_v); + value_commit_v.mul_short(layouter.namespace(|| "[value] ValueCommitV"), (value, one))? + }; + + // r_V*G_2 + let (blind, _rcv) = { + let rcv = self.value_blind; + let value_commit_r = OrchardFixedBases::ValueCommitR; + let value_commit_r = FixedPoint::from_inner(ecc_chip.clone(), value_commit_r); + value_commit_r.mul(layouter.namespace(|| "[value_blind] ValueCommitR"), rcv)? + }; + + // Constrain the x and y; indexes in public values are 1 and 2 + let value_commit = commitment.add(layouter.namespace(|| "valuecommit"), &blind)?; + layouter.constrain_instance(value_commit.inner().x().cell(), config.primary, 1)?; + layouter.constrain_instance(value_commit.inner().y().cell(), config.primary, 2)?; + + // ==================== + // = Asset commitment = + // ==================== + + // a*G_1 + let (commitment, _) = { + let asset_commit_v = OrchardFixedBases::ValueCommitV; + let asset_commit_v = FixedPoint::from_inner(ecc_chip.clone(), asset_commit_v); + asset_commit_v.mul_short(layouter.namespace(|| "[asset] ValueCommitV"), (asset, one))? + }; + + // r_A*G_2 + let (blind, _rca) = { + let rca = self.asset_blind; + let asset_commit_r = OrchardFixedBases::ValueCommitR; + let asset_commit_r = FixedPoint::from_inner(ecc_chip.clone(), asset_commit_r); + asset_commit_r.mul(layouter.namespace(|| "[asset_blind] ValueCommitR"), rca)? + }; + + // Constrain the x and y; indexes in public values are 3 and 4 + let asset_commit = commitment.add(layouter.namespace(|| "assetcommit"), &blind)?; + layouter.constrain_instance(asset_commit.inner().x().cell(), config.primary, 3)?; + layouter.constrain_instance(asset_commit.inner().y().cell(), config.primary, 4)?; + + Ok(()) + } +} + +#[derive(Debug)] +struct VerifyingKey { + params: commitment::Params, + vk: plonk::VerifyingKey, +} + +impl VerifyingKey { + fn build() -> Self { + let params = commitment::Params::new(K); + let circuit: MintCircuit = Default::default(); + + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + + VerifyingKey { params, vk } + } +} + +#[derive(Debug)] +struct ProvingKey { + params: commitment::Params, + pk: plonk::ProvingKey, +} + +impl ProvingKey { + fn build() -> Self { + let params = commitment::Params::new(K); + let circuit: MintCircuit = Default::default(); + + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + let pk = plonk::keygen_pk(¶ms, vk, &circuit).unwrap(); + + ProvingKey { params, pk } + } +} + +#[derive(Clone, Debug)] +struct Proof(Vec); + +impl AsRef<[u8]> for Proof { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl Proof { + fn create(pk: &ProvingKey, circuits: &[MintCircuit], pubinputs: &[Fp]) -> Result { + let mut transcript = Blake2bWrite::<_, vesta::Affine, _>::init(vec![]); + plonk::create_proof( + &pk.params, + &pk.pk, + circuits, + &[&[pubinputs]], + &mut transcript, + )?; + Ok(Proof(transcript.finalize())) + } + + fn verify(&self, vk: &VerifyingKey, pubinputs: &[Fp]) -> Result<(), plonk::Error> { + let msm = vk.params.empty_msm(); + let mut transcript = Blake2bRead::init(&self.0[..]); + let guard = plonk::verify_proof(&vk.params, &vk.vk, msm, &[&[pubinputs]], &mut transcript)?; + let msm = guard.clone().use_challenges(); + if msm.eval() { + Ok(()) + } else { + Err(Error::ConstraintSystemFailure) + } + } + + // fn new(bytes: Vec) -> Self { + // Proof(bytes) + // } +} + +fn main() { + let pubkey = Ep::random(&mut OsRng); + let coords = pubkey.to_affine().coordinates().unwrap(); + + let value = 110; + let asset = 1; + + let value_blind = Fq::random(&mut OsRng); + let asset_blind = Fq::random(&mut OsRng); + + let serial = Fp::random(&mut OsRng); + let coin_blind = Fp::random(&mut OsRng); + + let mut coin = Fp::zero(); + + let messages = [ + [*coords.x(), *coords.y()], + [Fp::from(value), Fp::from(asset)], + [serial, coin_blind], + ]; + + // TODO: This is a hack until issue is fixed in poseidon gadget + for msg in messages.iter() { + coin += Hash::init(OrchardNullifier, ConstantLength::<2>).hash(*msg); + } + + let value_commit = pedersen_commitment(value, value_blind); + let value_coords = value_commit.to_affine().coordinates().unwrap(); + + let asset_commit = pedersen_commitment(asset, asset_blind); + let asset_coords = asset_commit.to_affine().coordinates().unwrap(); + + let mut public_inputs = vec![ + coin, + *value_coords.x(), + *value_coords.y(), + *asset_coords.x(), + *asset_coords.y(), + ]; + + let circuit = MintCircuit { + pub_x: Some(*coords.x()), + pub_y: Some(*coords.y()), + value: Some(vesta::Scalar::from(value)), + asset: Some(vesta::Scalar::from(asset)), + serial: Some(serial), + coin_blind: Some(coin_blind), + value_blind: Some(value_blind), + asset_blind: Some(asset_blind), + }; + + // Valid MockProver + let prover = MockProver::run(K, &circuit, vec![public_inputs.clone()]).unwrap(); + assert_eq!(prover.verify(), Ok(())); + + // Add 1 to break the public inputs + public_inputs[0] += Fp::from(0xdeadbeef); + + // Invalid MockProver + let prover = MockProver::run(K, &circuit, vec![public_inputs.clone()]).unwrap(); + assert!(prover.verify().is_err()); + + // Remove 1 to make the public inputs valid again + public_inputs[0] -= Fp::from(0xdeadbeef); + + // Actual ZK proof + let start = Instant::now(); + let vk = VerifyingKey::build(); + let pk = ProvingKey::build(); + println!("\nSetup: [{:?}]", start.elapsed()); + + let start = Instant::now(); + let proof = Proof::create(&pk, &[circuit], &public_inputs).unwrap(); + println!("Prove: [{:?}]", start.elapsed()); + + let start = Instant::now(); + assert!(proof.verify(&vk, &public_inputs).is_ok()); + println!("Verify: [{:?}]", start.elapsed()); +} diff --git a/example/halo2/src/bin/poseidon.rs b/example/halo2/src/bin/poseidon.rs new file mode 100644 index 000000000..3e2a2bc29 --- /dev/null +++ b/example/halo2/src/bin/poseidon.rs @@ -0,0 +1,298 @@ +use std::convert::TryInto; +use std::time::Instant; + +use halo2::{ + circuit::{floor_planner, Layouter}, + pasta::{vesta, Fp}, + plonk, + plonk::{ + Advice, Circuit, Column, ConstraintSystem, Error, Instance as InstanceColumn, Selector, + }, + poly::{commitment, Rotation}, + transcript::{Blake2bRead, Blake2bWrite}, +}; + +use halo2_poseidon::{ + gadget::{Hash as PoseidonHash, Word}, + pow5t3::{Pow5T3Chip as PoseidonChip, Pow5T3Config as PoseidonConfig, StateWord}, + primitive::{ConstantLength, Hash, P128Pow5T3 as OrchardNullifier}, +}; +use halo2_utilities::{copy, CellValue, UtilitiesInstructions, Var}; + +const K: u32 = 6; + +#[derive(Clone, Debug)] +struct Config { + primary: Column, + q_add: Selector, + advices: [Column; 10], + poseidon_config: PoseidonConfig, +} + +#[derive(Default, Debug)] +struct HashCircuit { + a: Option, // First input for hash + b: Option, // Second input for hash + c: Option, // c is summed with hash +} + +impl UtilitiesInstructions for HashCircuit { + type Var = CellValue; +} + +impl Circuit for HashCircuit { + type Config = Config; + type FloorPlanner = floor_planner::V1; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + // 10 advice columns + let advices = [ + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + meta.advice_column(), + ]; + + // Addition of two field elements: poseidon_hash(a, b) + c + let q_add = meta.selector(); + + meta.create_gate("poseidon_hash(a, b) + c", |meta| { + let q_add = meta.query_selector(q_add); + let sum = meta.query_advice(advices[6], Rotation::cur()); + let hash = meta.query_advice(advices[7], Rotation::cur()); + let c = meta.query_advice(advices[8], Rotation::cur()); + + vec![q_add * (hash + c - sum)] + }); + + let primary = meta.instance_column(); + meta.enable_equality(primary.into()); + + for advice in advices.iter() { + meta.enable_equality((*advice).into()); + } + + let lagrange_coeffs = [ + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + meta.fixed_column(), + ]; + + let rc_a = lagrange_coeffs[2..5].try_into().unwrap(); + let rc_b = lagrange_coeffs[5..8].try_into().unwrap(); + + meta.enable_constant(lagrange_coeffs[0]); + + let poseidon_config = PoseidonChip::configure( + meta, + OrchardNullifier, + advices[6..9].try_into().unwrap(), + advices[5], + rc_a, + rc_b, + ); + + Config { + primary, + q_add, + advices, + poseidon_config, + } + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let a = self.load_private(layouter.namespace(|| "load a"), config.advices[0], self.a)?; + let b = self.load_private(layouter.namespace(|| "load b"), config.advices[0], self.b)?; + let c = self.load_private(layouter.namespace(|| "load c"), config.advices[0], self.c)?; + + let hash = { + let message = [a, b]; + + let poseidon_message = layouter.assign_region( + || "load message", + |mut region| { + let mut message_word = |i: usize| { + let value = message[i].value(); + let var = region.assign_advice( + || format!("load message_{}", i), + config.poseidon_config.state()[i], + 0, + || value.ok_or(Error::SynthesisError), + )?; + region.constrain_equal(var, message[i].cell())?; + Ok(Word::<_, _, OrchardNullifier, 3, 2>::from_inner( + StateWord::new(var, value), + )) + }; + Ok([message_word(0)?, message_word(1)?]) + }, + )?; + + let poseidon_hasher = PoseidonHash::init( + //config.poseidon_chip(), + PoseidonChip::construct(config.poseidon_config.clone()), + layouter.namespace(|| "Poseidon init"), + ConstantLength::<2>, + )?; + + let poseidon_output = poseidon_hasher.hash( + layouter.namespace(|| "Poseidon hash (a, b)"), + poseidon_message, + )?; + + let poseidon_output: CellValue = poseidon_output.inner().into(); + poseidon_output + }; + + // Add hash output to c + let scalar = layouter.assign_region( + || " `scalar` = poseidon_hash(a, b) + c", + |mut region| { + config.q_add.enable(&mut region, 0)?; + + copy(&mut region, || "copy hash", config.advices[7], 0, &hash)?; + copy(&mut region, || "copy c", config.advices[8], 0, &c)?; + + let scalar_val = hash.value().zip(c.value()).map(|(hash, c)| hash + c); + + let cell = region.assign_advice( + || "poseidon_hash(a, b) + c", + config.advices[6], + 0, + || scalar_val.ok_or(Error::SynthesisError), + )?; + Ok(CellValue::new(cell, scalar_val)) + }, + )?; + + layouter.constrain_instance(scalar.cell(), config.primary, 0) + } +} + +#[derive(Debug)] +struct VerifyingKey { + params: commitment::Params, + vk: plonk::VerifyingKey, +} + +impl VerifyingKey { + fn build() -> Self { + let params = commitment::Params::new(K); + let circuit: HashCircuit = Default::default(); + + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + + VerifyingKey { params, vk } + } +} + +#[derive(Debug)] +struct ProvingKey { + params: commitment::Params, + pk: plonk::ProvingKey, +} + +impl ProvingKey { + fn build() -> Self { + let params = commitment::Params::new(K); + let circuit: HashCircuit = Default::default(); + + let vk = plonk::keygen_vk(¶ms, &circuit).unwrap(); + let pk = plonk::keygen_pk(¶ms, vk, &circuit).unwrap(); + + ProvingKey { params, pk } + } +} + +#[derive(Clone, Debug)] +struct Proof(Vec); + +impl AsRef<[u8]> for Proof { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl Proof { + fn create(pk: &ProvingKey, circuits: &[HashCircuit], pubinputs: &[Fp]) -> Result { + let mut transcript = Blake2bWrite::<_, vesta::Affine, _>::init(vec![]); + plonk::create_proof( + &pk.params, + &pk.pk, + circuits, + &[&[pubinputs]], + &mut transcript, + )?; + Ok(Proof(transcript.finalize())) + } + + fn verify(&self, vk: &VerifyingKey, pubinputs: &[Fp]) -> Result<(), plonk::Error> { + let msm = vk.params.empty_msm(); + let mut transcript = Blake2bRead::init(&self.0[..]); + let guard = plonk::verify_proof(&vk.params, &vk.vk, msm, &[&[pubinputs]], &mut transcript)?; + let msm = guard.clone().use_challenges(); + if msm.eval() { + Ok(()) + } else { + Err(Error::ConstraintSystemFailure) + } + } + + // fn new(bytes: Vec) -> Self { + // Proof(bytes) + // } +} + +fn main() { + let a = Fp::from(13); + let b = Fp::from(69); + let c = Fp::from(42); + + let message = [a, b]; + let output = Hash::init(OrchardNullifier, ConstantLength::<2>).hash(message); + + let circuit = HashCircuit { + a: Some(a), + b: Some(b), + c: Some(c), + }; + + let sum = output + c; + + // Correct: + let public_inputs = vec![sum]; + // Incorrect: + // let public_inputs = vec![sum + Fp::one()]; + + let start = Instant::now(); + let vk = VerifyingKey::build(); + let pk = ProvingKey::build(); + println!("Setup: [{:?}]", start.elapsed()); + + let start = Instant::now(); + let proof = Proof::create(&pk, &[circuit], &public_inputs).unwrap(); + println!("Prove: [{:?}]", start.elapsed()); + + let start = Instant::now(); + assert!(proof.verify(&vk, &public_inputs).is_ok()); + println!("Verify: [{:?}]", start.elapsed()); +} diff --git a/example/halo2/src/bin/simple3.rs b/example/halo2/src/bin/simple3.rs new file mode 100644 index 000000000..4554fdfac --- /dev/null +++ b/example/halo2/src/bin/simple3.rs @@ -0,0 +1,130 @@ +use halo2::{ + circuit::{SimpleFloorPlanner, Chip, Layouter}, + pasta::{EqAffine, Fp}, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Expression, Selector, create_proof, verify_proof, keygen_vk, keygen_pk}, + poly::{commitment::Params, Rotation}, + transcript::{Blake2bRead, Blake2bWrite, Challenge255}, +}; +use std::time::Instant; + +#[derive(Clone, Debug)] +struct CoolConfig { + a_col: Column, + s_range: Selector, +} + +struct CoolChip { + config: CoolConfig +} + +impl Chip for CoolChip { + type Config = CoolConfig; + type Loaded = (); + + fn config(&self) -> &Self::Config { + &self.config + } + + fn loaded(&self) -> &Self::Loaded { + &() + } +} + +impl CoolChip { + fn construct(config: CoolConfig) -> Self { + Self { config } + } + + fn configure(cs: &mut ConstraintSystem) -> CoolConfig { + let a_col = cs.advice_column(); + let s_range = cs.selector(); + + cs.create_gate("check", |cs| { + let a = cs.query_advice(a_col, Rotation::cur()); + let s_range = cs.query_selector(s_range); + vec![s_range * (a - Expression::Constant(Fp::from(2)))] + }); + + CoolConfig { a_col, s_range } + } + + fn alloc_and_check( + &self, + layouter: &mut impl Layouter, + a: Option, + ) -> Result<(), Error> { + layouter.assign_region( + || "load private inputs", + |mut region| { + let row_offset = 0; + self.config.s_range.enable(&mut region, row_offset)?; + region.assign_advice( + || "private input 'a'", + self.config.a_col, + row_offset, + || a.ok_or(Error::SynthesisError), + )?; + Ok(()) + }, + ) + } +} + +#[derive(Clone)] +struct CoolCircuit { + // Private input. + a: Option, +} + +impl Circuit for CoolCircuit { + type Config = CoolConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self { a: None } + } + + fn configure(cs: &mut ConstraintSystem) -> Self::Config { + CoolChip::configure(cs) + } + + fn synthesize(&self, config: Self::Config, mut layouter: impl Layouter) -> Result<(), Error> { + let chip = CoolChip::construct(config); + chip.alloc_and_check(&mut layouter, self.a) + } +} + +fn main() { + let start = Instant::now(); + let params: Params = Params::new(4); + + let empty_circuit = CoolCircuit { a: None }; + let vk = keygen_vk(¶ms, &empty_circuit).expect("keygen_vk should not fail"); + let pk = keygen_pk(¶ms, vk, &empty_circuit).expect("keygen_pk should not fail"); + println!("Setup: [{:?}]", start.elapsed()); + + let start = Instant::now(); + let circuit = CoolCircuit { + a: Some(Fp::from(2)), + }; + + // Create a proof + let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); + create_proof(¶ms, &pk, &[circuit], &[&[]], &mut transcript) + .expect("proof generation should not fail"); + let proof = transcript.finalize(); + println!("Prove: [{:?}]", start.elapsed()); + + let start = Instant::now(); + let msm = params.empty_msm(); + let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]); + let verification = verify_proof(¶ms, pk.get_vk(), msm, &[&[]], &mut transcript); + if let Err(err) = verification { + panic!("error {:?}", err); + } + let guard = verification.unwrap(); + let msm = guard.clone().use_challenges(); + assert!(msm.eval()); + println!("Verify: [{:?}]", start.elapsed()); +} + diff --git a/example/halo2/src/bin/simple4.rs b/example/halo2/src/bin/simple4.rs new file mode 100644 index 000000000..7b39e319d --- /dev/null +++ b/example/halo2/src/bin/simple4.rs @@ -0,0 +1,267 @@ +use halo2::{ + circuit::{SimpleFloorPlanner, Cell, Chip, Layouter}, + pasta::{EqAffine, Fp}, + plonk::{Advice, Any, Circuit, Column, ConstraintSystem, Error, Expression, Selector, create_proof, verify_proof, keygen_vk, keygen_pk, Permutation}, + poly::{commitment::{Blind, Params}, Rotation}, + transcript::{Blake2bRead, Blake2bWrite, Challenge255}, +}; +use group::Curve; +use std::time::Instant; + +#[derive(Clone, Debug)] +struct CoolConfig { + a_col: Column, + b_col: Column, + permute: Permutation, + s_range: Selector, + s_mul: Selector, + s_pub: Selector, +} + +struct CoolChip { + config: CoolConfig +} + +impl Chip for CoolChip { + type Config = CoolConfig; + type Loaded = (); + + fn config(&self) -> &Self::Config { + &self.config + } + + fn loaded(&self) -> &Self::Loaded { + &() + } +} + +#[derive(Clone, Debug)] +struct Number { + cell: Cell, + value: Option, +} + +impl CoolChip { + fn construct(config: CoolConfig) -> Self { + Self { config } + } + + fn configure(cs: &mut ConstraintSystem) -> CoolConfig { + let a_col = cs.advice_column(); + let b_col = cs.advice_column(); + + let instance = cs.instance_column(); + + let permute = { + // Convert advice columns into an "any" columns. + let cols: [Column; 2] = [a_col.into(), b_col.into()]; + Permutation::new(cs, &cols) + }; + + let s_range = cs.selector(); + let s_mul = cs.selector(); + let s_pub = cs.selector(); + + cs.create_gate("check", |cs| { + let a = cs.query_advice(a_col, Rotation::cur()); + let s_range = cs.query_selector(s_range); + vec![s_range * (a - Expression::Constant(Fp::from(2)))] + }); + + cs.create_gate("mul", |cs| { + let lhs = cs.query_advice(a_col, Rotation::cur()); + let rhs = cs.query_advice(b_col, Rotation::cur()); + let out = cs.query_advice(a_col, Rotation::next()); + let s_mul = cs.query_selector(s_mul); + + vec![s_mul * (lhs * rhs + out * -Fp::one())] + }); + + cs.create_gate("public input", |cs| { + let a = cs.query_advice(b_col, Rotation::cur()); + let p = cs.query_instance(instance, Rotation::cur()); + let s = cs.query_selector(s_pub); + + vec![s * (p + a * -Fp::one())] + }); + + CoolConfig { a_col, b_col, permute, s_range, s_mul, s_pub } + } + + fn alloc_left( + &self, + layouter: &mut impl Layouter, + value: Option + ) -> Result { + layouter.assign_region( + || "load left private input", + |mut region| { + let cell = region.assign_advice( + || "private input 'a'", + self.config.a_col, + 0, + || value.ok_or(Error::SynthesisError), + )?; + Ok(Number { cell, value }) + } + ) + } + + fn check( + &self, + layouter: &mut impl Layouter, + number: Number + ) -> Result<(), Error> { + layouter.assign_region( + || "load private inputs", + |mut region| { + self.config.s_range.enable(&mut region, 0)?; + + let a = region.assign_advice( + || "lhs", + self.config.a_col, + 0, + || number.value.ok_or(Error::SynthesisError), + )?; + region.constrain_equal(&self.config.permute, number.cell, a)?; + + Ok(()) + }, + ) + } + + fn mul( + &self, + layouter: &mut impl Layouter, + a: Number, + b: Number + ) -> Result { + let mut out = None; + layouter.assign_region( + || "mul", + |mut region| { + self.config.s_mul.enable(&mut region, 0)?; + + let lhs = region.assign_advice( + || "lhs", + self.config.a_col, + 0, + || a.value.ok_or(Error::SynthesisError), + )?; + let rhs = region.assign_advice( + || "rhs", + self.config.b_col, + 0, + || b.value.ok_or(Error::SynthesisError), + )?; + region.constrain_equal(&self.config.permute, a.cell, lhs)?; + region.constrain_equal(&self.config.permute, b.cell, rhs)?; + + let value = a.value.and_then(|a| b.value.map(|b| a * b)); + let cell = region.assign_advice( + || "lhs * rhs", + self.config.a_col, + 1, + || value.ok_or(Error::SynthesisError), + )?; + + out = Some(Number { cell, value }); + Ok(()) + }, + )?; + + Ok(out.unwrap()) + } + + fn expose_public(&self, layouter: &mut impl Layouter, num: Number) -> Result<(), Error> { + layouter.assign_region( + || "expose public", + |mut region| { + self.config.s_pub.enable(&mut region, 0)?; + + let out = region.assign_advice( + || "public advice", + self.config.b_col, + 0, + || num.value.ok_or(Error::SynthesisError), + )?; + region.constrain_equal(&self.config.permute, num.cell, out)?; + + Ok(()) + }, + ) + } +} + +#[derive(Clone)] +struct CoolCircuit { + // Private input. + a: Option, +} + +impl Circuit for CoolCircuit { + type Config = CoolConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self { a: None } + } + + fn configure(cs: &mut ConstraintSystem) -> Self::Config { + CoolChip::configure(cs) + } + + fn synthesize(&self, config: Self::Config, mut layouter: impl Layouter) -> Result<(), Error> { + let chip = CoolChip::construct(config); + let a = chip.alloc_left(&mut layouter, self.a)?; + chip.check(&mut layouter, a.clone())?; + let a2 = chip.mul(&mut layouter, a.clone(), a)?; + chip.expose_public(&mut layouter, a2)?; + Ok(()) + } +} + +fn main() { + let k = 6; + + let start = Instant::now(); + let params: Params = Params::new(k); + + let empty_circuit = CoolCircuit { a: None }; + let vk = keygen_vk(¶ms, &empty_circuit).expect("keygen_vk should not fail"); + let pk = keygen_pk(¶ms, vk, &empty_circuit).expect("keygen_pk should not fail"); + println!("Setup: [{:?}]", start.elapsed()); + + let start = Instant::now(); + let circuit = CoolCircuit { + a: Some(Fp::from(2)), + }; + + let mut public_inputs = pk.get_vk().get_domain().empty_lagrange(); + public_inputs[4] = Fp::from(4); + + // Create a proof + let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); + create_proof(¶ms, &pk, &[circuit], &[&[public_inputs.clone()]], &mut transcript) + .expect("proof generation should not fail"); + let proof = transcript.finalize(); + println!("Prove: [{:?}]", start.elapsed()); + + let pubinput = params + .commit_lagrange(&public_inputs, Blind::default()) + .to_affine(); + let pubinput_slice = &[pubinput]; + + let start = Instant::now(); + let msm = params.empty_msm(); + let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]); + let verification = verify_proof(¶ms, pk.get_vk(), msm, &[pubinput_slice], &mut transcript); + if let Err(err) = verification { + panic!("error {:?}", err); + } + let guard = verification.unwrap(); + let msm = guard.clone().use_challenges(); + assert!(msm.eval()); + println!("Verify: [{:?}]", start.elapsed()); +} + diff --git a/example/halo2/src/circuit.rs b/example/halo2/src/circuit.rs new file mode 100644 index 000000000..936c25708 --- /dev/null +++ b/example/halo2/src/circuit.rs @@ -0,0 +1,16 @@ +use halo2::{ + pasta::pallas, + plonk::{Advice, Column, Instance as InstanceColumn, Selector}, +}; + +use halo2_ecc::chip::EccConfig; +use halo2_poseidon::pow5t3::Pow5T3Config as PoseidonConfig; + +#[derive(Clone, Debug)] +pub struct Config { + pub primary: Column, + pub q_add: Selector, + pub advices: [Column; 10], + pub ecc_config: EccConfig, + pub poseidon_config: PoseidonConfig, +} diff --git a/example/halo2/src/lib.rs b/example/halo2/src/lib.rs new file mode 100644 index 000000000..29f165bed --- /dev/null +++ b/example/halo2/src/lib.rs @@ -0,0 +1,19 @@ +pub mod circuit; + +use halo2::{ + arithmetic::{CurveExt, FieldExt}, + pasta::{Ep, Fq}, +}; +use orchard::constants::fixed_bases::{ + VALUE_COMMITMENT_PERSONALIZATION, VALUE_COMMITMENT_R_BYTES, VALUE_COMMITMENT_V_BYTES, +}; + +#[allow(non_snake_case)] +pub fn pedersen_commitment(value: u64, blind: Fq) -> Ep { + let hasher = Ep::hash_to_curve(VALUE_COMMITMENT_PERSONALIZATION); + let V = hasher(&VALUE_COMMITMENT_V_BYTES); + let R = hasher(&VALUE_COMMITMENT_R_BYTES); + let value = Fq::from_u64(value); + + V * value + R * blind +} diff --git a/old/compile.py b/old/compile.py new file mode 100644 index 000000000..152583358 --- /dev/null +++ b/old/compile.py @@ -0,0 +1,460 @@ +import argparse +import sys +from enum import Enum + +alloc_commands = { + "param": 1, + "private": 1, + "public": 1, +} + +op_commands = { + "set": 2, + "mul": 2, + "add": 2, + "sub": 2, + "divide": 2, + "double": 1, + "square": 1, + "invert": 1, + "unpack_bits": 3, + "load": 2, + "local": 1, + "debug": 1, + "dump_alloc": 0, + "dump_local": 0, +} + +constraint_commands = { + "lc0_add": 1, + "lc1_add": 1, + "lc2_add": 1, + "lc0_sub": 1, + "lc1_sub": 1, + "lc2_sub": 1, + "lc0_add_one": 0, + "lc1_add_one": 0, + "lc2_add_one": 0, + "lc0_sub_one": 0, + "lc1_sub_one": 0, + "lc2_sub_one": 0, + "lc0_add_coeff": 2, + "lc1_add_coeff": 2, + "lc2_add_coeff": 2, + "lc0_add_constant": 1, + "lc1_add_constant": 1, + "lc2_add_constant": 1, + "enforce": 0, + "lc_coeff_reset": 0, + "lc_coeff_double": 0, +} + +def eprint(*args): + print(*args, file=sys.stderr) + +class Line: + + def __init__(self, text, line_number): + self.text = text + self.orig = text + self.lineno = line_number + + self.clean() + + def clean(self): + # Remove the comments + self.text = self.text.split("#", 1)[0] + # Remove whitespace + self.text = self.text.strip() + + def is_empty(self): + return bool(self.text) + + def __repr__(self): + return "Line %s: %s" % (self.lineno, self.orig.lstrip()) + + def command(self): + if not self.is_empty(): + return None + return self.text.split(" ")[0] + + def args(self): + if not self.is_empty(): + return None + return self.text.split()[1:] + +def clean(contents): + # Split input into lines + contents = contents.split("\n") + contents = [Line(line, i + 1) for i, line in enumerate(contents)] + # Remove empty blank lines + contents = [line for line in contents if line.is_empty()] + return contents + +def divide_sections(contents): + state = "NOSCOPE" + segments = {} + current_segment = [] + contract_name = None + + for line in contents: + if line.command() == "contract": + if len(line.args()) != 1: + eprint("error: missing contract name") + eprint(line) + return None + contract_name = line.args()[0] + + if state == "NOSCOPE": + assert not current_segment + state = "INSCOPE" + continue + else: + assert state == "INSCOPE" + eprint("error: double contract entry violation") + eprint(line) + return None + elif line.command() == "end": + if len(line.args()) != 0: + eprint("error: end takes no args") + eprint(line) + return None + + if state == "NOSCOPE": + eprint("error: missing contract start for end") + eprint(line) + return None + else: + assert state == "INSCOPE" + state = "NOSCOPE" + segments[contract_name] = current_segment + current_segment = [] + continue + elif state == "NOSCOPE": + # Ignore lines outside any contract + continue + + current_segment.append(line) + + if state != "NOSCOPE": + eprint("error: reached end of file with unclosed scope") + return None + + return segments + +def extract_relevant_lines(contract, commands_table): + relevant_lines = [] + + for line in contract: + command = line.command() + + if command not in commands_table.keys(): + continue + + define = commands_table[command] + + if len(line.args()) != define: + eprint("error: wrong number of args") + return None + + relevant_lines.append(line) + + return relevant_lines + +class VariableType(Enum): + PUBLIC = 1 + PRIVATE = 2 + +class Variable: + + def __init__(self, symbol, index, type, is_param): + self.symbol = symbol + self.index = index + self.type = type + self.is_param = is_param + + def __repr__(self): + return "" % (self.symbol, self.index) + +def generate_alloc_table(contract): + relevant_lines = extract_relevant_lines(contract, alloc_commands) + alloc_table = {} + for i, line in enumerate(relevant_lines): + assert len(line.args()) == 1 + symbol = line.args()[0] + + command = line.command() + + if command == "param": + type = VariableType.PRIVATE + is_param = True + elif command == "private": + type = VariableType.PRIVATE + is_param = False + elif command == "public": + type = VariableType.PUBLIC + is_param = False + else: + assert False + + if symbol in alloc_table: + eprint("error: duplicate symbol '%s'" % symbol) + eprint(line) + return None + + alloc_table[symbol] = Variable(symbol, i, type, is_param) + + return alloc_table + +class Operation: + + def __init__(self, line, indexes): + self.command = line.command() + self.args = indexes + self.line = line + +class VariableRefType(Enum): + AUX = 1 + LOCAL = 2 + CONST = 3 + +class VariableRef: + + def __init__(self, type, index): + self.type = type + self.index = index + + def __repr__(self): + return "%s(%s)" % (self.type.name, self.index) + +def symbols_list_to_refs(line, alloc, local_vars, constants): + indexes = [] + for symbol in line.args(): + if symbol in alloc: + # Lookup variable index + index = alloc[symbol].index + index = VariableRef(VariableRefType.AUX, index) + elif symbol in local_vars: + index = local_vars[symbol] + index = VariableRef(VariableRefType.LOCAL, index) + elif symbol in constants: + index = constants[symbol][0] + index = VariableRef(VariableRefType.CONST, index) + else: + eprint("error: missing unallocated symbol '%s'" % symbol) + eprint(line) + return None + indexes.append(index) + return indexes + +def generate_ops_table(contract, alloc, constants): + relevant_lines = extract_relevant_lines(contract, op_commands) + ops = [] + local_vars = {} + for line in relevant_lines: + # This is a special case which creates a new local stack value + if line.command() == "local": + assert len(line.args()) == 1 + symbol = line.args()[0] + local_vars[symbol] = len(local_vars) + indexes = [] + else: + if (indexes := symbols_list_to_refs(line, alloc, + local_vars, constants)) is None: + return None + + # Handle this here directly since only the + # load command deals with constants + if line.command() == "load": + assert len(indexes) == 2 + # This is the only command which uses consts + if indexes[1].type != VariableRefType.CONST: + eprint("error: load command takes a const argument") + eprint(line) + return None + elif any(index.type == VariableRefType.CONST for index in indexes): + eprint("error: invalid const arg") + eprint(line) + return None + + ops.append(Operation(line, indexes)) + return ops + +class Constraint: + + def __init__(self, line, lcargs): + self.command = line.command() + self.args = lcargs + self.line = line + + def args_comment(self): + return ", ".join("%s" % symbol for symbol in self.line.args()) + +def symbols_list_to_lcargs(line, alloc, constants): + lcargs = [] + for symbol in line.args(): + if symbol in alloc: + # Lookup variable index + index = alloc[symbol].index + lcargs.append(index) + elif symbol in constants: + value = constants[symbol] + lcargs.append(value) + else: + eprint("error: missing unallocated symbol '%s'" % symbol) + eprint(line) + return None + return lcargs + +def generate_constraints_table(contract, alloc, constants): + relevant_lines = extract_relevant_lines(contract, constraint_commands) + constraints = [] + for line in relevant_lines: + if (lcargs := symbols_list_to_lcargs(line, alloc, constants)) is None: + return None + constraints.append(Constraint(line, lcargs)) + return constraints + +class Contract: + + def __init__(self, constants, alloc, ops, constraints): + self.constants = constants + self.alloc = alloc + self.ops = ops + self.constraints = constraints + + def __repr__(self): + repr_str = "" + + repr_str += "Constants:\n" + for symbol, value in self.constants.items(): + repr_str += " // %s\n" % symbol + repr_str += " %s: %s\n" % value + + repr_str += "Alloc table:\n" + for symbol, variable in self.alloc.items(): + repr_str += " // %s\n" % symbol + repr_str += " %s %s\n" % (variable.type, variable.index) + + repr_str += "Operations:\n" + for op in self.ops: + repr_str += " // %s\n" % op.line + repr_str += " %s %s\n" % (op.command, op.args) + + repr_str += "Constraints:\n" + for constraint in self.constraints: + if constraint.args: + repr_str += " // %s\n" % constraint.args_comment() + repr_str += " %s %s\n" % (constraint.command, constraint.args) + + repr_str += "Stats:\n" + repr_str += " Constants: %s\n" % len(self.constants) + repr_str += " Alloc: %s\n" % len(self.alloc) + repr_str += " Operations: %s\n" % len(self.ops) + repr_str += " Constraint Instructions: %s\n" % len(self.constraints) + + return repr_str + +def compile(contract, constants): + # Allocation table + # symbol: Private/Public, is_param, index + if (alloc := generate_alloc_table(contract)) is None: + return None + # Operations lines list + if (ops := generate_ops_table(contract, alloc, constants)) is None: + return None + # Constraint commands + if (constraints := generate_constraints_table( + contract, alloc, constants)) is None: + return None + return Contract(constants, alloc, ops, constraints) + +def parse_constants(contents): + relevant_lines = [line for line in contents if line.command() == "constant"] + constants = {} + for line in relevant_lines: + assert line.command() == "constant" + if len(line.args()) != 2: + eprint("error: wrong number of args for constant") + eprint(line) + return None + symbol, value = line.args() + + try: + int(value, 16) + except ValueError: + eprint("error: invalid constant value for '%s'" % symbol) + eprint(line) + return None + + if len(value) != 32*2 + 2 or value[:2] != "0x": + eprint("error: invalid hex value for constant") + eprint(line) + return None + + # Remove 0x prefix + value = value[2:] + + constants[symbol] = (len(constants), value) + return constants + +def process(contents): + # Remove left whitespace + contents = clean(contents) + # Parse all constants + if (constants := parse_constants(contents)) is None: + return None + # Divide into contract sections + if (pre_contracts := divide_sections(contents)) is None: + return None + # Process each contract + contracts = {} + for contract_name, pre_contract in pre_contracts.items(): + if (contract := compile(pre_contract, constants)) is None: + return None + contracts[contract_name] = contract + return contracts + +def main(argv): + parser = argparse.ArgumentParser() + parser.add_argument("filename", help="VM PISM file: proofs/vm.pism") + parser.add_argument("--output", type=argparse.FileType('wb', 0), + default=sys.stdout.buffer, help="Output file") + group = parser.add_mutually_exclusive_group() + group.add_argument('--display', action='store_true', + help="show the compiled code in human readable format") + group.add_argument('--rust', action='store_true', + help="output compiled code to rust for testing") + group.add_argument('--supervisor', action='store_true', + help="output compiled code to zkvm supervisor") + args = parser.parse_args() + + src_filename = args.filename + contents = open(src_filename).read() + if (contracts := process(contents)) is None: + return -2 + + def default_display(): + for contract_name, contract in contracts.items(): + print("Contract:", contract_name) + print(contract) + + if args.display: + default_display() + elif args.rust: + import compile_export_rust + for contract_name, contract in contracts.items(): + compile_export_rust.display(contract) + elif args.supervisor: + import compile_export_supervisor + for contract_name, contract in contracts.items(): + compile_export_supervisor.export(args.output, contract_name, + contract) + else: + default_display() + + return 0 + +if __name__ == "__main__": + sys.exit(main(sys.argv)) + diff --git a/old/mint.aux b/old/mint.aux new file mode 100644 index 000000000..196019b7d --- /dev/null +++ b/old/mint.aux @@ -0,0 +1,40 @@ +{ + "constants": { + "G_SPEND": { + "maps_to": "zcash_proofs::constants::SPENDING_KEY_GENERATOR" + }, + "G_PROOF": { + "maps_to": "zcash_proofs::constants::PROOF_GENERATION_KEY_GENERATOR" + }, + "CRH_IVK": { + "maps_to": "zcash_primitives::constants::CRH_IVK_PERSONALIZATION" + }, + "PRF_NF": { + "maps_to": "zcash_primitives::constants::PRF_NF_PERSONALIZATION" + }, + "G_VCV": { + "maps_to": "zcash_proofs::constants::VALUE_COMMITMENT_VALUE_GENERATOR" + }, + "G_VCR": { + "maps_to": "zcash_proofs::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR" + }, + "JUBJUB_FR_CAPACITY": { + "maps_to": "jubjub::Fr::CAPACITY as usize" + }, + "NOTE_COMMIT": { + "maps_to": "pedersen_hash::Personalization::NoteCommitment" + }, + "MERKLE_0": { + "maps_to": "pedersen_hash::Personalization::MerkleTree(0)" + }, + "MERKLE_1": { + "maps_to": "pedersen_hash::Personalization::MerkleTree(1)" + }, + "MERKLE_2": { + "maps_to": "pedersen_hash::Personalization::MerkleTree(2)" + }, + "MERKLE_3": { + "maps_to": "pedersen_hash::Personalization::MerkleTree(3)" + } + } +} diff --git a/old/pism.py b/old/pism.py new file mode 100644 index 000000000..2761946f0 --- /dev/null +++ b/old/pism.py @@ -0,0 +1,528 @@ +import json +import os +import sys + +import codegen + +symbol_table = { + "contract": 1, + "param": 2, + "start": 0, + "end": 0, +} + +types_map = { + "U64": "u64", + "Fr": "jubjub::Fr", + "Point": "jubjub::SubgroupPoint", + "Scalar": "bls12_381::Scalar", + "Bool": "bool" +} + +feature_includes = {"G_SPEND": "use crate::crypto::merkle_node::SAPLING_COMMITMENT_TREE_DEPTH;\n"} + +command_desc = { + "witness": ( + ("EdwardsPoint", True), + ("Point", False) + ), + "assert_not_small_order": ( + ("EdwardsPoint", False), + ), + "u64_as_binary_le": ( + ("Vec", True), + ("U64", False), + ), + "fr_as_binary_le": ( + ("Vec", True), + ("Fr", False) + ), + "ec_mul_const": ( + ("EdwardsPoint", True), + ("Vec", False), + ("FixedGenerator", False) + ), + "ec_mul": ( + ("EdwardsPoint", True), + ("Vec", False), + ("EdwardsPoint", False), + ), + "ec_add": ( + ("EdwardsPoint", True), + ("EdwardsPoint", False), + ("EdwardsPoint", False), + ), + "ec_repr": ( + ("Vec", True), + ("EdwardsPoint", False), + ), + "ec_get_u": ( + ("ScalarNum", True), + ("EdwardsPoint", False), + ), + "emit_ec": ( + ("EdwardsPoint", False), + ), + "alloc_binary": ( + ("Vec", True), + ), + "binary_clone": ( + ("Vec", True), + ("Vec", False), + ), + "binary_extend": ( + ("Vec", False), + ("Vec", False), + ), + "binary_push": ( + ("Vec", False), + ("Boolean", False), + ), + "binary_truncate": ( + ("Vec", False), + ("BinarySize", False), + ), + "static_assert_binary_size": ( + ("Vec", False), + ("INTEGER", False), + ), + "blake2s": ( + ("Vec", True), + ("Vec", False), + ("BlakePersonalization", False), + ), + "pedersen_hash": ( + ("EdwardsPoint", True), + ("Vec", False), + ("PedersenPersonalization", False), + ), + "emit_binary": ( + ("Vec", False), + ), + "alloc_bit": ( + ("Boolean", True), + ("Bool", False), + ), + "alloc_const_bit": ( + ("Boolean", True), + ("BOOL_CONST", False), + ), + "clone_bit": ( + ("Boolean", True), + ("Boolean", False), + ), + "alloc_scalar": ( + ("ScalarNum", True), + ("Scalar", False), + ), + "scalar_as_binary": ( + ("Vec", True), + ("ScalarNum", False), + ), + "emit_scalar": ( + ("ScalarNum", False), + ), + "scalar_enforce_equal": ( + ("ScalarNum", False), + ("ScalarNum", False), + ), + "conditionally_reverse": ( + ("ScalarNum", True), + ("ScalarNum", True), + ("ScalarNum", False), + ("ScalarNum", False), + ("Boolean", False), + ), +} + +def eprint(*args): + print(*args, file=sys.stderr) + +class Line: + + def __init__(self, text, line_number): + self.text = text + self.orig = text + self.lineno = line_number + + self.clean() + + def clean(self): + # Remove the comments + self.text = self.text.split("#", 1)[0] + # Remove whitespace + self.text = self.text.strip() + + def is_empty(self): + return bool(self.text) + + def __repr__(self): + return "Line %s: %s" % (self.lineno, self.orig.lstrip()) + + def command(self): + if not self.is_empty(): + return None + return self.text.split(" ")[0] + + def args(self): + if not self.is_empty(): + return None + return self.text.split(" ")[1:] + +def clean(contents): + # Split input into lines + contents = contents.split("\n") + contents = [Line(line, i) for i, line in enumerate(contents)] + # Remove empty blank lines + contents = [line for line in contents if line.is_empty()] + return contents + +def make_segments(contents): + constants = [line for line in contents if line.command() == "constant"] + + segments = [] + current_segment = [] + for line in contents: + if line.command() == "contract": + current_segment = [] + + current_segment.append(line) + + if line.command() == "end": + segments.append(current_segment) + current_segment = [] + + return constants, segments + +def build_constants_table(constants): + table = {} + for line in constants: + args = line.args() + if len(args) != 2: + eprint("error: wrong number of args") + eprint(line) + return None + name, type = args + table[name] = type + return table + +def extract(segment): + assert segment + # Does it have a declaration? + if not segment[0].command() == "contract": + eprint("error: missing contract declaration") + eprint(segment[0]) + return None + # Does it have an end? + if not segment[-1].command() == "end": + eprint("error: missing contract end") + eprint(segment[-1]) + return None + # Does it have a start? + if not [line for line in segment if line.command() == "start"]: + eprint("error: missing contract start") + eprint(segment[0]) + return None + + for line in segment: + command, args = line.command(), line.args() + + if command in symbol_table: + if symbol_table[command] != len(args): + eprint("error: wrong number of args for command '%s'" % command) + eprint(line) + return None + elif command in command_desc: + if len(command_desc[command]) != len(args): + eprint("error: wrong number of args for command '%s'" % command) + eprint(line) + return None + else: + eprint("error: missing symbol for command '%s'" % command) + eprint(line) + return None + + contract_name = segment[0].args()[0] + + start_index = [index for index, line in enumerate(segment) + if line.command() == "start"] + if len(start_index) > 1: + eprint("error: multiple start statements in contract '%s'" % + contract_name) + for index in start_index: + eprint(segment[index]) + eprint("Aborting.") + return None + assert len(start_index) == 1 + start_index = start_index[0] + + header = segment[1:start_index] + code = segment[start_index + 1:-1] + + params = {} + for param_decl in header: + args = param_decl.args() + assert len(args) == 2 + name, type = args + params[name] = type + + program = [] + for line in code: + command, args = line.command(), line.args() + program.append((command, args, line)) + + return Contract(contract_name, params, program) + +def to_initial_caps(snake_str): + components = snake_str.split("_") + return "".join(x.title() for x in components) + +class Contract: + + def __init__(self, name, params, program): + self.name = name + self.params = params + self.program = program + + def _includes(self): + return \ +r"""#![allow(unused_imports)] +#![allow(unused_mut)] +use bellman::{ + gadgets::{ + boolean, + boolean::{AllocatedBit, Boolean}, + multipack, + blake2s, + num, + Assignment, + }, + groth16, Circuit, ConstraintSystem, SynthesisError, +}; +use bls12_381::Bls12; +use ff::{PrimeField, Field}; +use group::Curve; +use zcash_proofs::circuit::{ecc, pedersen_hash}; +""" + + def _compile_header(self): + code = "pub struct %s {\n" % to_initial_caps(self.name) + for param_name, param_type in self.params.items(): + try: + mapped_type = types_map[param_type] + except KeyError: + return None + code += " pub %s: Option<%s>,\n" % (param_name, mapped_type) + code += "}\n" + return code + + def _compile_body(self): + self.stack = {} + code = "\n" + #indent = " " * 8 + for command, args, line in self.program: + if (code_text := self._compile_line(command, args, line)) is None: + return None + code += "// %s\n" % str(line) + code += code_text + "\n\n" + return code + + def _preprocess_args(self, args, line): + nargs = [] + for arg in args: + if not arg.startswith("param:"): + nargs.append((arg, False)) + continue + _, argname = arg.split(":", 1) + if argname not in self.params: + eprint("error: non-existant param referenced") + eprint(line) + return None + nargs.append((argname, True)) + return nargs + + def type_checking(self, command, args, line): + assert command in command_desc + type_list = command_desc[command] + if len(type_list) != len(args): + eprint("error: wrong number of arguments!") + eprint(line) + return False + + for (expected_type, new_val), (argname, is_param) in \ + zip(type_list, args): + # Only type check input arguments, not output values + if new_val: + continue + + if expected_type == "INTEGER" or expected_type == "BOOL_CONST": + continue + + if is_param: + actual_type = self.params[argname] + elif argname in self.constants: + actual_type = self.constants[argname] + else: + # Check the stack here + if argname not in self.stack: + eprint("error: cannot find value '%s' on the stack!" % + argname) + eprint(line) + return False + + actual_type = self.stack[argname] + + if expected_type != actual_type: + eprint("error: wrong type for arg '%s'!" % argname) + eprint(line) + return False + + return True + + def _check_args(self, command, args, line): + assert command in command_desc + type_list = command_desc[command] + assert len(type_list) == len(args) + + for (expected_type, is_new_val), (arg, is_param) in zip(type_list, args): + if is_param: + continue + if is_new_val: + continue + if arg in self.stack: + continue + if arg in self.constants: + continue + + if expected_type == "INTEGER" or expected_type == "BOOL_CONST": + continue + + eprint("error: cannot find '%s' in the stack" % arg) + eprint(line) + return False + return True + + def _compile_line(self, command, args, line): + if (args := self._preprocess_args(args, line)) is None: + return None + if not self.type_checking(command, args, line): + return None + + if not self._check_args(command, args, line): + return None + + self.modify_stack(command, args) + + args = [self.carg(arg) for arg in args] + + try: + codegen_method = getattr(codegen, command) + except AttributeError: + eprint("error: missing command '%s' does not exist" % command) + eprint(line) + return None + + return codegen_method(line, *args) + + def carg(self, arg): + argname, is_param = arg + if is_param: + return "self.%s" % argname + if argname in self.rename_consts: + return self.rename_consts[argname] + return argname + + def modify_stack(self, command, args): + type_list = command_desc[command] + assert len(type_list) == len(args) + for (expected_type, new_val), (argname, is_param) in \ + zip(type_list, args): + if is_param: + assert not new_val + continue + + # Now apply the new values to the stack + if new_val: + self.stack[argname] = expected_type + + def compile(self, constants, aux): + self.constants = constants + code = "" + + code += self._includes() + + self.rename_consts = {} + if "constants" in aux: + for const_name, value in aux["constants"].items(): + if "maps_to" not in value: + eprint("error: bad aux config '%s', missing maps_to" % + const_name) + return None + + if const_name in feature_includes: + code += feature_includes[const_name] + + mapped_type = value["maps_to"] + self.rename_consts[const_name] = mapped_type + + code += "\n" + + if (header := self._compile_header()) is None: + return None + code += header + + code += \ +r"""impl Circuit for %s { + fn synthesize>( + self, + cs: &mut CS, + ) -> Result<(), SynthesisError> { +""" % to_initial_caps(self.name) + + if (body := self._compile_body()) is None: + return None + code += body + code += "Ok(())\n" + + code += " }\n" + code += "}\n" + + return code + +def process(contents, aux): + contents = clean(contents) + constants, segments = make_segments(contents) + if (constants := build_constants_table(constants)) is None: + return False + + codes = [] + for segment in segments: + if (contract := extract(segment)) is None: + return False + if (code := contract.compile(constants, aux)) is None: + return False + codes.append(code) + + # Success! Output finished product. + [print(code) for code in codes] + + return True + +def main(argv): + if len(argv) != 3: + eprint("pism FILENAME AUX_FILENAME") + return -1 + + aux_filename = argv[2] + aux = json.loads(open(aux_filename).read()) + + src_filename = argv[1] + contents = open(src_filename).read() + if not process(contents, aux): + return -2 + + return 0 + +if __name__ == "__main__": + sys.exit(main(sys.argv)) + diff --git a/old/preprocess.py b/old/preprocess.py new file mode 100644 index 000000000..0a9bf58df --- /dev/null +++ b/old/preprocess.py @@ -0,0 +1,20 @@ +import os.path +import sys +from jinja2 import Environment, FileSystemLoader, Template + +def main(argv): + if len(argv) != 2: + print("error: missing arg", file=sys.stderr) + return -1 + + path = argv[1] + dirname, filename = os.path.dirname(path), os.path.basename(path) + env = Environment(loader = FileSystemLoader([dirname])) + template = env.get_template(filename) + print(template.render()) + + return 0 + +if __name__ == "__main__": + sys.exit(main(sys.argv)) + diff --git a/old/run_mint.sh b/old/run_mint.sh new file mode 100755 index 000000000..62de54b34 --- /dev/null +++ b/old/run_mint.sh @@ -0,0 +1,5 @@ +#!/bin/bash -x +python3 scripts/preprocess.py proofs/mint2.psm > /tmp/mint2.psm || exit $? +python3 scripts/compile.py --supervisor /tmp/mint2.psm --output mint.zcd || exit $? +cargo run --release --bin mint + diff --git a/old/run_mint_contract.sh b/old/run_mint_contract.sh new file mode 100755 index 000000000..1664f0d1f --- /dev/null +++ b/old/run_mint_contract.sh @@ -0,0 +1,4 @@ +#!/bin/bash -x +python scripts/preprocess.py proofs/mint.pism > /tmp/mint.pism +python scripts/pism.py /tmp/mint.pism proofs/mint.aux | rustfmt > src/mint_contract.rs +cargo run --release --bin mint diff --git a/old/run_spend_contract.sh b/old/run_spend_contract.sh new file mode 100755 index 000000000..82d0b2cad --- /dev/null +++ b/old/run_spend_contract.sh @@ -0,0 +1,4 @@ +#!/bin/bash -x +python scripts/preprocess.py proofs/spend.pism > /tmp/spend.pism +python scripts/pism.py /tmp/spend.pism proofs/mint.aux | rustfmt > src/spend_contract.rs +cargo run --release --bin spend diff --git a/proof/mint.pism b/proof/mint.pism new file mode 100644 index 000000000..4cbd0727f --- /dev/null +++ b/proof/mint.pism @@ -0,0 +1,92 @@ +# :set syntax=pism +# :source ../scripts/pism.vim +constant G_VCV FixedGenerator +constant G_VCR FixedGenerator +constant CRH_IVK BlakePersonalization +#constant JUBJUB_FR_CAPACITY BinarySize +#constant NOTE_COMMIT PedersenPersonalization + +contract mint_contract + # Value commitment + param value U64 + param asset_id Fr + param randomness_value Fr + param randomness_asset Fr + + param serial Fr + param randomness_coin Fr + param public Point +start + # Witness input values + u64_as_binary_le value param:value + fr_as_binary_le asset_id param:asset_id + fr_as_binary_le randomness_value param:randomness_value + fr_as_binary_le randomness_asset param:randomness_asset + fr_as_binary_le serial param:serial + fr_as_binary_le randomness_coin param:randomness_coin + + witness public param:public + assert_not_small_order public + + # Make value commitment + # V = v * G_VCV + r * G_VCR + + ec_mul_const vcv value G_VCV + ec_mul_const rcv randomness_value G_VCR + ec_add cv vcv rcv + # emit cv + emit_ec cv + + # Make asset_id commitment + # A = a * G_VCV + r_a * G_VCR + + ec_mul_const vca asset_id G_VCV + ec_mul_const rca randomness_asset G_VCR + ec_add ca vca rca + # emit ca + emit_ec ca + + + # Make the coin + # C = Hash(public_key, value, asset_id, serial, randomness_coin) + + # Build the preimage to hash + alloc_binary preimage + + # public_key + ec_repr repr_public public + binary_extend preimage repr_public + + # value + binary_extend preimage value + +# Fr values are 252 bits so we need to pad it with extra 0s +# to match the Rust values which are 256 bits +{% macro binary_put_fr(binary, var) -%} + binary_extend {{ binary }} {{ var }} + {% for n in range(4) %} + alloc_const_bit zero_bit false + binary_push {{ binary }} zero_bit + {% endfor %} +{%- endmacro %} + + # serial + {{ binary_put_fr("preimage", "serial") }} + + # randomness_coin + {{ binary_put_fr("preimage", "randomness_coin") }} + + # asset_id + {{ binary_put_fr("preimage", "asset_id") }} + + # Public key: SubgroupPoint = 256 bits + # Value: u64 = 64 bits + # AssetID: Fr = 252 + 4 bits padding + # Serial: Fr = 252 + 4 bits padding + # Randomness coin Fr = 252 + 4 bits padding + # TOTAL: 1088 bits for preimage + static_assert_binary_size preimage 1088 + blake2s coin preimage CRH_IVK + emit_binary coin +end + diff --git a/proof/spend.pism b/proof/spend.pism new file mode 100644 index 000000000..1fc056d6b --- /dev/null +++ b/proof/spend.pism @@ -0,0 +1,158 @@ +constant G_VCV FixedGenerator +constant G_VCR FixedGenerator +constant G_SPEND FixedGenerator +constant PRF_NF BlakePersonalization +constant CRH_IVK BlakePersonalization +constant NOTE_COMMIT PedersenPersonalization +{% for i in range(32) %} + constant MERKLE_{{ i }} PedersenPersonalization +{% endfor %} + +contract spend_contract + # Value commitment + param value U64 + param asset_id Fr + param randomness_value Fr + param randomness_asset Fr + + param serial Fr + param randomness_coin Fr + param secret Fr + param signature_secret Fr + +{% for i in range(32) %} + param branch_{{ i }} Scalar + param is_right_{{ i }} Bool +{% endfor %} +start + # Witness input values + u64_as_binary_le value param:value + fr_as_binary_le asset_id param:asset_id + fr_as_binary_le randomness_value param:randomness_value + fr_as_binary_le randomness_asset param:randomness_asset + + # Make value commitment + # V = v * G_VCV + r * G_VCR + + ec_mul_const vcv value G_VCV + ec_mul_const rcv randomness_value G_VCR + ec_add cv vcv rcv + # emit cv + emit_ec cv + + # Make asset_id commitment + # A = a * G_VCV + r * G_VCR + + ec_mul_const vca asset_id G_VCV + ec_mul_const rca randomness_asset G_VCR + ec_add ca vca rca + # emit ca + emit_ec ca + + # Make the nullifier + # N = Hash(secret, serial) + fr_as_binary_le serial param:serial + fr_as_binary_le secret param:secret + + alloc_binary nf_preimage + +# Fr values are 252 bits so we need to pad it with extra 0s +# to match the Rust values which are 256 bits +{% macro binary_put_fr(binary, var) -%} + binary_extend {{ binary }} {{ var }} + {% for n in range(4) %} + alloc_const_bit zero_bit false + binary_push {{ binary }} zero_bit + {% endfor %} +{%- endmacro %} + + # secret + binary_clone secret2 secret + {{ binary_put_fr("nf_preimage", "secret2") }} + + # serial + binary_clone serial2 serial + {{ binary_put_fr("nf_preimage", "serial2") }} + + # Secret: Fr = 252 + 4 bits padding + # Serial: Fr = 252 + 4 bits padding + # TOTAL: 512 bits for preimage + static_assert_binary_size nf_preimage 512 + blake2s nf nf_preimage PRF_NF + emit_binary nf + + # Derive the public key + # P = secret * G + ec_mul_const public secret G_SPEND + + # Make the coin (same as mint contract) + # C = Hash(public_key, value, asset_id, serial, randomness_coin) + fr_as_binary_le randomness_coin param:randomness_coin + + # Build the preimage to hash + alloc_binary preimage + + # public_key + ec_repr repr_public public + binary_extend preimage repr_public + + # value + binary_extend preimage value + + # serial + {{ binary_put_fr("preimage", "serial") }} + + # randomness_coin + {{ binary_put_fr("preimage", "randomness_coin") }} + + # asset_id + {{ binary_put_fr("preimage", "asset_id") }} + + # Public key: SubgroupPoint = 256 bits + # Value: u64 = 64 bits + # AssetID: Fr = 252 + 4 bits padding + # Serial: Fr = 252 + 4 bits padding + # Randomness coin Fr = 252 + 4 bits padding + # TOTAL: 1088 bits for preimage + static_assert_binary_size preimage 1088 + blake2s coin preimage CRH_IVK + # Debug stuff. Normally we don't reveal the coin in the spend proof. + #binary_clone coin2 coin + #emit_binary coin2 + + # coin_commit = PedersenHash(coin) + pedersen_hash cm coin NOTE_COMMIT + # left = coin_commit.u + ec_get_u current cm + + # Our merkle tree has a height of 32 +{% for i in range(32) %} + # left = current + # right = branch[{{ i }}] + alloc_scalar branch param:branch_{{ i }} + + # is_right = is_right[{{ i }}] + alloc_bit is_right param:is_right_{{ i }} + + # reverse(a, b, condition) = if condition (b, a) else (a, b) + conditionally_reverse left right current branch is_right + + # coin_commit = PedersenHash(left || right) + scalar_as_binary left left + scalar_as_binary right right + alloc_binary preimage + binary_extend preimage left + binary_extend preimage right + pedersen_hash cm preimage MERKLE_{{ i }} + # current = coin_commit.u + ec_get_u current cm +{% endfor %} + # Reveal the merkle root + emit_scalar current + + # Emit the signature public key + fr_as_binary_le signature_secret param:signature_secret + ec_mul_const signature_public signature_secret G_SPEND + emit_ec signature_public +end + diff --git a/script/run_demo.sh b/script/run_demo.sh new file mode 100755 index 000000000..60d2ba5b8 --- /dev/null +++ b/script/run_demo.sh @@ -0,0 +1,74 @@ +#!/bin/bash + + +arg=$1 +gatewayd_path="./target/release/gatewayd" +cashierd_path="./target/release/cashierd" +darkfid_path="./target/release/darkfid" +drk_path="./target/release/drk" + +echo Running demo... + +if [ "$arg" = "-d" ]; then + echo DEBUG MODE + gatewayd_path="./target/debug/gatewayd" + cashierd_path="./target/debug/cashierd" + darkfid_path="./target/debug/darkfid" + drk_path="./target/debug/drk" +fi + +echo Open new tab and run: +echo " $ " $drk_path --help + +trap cleanup SIGINT + +function cleanup() +{ + screen -X -S "gatewayd" quit + screen -X -S "cashierd" quit + screen -X -S "darkfid" quit + echo Exit demo... +} + +# Start gateway daemon +screen -S "gatewayd" -dm "$gatewayd_path" -v +status=$? +if [ $status -ne 0 ]; then + echo "Failed to start gateway daemon: $status" + exit $status +fi + +# Start cashier daemon +screen -S "cashierd" -dm "$cashierd_path" -v +status=$? +if [ $status -ne 0 ]; then + echo "Failed to start cashier daemon: $status" + exit $status +fi + +# Start darkfi daemon +screen -S "darkfid" -dm "$darkfid_path" -v +status=$? +if [ $status -ne 0 ]; then + echo "Failed to start darkfi daemon: $status" + exit $status +fi + +# Exit with an error if it detects that either of the processes has exited. +# Otherwise it loops forever, waking up every 60 seconds +while sleep 60; do + ps aux |grep "gatewayd" |grep -q -v grep + PROCESS_1_STATUS=$? + ps aux |grep "cashierd" |grep -q -v grep + PROCESS_2_STATUS=$? + ps aux |grep "darkfid" |grep -q -v grep + PROCESS_3_STATUS=$? + + if [ $PROCESS_1_STATUS -ne 0 -o $PROCESS_2_STATUS -ne 0 -o $PROCESS_3_STATUS -ne 0 ]; then + echo "One of the processes has already exited." + cleanup + exit 1 + fi +done + +