Просмотр исходного кода

Merge branch 'master' of https://github.com/darkrenaissance/darkfi

mohab 4 лет назад
Родитель
Сommit
8895116a1e
63 измененных файлов с 1889 добавлено и 875 удалено
  1. 79 109
      Cargo.lock
  2. 18 9
      Cargo.toml
  3. 2 1
      Makefile
  4. 9 14
      bin/cashierd/src/main.rs
  5. 7 16
      bin/darkfid/src/main.rs
  6. 7 16
      bin/drk/src/main.rs
  7. 7 16
      bin/gatewayd/src/main.rs
  8. 2 2
      bin/ircd/Cargo.toml
  9. 14 39
      bin/ircd/src/main.rs
  10. 1 1
      bin/ircd/src/protocol_privmsg.rs
  11. 2 2
      bin/map/src/lib.rs
  12. 50 47
      bin/map/src/main.rs
  13. 17 12
      bin/map/src/model.rs
  14. 5 3
      contrib/zk.lua
  15. 110 0
      example/dao.rs
  16. BIN
      lc.file
  17. 66 0
      proof/arithmetic.rs
  18. 14 0
      proof/arithmetic.zk
  19. 6 5
      proof/burn.rs
  20. 2 2
      proof/burn.zk
  21. 516 0
      proof/dao.rs
  22. 46 0
      proof/dao.zk
  23. 4 4
      proof/mint.rs
  24. 1 1
      proof/mint.zk
  25. 29 1
      src/cli/cli_config.rs
  26. 9 0
      src/cli/cli_parser.rs
  27. 1 1
      src/cli/mod.rs
  28. 5 5
      src/crypto/coin.rs
  29. 11 1
      src/crypto/constants.rs
  30. 100 153
      src/crypto/constants/fixed_bases.rs
  31. 11 13
      src/crypto/constants/fixed_bases/commit_ivk_r.rs
  32. 13 16
      src/crypto/constants/fixed_bases/note_commit_r.rs
  33. 9 13
      src/crypto/constants/fixed_bases/nullifier_k.rs
  34. 9 10
      src/crypto/constants/fixed_bases/spend_auth_g.rs
  35. 9 12
      src/crypto/constants/fixed_bases/value_commit_r.rs
  36. 11 15
      src/crypto/constants/fixed_bases/value_commit_v.rs
  37. 257 0
      src/crypto/constants/load.rs
  38. 32 55
      src/crypto/constants/sinsemilla.rs
  39. 2 10
      src/crypto/constants/util.rs
  40. 17 15
      src/crypto/keypair.rs
  41. 2 3
      src/crypto/merkle_node.rs
  42. 9 12
      src/crypto/mint_proof.rs
  43. 0 1
      src/crypto/mod.rs
  44. 7 6
      src/crypto/nullifier.rs
  45. 17 15
      src/crypto/proof.rs
  46. 10 6
      src/crypto/schnorr.rs
  47. 10 14
      src/crypto/spend_proof.rs
  48. 13 2
      src/crypto/util.rs
  49. 3 10
      src/error.rs
  50. 1 1
      src/net/message.rs
  51. 1 1
      src/net/mod.rs
  52. 6 11
      src/net/protocol/protocol_registry.rs
  53. 3 3
      src/node/service/gateway_p2p.rs
  54. 23 18
      src/zk/arith_chip.rs
  55. 30 32
      src/zk/circuit/mint_contract.rs
  56. 54 55
      src/zk/circuit/spend_contract.rs
  57. 5 1
      src/zk/mod.rs
  58. 95 55
      src/zk/vm.rs
  59. 25 7
      src/zk/vm_stack.rs
  60. 1 1
      src/zkas/error.rs
  61. 16 2
      src/zkas/opcode.rs
  62. 38 0
      src/zkas/parser.rs
  63. 10 0
      src/zkas/types.rs

+ 79 - 109
Cargo.lock

@@ -462,16 +462,6 @@ version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cf9ff0bbfd639f15c74af777d81383cf53efb7c93613f6cab67c6c11e05bbf8b"
 
-[[package]]
-name = "bigint"
-version = "4.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0e8c8a600052b52482eff2cf4d810e462fdff1f656ac1ecb6232132a1ed7def"
-dependencies = [
- "byteorder",
- "crunchy 0.1.6",
-]
-
 [[package]]
 name = "bincode"
 version = "1.3.3"
@@ -548,10 +538,22 @@ version = "0.22.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5237f00a8c86130a0cc317830e558b966dd7850d48a953d998c813f01a41b527"
 dependencies = [
- "funty",
- "radium",
+ "funty 1.2.0",
+ "radium 0.6.2",
  "tap",
- "wyz",
+ "wyz 0.4.0",
+]
+
+[[package]]
+name = "bitvec"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1489fcb93a5bb47da0462ca93ad252ad6af2145cce58d10d46a83931ba9f016b"
+dependencies = [
+ "funty 2.0.0",
+ "radium 0.7.0",
+ "tap",
+ "wyz 0.5.0",
 ]
 
 [[package]]
@@ -629,17 +631,6 @@ dependencies = [
  "once_cell",
 ]
 
-[[package]]
-name = "bls12_381"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d28daeeded7949f1c7c72693377c98473b00be0aa0023760a84a300e4e7c74b"
-dependencies = [
- "ff",
- "rand_core 0.6.3",
- "subtle",
-]
-
 [[package]]
 name = "borsh"
 version = "0.9.1"
@@ -705,9 +696,9 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.9.1"
+version = "3.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
+checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
 
 [[package]]
 name = "bv"
@@ -1241,12 +1232,6 @@ dependencies = [
  "lazy_static",
 ]
 
-[[package]]
-name = "crunchy"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda"
-
 [[package]]
 name = "crunchy"
 version = "0.2.2"
@@ -1364,6 +1349,7 @@ dependencies = [
  "async-trait",
  "async-tungstenite",
  "bincode",
+ "bitvec 1.0.0",
  "blake2b_simd 1.0.0",
  "bs58",
  "bytes",
@@ -1372,8 +1358,8 @@ dependencies = [
  "dirs 4.0.0",
  "futures",
  "group",
- "halo2",
  "halo2_gadgets",
+ "halo2_proofs",
  "hex",
  "incrementalmerkletree",
  "indexmap",
@@ -1855,7 +1841,7 @@ version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b2958d04124b9f27f175eaeb9a9f383d026098aa837eadd8ba22c11f13a05b9e"
 dependencies = [
- "bitvec",
+ "bitvec 0.22.3",
  "rand_core 0.6.3",
  "subtle",
 ]
@@ -2007,6 +1993,12 @@ version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e"
 
+[[package]]
+name = "funty"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
+
 [[package]]
 name = "futures"
 version = "0.3.19"
@@ -2259,42 +2251,39 @@ dependencies = [
 ]
 
 [[package]]
-name = "halo2"
-version = "0.1.0-beta.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f186b85ed81082fb1cf59d52b0111f02915e89a4ac61d292b38d075e570f3a9"
+name = "halo2_gadgets"
+version = "0.0.0"
+source = "git+https://github.com/zcash/halo2?branch=main#9617336d46a18f3949260731d02bd711fba9d863"
 dependencies = [
- "backtrace",
- "blake2b_simd 0.5.11",
+ "arrayvec 0.7.2",
+ "bitvec 0.22.3",
  "ff",
  "group",
+ "halo2_proofs",
+ "lazy_static",
  "pasta_curves",
  "plotters",
+ "proptest",
  "rand 0.8.4",
- "rayon",
- "tabbycat",
+ "subtle",
+ "uint",
 ]
 
 [[package]]
-name = "halo2_gadgets"
-version = "0.0.0"
-source = "git+https://github.com/parazyd/halo2_gadgets.git?rev=b45c527276bb2309f3b256eb5f45ccdcc5bd8c0f#b45c527276bb2309f3b256eb5f45ccdcc5bd8c0f"
+name = "halo2_proofs"
+version = "0.1.0-beta.1"
+source = "git+https://github.com/zcash/halo2?branch=main#9617336d46a18f3949260731d02bd711fba9d863"
 dependencies = [
- "arrayvec 0.7.2",
- "bigint",
- "bitvec",
+ "backtrace",
+ "blake2b_simd 1.0.0",
+ "bumpalo",
  "ff",
  "group",
- "halo2",
- "lazy_static",
- "memuse",
- "nonempty",
  "pasta_curves",
  "plotters",
- "proptest",
- "rand 0.8.4",
- "reddsa",
- "subtle",
+ "rand_core 0.6.3",
+ "rayon",
+ "tabbycat",
 ]
 
 [[package]]
@@ -2309,7 +2298,7 @@ version = "0.15.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "92c171d55b98633f4ed3860808f004099b36c1cc29c42cfc53aa8591b21efcf2"
 dependencies = [
- "crunchy 0.2.2",
+ "crunchy",
 ]
 
 [[package]]
@@ -2585,7 +2574,7 @@ dependencies = [
  "async-executor",
  "async-std",
  "async-trait",
- "clap 2.34.0",
+ "clap 3.0.7",
  "darkfi",
  "futures",
  "log",
@@ -2655,20 +2644,6 @@ dependencies = [
  "serde_json",
 ]
 
-[[package]]
-name = "jubjub"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2e7baec19d4e83f9145d4891178101a604565edff9645770fc979804138b04c"
-dependencies = [
- "bitvec",
- "bls12_381",
- "ff",
- "group",
- "rand_core 0.6.3",
- "subtle",
-]
-
 [[package]]
 name = "keccak"
 version = "0.1.0"
@@ -2759,7 +2734,7 @@ version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80"
 dependencies = [
- "crunchy 0.2.2",
+ "crunchy",
  "digest 0.9.0",
  "subtle",
 ]
@@ -2880,15 +2855,6 @@ dependencies = [
  "autocfg 1.0.1",
 ]
 
-[[package]]
-name = "memuse"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f69d25cd7528769ad3d897e99eb942774bff8b23165012af490351a44c5b583b"
-dependencies = [
- "nonempty",
-]
-
 [[package]]
 name = "mime"
 version = "0.3.16"
@@ -2994,12 +2960,6 @@ dependencies = [
  "version_check",
 ]
 
-[[package]]
-name = "nonempty"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7"
-
 [[package]]
 name = "ntapi"
 version = "0.3.6"
@@ -3237,11 +3197,11 @@ dependencies = [
 
 [[package]]
 name = "pasta_curves"
-version = "0.2.1"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d647d91972bad78120fd61e06b225fcda117805c9bbf17676b51bd03a251278b"
+checksum = "82b6fc4f73033f6aa52fdde0c38f1f570e7f2c244f22e441f62a144556891b8c"
 dependencies = [
- "blake2b_simd 0.5.11",
+ "blake2b_simd 1.0.0",
  "ff",
  "group",
  "lazy_static",
@@ -3569,6 +3529,12 @@ version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb"
 
+[[package]]
+name = "radium"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
+
 [[package]]
 name = "rand"
 version = "0.6.5"
@@ -3799,23 +3765,6 @@ dependencies = [
  "rand_core 0.3.1",
 ]
 
-[[package]]
-name = "reddsa"
-version = "0.0.0"
-source = "git+https://github.com/str4d/redjubjub.git?rev=416a6a8ebf8bd42c114c938883016c04f338de72#416a6a8ebf8bd42c114c938883016c04f338de72"
-dependencies = [
- "blake2b_simd 0.5.11",
- "byteorder",
- "digest 0.9.0",
- "group",
- "jubjub",
- "pasta_curves",
- "rand_core 0.6.3",
- "serde",
- "thiserror",
- "zeroize",
-]
-
 [[package]]
 name = "redox_syscall"
 version = "0.1.57"
@@ -5400,7 +5349,7 @@ version = "2.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
 dependencies = [
- "crunchy 0.2.2",
+ "crunchy",
 ]
 
 [[package]]
@@ -5567,6 +5516,18 @@ version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
 
+[[package]]
+name = "uint"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6470ab50f482bde894a037a57064480a246dbfdd5960bd65a44824693f08da5f"
+dependencies = [
+ "byteorder",
+ "crunchy",
+ "hex",
+ "static_assertions",
+]
+
 [[package]]
 name = "unicode-bidi"
 version = "0.3.7"
@@ -5940,6 +5901,15 @@ dependencies = [
  "tap",
 ]
 
+[[package]]
+name = "wyz"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30b31594f29d27036c383b53b59ed3476874d518f0efb151b27a4c275141390e"
+dependencies = [
+ "tap",
+]
+
 [[package]]
 name = "xattr"
 version = "0.2.2"

+ 18 - 9
Cargo.toml

@@ -67,15 +67,17 @@ tungstenite = {version = "0.16.0", optional = true}
 async-tungstenite = {version = "0.16.1", optional = true}
 
 # Crypto
+bitvec = {version = "1.0.0", optional = true}
 rand = {version = "0.8.4", optional = true}
 sha2 = {version = "0.10.1", optional = true}
 group = {version = "0.11.0", optional = true}
 arrayvec = {version = "0.7.2", optional = true}
 blake2b_simd = {version = "1.0.0", optional = true}
-pasta_curves = {version = "0.2.1", optional = true}
+pasta_curves = {version = "0.3.0", optional = true}
 crypto_api_chachapoly = {version = "0.5.0", optional = true}
 incrementalmerkletree = {version = "0.2.0", optional = true}
-halo2 = {version = "=0.1.0-beta.1", features = ["dev-graph", "gadget-traces", "sanity-checks"], optional = true}
+halo2_proofs = {git = "https://github.com/zcash/halo2", branch = "main", features = ["dev-graph", "gadget-traces", "sanity-checks"], optional = true}
+halo2_gadgets = {git = "https://github.com/zcash/halo2", branch = "main", features = ["dev-graph", "test-dependencies"], optional = true}
 
 # Wallet management
 sqlx = {version = "0.5.10", features = ["runtime-async-std-native-tls", "sqlite"], optional = true}
@@ -100,12 +102,6 @@ default-features = false
 features = ["zstd"]
 optional = true
 
-[dependencies.halo2_gadgets]
-# TODO: Use upstream when published
-git = "https://github.com/parazyd/halo2_gadgets.git"
-rev = "b45c527276bb2309f3b256eb5f45ccdcc5bd8c0f"
-features = ["dev-graph", "test-dependencies"]
-optional = true
 
 [features]
 async-runtime = [
@@ -178,11 +174,12 @@ net = [
 ]
 
 crypto = [
+    "bitvec",
     "rand",
     "pasta_curves",
     "blake2b_simd",
     "incrementalmerkletree",
-    "halo2",
+    "halo2_proofs",
     "halo2_gadgets",
     "subtle",
     "lazy_static",
@@ -244,6 +241,13 @@ name = "tree"
 path = "example/tree.rs"
 required-features = ["crypto"]
 
+# ZK VM Proof examples
+
+[[example]]
+name = "arithmetic"
+path = "proof/arithmetic.rs"
+required-features = ["cli", "crypto", "zkas"]
+
 [[example]]
 name = "mint"
 path = "proof/mint.rs"
@@ -253,3 +257,8 @@ required-features = ["cli", "crypto", "zkas"]
 name = "burn"
 path = "proof/burn.rs"
 required-features = ["cli", "crypto", "zkas"]
+
+[[example]]
+name = "dao"
+path = "proof/dao.rs"
+required-features = ["cli", "crypto", "zkas"]

+ 2 - 1
Makefile

@@ -39,13 +39,14 @@ test: test-vm test-tx
 test-tx:
 	$(CARGO) run --release --features=node,zkas --example tx
 
-VM_SRC = proof/mint.zk proof/burn.zk
+VM_SRC = proof/arithmetic.zk proof/mint.zk proof/burn.zk
 VM_BIN = $(VM_SRC:=.bin)
 
 $(VM_BIN): zkas $(VM_SRC)
 	./zkas $(basename $@) -o $@
 
 test-vm: $(VM_BIN)
+	$(CARGO) run --release --features=cli,crypto,zkas --example arithmetic
 	$(CARGO) run --release --features=cli,crypto,zkas --example mint
 	$(CARGO) run --release --features=cli,crypto,zkas --example burn
 

+ 9 - 14
bin/cashierd/src/main.rs

@@ -12,7 +12,10 @@ use simplelog::{ColorChoice, LevelFilter, TermLogger, TerminalMode};
 
 use darkfi::{
     blockchain::{rocks::columns, Rocks, RocksColumn},
-    cli::{cli_config::spawn_config, CashierdConfig, CliCashierd, Config},
+    cli::{
+        cli_config::{log_config, spawn_config},
+        CashierdConfig, CliCashierd, Config,
+    },
     crypto::{
         address::Address,
         keypair::{PublicKey, SecretKey},
@@ -679,20 +682,12 @@ async fn main() -> Result<()> {
     // Spawn config file if it's not in place already.
     spawn_config(&config_path, CONFIG_FILE_CONTENTS)?;
 
-    let mut verbosity_level = 0;
-    verbosity_level += matches.occurrences_of("verbose");
-    let loglevel = match verbosity_level {
-        0 => LevelFilter::Info,
-        1 => LevelFilter::Debug,
-        _ => LevelFilter::Trace,
-    };
+    let conf: simplelog::Config;
+    let lvl: LevelFilter;
+
+    (lvl, conf) = log_config(matches)?;
 
-    TermLogger::init(
-        loglevel,
-        simplelog::Config::default(),
-        TerminalMode::Mixed,
-        ColorChoice::Auto,
-    )?;
+    TermLogger::init(lvl, conf, TerminalMode::Mixed, ColorChoice::Auto)?;
 
     let config: CashierdConfig = Config::<CashierdConfig>::load(config_path)?;
 

+ 7 - 16
bin/darkfid/src/main.rs

@@ -8,12 +8,15 @@ use easy_parallel::Parallel;
 use log::{debug, info};
 use num_bigint::BigUint;
 use serde_json::{json, Value};
-use simplelog::{ColorChoice, LevelFilter, TermLogger, TerminalMode};
+use simplelog::{ColorChoice, TermLogger, TerminalMode};
 use url::Url;
 
 use darkfi::{
     blockchain::{rocks::columns, Rocks, RocksColumn},
-    cli::{cli_config::spawn_config, CliDarkfid, Config, DarkfidConfig},
+    cli::{
+        cli_config::{log_config, spawn_config},
+        CliDarkfid, Config, DarkfidConfig,
+    },
     crypto::{
         address::Address,
         keypair::{Keypair, PublicKey, SecretKey},
@@ -815,20 +818,8 @@ async fn main() -> Result<()> {
     // Spawn config file if it's not in place already.
     spawn_config(&config_path, CONFIG_FILE_CONTENTS)?;
 
-    let mut verbosity_level = 0;
-    verbosity_level += matches.occurrences_of("verbose");
-    let loglevel = match verbosity_level {
-        0 => LevelFilter::Info,
-        1 => LevelFilter::Debug,
-        _ => LevelFilter::Trace,
-    };
-
-    TermLogger::init(
-        loglevel,
-        simplelog::Config::default(),
-        TerminalMode::Mixed,
-        ColorChoice::Auto,
-    )?;
+    let (lvl, conf) = log_config(matches)?;
+    TermLogger::init(lvl, conf, TerminalMode::Mixed, ColorChoice::Auto)?;
 
     let config: DarkfidConfig = Config::<DarkfidConfig>::load(config_path)?;
 

+ 7 - 16
bin/drk/src/main.rs

@@ -4,10 +4,13 @@ use clap::{IntoApp, Parser};
 use log::{debug, error};
 use prettytable::{cell, format, row, Table};
 use serde_json::{json, Value};
-use simplelog::{ColorChoice, LevelFilter, TermLogger, TerminalMode};
+use simplelog::{ColorChoice, TermLogger, TerminalMode};
 
 use darkfi::{
-    cli::{cli_config::spawn_config, CliDrk, CliDrkSubCommands, Config, DrkConfig},
+    cli::{
+        cli_config::{log_config, spawn_config},
+        CliDrk, CliDrkSubCommands, Config, DrkConfig,
+    },
     rpc::{jsonrpc, jsonrpc::JsonResult},
     util::{join_config_path, path::expand_path, NetworkName},
     Error, Result,
@@ -361,20 +364,8 @@ async fn main() -> Result<()> {
     // Spawn config file if it's not in place already.
     spawn_config(&config_path, CONFIG_FILE_CONTENTS)?;
 
-    let mut verbosity_level = 0;
-    verbosity_level += matches.occurrences_of("verbose");
-    let loglevel = match verbosity_level {
-        0 => LevelFilter::Info,
-        1 => LevelFilter::Debug,
-        _ => LevelFilter::Trace,
-    };
-
-    TermLogger::init(
-        loglevel,
-        simplelog::Config::default(),
-        TerminalMode::Mixed,
-        ColorChoice::Auto,
-    )?;
+    let (lvl, conf) = log_config(matches)?;
+    TermLogger::init(lvl, conf, TerminalMode::Mixed, ColorChoice::Auto)?;
 
     let config = Config::<DrkConfig>::load(config_path)?;
 

+ 7 - 16
bin/gatewayd/src/main.rs

@@ -4,11 +4,14 @@ use async_executor::Executor;
 use clap::{IntoApp, Parser};
 use easy_parallel::Parallel;
 use log::debug;
-use simplelog::{ColorChoice, LevelFilter, TermLogger, TerminalMode};
+use simplelog::{ColorChoice, TermLogger, TerminalMode};
 
 use darkfi::{
     blockchain::{rocks::columns, Rocks, RocksColumn},
-    cli::{cli_config::spawn_config, CliGatewayd, Config, GatewaydConfig},
+    cli::{
+        cli_config::{log_config, spawn_config},
+        CliGatewayd, Config, GatewaydConfig,
+    },
     node::service::gateway::GatewayService,
     util::{expand_path, join_config_path},
     Result,
@@ -43,20 +46,8 @@ async fn main() -> Result<()> {
     // Spawn config file if it's not in place already.
     spawn_config(&config_path, CONFIG_FILE_CONTENTS)?;
 
-    let mut verbosity_level = 0;
-    verbosity_level += matches.occurrences_of("verbose");
-    let loglevel = match verbosity_level {
-        0 => LevelFilter::Info,
-        1 => LevelFilter::Debug,
-        _ => LevelFilter::Trace,
-    };
-
-    TermLogger::init(
-        loglevel,
-        simplelog::Config::default(),
-        TerminalMode::Mixed,
-        ColorChoice::Auto,
-    )?;
+    let (lvl, conf) = log_config(matches)?;
+    TermLogger::init(lvl, conf, TerminalMode::Mixed, ColorChoice::Auto)?;
 
     let config: GatewaydConfig = Config::<GatewaydConfig>::load(config_path)?;
 

+ 2 - 2
bin/ircd/Cargo.toml

@@ -5,7 +5,7 @@ edition = "2021"
 
 [dependencies.darkfi]
 path = "../../"
-features = ["net", "rpc"]
+features = ["net", "rpc", "cli"]
 
 [dependencies]
 # Async
@@ -20,7 +20,7 @@ async-executor = "1.4.1"
 rand = "0.8.4"
 
 # Misc
-clap = "2.34.0"
+clap = "3.0.7"
 log = "0.4.14"
 simplelog = "0.11.2"
 

+ 14 - 39
bin/ircd/src/main.rs

@@ -3,6 +3,7 @@ extern crate clap;
 use async_executor::Executor;
 use async_std::io::BufReader;
 use async_trait::async_trait;
+use clap::{ArgMatches, IntoApp};
 use futures::{AsyncBufReadExt, AsyncReadExt, FutureExt};
 use log::{debug, error, info, warn};
 use serde_json::{json, Value};
@@ -14,6 +15,7 @@ use std::{
 };
 
 use darkfi::{
+    cli::{cli_config::log_config, cli_parser::CliIrcd},
     net,
     rpc::{
         jsonrpc::{error as jsonerr, response as jsonresp, ErrorCode::*, JsonRequest, JsonResult},
@@ -135,15 +137,13 @@ async fn start(executor: Arc<Executor<'_>>, options: ProgramOptions) -> Result<(
     let (sender, recvr) = async_channel::unbounded();
     let seen_privmsg_ids2 = seen_privmsg_ids.clone();
     let sender2 = sender.clone();
-    registry.register(
-        !net::SESSION_SEED,
-        move |channel, p2p| {
+    registry
+        .register(!net::SESSION_SEED, move |channel, p2p| {
             let sender = sender2.clone();
             let seen_privmsg_ids = seen_privmsg_ids2.clone();
-            async move {
-                ProtocolPrivMsg::new(channel, sender, seen_privmsg_ids, p2p).await
-            }
-        }).await;
+            async move { ProtocolPrivMsg::new(channel, sender, seen_privmsg_ids, p2p).await }
+        })
+        .await;
 
     //
     // p2p network main instance
@@ -217,41 +217,16 @@ impl JsonRpcInterface {
     async fn say_hello(&self, id: Value, _params: Value) -> JsonResult {
         JsonResult::Resp(jsonresp(json!("hello world"), id))
     }
-
-    //--> {"jsonrpc": "2.0", "method": "poll", "params": [], "id": 42}
-    // <-- {"jsonrpc": "2.0", "result": {"nodeID": [], "nodeinfo" [], "id": 42}
-    async fn get_info(&self, id: Value, _params: Value) -> JsonResult {
-        let resp: serde_json::Value = json!({
-            "nodes": [{
-                "id": "dfk34123kl213kp213sd",
-                "connections": 1,
-                "message": "gm",
-                "is_active": true,
-            },
-            {
-                "id": "138032139034903499s8",
-                "connections": 3,
-                "message": "ok",
-                "is_active": false,
-            },
-            {
-                "id": "123423ml1k2j3ll123kl",
-                "connections": 6,
-                "message": "lol",
-                "is_active": true,
-            }]
-        });
-        JsonResult::Resp(jsonresp(resp, id))
-    }
 }
 
 fn main() -> Result<()> {
-    TermLogger::init(
-        LevelFilter::Debug,
-        simplelog::Config::default(),
-        TerminalMode::Mixed,
-        ColorChoice::Auto,
-    )?;
+    let matches = CliIrcd::into_app().get_matches();
+    let conf: simplelog::Config;
+    let lvl: LevelFilter;
+
+    (lvl, conf) = log_config(matches)?;
+
+    TermLogger::init(lvl, conf, TerminalMode::Mixed, ColorChoice::Auto)?;
 
     let options = ProgramOptions::load()?;
 

+ 1 - 1
bin/ircd/src/protocol_privmsg.rs

@@ -1,5 +1,5 @@
-use async_trait::async_trait;
 use async_executor::Executor;
+use async_trait::async_trait;
 
 use darkfi::{net, Result};
 use log::debug;

+ 2 - 2
bin/map/src/lib.rs

@@ -1,7 +1,7 @@
 pub mod model;
 pub mod ui;
-pub mod view;
+//pub mod view;
 
 pub use model::{IdList, InfoList, Model, NodeInfo};
 pub use ui::ui;
-pub use view::{IdListView, InfoListView, View};
+//pub use view::{IdListView, InfoListView, View};

+ 50 - 47
bin/map/src/main.rs

@@ -79,48 +79,43 @@ async fn main() -> Result<()> {
 
     terminal.clear()?;
 
-    let infos = vec![
-        NodeInfo {
-            id: "0385048034sodisofjhosd1111q3434".to_string(),
-            connections: 10,
-            is_active: true,
-            last_message: "hey how are you?".to_string(),
-        },
-        NodeInfo {
-            id: "09w30we9wsnfksdfkdjflsjkdfjdfsd".to_string(),
-            connections: 5,
-            is_active: false,
-            last_message: "lmao".to_string(),
-        },
-        NodeInfo {
-            id: "038043325alsdlasjfrsdfsdfsdjsdf".to_string(),
-            connections: 7,
-            is_active: true,
-            last_message: "gm".to_string(),
-        },
-        NodeInfo {
-            id: "04985034953ldflsdjflsdjflsdjfii".to_string(),
-            connections: 2,
-            is_active: true,
-            last_message: "hihi".to_string(),
-        },
-        NodeInfo {
-            id: "09850249352asdjapsdikalskasdkas".to_string(),
-            connections: 10,
-            is_active: true,
-            last_message: "wtf".to_string(),
-        },
-    ];
+    let infos = vec![NodeInfo::new()];
+    //let infos = vec![
+    //    NodeInfo {
+    //        id: "0385048034sodisofjhosd1111q3434".to_string(),
+    //        connections: 10,
+    //        is_active: true,
+    //        last_message: "hey how are you?".to_string(),
+    //    },
+    //    NodeInfo {
+    //        id: "09w30we9wsnfksdfkdjflsjkdfjdfsd".to_string(),
+    //        connections: 5,
+    //        is_active: false,
+    //        last_message: "lmao".to_string(),
+    //    },
+    //    NodeInfo {
+    //        id: "038043325alsdlasjfrsdfsdfsdjsdf".to_string(),
+    //        connections: 7,
+    //        is_active: true,
+    //        last_message: "gm".to_string(),
+    //    },
+    //    NodeInfo {
+    //        id: "04985034953ldflsdjflsdjflsdjfii".to_string(),
+    //        connections: 2,
+    //        is_active: true,
+    //        last_message: "hihi".to_string(),
+    //    },
+    //    NodeInfo {
+    //        id: "09850249352asdjapsdikalskasdkas".to_string(),
+    //        connections: 10,
+    //        is_active: true,
+    //        last_message: "wtf".to_string(),
+    //    },
+    //];
 
     let info_list = InfoList::new(infos.clone());
 
-    let ids = vec![
-        infos[0].id.clone(),
-        infos[1].id.clone(),
-        infos[2].id.clone(),
-        infos[3].id.clone(),
-        infos[4].id.clone(),
-    ];
+    let ids = vec![String::new()];
 
     let id_list = IdList::new(ids);
 
@@ -156,25 +151,33 @@ async fn run_rpc(ex: Arc<Executor<'_>>, model: Arc<Model>) -> Result<()> {
     Ok(())
 }
 
-async fn poll(client: Map, _model: Arc<Model>) -> Result<()> {
+async fn poll(client: Map, model: Arc<Model>) -> Result<()> {
     loop {
         let reply = client.get_info().await?;
 
         if reply.as_object().is_some() && !reply.as_object().unwrap().is_empty() {
             let nodes = reply.as_object().unwrap().get("nodes").unwrap();
 
+            // todo: generalize this
             let node1 = &nodes[0];
-            let node2 = &nodes[1];
-            let node3 = &nodes[2];
+            //let node2 = &nodes[1];
+            //let node3 = &nodes[2];
 
-            let _infos = vec![NodeInfo {
+            // TODO: error handling
+            let infos = vec![NodeInfo {
                 id: node1["id"].to_string(),
                 connections: node1["connections"].as_u64().unwrap() as usize,
-                is_active: node2["is_active"].as_bool().unwrap(),
-                last_message: node3["message"].to_string(),
+                is_active: node1["is_active"].as_bool().unwrap(),
+                last_message: node1["message"].to_string(),
             }];
 
-            //model.lock().await.update(infos).await;
+            //model.update(infos).await;
+
+            for node in infos {
+                model.id_list.node_id.lock().await.push(node.id);
+                //self.info_list.infos.lock().await.push(node.info);
+                //self.id_list.
+            }
         } else {
             // TODO: error handling
             println!("Reply is an error");
@@ -219,7 +222,7 @@ async fn render<B: Backend>(terminal: &mut Terminal<B>, model: Arc<Model>) -> io
             match k.unwrap() {
                 Key::Char('q') => {
                     terminal.clear()?;
-                    return Ok(());
+                    return Ok(())
                 }
                 Key::Char('j') => {
                     view.id_list.next();

+ 17 - 12
bin/map/src/model.rs

@@ -1,4 +1,5 @@
 use async_std::sync::Mutex;
+use darkfi::error::{Error, Result};
 use tui::widgets::ListState;
 
 pub struct Model {
@@ -11,21 +12,25 @@ impl Model {
         Model { id_list, info_list }
     }
 
-    pub async fn update(self, node_vec: Vec<NodeInfo>) -> Model {
-        let ids = vec![node_vec[0].id.clone()];
-
-        for id in ids {
-            self.id_list.node_id.lock().await.push(id);
+    pub async fn update(self, node_vec: Vec<NodeInfo>) -> Result<()> {
+        for node in node_vec {
+            self.id_list.node_id.lock().await.push(node.id);
+            //self.info_list.infos.lock().await.push(node.info);
+            //self.id_list.
         }
+        //let ids = vec![node_vec[0].id.clone()];
 
-        let id_list = self.id_list;
+        //for id in ids {
+        //    self.id_list.node_id.lock().await.push(id);
+        //}
 
-        for info in node_vec {
-            self.info_list.infos.lock().await.push(info);
-        }
-        let info_list = self.info_list;
+        //let id_list = self.id_list;
 
-        Model { id_list, info_list }
+        //for info in node_vec {
+        //    self.info_list.infos.lock().await.push(info);
+        //}
+        //let info_list = self.info_list;
+        Ok(())
     }
 }
 
@@ -56,7 +61,7 @@ impl InfoList {
     }
 }
 
-pub type NodeId = u32;
+//pub type NodeId = u32;
 
 #[derive(Clone)]
 pub struct NodeInfo {

+ 5 - 3
contrib/zk.lua

@@ -22,15 +22,17 @@ local keyword = token(l.KEYWORD, word_match{
 
 -- Types.
 local type = token(l.TYPE, word_match{
-  'EcPoint', 'EcFixedPoint', 'Base', 'BaseArray',
-  'Scalar', 'ScalarArray', 'MerklePath', 'Uint32',
-  'Uint64',
+  'EcPoint', 'EcFixedPoint', 'EcFixedPointBase', 'EcFixedPointShort',
+  'Base', 'BaseArray', 'Scalar', 'ScalarArray',
+  'MerklePath',
+  'Uint32', 'Uint64',
 })
 
 -- Instructions.
 local instruction = token('instruction', word_match{
   'ec_add', 'ec_mul', 'ec_mul_base', 'ec_mul_short',
   'ec_get_x', 'ec_get_y',
+  'base_add', 'base_mul',
   'poseidon_hash', 'calculate_merkle_root',
   'constrain_instance',
 })

+ 110 - 0
example/dao.rs

@@ -0,0 +1,110 @@
+use bitvec::prelude::*;
+use halo2_gadgets::primitives::{
+    poseidon,
+    poseidon::{ConstantLength, P128Pow5T3},
+};
+use incrementalmerkletree::{bridgetree::BridgeTree, Frontier, Tree};
+use pasta_curves::{
+    arithmetic::{CurveAffine, Field, FieldExt},
+    group::{Curve, Group},
+    pallas,
+};
+use rand::rngs::OsRng;
+use simplelog::{ColorChoice::Auto, Config, LevelFilter, TermLogger, TerminalMode::Mixed};
+
+use darkfi::{
+    crypto::{
+        keypair::Keypair,
+        merkle_node::MerkleNode,
+        schnorr::SchnorrSecret,
+        util::{mod_r_p, pedersen_commitment_scalar},
+    },
+    Result,
+};
+
+fn main() -> Result<()> {
+    let loglevel = match option_env!("RUST_LOG") {
+        Some("debug") => LevelFilter::Debug,
+        Some("trace") => LevelFilter::Trace,
+        Some(_) | None => LevelFilter::Info,
+    };
+    TermLogger::init(loglevel, Config::default(), Mixed, Auto)?;
+
+    /*
+    let bincode = include_bytes!("../proof/dao.zk.bin");
+    let zkbin = ZkBinary::decode(bincode)?;
+    */
+
+    // Contract address
+    let a = pallas::Base::random(&mut OsRng);
+    // Money in treasury
+    let t = pallas::Base::from(666);
+    // Serial number
+    let s = pallas::Base::random(&mut OsRng);
+    // Bulla blind
+    let b_b = pallas::Base::random(&mut OsRng);
+
+    let message = [a, t, s, b_b];
+    let hasher = poseidon::Hash::init(P128Pow5T3, ConstantLength::<4>);
+    let bulla = hasher.hash(message);
+
+    // Merkle tree of DAOs
+    let mut tree = BridgeTree::<MerkleNode, 32>::new(100);
+    let dao0 = pallas::Base::random(&mut OsRng);
+    let dao2 = pallas::Base::random(&mut OsRng);
+    tree.append(&MerkleNode(dao0));
+    tree.witness();
+    tree.append(&MerkleNode(bulla));
+    tree.witness();
+    tree.append(&MerkleNode(dao2));
+    tree.witness();
+
+    let (leaf_pos, merkle_path) = tree.authentication_path(&MerkleNode(bulla)).unwrap();
+    let leaf_pos: u64 = leaf_pos.into();
+    let leaf_pos = leaf_pos as u32;
+
+    // Output 0:
+    let output0_val = 42_u64;
+    let output0_dest = pallas::Point::random(&mut OsRng);
+    let output0_coords = output0_dest.to_affine().coordinates().unwrap();
+    let output0_blind = pallas::Base::random(&mut OsRng);
+
+    let message =
+        [pallas::Base::from(output0_val), *output0_coords.x(), *output0_coords.y(), output0_blind];
+    let hasher = poseidon::Hash::init(P128Pow5T3, ConstantLength::<4>);
+    let output0 = hasher.hash(message);
+
+    let authority = Keypair::random(&mut OsRng);
+    let signature = authority.secret.sign(&output0.to_bytes());
+
+    let vote_1 = pallas::Base::from(44);
+    let vote_2 = pallas::Base::from(13);
+    // This is a NO vote
+    let vote_3 = -pallas::Base::from(49);
+
+    let vote_1_blind = pallas::Scalar::random(&mut OsRng);
+    let vote_1_commit = pedersen_commitment_scalar(mod_r_p(vote_1), vote_1_blind);
+
+    let vote_2_blind = pallas::Scalar::random(&mut OsRng);
+    let vote_2_commit = pedersen_commitment_scalar(mod_r_p(vote_2), vote_2_blind);
+
+    let vote_3_blind = pallas::Scalar::random(&mut OsRng);
+    let vote_3_commit = pedersen_commitment_scalar(mod_r_p(vote_3), vote_3_blind);
+
+    let vote_commit = vote_1_commit + vote_2_commit + vote_3_commit;
+    let vote_blinds = vote_1_blind + vote_2_blind + vote_3_blind;
+    let vote_commit_coords = vote_commit.to_affine().coordinates().unwrap();
+
+    /*
+    let number = pallas::Base::from(u64::MAX).to_bytes();
+    let bits = number.view_bits::<Lsb0>();
+    println!("Positive: {:?}", bits);
+
+    //let number = (-pallas::Base::from(u64::MAX)).to_bytes();
+    let number = pallas::Base::from(0).to_bytes();
+    let bits = number.view_bits::<Lsb0>();
+    println!("Negative: {:?}", bits);
+    */
+
+    Ok(())
+}


+ 66 - 0
proof/arithmetic.rs

@@ -0,0 +1,66 @@
+use darkfi::{
+    crypto::{
+        proof::{ProvingKey, VerifyingKey},
+        Proof,
+    },
+    zk::vm::{Witness, ZkCircuit},
+    zkas::decoder::ZkBinary,
+    Result,
+};
+use log::info;
+use pasta_curves::pallas;
+use rand::rngs::OsRng;
+use simplelog::{ColorChoice::Auto, Config, LevelFilter, TermLogger, TerminalMode::Mixed};
+
+fn main() -> Result<()> {
+    let loglevel = match option_env!("RUST_LOG") {
+        Some("debug") => LevelFilter::Debug,
+        Some("trace") => LevelFilter::Trace,
+        Some(_) | None => LevelFilter::Info,
+    };
+    TermLogger::init(loglevel, Config::default(), Mixed, Auto)?;
+
+    /* ANCHOR: main */
+    let bincode = include_bytes!("arithmetic.zk.bin");
+    let zkbin = ZkBinary::decode(bincode)?;
+
+    // ======
+    // Prover
+    // ======
+
+    // Witness values
+    let a = pallas::Base::from(42);
+    let b = pallas::Base::from(69);
+
+    let prover_witnesses = vec![Witness::Base(Some(a)), Witness::Base(Some(b))];
+
+    // Create the public inputs
+    let sum = a + b;
+    let product = a * b;
+
+    let public_inputs = vec![sum, product];
+
+    // Create the circuit
+    let circuit = ZkCircuit::new(prover_witnesses, zkbin.clone());
+
+    info!(target: "PROVER", "Building proving key and creating the zero-knowledge proof");
+    let proving_key = ProvingKey::build(11, &circuit);
+    let proof = Proof::create(&proving_key, &[circuit], &public_inputs, &mut OsRng)?;
+
+    // ========
+    // Verifier
+    // ========
+
+    // Construct empty witnesses
+    let verifier_witnesses = vec![Witness::Base(None), Witness::Base(None)];
+
+    // Create the circuit
+    let circuit = ZkCircuit::new(verifier_witnesses, zkbin);
+
+    info!(target: "VERIFIER", "Building verifying key and verifying the zero-knowledge proof");
+    let verifying_key = VerifyingKey::build(11, &circuit);
+    proof.verify(&verifying_key, &public_inputs)?;
+    /* ANCHOR_END: main */
+
+    Ok(())
+}

+ 14 - 0
proof/arithmetic.zk

@@ -0,0 +1,14 @@
+constant "Arith" {}
+
+contract "Arith" {
+	Base a,
+	Base b,
+}
+
+circuit "Arith" {
+	sum = base_add(a, b);
+	constrain_instance(sum);
+
+	product = base_mul(a, b);
+	constrain_instance(product);
+}

+ 6 - 5
proof/burn.rs

@@ -17,8 +17,8 @@ use halo2_gadgets::primitives::{
 use incrementalmerkletree::{bridgetree::BridgeTree, Frontier, Tree};
 use log::info;
 use pasta_curves::{
-    arithmetic::{CurveAffine, Field},
-    group::Curve,
+    arithmetic::CurveAffine,
+    group::{ff::Field, Curve},
     pallas,
 };
 use rand::rngs::OsRng;
@@ -56,7 +56,7 @@ fn main() -> Result<()> {
         let messages =
             [*coords.x(), *coords.y(), pallas::Base::from(value), token_id, serial, coin_blind];
 
-        poseidon::Hash::init(P128Pow5T3, ConstantLength::<6>).hash(messages)
+        poseidon::Hash::<_, P128Pow5T3, ConstantLength<6>, 3, 2>::init().hash(messages)
     };
 
     // Fill the merkle tree with some random coins that we want to witness,
@@ -93,7 +93,8 @@ fn main() -> Result<()> {
 
     // Create the public inputs
     let nullifier = [secret.0, serial];
-    let nullifier = poseidon::Hash::init(P128Pow5T3, ConstantLength::<2>).hash(nullifier);
+    let nullifier =
+        poseidon::Hash::<_, P128Pow5T3, ConstantLength<2>, 3, 2>::init().hash(nullifier);
 
     let value_commit = pedersen_commitment_u64(value, value_blind);
     let value_coords = value_commit.to_affine().coordinates().unwrap();
@@ -122,7 +123,7 @@ fn main() -> Result<()> {
 
     info!(target: "PROVER", "Building proving key and creating the zero-knowledge proof");
     let proving_key = ProvingKey::build(11, &circuit);
-    let proof = Proof::create(&proving_key, &[circuit], &public_inputs)?;
+    let proof = Proof::create(&proving_key, &[circuit], &public_inputs, &mut OsRng)?;
 
     // ========
     // Verifier

+ 2 - 2
proof/burn.zk

@@ -1,7 +1,7 @@
 constant "Burn" {
-	EcFixedPoint VALUE_COMMIT_VALUE,
+	EcFixedPointShort VALUE_COMMIT_VALUE,
 	EcFixedPoint VALUE_COMMIT_RANDOM,
-	EcFixedPoint NULLIFIER_K,
+	EcFixedPointBase NULLIFIER_K,
 }
 
 contract "Burn" {

+ 516 - 0
proof/dao.rs

@@ -0,0 +1,516 @@
+use bitvec::prelude::*;
+use halo2_gadgets::{
+    ecc::{
+        chip::{EccChip, EccConfig},
+        FixedPoint, FixedPointShort, Point,
+    },
+    poseidon::{Hash as PoseidonHash, Pow5Chip as PoseidonChip, Pow5Config as PoseidonConfig},
+    primitives::{
+        poseidon,
+        poseidon::{ConstantLength, P128Pow5T3},
+    },
+    sinsemilla::{
+        chip::{SinsemillaChip, SinsemillaConfig},
+        merkle::{
+            chip::{MerkleChip, MerkleConfig},
+            MerklePath,
+        },
+    },
+    utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions},
+};
+use halo2_proofs::{
+    arithmetic::Field,
+    circuit::{AssignedCell, Layouter, SimpleFloorPlanner},
+    dev::MockProver,
+    plonk,
+    plonk::{Advice, Circuit, Column, ConstraintSystem, Instance as InstanceColumn},
+};
+use incrementalmerkletree::{bridgetree::BridgeTree, Frontier, Tree};
+use log::debug;
+use pasta_curves::{
+    arithmetic::{CurveAffine, FieldExt},
+    group::{ff::PrimeField, Curve, Group},
+    pallas,
+};
+use rand::rngs::OsRng;
+use simplelog::{ColorChoice::Auto, Config, LevelFilter, TermLogger, TerminalMode::Mixed};
+
+use darkfi::{
+    crypto::{
+        constants::{
+            sinsemilla::{OrchardCommitDomains, OrchardHashDomains},
+            util::gen_const_array,
+            OrchardFixedBases, OrchardFixedBasesFull, ValueCommitV, MERKLE_DEPTH_ORCHARD,
+        },
+        keypair::Keypair,
+        merkle_node::MerkleNode,
+        schnorr::SchnorrSecret,
+        util::{mod_r_p, pedersen_commitment_scalar},
+    },
+    Result,
+};
+
+#[derive(Clone)]
+pub struct VmConfig {
+    primary: Column<InstanceColumn>,
+    advices: [Column<Advice>; 10],
+    ecc_config: EccConfig<OrchardFixedBases>,
+    merkle_cfg1: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
+    merkle_cfg2: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
+    sinsemilla_cfg1: SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
+    _sinsemilla_cfg2: SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
+    poseidon_config: PoseidonConfig<pallas::Base, 3, 2>,
+}
+
+impl VmConfig {
+    fn ecc_chip(&self) -> EccChip<OrchardFixedBases> {
+        EccChip::construct(self.ecc_config.clone())
+    }
+
+    fn merkle_chip_1(
+        &self,
+    ) -> MerkleChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
+        MerkleChip::construct(self.merkle_cfg1.clone())
+    }
+
+    fn merkle_chip_2(
+        &self,
+    ) -> MerkleChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
+        MerkleChip::construct(self.merkle_cfg2.clone())
+    }
+
+    fn poseidon_chip(&self) -> PoseidonChip<pallas::Base, 3, 2> {
+        PoseidonChip::construct(self.poseidon_config.clone())
+    }
+}
+
+#[derive(Clone, Default)]
+pub struct ZkCircuit {
+    a: Option<pallas::Base>,   // contract address
+    s: Option<pallas::Base>,   // serial number
+    t: Option<pallas::Base>,   // treasury balance
+    b_b: Option<pallas::Base>, // bulla blinding
+
+    leaf_pos: Option<u32>,
+    merkle_path: Option<[MerkleNode; 32]>,
+
+    u: Option<pallas::Base>,   // output 0 value
+    p_x: Option<pallas::Base>, // output0 pub_x
+    p_y: Option<pallas::Base>, // output0 pub_y
+    b_m: Option<pallas::Base>, // output0 blind
+
+    votes: Option<pallas::Base>,
+    vote_blinds: Option<pallas::Scalar>,
+
+    output_1_blind: Option<pallas::Scalar>,
+}
+
+impl UtilitiesInstructions<pallas::Base> for ZkCircuit {
+    type Var = AssignedCell<pallas::Base, pallas::Base>;
+}
+
+impl Circuit<pallas::Base> for ZkCircuit {
+    type Config = VmConfig;
+    type FloorPlanner = SimpleFloorPlanner;
+
+    fn without_witnesses(&self) -> Self {
+        Self::default()
+    }
+
+    fn configure(meta: &mut ConstraintSystem<pallas::Base>) -> Self::Config {
+        // Advice columns used in the circuit
+        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(),
+        ];
+
+        // Fixed columns for the Sinsemilla generator lookup table
+        let table_idx = meta.lookup_table_column();
+        let lookup = (table_idx, meta.lookup_table_column(), meta.lookup_table_column());
+
+        // Instance column used for public inputs
+        let primary = meta.instance_column();
+        meta.enable_equality(primary);
+
+        // Permutation over all advice columns
+        for advice in advices.iter() {
+            meta.enable_equality(*advice);
+        }
+
+        // Poseidon requires four advice columns, while ECC incomplete addition
+        // requires six. We can reduce the proof size by sharing fixed columns
+        // between the ECC and Poseidon chips.
+        // TODO: For multiple invocations perhaps they could/should be configured
+        // in parallel rather than sharing?
+        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();
+
+        // Also use the first Lagrange coefficient column for loading global constants.
+        meta.enable_constant(lagrange_coeffs[0]);
+
+        // Use one of the right-most advice columns for all of our range checks.
+        let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx);
+
+        // Configuration for curve point operations.
+        // This uses 10 advice columns and spans the whole circuit.
+        let ecc_config = EccChip::<OrchardFixedBases>::configure(
+            meta,
+            advices,
+            lagrange_coeffs,
+            range_check.clone(),
+        );
+
+        // Configuration for the Poseidon hash
+        let poseidon_config = PoseidonChip::configure::<P128Pow5T3>(
+            meta,
+            advices[6..9].try_into().unwrap(),
+            advices[5],
+            rc_a,
+            rc_b,
+        );
+
+        // Configuration for a Sinsemilla hash instantiation and a
+        // Merkle hash instantiation using this Sinsemilla instance.
+        // Since the Sinsemilla config uses only 5 advice columns,
+        // we can fit two instances side-by-side.
+        let (sinsemilla_cfg1, merkle_cfg1) = {
+            let sinsemilla_cfg1 = SinsemillaChip::configure(
+                meta,
+                advices[..5].try_into().unwrap(),
+                advices[6],
+                lagrange_coeffs[0],
+                lookup,
+                range_check.clone(),
+            );
+            let merkle_cfg1 = MerkleChip::configure(meta, sinsemilla_cfg1.clone());
+            (sinsemilla_cfg1, merkle_cfg1)
+        };
+
+        let (_sinsemilla_cfg2, merkle_cfg2) = {
+            let sinsemilla_cfg2 = SinsemillaChip::configure(
+                meta,
+                advices[5..].try_into().unwrap(),
+                advices[7],
+                lagrange_coeffs[1],
+                lookup,
+                range_check,
+            );
+            let merkle_cfg2 = MerkleChip::configure(meta, sinsemilla_cfg2.clone());
+            (sinsemilla_cfg2, merkle_cfg2)
+        };
+
+        VmConfig {
+            primary,
+            advices,
+            ecc_config,
+            merkle_cfg1,
+            merkle_cfg2,
+            sinsemilla_cfg1,
+            _sinsemilla_cfg2,
+            poseidon_config,
+        }
+    }
+
+    fn synthesize(
+        &self,
+        config: Self::Config,
+        mut layouter: impl Layouter<pallas::Base>,
+    ) -> std::result::Result<(), plonk::Error> {
+        debug!("Entering synthesize()");
+        // Load the Sinsemilla generator lookup table used by the whole circuit.
+        SinsemillaChip::load(config.sinsemilla_cfg1.clone(), &mut layouter)?;
+
+        // Construct the ECC chip.
+        let ecc_chip = config.ecc_chip();
+
+        // This constant one is used for short multiplication
+        let one = self.load_private(
+            layouter.namespace(|| "Load constant one"),
+            config.advices[0],
+            Some(pallas::Base::one()),
+        )?;
+
+        let contract_address = self.load_private(
+            layouter.namespace(|| "Load contract address"),
+            config.advices[0],
+            self.a,
+        )?;
+
+        let serial_number = self.load_private(
+            layouter.namespace(|| "Load serial number"),
+            config.advices[0],
+            self.s,
+        )?;
+
+        let treasury_balance = self.load_private(
+            layouter.namespace(|| "Load treasury balance"),
+            config.advices[0],
+            self.t,
+        )?;
+
+        let bulla_blind = self.load_private(
+            layouter.namespace(|| "Load bulla blind"),
+            config.advices[0],
+            self.b_b,
+        )?;
+
+        let output0_value = self.load_private(
+            layouter.namespace(|| "Load output0 value"),
+            config.advices[0],
+            self.u,
+        )?;
+
+        let output0_pub_x = self.load_private(
+            layouter.namespace(|| "Load output0 dest pub x"),
+            config.advices[0],
+            self.p_x,
+        )?;
+
+        let output0_pub_y = self.load_private(
+            layouter.namespace(|| "Load output0 dest pub y"),
+            config.advices[0],
+            self.p_y,
+        )?;
+
+        let output0_blind = self.load_private(
+            layouter.namespace(|| "Load output0 blind"),
+            config.advices[0],
+            self.b_m,
+        )?;
+
+        let votes = self.load_private(
+            layouter.namespace(|| "Load votes summed"),
+            config.advices[0],
+            self.votes,
+        )?;
+
+        // Constrain the serial number
+        println!("Serial in circuit: {:?}", serial_number.value());
+        layouter.constrain_instance(serial_number.cell(), config.primary, 0)?;
+
+        // Hash the treasury bulla
+        let mut poseidon_message: Vec<AssignedCell<pallas::Base, pallas::Base>> =
+            Vec::with_capacity(4);
+        poseidon_message.push(contract_address);
+        poseidon_message.push(serial_number);
+        poseidon_message.push(treasury_balance);
+        poseidon_message.push(bulla_blind);
+
+        let hasher = PoseidonHash::<_, _, P128Pow5T3, ConstantLength<4>, 3, 2>::init(
+            config.poseidon_chip(),
+            layouter.namespace(|| "PoseidonHash init"),
+        )?;
+
+        let output = hasher.hash(
+            layouter.namespace(|| "PoseidonHash hash"),
+            poseidon_message.try_into().unwrap(),
+        )?;
+
+        let dao_bulla: AssignedCell<pallas::Base, pallas::Base> = output.into();
+
+        // Constrain the merkle root
+        let path: Option<[pallas::Base; MERKLE_DEPTH_ORCHARD]> =
+            self.merkle_path.map(|typed_path| gen_const_array(|i| typed_path[i].inner()));
+
+        let merkle_inputs = MerklePath::construct(
+            config.merkle_chip_1(),
+            config.merkle_chip_2(),
+            OrchardHashDomains::MerkleCrh,
+            self.leaf_pos,
+            path,
+        );
+
+        let root = merkle_inputs
+            .calculate_root(layouter.namespace(|| "Calculate merkle root"), dao_bulla)?;
+
+        println!("Merkle root in circuit: {:?}", root.value());
+        layouter.constrain_instance(root.cell(), config.primary, 1)?;
+
+        // Hash output 0
+        let mut poseidon_message: Vec<AssignedCell<pallas::Base, pallas::Base>> =
+            Vec::with_capacity(4);
+        poseidon_message.push(output0_value);
+        poseidon_message.push(output0_pub_x);
+        poseidon_message.push(output0_pub_y);
+        poseidon_message.push(output0_blind);
+
+        let hasher = PoseidonHash::<_, _, P128Pow5T3, ConstantLength<4>, 3, 2>::init(
+            config.poseidon_chip(),
+            layouter.namespace(|| "PoseidonHash init"),
+        )?;
+
+        let output = hasher.hash(
+            layouter.namespace(|| "PoseidonHash hash"),
+            poseidon_message.try_into().unwrap(),
+        )?;
+
+        let output0: AssignedCell<pallas::Base, pallas::Base> = output.into();
+        println!("Output0 in circuit: {:?}", output0.value());
+
+        // Constrain output 0
+        layouter.constrain_instance(output0.cell(), config.primary, 2)?;
+
+        // Commit to votes with votes_blind
+        let (commitment, _) = {
+            let value_commit_v = ValueCommitV;
+            let value_commit_v = FixedPointShort::from_inner(ecc_chip.clone(), value_commit_v);
+            value_commit_v.mul(layouter.namespace(|| "[value] ValueCommitV"), (votes, one))?
+        };
+
+        let (blind, _) = {
+            let rcv = self.vote_blinds;
+            let value_commit_r = OrchardFixedBasesFull::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 votes_commit_x and votes_commit_y
+        let votes_commit = commitment.add(layouter.namespace(|| "valuecommit"), &blind)?;
+
+        println!("VoteComX in circuit: {:?}", votes_commit.inner().x().value());
+        println!("VoteComY in circuit: {:?}", votes_commit.inner().y().value());
+        layouter.constrain_instance(votes_commit.inner().x().cell(), config.primary, 3)?;
+        layouter.constrain_instance(votes_commit.inner().y().cell(), config.primary, 4)?;
+
+        // TODO: Enforce votes > 0
+
+        // TODO: Output 1 (change) = treasury_balance - output0_value
+
+        // Commit to output 1 value
+        // Constrain output1_commit_x and output1_commit_y
+
+        debug!("Exiting synthesize()");
+        Ok(())
+    }
+}
+
+fn main() -> Result<()> {
+    let loglevel = match option_env!("RUST_LOG") {
+        Some("debug") => LevelFilter::Debug,
+        Some("trace") => LevelFilter::Trace,
+        Some(_) | None => LevelFilter::Info,
+    };
+    TermLogger::init(loglevel, Config::default(), Mixed, Auto)?;
+
+    /*
+    let bincode = include_bytes!("../proof/dao.zk.bin");
+    let zkbin = ZkBinary::decode(bincode)?;
+    */
+
+    // Contract address
+    let a = pallas::Base::random(&mut OsRng);
+    // Serial number
+    let s = pallas::Base::random(&mut OsRng);
+    // Money in treasury
+    let t = pallas::Base::from(666);
+    // Bulla blind
+    let b_b = pallas::Base::random(&mut OsRng);
+
+    let message = [a, s, t, b_b];
+    let hasher = poseidon::Hash::<_, P128Pow5T3, ConstantLength<4>, 3, 2>::init();
+    let bulla = hasher.hash(message);
+
+    // Merkle tree of DAOs
+    let mut tree = BridgeTree::<MerkleNode, 32>::new(100);
+    let dao0 = pallas::Base::random(&mut OsRng);
+    let dao2 = pallas::Base::random(&mut OsRng);
+    tree.append(&MerkleNode(dao0));
+    tree.witness();
+    tree.append(&MerkleNode(bulla));
+    tree.witness();
+    tree.append(&MerkleNode(dao2));
+    tree.witness();
+
+    let (leaf_pos, merkle_path) = tree.authentication_path(&MerkleNode(bulla)).unwrap();
+    let leaf_pos: u64 = leaf_pos.into();
+    let leaf_pos = leaf_pos as u32;
+
+    // Output 0:
+    let output0_val = pallas::Base::from(42);
+    let output0_dest = pallas::Point::random(&mut OsRng);
+    let output0_coords = output0_dest.to_affine().coordinates().unwrap();
+    let output0_blind = pallas::Base::random(&mut OsRng);
+
+    let message = [output0_val, *output0_coords.x(), *output0_coords.y(), output0_blind];
+    let hasher = poseidon::Hash::<_, P128Pow5T3, ConstantLength<4>, 3, 2>::init();
+    let output0 = hasher.hash(message);
+
+    let authority = Keypair::random(&mut OsRng);
+    let _signature = authority.secret.sign(&output0.to_repr());
+
+    let vote_1 = pallas::Base::from(44);
+    let vote_2 = pallas::Base::from(13);
+    // This is a NO vote
+    let vote_3 = -pallas::Base::from(49);
+
+    let vote_1_blind = pallas::Scalar::random(&mut OsRng);
+    let vote_1_commit = pedersen_commitment_scalar(mod_r_p(vote_1), vote_1_blind);
+
+    let vote_2_blind = pallas::Scalar::random(&mut OsRng);
+    let vote_2_commit = pedersen_commitment_scalar(mod_r_p(vote_2), vote_2_blind);
+
+    let vote_3_blind = pallas::Scalar::random(&mut OsRng);
+    let vote_3_commit = pedersen_commitment_scalar(mod_r_p(vote_3), vote_3_blind);
+
+    let vote_commit = vote_1_commit + vote_2_commit; //+ vote_3_commit;
+    let vote_commit_coords = vote_commit.to_affine().coordinates().unwrap();
+
+    let votes = vote_1 + vote_2; //+vote_3;
+    let vote_blinds = vote_1_blind + vote_2_blind; //+ vote_3_blind;
+
+    let output_1_blind = pallas::Scalar::random(&mut OsRng);
+
+    /*
+    let number = pallas::Base::from(u64::MAX).to_bytes();
+    let bits = number.view_bits::<Lsb0>();
+    println!("Positive: {:?}", bits);
+
+    //let number = (-pallas::Base::from(u64::MAX)).to_bytes();
+    let number = pallas::Base::from(0).to_bytes();
+    let bits = number.view_bits::<Lsb0>();
+    println!("Negative: {:?}", bits);
+    */
+
+    let circuit = ZkCircuit {
+        a: Some(a),
+        s: Some(s),
+        t: Some(t),
+        b_b: Some(b_b),
+        leaf_pos: Some(leaf_pos),
+        merkle_path: Some(merkle_path.try_into().unwrap()),
+        u: Some(output0_val),
+        p_x: Some(*output0_coords.x()),
+        p_y: Some(*output0_coords.y()),
+        b_m: Some(output0_blind),
+        votes: Some(votes),
+        vote_blinds: Some(vote_blinds),
+        output_1_blind: Some(output_1_blind),
+    };
+
+    let public_inputs =
+        vec![s, tree.root().inner(), output0, *vote_commit_coords.x(), *vote_commit_coords.y()];
+    println!("{:#?}", public_inputs);
+
+    let prover = MockProver::run(11, &circuit, vec![public_inputs]).unwrap();
+    assert_eq!(prover.verify(), Ok(()));
+
+    Ok(())
+}

+ 46 - 0
proof/dao.zk

@@ -0,0 +1,46 @@
+constant "DAO" {
+	EcFixedPoint VALUE_COMMIT_VALUE,
+	EcFixedPoint VALUE_COMMIT_RANDOM,
+}
+
+contract "DAO" {
+	Base a, # contract address
+	Base s,  # serial number
+	Base T, # treasury balance
+	Base B_b, # bulla blinding
+
+	Uint32 leaf_pos,
+	MerklePath W, # merkle path to DAO
+
+	Base u, # output 0 value
+	Base P_x, # output 0 addr x
+	Base P_y, # output 0 addr y
+	Base b_m, # output blinding
+
+	Base votes,
+	Scalar vote_blinds,
+
+	Scalar output_1_blind,
+}
+
+circuit "DAO" {
+	# Reveal serial number
+	constrain_instance(s);
+
+	# Poseidon hash of the Bulla
+	bulla = poseidon_hash(a, s, T, B_b);
+	D = calculate_merkle_root(leaf_pos, W, bulla);
+	constrain_instance(D);
+
+	# Output 0:
+	M = poseidon_hash(u, P_x, P_y, b_m);
+	constrain_instance(M);
+
+	vcv = ec_mul_short(votes, VALUE_COMMIT_VALUE);
+	vcr = ec_mul(vote_blinds, VALUE_COMMIT_RANDOM);
+	vote_commit = ec_add(vcv, vcr);
+	vote_commit_x = ec_get_x(vote_commit);
+	vote_commit_y = ec_get_y(vote_commit);
+	constrain_instance(vote_commit_x);
+	constrain_instance(vote_commit_y);
+}

+ 4 - 4
proof/mint.rs

@@ -15,8 +15,8 @@ use halo2_gadgets::primitives::{
 };
 use log::info;
 use pasta_curves::{
-    arithmetic::{CurveAffine, Field},
-    group::Curve,
+    arithmetic::CurveAffine,
+    group::{ff::Field, Curve},
     pallas,
 };
 use rand::rngs::OsRng;
@@ -61,7 +61,7 @@ fn main() -> Result<()> {
 
     // Create the public inputs
     let msgs = [*coords.x(), *coords.y(), pallas::Base::from(value), token_id, serial, coin_blind];
-    let coin = poseidon::Hash::init(P128Pow5T3, ConstantLength::<6>).hash(msgs);
+    let coin = poseidon::Hash::<_, P128Pow5T3, ConstantLength<6>, 3, 2>::init().hash(msgs);
 
     let value_commit = pedersen_commitment_u64(value, value_blind);
     let value_coords = value_commit.to_affine().coordinates().unwrap();
@@ -77,7 +77,7 @@ fn main() -> Result<()> {
 
     info!(target: "PROVER", "Building proving key and creating the zero-knowledge proof");
     let proving_key = ProvingKey::build(11, &circuit);
-    let proof = Proof::create(&proving_key, &[circuit], &public_inputs)?;
+    let proof = Proof::create(&proving_key, &[circuit], &public_inputs, &mut OsRng)?;
 
     // ========
     // Verifier

+ 1 - 1
proof/mint.zk

@@ -1,5 +1,5 @@
 constant "Mint" {
-	EcFixedPoint VALUE_COMMIT_VALUE,
+	EcFixedPointShort VALUE_COMMIT_VALUE,
 	EcFixedPoint VALUE_COMMIT_RANDOM,
 }
 

+ 29 - 1
src/cli/cli_config.rs

@@ -1,5 +1,5 @@
 use std::{
-    fs,
+    env, fs,
     io::Write,
     marker::PhantomData,
     net::SocketAddr,
@@ -9,6 +9,9 @@ use std::{
 
 use serde::{de::DeserializeOwned, Deserialize, Serialize};
 
+use clap::ArgMatches;
+use simplelog::{ConfigBuilder, LevelFilter};
+
 use crate::{Error, Result};
 
 #[derive(Clone, Default)]
@@ -153,3 +156,28 @@ pub fn spawn_config(path: &Path, contents: &[u8]) -> Result<()> {
 
     Ok(())
 }
+
+pub fn log_config(matches: ArgMatches) -> Result<(LevelFilter, simplelog::Config)> {
+    let mut verbosity_level = 0;
+    verbosity_level += matches.occurrences_of("verbose");
+    let log_level = match verbosity_level {
+        0 => LevelFilter::Info,
+        1 => LevelFilter::Debug,
+        _ => LevelFilter::Trace,
+    };
+
+    let log_config = match env::var("LOG_TARGETS") {
+        Ok(x) => {
+            let targets: Vec<&str> = x.split(',').collect();
+            let mut cfgbuilder = ConfigBuilder::new();
+            for i in targets {
+                cfgbuilder.add_filter_allow(i.to_string());
+            }
+
+            cfgbuilder.build()
+        }
+        Err(_) => simplelog::Config::default(),
+    };
+
+    Ok((log_level, log_config))
+}

+ 9 - 0
src/cli/cli_parser.rs

@@ -148,3 +148,12 @@ pub struct CliCashierd {
     #[clap(short, long)]
     pub refresh: bool,
 }
+
+/// Ircd cli
+#[derive(Parser)]
+#[clap(name = "ircd")]
+pub struct CliIrcd {
+    /// Increase verbosity
+    #[clap(short, parse(from_occurrences))]
+    pub verbose: u8,
+}

+ 1 - 1
src/cli/mod.rs

@@ -3,4 +3,4 @@ pub mod cli_parser;
 
 pub use cli_config::{CashierdConfig, Config, DarkfidConfig, DrkConfig, GatewaydConfig};
 
-pub use cli_parser::{CliCashierd, CliDarkfid, CliDrk, CliDrkSubCommands, CliGatewayd};
+pub use cli_parser::{CliCashierd, CliDarkfid, CliDrk, CliDrkSubCommands, CliGatewayd, CliIrcd};

+ 5 - 5
src/crypto/coin.rs

@@ -1,6 +1,6 @@
 use std::io;
 
-use pasta_curves::{arithmetic::FieldExt, pallas};
+use pasta_curves::{group::ff::PrimeField, pallas};
 
 use crate::{
     util::serial::{Decodable, Encodable, ReadExt, WriteExt},
@@ -11,12 +11,12 @@ use crate::{
 pub struct Coin(pub pallas::Base);
 
 impl Coin {
-    pub fn from_bytes(bytes: &[u8; 32]) -> Self {
-        pallas::Base::from_bytes(bytes).map(Coin).unwrap()
+    pub fn from_bytes(bytes: [u8; 32]) -> Self {
+        pallas::Base::from_repr(bytes).map(Coin).unwrap()
     }
 
     pub fn to_bytes(self) -> [u8; 32] {
-        self.0.to_bytes()
+        self.0.to_repr()
     }
 }
 
@@ -31,6 +31,6 @@ impl Decodable for Coin {
     fn decode<D: io::Read>(mut d: D) -> Result<Self> {
         let mut bytes = [0u8; 32];
         d.read_slice(&mut bytes)?;
-        Ok(Self::from_bytes(&bytes))
+        Ok(Self::from_bytes(bytes))
     }
 }

+ 11 - 1
src/crypto/constants.rs

@@ -2,10 +2,20 @@ pub mod fixed_bases;
 pub mod sinsemilla;
 pub mod util;
 
-pub use fixed_bases::OrchardFixedBases;
+pub use fixed_bases::{NullifierK, OrchardFixedBases, OrchardFixedBasesFull, ValueCommitV, H};
 
 pub const DRK_SCHNORR_DOMAIN: &[u8] = b"DarkFi_Schnorr";
 
 pub const MERKLE_DEPTH_ORCHARD: usize = 32;
 
 pub const L_ORCHARD_MERKLE: usize = 255;
+
+#[allow(dead_code)]
+/// $\ell^\mathsf{Orchard}_\mathsf{base}$
+pub(crate) const L_ORCHARD_BASE: usize = 255;
+
+/// $\ell^\mathsf{Orchard}_\mathsf{scalar}$
+pub(crate) const L_ORCHARD_SCALAR: usize = 255;
+
+/// $\ell_\mathsf{value}$
+pub(crate) const L_VALUE: usize = 64;

+ 100 - 153
src/crypto/constants/fixed_bases.rs

@@ -1,14 +1,12 @@
-use arrayvec::ArrayVec;
+//! Orchard fixed bases.
+use super::{L_ORCHARD_SCALAR, L_VALUE};
 use halo2_gadgets::ecc::{
-    chip::{compute_lagrange_coeffs, NUM_WINDOWS, NUM_WINDOWS_SHORT},
-    FixedPoints, H,
-};
-use pasta_curves::{
-    arithmetic::{CurveAffine, Field, FieldExt},
-    group::Curve,
-    pallas,
+    chip::{BaseFieldElem, FixedPoint, FullScalar, ShortScalar},
+    FixedPoints,
 };
 
+use pasta_curves::pallas;
+
 pub mod commit_ivk_r;
 pub mod note_commit_r;
 pub mod nullifier_k;
@@ -16,14 +14,18 @@ pub mod spend_auth_g;
 pub mod value_commit_r;
 pub mod value_commit_v;
 
+/// SWU hash-to-curve personalization for the spending key base point and
+/// the nullifier base point K^Orchard
+pub const ORCHARD_PERSONALIZATION: &str = "z.cash:Orchard";
+
 /// SWU hash-to-curve personalization for the value commitment generator
 pub const VALUE_COMMITMENT_PERSONALIZATION: &str = "z.cash:Orchard-cv";
 
 /// SWU hash-to-curve value for the value commitment generator
-pub const VALUE_COMMITMENT_R_BYTES: [u8; 1] = *b"r";
+pub const VALUE_COMMITMENT_V_BYTES: [u8; 1] = *b"v";
 
 /// SWU hash-to-curve value for the value commitment generator
-pub const VALUE_COMMITMENT_V_BYTES: [u8; 1] = *b"v";
+pub const VALUE_COMMITMENT_R_BYTES: [u8; 1] = *b"r";
 
 /// SWU hash-to-curve personalization for the note commitment generator
 pub const NOTE_COMMITMENT_PERSONALIZATION: &str = "z.cash:Orchard-NoteCommit";
@@ -31,184 +33,129 @@ pub const NOTE_COMMITMENT_PERSONALIZATION: &str = "z.cash:Orchard-NoteCommit";
 /// SWU hash-to-curve personalization for the IVK commitment generator
 pub const COMMIT_IVK_PERSONALIZATION: &str = "z.cash:Orchard-CommitIvk";
 
-/// SWU hash-to-curve personalization for the spending key base point and
-/// the nullifier base point K^Orchard
-pub const ORCHARD_PERSONALIZATION: &str = "z.cash:Orchard";
-
 /// Window size for fixed-base scalar multiplication
 pub const FIXED_BASE_WINDOW_SIZE: usize = 3;
 
+/// $2^{`FIXED_BASE_WINDOW_SIZE`}$
+pub const H: usize = 1 << FIXED_BASE_WINDOW_SIZE;
+
+/// Number of windows for a full-width scalar
+pub const NUM_WINDOWS: usize =
+    (L_ORCHARD_SCALAR + FIXED_BASE_WINDOW_SIZE - 1) / FIXED_BASE_WINDOW_SIZE;
+
+/// Number of windows for a short signed scalar
+pub const NUM_WINDOWS_SHORT: usize =
+    (L_VALUE + FIXED_BASE_WINDOW_SIZE - 1) / FIXED_BASE_WINDOW_SIZE;
+
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
+// A sum type for both full-width and short bases. This enables us to use the
+// shared functionality of full-width and short fixed-base scalar multiplication.
 pub enum OrchardFixedBases {
+    Full(OrchardFixedBasesFull),
+    NullifierK,
+    ValueCommitV,
+}
+
+impl From<OrchardFixedBasesFull> for OrchardFixedBases {
+    fn from(full_width_base: OrchardFixedBasesFull) -> Self {
+        Self::Full(full_width_base)
+    }
+}
+
+impl From<ValueCommitV> for OrchardFixedBases {
+    fn from(_value_commit_v: ValueCommitV) -> Self {
+        Self::ValueCommitV
+    }
+}
+
+impl From<NullifierK> for OrchardFixedBases {
+    fn from(_nullifier_k: NullifierK) -> Self {
+        Self::NullifierK
+    }
+}
+
+/// The Orchard fixed bases used in scalar mul with full-width scalars.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum OrchardFixedBasesFull {
     CommitIvkR,
     NoteCommitR,
     ValueCommitR,
     SpendAuthG,
-    NullifierK,
-    ValueCommitV,
 }
 
+/// NullifierK is used in scalar mul with a base field element.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub struct NullifierK;
+
+/// ValueCommitV is used in scalar mul with a short signed scalar.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub struct ValueCommitV;
+
 impl FixedPoints<pallas::Affine> for OrchardFixedBases {
+    type FullScalar = OrchardFixedBasesFull;
+    type Base = NullifierK;
+    type ShortScalar = ValueCommitV;
+}
+
+impl FixedPoint<pallas::Affine> for OrchardFixedBasesFull {
+    type ScalarKind = FullScalar;
+
     fn generator(&self) -> pallas::Affine {
         match self {
-            OrchardFixedBases::CommitIvkR => commit_ivk_r::generator(),
-            OrchardFixedBases::NoteCommitR => note_commit_r::generator(),
-            OrchardFixedBases::ValueCommitR => value_commit_r::generator(),
-            OrchardFixedBases::SpendAuthG => spend_auth_g::generator(),
-            OrchardFixedBases::NullifierK => nullifier_k::generator(),
-            OrchardFixedBases::ValueCommitV => value_commit_v::generator(),
+            Self::CommitIvkR => commit_ivk_r::generator(),
+            Self::NoteCommitR => note_commit_r::generator(),
+            Self::ValueCommitR => value_commit_r::generator(),
+            Self::SpendAuthG => spend_auth_g::generator(),
         }
     }
+
     fn u(&self) -> Vec<[[u8; 32]; H]> {
         match self {
-            OrchardFixedBases::CommitIvkR => commit_ivk_r::U.to_vec(),
-            OrchardFixedBases::NoteCommitR => note_commit_r::U.to_vec(),
-            OrchardFixedBases::ValueCommitR => value_commit_r::U.to_vec(),
-            OrchardFixedBases::SpendAuthG => spend_auth_g::U.to_vec(),
-            OrchardFixedBases::NullifierK => nullifier_k::U.to_vec(),
-            OrchardFixedBases::ValueCommitV => value_commit_v::U_SHORT.to_vec(),
+            Self::CommitIvkR => commit_ivk_r::U.to_vec(),
+            Self::NoteCommitR => note_commit_r::U.to_vec(),
+            Self::ValueCommitR => value_commit_r::U.to_vec(),
+            Self::SpendAuthG => spend_auth_g::U.to_vec(),
         }
     }
 
     fn z(&self) -> Vec<u64> {
         match self {
-            OrchardFixedBases::CommitIvkR => commit_ivk_r::Z.to_vec(),
-            OrchardFixedBases::NoteCommitR => note_commit_r::Z.to_vec(),
-            OrchardFixedBases::ValueCommitR => value_commit_r::Z.to_vec(),
-            OrchardFixedBases::SpendAuthG => spend_auth_g::Z.to_vec(),
-            OrchardFixedBases::NullifierK => nullifier_k::Z.to_vec(),
-            OrchardFixedBases::ValueCommitV => value_commit_v::Z_SHORT.to_vec(),
+            Self::CommitIvkR => commit_ivk_r::Z.to_vec(),
+            Self::NoteCommitR => note_commit_r::Z.to_vec(),
+            Self::ValueCommitR => value_commit_r::Z.to_vec(),
+            Self::SpendAuthG => spend_auth_g::Z.to_vec(),
         }
     }
+}
 
-    fn lagrange_coeffs(&self) -> Vec<[pallas::Base; H]> {
-        match self {
-            OrchardFixedBases::ValueCommitV => {
-                compute_lagrange_coeffs(self.generator(), NUM_WINDOWS_SHORT)
-            }
-            _ => compute_lagrange_coeffs(self.generator(), NUM_WINDOWS),
-        }
+impl FixedPoint<pallas::Affine> for NullifierK {
+    type ScalarKind = BaseFieldElem;
+
+    fn generator(&self) -> pallas::Affine {
+        nullifier_k::generator()
     }
-}
 
-/// For each fixed base, we calculate its scalar multiples in three-bit windows.
-/// Each window will have $2^3 = 8$ points.
-#[allow(dead_code)]
-fn compute_window_table<C: CurveAffine>(base: C, num_windows: usize) -> Vec<[C; H]> {
-    let mut window_table: Vec<[C; H]> = Vec::with_capacity(num_windows);
-
-    // Generate window table entries for all windows but the last.
-    // For these first `num_windows - 1` windows, we compute the multiple [(k+2)*(2^3)^w]B.
-    // Here, w ranges from [0..`num_windows - 1`)
-    for w in 0..(num_windows - 1) {
-        window_table.push(
-            (0..H)
-                .map(|k| {
-                    // scalar = (k+2)*(8^w)
-                    let scalar = C::ScalarExt::from_u64(k as u64 + 2) *
-                        C::ScalarExt::from_u64(H as u64).pow(&[w as u64, 0, 0, 0]);
-                    (base * scalar).to_affine()
-                })
-                .collect::<ArrayVec<C, H>>()
-                .into_inner()
-                .unwrap(),
-        );
+    fn u(&self) -> Vec<[[u8; 32]; H]> {
+        nullifier_k::U.to_vec()
     }
 
-    // Generate window table entries for the last window, w = `num_windows - 1`.
-    // For the last window, we compute [k * (2^3)^w - sum]B, where sum is defined
-    // as sum = \sum_{j = 0}^{`num_windows - 2`} 2^{3j+1}
-    let sum = (0..(num_windows - 1)).fold(C::ScalarExt::zero(), |acc, j| {
-        acc + C::ScalarExt::from_u64(2).pow(&[
-            FIXED_BASE_WINDOW_SIZE as u64 * j as u64 + 1,
-            0,
-            0,
-            0,
-        ])
-    });
-    window_table.push(
-        (0..H)
-            .map(|k| {
-                // scalar = k * (2^3)^w - sum, where w = `num_windows - 1`
-                let scalar = C::ScalarExt::from_u64(k as u64) *
-                    C::ScalarExt::from_u64(H as u64).pow(&[(num_windows - 1) as u64, 0, 0, 0]) -
-                    sum;
-                (base * scalar).to_affine()
-            })
-            .collect::<ArrayVec<C, H>>()
-            .into_inner()
-            .unwrap(),
-    );
-
-    window_table
+    fn z(&self) -> Vec<u64> {
+        nullifier_k::Z.to_vec()
+    }
 }
 
-#[cfg(test)]
-// Test that Lagrange interpolation coefficients reproduce the correct x-coordinate
-// for each fixed-base multiple in each window.
-fn test_lagrange_coeffs<C: CurveAffine>(base: C, num_windows: usize) {
-    let lagrange_coeffs = compute_lagrange_coeffs(base, num_windows);
-
-    // Check first 84 windows, i.e. `k_0, k_1, ..., k_83`
-    for (idx, coeffs) in lagrange_coeffs[0..(num_windows - 1)].iter().enumerate() {
-        // Test each three-bit chunk in this window.
-        for bits in 0..(1 << FIXED_BASE_WINDOW_SIZE) {
-            {
-                // Interpolate the x-coordinate using this window's coefficients
-                let interpolated_x = super::util::evaluate::<C>(bits, coeffs);
-
-                // Compute the actual x-coordinate of the multiple [(k+2)*(8^w)]B.
-                let point = base *
-                    C::Scalar::from_u64(bits as u64 + 2) *
-                    C::Scalar::from_u64(H as u64).pow(&[idx as u64, 0, 0, 0]);
-                let x = *point.to_affine().coordinates().unwrap().x();
-
-                // Check that the interpolated x-coordinate matches the actual one.
-                assert_eq!(x, interpolated_x);
-            }
-        }
+impl FixedPoint<pallas::Affine> for ValueCommitV {
+    type ScalarKind = ShortScalar;
+
+    fn generator(&self) -> pallas::Affine {
+        value_commit_v::generator()
     }
 
-    // Check last window.
-    for bits in 0..(1 << FIXED_BASE_WINDOW_SIZE) {
-        // Interpolate the x-coordinate using the last window's coefficients
-        let interpolated_x = super::util::evaluate::<C>(bits, &lagrange_coeffs[num_windows - 1]);
-
-        // Compute the actual x-coordinate of the multiple [k * (8^84) - offset]B,
-        // where offset = \sum_{j = 0}^{83} 2^{3j+1}
-        let offset = (0..(num_windows - 1)).fold(C::Scalar::zero(), |acc, w| {
-            acc + C::Scalar::from_u64(2).pow(&[
-                FIXED_BASE_WINDOW_SIZE as u64 * w as u64 + 1,
-                0,
-                0,
-                0,
-            ])
-        });
-        let scalar = C::Scalar::from_u64(bits as u64) *
-            C::Scalar::from_u64(H as u64).pow(&[(num_windows - 1) as u64, 0, 0, 0]) -
-            offset;
-        let point = base * scalar;
-        let x = *point.to_affine().coordinates().unwrap().x();
-
-        // Check that the interpolated x-coordinate matches the actual one.
-        assert_eq!(x, interpolated_x);
+    fn u(&self) -> Vec<[[u8; 32]; H]> {
+        value_commit_v::U_SHORT.to_vec()
     }
-}
 
-#[cfg(test)]
-// Test that the z-values and u-values satisfy the conditions:
-//      1. z + y = u^2,
-//      2. z - y is not a square
-// for the y-coordinate of each fixed-base multiple in each window.
-fn test_zs_and_us<C: CurveAffine>(base: C, z: &[u64], u: &[[[u8; 32]; H]], num_windows: usize) {
-    let window_table = compute_window_table(base, num_windows);
-
-    for ((u, z), window_points) in u.iter().zip(z.iter()).zip(window_table) {
-        for (u, point) in u.iter().zip(window_points.iter()) {
-            let y = *point.coordinates().unwrap().y();
-            let u = C::Base::from_bytes(u).unwrap();
-            assert_eq!(C::Base::from_u64(*z) + y, u * u); // allow either square root
-            assert!(bool::from((C::Base::from_u64(*z) - y).sqrt().is_none()));
-        }
+    fn z(&self) -> Vec<u64> {
+        value_commit_v::Z_SHORT.to_vec()
     }
 }

+ 11 - 13
src/crypto/constants/fixed_bases/commit_ivk_r.rs

@@ -1,7 +1,5 @@
-use pasta_curves::{
-    arithmetic::{CurveAffine, FieldExt},
-    pallas,
-};
+use group::ff::PrimeField;
+use pasta_curves::{arithmetic::CurveAffine, pallas};
 
 /// Generator used in SinsemillaCommit randomness for IVK commitment
 pub const GENERATOR: ([u8; 32], [u8; 32]) = (
@@ -2922,8 +2920,8 @@ pub const U: [[[u8; 32]; super::H]; super::NUM_WINDOWS] = [
 
 pub fn generator() -> pallas::Affine {
     pallas::Affine::from_xy(
-        pallas::Base::from_bytes(&GENERATOR.0).unwrap(),
-        pallas::Base::from_bytes(&GENERATOR.1).unwrap(),
+        pallas::Base::from_repr(GENERATOR.0).unwrap(),
+        pallas::Base::from_repr(GENERATOR.1).unwrap(),
     )
     .unwrap()
 }
@@ -2931,15 +2929,15 @@ pub fn generator() -> pallas::Affine {
 #[cfg(test)]
 mod tests {
     use super::{
-        super::{test_lagrange_coeffs, test_zs_and_us, COMMIT_IVK_PERSONALIZATION, NUM_WINDOWS},
+        super::{COMMIT_IVK_PERSONALIZATION, NUM_WINDOWS},
         *,
     };
     use group::Curve;
-    use halo2_gadgets::primitives::sinsemilla::CommitDomain;
-    use pasta_curves::{
-        arithmetic::{CurveAffine, FieldExt},
-        pallas,
+    use halo2_gadgets::{
+        ecc::chip::constants::{test_lagrange_coeffs, test_zs_and_us},
+        primitives::sinsemilla::CommitDomain,
     };
+    use pasta_curves::{arithmetic::CurveAffine, pallas};
 
     #[test]
     fn generator() {
@@ -2947,8 +2945,8 @@ mod tests {
         let point = domain.R();
         let coords = point.to_affine().coordinates().unwrap();
 
-        assert_eq!(*coords.x(), pallas::Base::from_bytes(&GENERATOR.0).unwrap());
-        assert_eq!(*coords.y(), pallas::Base::from_bytes(&GENERATOR.1).unwrap());
+        assert_eq!(*coords.x(), pallas::Base::from_repr(GENERATOR.0).unwrap());
+        assert_eq!(*coords.y(), pallas::Base::from_repr(GENERATOR.1).unwrap());
     }
 
     #[test]

+ 13 - 16
src/crypto/constants/fixed_bases/note_commit_r.rs

@@ -1,7 +1,5 @@
-use pasta_curves::{
-    arithmetic::{CurveAffine, FieldExt},
-    pallas,
-};
+use group::ff::PrimeField;
+use pasta_curves::{arithmetic::CurveAffine, pallas};
 
 /// Generator used in SinsemillaCommit randomness for note commitment
 pub const GENERATOR: ([u8; 32], [u8; 32]) = (
@@ -2922,8 +2920,8 @@ pub const U: [[[u8; 32]; super::H]; super::NUM_WINDOWS] = [
 
 pub fn generator() -> pallas::Affine {
     pallas::Affine::from_xy(
-        pallas::Base::from_bytes(&GENERATOR.0).unwrap(),
-        pallas::Base::from_bytes(&GENERATOR.1).unwrap(),
+        pallas::Base::from_repr(GENERATOR.0).unwrap(),
+        pallas::Base::from_repr(GENERATOR.1).unwrap(),
     )
     .unwrap()
 }
@@ -2931,26 +2929,25 @@ pub fn generator() -> pallas::Affine {
 #[cfg(test)]
 mod tests {
     use super::{
-        super::{
-            test_lagrange_coeffs, test_zs_and_us, NOTE_COMMITMENT_PERSONALIZATION, NUM_WINDOWS,
-        },
+        super::{NOTE_COMMITMENT_PERSONALIZATION, NUM_WINDOWS},
         *,
     };
-    use group::Curve;
-    use halo2_gadgets::primitives::sinsemilla::CommitDomain;
-    use pasta_curves::{
-        arithmetic::{CurveAffine, FieldExt},
-        pallas,
+    use halo2_gadgets::{
+        ecc::chip::constants::{test_lagrange_coeffs, test_zs_and_us},
+        primitives::sinsemilla::CommitDomain,
     };
 
+    use group::Curve;
+    use pasta_curves::{arithmetic::CurveAffine, pallas};
+
     #[test]
     fn generator() {
         let domain = CommitDomain::new(NOTE_COMMITMENT_PERSONALIZATION);
         let point = domain.R();
         let coords = point.to_affine().coordinates().unwrap();
 
-        assert_eq!(*coords.x(), pallas::Base::from_bytes(&GENERATOR.0).unwrap());
-        assert_eq!(*coords.y(), pallas::Base::from_bytes(&GENERATOR.1).unwrap());
+        assert_eq!(*coords.x(), pallas::Base::from_repr(GENERATOR.0).unwrap());
+        assert_eq!(*coords.y(), pallas::Base::from_repr(GENERATOR.1).unwrap());
     }
 
     #[test]

+ 9 - 13
src/crypto/constants/fixed_bases/nullifier_k.rs

@@ -1,7 +1,5 @@
-use pasta_curves::{
-    arithmetic::{CurveAffine, FieldExt},
-    pallas,
-};
+use group::ff::PrimeField;
+use pasta_curves::{arithmetic::CurveAffine, pallas};
 
 pub const GENERATOR: ([u8; 32], [u8; 32]) = (
     [
@@ -2921,8 +2919,8 @@ pub const U: [[[u8; 32]; super::H]; super::NUM_WINDOWS] = [
 
 pub fn generator() -> pallas::Affine {
     pallas::Affine::from_xy(
-        pallas::Base::from_bytes(&GENERATOR.0).unwrap(),
-        pallas::Base::from_bytes(&GENERATOR.1).unwrap(),
+        pallas::Base::from_repr(GENERATOR.0).unwrap(),
+        pallas::Base::from_repr(GENERATOR.1).unwrap(),
     )
     .unwrap()
 }
@@ -2930,14 +2928,12 @@ pub fn generator() -> pallas::Affine {
 #[cfg(test)]
 mod tests {
     use super::{
-        super::{test_lagrange_coeffs, test_zs_and_us, NUM_WINDOWS, ORCHARD_PERSONALIZATION},
+        super::{NUM_WINDOWS, ORCHARD_PERSONALIZATION},
         *,
     };
     use group::Curve;
-    use pasta_curves::{
-        arithmetic::{CurveExt, FieldExt},
-        pallas,
-    };
+    use halo2_gadgets::ecc::chip::constants::{test_lagrange_coeffs, test_zs_and_us};
+    use pasta_curves::{arithmetic::CurveExt, pallas};
 
     #[test]
     fn generator() {
@@ -2945,8 +2941,8 @@ mod tests {
         let point = hasher(b"K");
         let coords = point.to_affine().coordinates().unwrap();
 
-        assert_eq!(*coords.x(), pallas::Base::from_bytes(&GENERATOR.0).unwrap());
-        assert_eq!(*coords.y(), pallas::Base::from_bytes(&GENERATOR.1).unwrap());
+        assert_eq!(*coords.x(), pallas::Base::from_repr(GENERATOR.0).unwrap());
+        assert_eq!(*coords.y(), pallas::Base::from_repr(GENERATOR.1).unwrap());
     }
 
     #[test]

+ 9 - 10
src/crypto/constants/fixed_bases/spend_auth_g.rs

@@ -1,7 +1,5 @@
-use pasta_curves::{
-    arithmetic::{CurveAffine, FieldExt},
-    pallas,
-};
+use group::ff::PrimeField;
+use pasta_curves::{arithmetic::CurveAffine, pallas};
 
 /// The value commitment is used to check balance between inputs and outputs. The value is
 /// placed over this generator.
@@ -2923,8 +2921,8 @@ pub const U: [[[u8; 32]; super::H]; super::NUM_WINDOWS] = [
 
 pub fn generator() -> pallas::Affine {
     pallas::Affine::from_xy(
-        pallas::Base::from_bytes(&GENERATOR.0).unwrap(),
-        pallas::Base::from_bytes(&GENERATOR.1).unwrap(),
+        pallas::Base::from_repr(GENERATOR.0).unwrap(),
+        pallas::Base::from_repr(GENERATOR.1).unwrap(),
     )
     .unwrap()
 }
@@ -2932,12 +2930,13 @@ pub fn generator() -> pallas::Affine {
 #[cfg(test)]
 mod tests {
     use super::{
-        super::{test_lagrange_coeffs, test_zs_and_us, NUM_WINDOWS, ORCHARD_PERSONALIZATION},
+        super::{NUM_WINDOWS, ORCHARD_PERSONALIZATION},
         *,
     };
     use group::Curve;
+    use halo2_gadgets::ecc::chip::constants::{test_lagrange_coeffs, test_zs_and_us};
     use pasta_curves::{
-        arithmetic::{CurveAffine, CurveExt, FieldExt},
+        arithmetic::{CurveAffine, CurveExt},
         pallas,
     };
 
@@ -2947,8 +2946,8 @@ mod tests {
         let point = hasher(b"G");
         let coords = point.to_affine().coordinates().unwrap();
 
-        assert_eq!(*coords.x(), pallas::Base::from_bytes(&GENERATOR.0).unwrap());
-        assert_eq!(*coords.y(), pallas::Base::from_bytes(&GENERATOR.1).unwrap());
+        assert_eq!(*coords.x(), pallas::Base::from_repr(GENERATOR.0).unwrap());
+        assert_eq!(*coords.y(), pallas::Base::from_repr(GENERATOR.1).unwrap());
     }
 
     #[test]

+ 9 - 12
src/crypto/constants/fixed_bases/value_commit_r.rs

@@ -1,7 +1,5 @@
-use pasta_curves::{
-    arithmetic::{CurveAffine, FieldExt},
-    pallas,
-};
+use group::ff::PrimeField;
+use pasta_curves::{arithmetic::CurveAffine, pallas};
 
 /// The value commitment is used to check balance between inputs and outputs. The value is
 /// placed over this generator.
@@ -2923,8 +2921,8 @@ pub const U: [[[u8; 32]; super::H]; super::NUM_WINDOWS] = [
 
 pub fn generator() -> pallas::Affine {
     pallas::Affine::from_xy(
-        pallas::Base::from_bytes(&GENERATOR.0).unwrap(),
-        pallas::Base::from_bytes(&GENERATOR.1).unwrap(),
+        pallas::Base::from_repr(GENERATOR.0).unwrap(),
+        pallas::Base::from_repr(GENERATOR.1).unwrap(),
     )
     .unwrap()
 }
@@ -2932,14 +2930,13 @@ pub fn generator() -> pallas::Affine {
 #[cfg(test)]
 mod tests {
     use super::{
-        super::{
-            test_lagrange_coeffs, test_zs_and_us, NUM_WINDOWS, VALUE_COMMITMENT_PERSONALIZATION,
-        },
+        super::{NUM_WINDOWS, VALUE_COMMITMENT_PERSONALIZATION},
         *,
     };
     use group::Curve;
+    use halo2_gadgets::ecc::chip::constants::{test_lagrange_coeffs, test_zs_and_us};
     use pasta_curves::{
-        arithmetic::{CurveAffine, CurveExt, FieldExt},
+        arithmetic::{CurveAffine, CurveExt},
         pallas,
     };
 
@@ -2949,8 +2946,8 @@ mod tests {
         let point = hasher(b"r");
         let coords = point.to_affine().coordinates().unwrap();
 
-        assert_eq!(*coords.x(), pallas::Base::from_bytes(&GENERATOR.0).unwrap());
-        assert_eq!(*coords.y(), pallas::Base::from_bytes(&GENERATOR.1).unwrap());
+        assert_eq!(*coords.x(), pallas::Base::from_repr(GENERATOR.0).unwrap());
+        assert_eq!(*coords.y(), pallas::Base::from_repr(GENERATOR.1).unwrap());
     }
 
     #[test]

+ 11 - 15
src/crypto/constants/fixed_bases/value_commit_v.rs

@@ -1,7 +1,5 @@
-use pasta_curves::{
-    arithmetic::{CurveAffine, FieldExt},
-    pallas,
-};
+use group::ff::PrimeField;
+use pasta_curves::{arithmetic::CurveAffine, pallas};
 
 /// The value commitment is used to check balance between inputs and outputs. The value is
 /// placed over this generator.
@@ -776,8 +774,8 @@ pub const U_SHORT: [[[u8; 32]; super::H]; super::NUM_WINDOWS_SHORT] = [
 
 pub fn generator() -> pallas::Affine {
     pallas::Affine::from_xy(
-        pallas::Base::from_bytes(&GENERATOR.0).unwrap(),
-        pallas::Base::from_bytes(&GENERATOR.1).unwrap(),
+        pallas::Base::from_repr(GENERATOR.0).unwrap(),
+        pallas::Base::from_repr(GENERATOR.1).unwrap(),
     )
     .unwrap()
 }
@@ -785,15 +783,13 @@ pub fn generator() -> pallas::Affine {
 #[cfg(test)]
 mod tests {
     use super::{
-        super::{
-            test_lagrange_coeffs, test_zs_and_us, NUM_WINDOWS_SHORT,
-            VALUE_COMMITMENT_PERSONALIZATION,
-        },
+        super::{NUM_WINDOWS_SHORT, VALUE_COMMITMENT_PERSONALIZATION},
         *,
     };
     use group::Curve;
+    use halo2_gadgets::ecc::chip::constants::{test_lagrange_coeffs, test_zs_and_us};
     use pasta_curves::{
-        arithmetic::{CurveAffine, CurveExt, FieldExt},
+        arithmetic::{CurveAffine, CurveExt},
         pallas,
     };
 
@@ -803,18 +799,18 @@ mod tests {
         let point = hasher(b"v");
         let coords = point.to_affine().coordinates().unwrap();
 
-        assert_eq!(*coords.x(), pallas::Base::from_bytes(&GENERATOR.0).unwrap());
-        assert_eq!(*coords.y(), pallas::Base::from_bytes(&GENERATOR.1).unwrap());
+        assert_eq!(*coords.x(), pallas::Base::from_repr(GENERATOR.0).unwrap());
+        assert_eq!(*coords.y(), pallas::Base::from_repr(GENERATOR.1).unwrap());
     }
 
     #[test]
-    fn lagrange_coeffs_short() {
+    fn lagrange_coeffs() {
         let base = super::generator();
         test_lagrange_coeffs(base, NUM_WINDOWS_SHORT);
     }
 
     #[test]
-    fn z_short() {
+    fn z() {
         let base = super::generator();
         test_zs_and_us(base, &Z_SHORT, &U_SHORT, NUM_WINDOWS_SHORT);
     }

+ 257 - 0
src/crypto/constants/load.rs

@@ -0,0 +1,257 @@
+use std::convert::TryInto;
+
+use crate::constants::{self, compute_lagrange_coeffs, H, NUM_WINDOWS, NUM_WINDOWS_SHORT};
+use group::ff::PrimeField;
+use pasta_curves::pallas;
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum OrchardFixedBasesFull {
+    CommitIvkR,
+    NoteCommitR,
+    ValueCommitR,
+    SpendAuthG,
+}
+
+impl OrchardFixedBasesFull {
+    pub fn generator(&self) -> pallas::Affine {
+        match self {
+            OrchardFixedBasesFull::CommitIvkR => super::commit_ivk_r::generator(),
+            OrchardFixedBasesFull::NoteCommitR => super::note_commit_r::generator(),
+            OrchardFixedBasesFull::ValueCommitR => super::value_commit_r::generator(),
+            OrchardFixedBasesFull::SpendAuthG => super::spend_auth_g::generator(),
+        }
+    }
+
+    pub fn u(&self) -> U {
+        match self {
+            OrchardFixedBasesFull::CommitIvkR => super::commit_ivk_r::U.into(),
+            OrchardFixedBasesFull::NoteCommitR => super::note_commit_r::U.into(),
+            OrchardFixedBasesFull::ValueCommitR => super::value_commit_r::U.into(),
+            OrchardFixedBasesFull::SpendAuthG => super::spend_auth_g::U.into(),
+        }
+    }
+}
+
+/// A fixed base to be used in scalar multiplication with a full-width scalar.
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct OrchardFixedBase {
+    pub generator: pallas::Affine,
+    pub lagrange_coeffs: LagrangeCoeffs,
+    pub z: Z,
+    pub u: U,
+}
+
+impl From<OrchardFixedBasesFull> for OrchardFixedBase {
+    fn from(base: OrchardFixedBasesFull) -> Self {
+        let (generator, z, u) = match base {
+            OrchardFixedBasesFull::CommitIvkR => (
+                super::commit_ivk_r::generator(),
+                super::commit_ivk_r::Z.into(),
+                super::commit_ivk_r::U.into(),
+            ),
+            OrchardFixedBasesFull::NoteCommitR => (
+                super::note_commit_r::generator(),
+                super::note_commit_r::Z.into(),
+                super::note_commit_r::U.into(),
+            ),
+            OrchardFixedBasesFull::ValueCommitR => (
+                super::value_commit_r::generator(),
+                super::value_commit_r::Z.into(),
+                super::value_commit_r::U.into(),
+            ),
+            OrchardFixedBasesFull::SpendAuthG => (
+                super::spend_auth_g::generator(),
+                super::spend_auth_g::Z.into(),
+                super::spend_auth_g::U.into(),
+            ),
+        };
+
+        Self {
+            generator,
+            lagrange_coeffs: compute_lagrange_coeffs(generator, NUM_WINDOWS).into(),
+            z,
+            u,
+        }
+    }
+}
+
+/// A fixed base to be used in scalar multiplication with a base field element.
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct ValueCommitV {
+    pub generator: pallas::Affine,
+    pub lagrange_coeffs_short: LagrangeCoeffsShort,
+    pub z_short: ZShort,
+    pub u_short: UShort,
+}
+
+impl ValueCommitV {
+    pub fn get() -> Self {
+        let generator = super::value_commit_v::generator();
+        Self {
+            generator,
+            lagrange_coeffs_short: compute_lagrange_coeffs(generator, NUM_WINDOWS_SHORT).into(),
+            z_short: super::value_commit_v::Z_SHORT.into(),
+            u_short: super::value_commit_v::U_SHORT.into(),
+        }
+    }
+}
+
+/// A fixed base to be used in scalar multiplication with a short signed exponent.
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub struct NullifierK;
+
+impl From<NullifierK> for OrchardFixedBase {
+    fn from(_nullifier_k: NullifierK) -> Self {
+        let (generator, z, u) = (
+            super::nullifier_k::generator(),
+            super::nullifier_k::Z.into(),
+            super::nullifier_k::U.into(),
+        );
+        Self {
+            generator,
+            lagrange_coeffs: compute_lagrange_coeffs(generator, NUM_WINDOWS).into(),
+            z,
+            u,
+        }
+    }
+}
+
+impl NullifierK {
+    pub fn generator(&self) -> pallas::Affine {
+        super::nullifier_k::generator()
+    }
+
+    pub fn u(&self) -> U {
+        super::nullifier_k::U.into()
+    }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+// 8 coefficients per window
+pub struct WindowLagrangeCoeffs(pub Box<[pallas::Base; H]>);
+
+impl From<&[pallas::Base; H]> for WindowLagrangeCoeffs {
+    fn from(array: &[pallas::Base; H]) -> Self {
+        Self(Box::new(*array))
+    }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+// 85 windows per base (with the exception of ValueCommitV)
+pub struct LagrangeCoeffs(pub Box<[WindowLagrangeCoeffs; constants::NUM_WINDOWS]>);
+
+impl From<Vec<WindowLagrangeCoeffs>> for LagrangeCoeffs {
+    fn from(windows: Vec<WindowLagrangeCoeffs>) -> Self {
+        Self(windows.into_boxed_slice().try_into().unwrap())
+    }
+}
+
+impl From<Vec<[pallas::Base; H]>> for LagrangeCoeffs {
+    fn from(arrays: Vec<[pallas::Base; H]>) -> Self {
+        let windows: Vec<WindowLagrangeCoeffs> = arrays.iter().map(|array| array.into()).collect();
+        windows.into()
+    }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+// 22 windows for ValueCommitV
+pub struct LagrangeCoeffsShort(pub Box<[WindowLagrangeCoeffs; NUM_WINDOWS_SHORT]>);
+
+impl From<Vec<WindowLagrangeCoeffs>> for LagrangeCoeffsShort {
+    fn from(windows: Vec<WindowLagrangeCoeffs>) -> Self {
+        Self(windows.into_boxed_slice().try_into().unwrap())
+    }
+}
+
+impl From<Vec<[pallas::Base; H]>> for LagrangeCoeffsShort {
+    fn from(arrays: Vec<[pallas::Base; H]>) -> Self {
+        let windows: Vec<WindowLagrangeCoeffs> = arrays.iter().map(|array| array.into()).collect();
+        windows.into()
+    }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+// 85 Z's per base (with the exception of ValueCommitV)
+pub struct Z(pub Box<[pallas::Base; NUM_WINDOWS]>);
+
+impl From<[u64; NUM_WINDOWS]> for Z {
+    fn from(zs: [u64; NUM_WINDOWS]) -> Self {
+        Self(
+            zs.iter()
+                .map(|z| pallas::Base::from(*z))
+                .collect::<Vec<_>>()
+                .into_boxed_slice()
+                .try_into()
+                .unwrap(),
+        )
+    }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+// 22 Z's for ValueCommitV
+pub struct ZShort(pub Box<[pallas::Base; NUM_WINDOWS_SHORT]>);
+
+impl From<[u64; NUM_WINDOWS_SHORT]> for ZShort {
+    fn from(zs: [u64; NUM_WINDOWS_SHORT]) -> Self {
+        Self(
+            zs.iter()
+                .map(|z| pallas::Base::from(*z))
+                .collect::<Vec<_>>()
+                .into_boxed_slice()
+                .try_into()
+                .unwrap(),
+        )
+    }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+// 8 u's per window
+pub struct WindowUs(pub Box<[pallas::Base; H]>);
+
+impl From<&[[u8; 32]; H]> for WindowUs {
+    fn from(window_us: &[[u8; 32]; H]) -> Self {
+        Self(
+            window_us
+                .iter()
+                .map(|u| pallas::Base::from_repr(*u).unwrap())
+                .collect::<Vec<_>>()
+                .into_boxed_slice()
+                .try_into()
+                .unwrap(),
+        )
+    }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+// 85 windows per base (with the exception of ValueCommitV)
+pub struct U(pub Box<[WindowUs; NUM_WINDOWS]>);
+
+impl From<Vec<WindowUs>> for U {
+    fn from(windows: Vec<WindowUs>) -> Self {
+        Self(windows.into_boxed_slice().try_into().unwrap())
+    }
+}
+
+impl From<[[[u8; 32]; H]; NUM_WINDOWS]> for U {
+    fn from(window_us: [[[u8; 32]; H]; NUM_WINDOWS]) -> Self {
+        let windows: Vec<WindowUs> = window_us.iter().map(|us| us.into()).collect();
+        windows.into()
+    }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+// 22 windows for ValueCommitV
+pub struct UShort(pub Box<[WindowUs; NUM_WINDOWS_SHORT]>);
+
+impl From<Vec<WindowUs>> for UShort {
+    fn from(windows: Vec<WindowUs>) -> Self {
+        Self(windows.into_boxed_slice().try_into().unwrap())
+    }
+}
+
+impl From<[[[u8; 32]; H]; NUM_WINDOWS_SHORT]> for UShort {
+    fn from(window_us: [[[u8; 32]; H]; NUM_WINDOWS_SHORT]) -> Self {
+        let windows: Vec<WindowUs> = window_us.iter().map(|us| us.into()).collect();
+        windows.into()
+    }
+}

+ 32 - 55
src/crypto/constants/sinsemilla.rs

@@ -1,12 +1,10 @@
 //! Sinsemilla generators
-use super::OrchardFixedBases;
-//use crate::spec::i2lebsp;
-
+use super::{OrchardFixedBases, OrchardFixedBasesFull};
+use crate::crypto::util::i2lebsp;
 use halo2_gadgets::sinsemilla::{CommitDomains, HashDomains};
-use pasta_curves::{
-    arithmetic::{CurveAffine, FieldExt},
-    pallas,
-};
+
+use group::ff::PrimeField;
+use pasta_curves::{arithmetic::CurveAffine, pallas};
 
 /// Number of bits of each message piece in $\mathsf{SinsemillaHashToPoint}$
 pub const K: usize = 10;
@@ -21,19 +19,13 @@ pub const INV_TWO_POW_K: [u8; 32] = [
 /// of Pallas.
 pub const C: usize = 253;
 
+#[allow(dead_code)]
+/// $\ell^\mathsf{Orchard}_\mathsf{Merkle}$
+pub(crate) const L_ORCHARD_MERKLE: usize = 255;
+
 /// SWU hash-to-curve personalization for the Merkle CRH generator
 pub const MERKLE_CRH_PERSONALIZATION: &str = "z.cash:Orchard-MerkleCRH";
 
-// Sinsemilla Q generators
-
-/// SWU hash-to-curve personalization for Sinsemilla $Q$ generators.
-pub const Q_PERSONALIZATION: &str = "z.cash:SinsemillaQ";
-
-// Sinsemilla S generators
-
-/// SWU hash-to-curve personalization for Sinsemilla $S$ generators.
-pub const S_PERSONALIZATION: &str = "z.cash:SinsemillaS";
-
 /// Generator used in SinsemillaHashToPoint for note commitment
 pub const Q_NOTE_COMMITMENT_M_GENERATOR: ([u8; 32], [u8; 32]) = (
     [
@@ -70,20 +62,15 @@ pub const Q_MERKLE_CRH: ([u8; 32], [u8; 32]) = (
     ],
 );
 
-pub fn i2lebsp<const NUM_BITS: usize>(int: u64) -> [bool; NUM_BITS] {
-    assert!(NUM_BITS <= 64);
-    super::util::gen_const_array(|mask: usize| (int & (1 << mask)) != 0)
-}
-
 #[allow(dead_code)]
-fn lebs2ip_k(bits: &[bool]) -> u32 {
+pub(crate) fn lebs2ip_k(bits: &[bool]) -> u32 {
     assert!(bits.len() == K);
     bits.iter().enumerate().fold(0u32, |acc, (i, b)| acc + if *b { 1 << i } else { 0 })
 }
 
 /// The sequence of K bits in little-endian order representing an integer
 /// up to `2^K` - 1.
-pub fn i2lebsp_k(int: usize) -> [bool; K] {
+pub(crate) fn i2lebsp_k(int: usize) -> [bool; K] {
     assert!(int < (1 << K));
     i2lebsp(int as u64)
 }
@@ -100,18 +87,18 @@ impl HashDomains<pallas::Affine> for OrchardHashDomains {
     fn Q(&self) -> pallas::Affine {
         match self {
             OrchardHashDomains::CommitIvk => pallas::Affine::from_xy(
-                pallas::Base::from_bytes(&Q_COMMIT_IVK_M_GENERATOR.0).unwrap(),
-                pallas::Base::from_bytes(&Q_COMMIT_IVK_M_GENERATOR.1).unwrap(),
+                pallas::Base::from_repr(Q_COMMIT_IVK_M_GENERATOR.0).unwrap(),
+                pallas::Base::from_repr(Q_COMMIT_IVK_M_GENERATOR.1).unwrap(),
             )
             .unwrap(),
             OrchardHashDomains::NoteCommit => pallas::Affine::from_xy(
-                pallas::Base::from_bytes(&Q_NOTE_COMMITMENT_M_GENERATOR.0).unwrap(),
-                pallas::Base::from_bytes(&Q_NOTE_COMMITMENT_M_GENERATOR.1).unwrap(),
+                pallas::Base::from_repr(Q_NOTE_COMMITMENT_M_GENERATOR.0).unwrap(),
+                pallas::Base::from_repr(Q_NOTE_COMMITMENT_M_GENERATOR.1).unwrap(),
             )
             .unwrap(),
             OrchardHashDomains::MerkleCrh => pallas::Affine::from_xy(
-                pallas::Base::from_bytes(&Q_MERKLE_CRH.0).unwrap(),
-                pallas::Base::from_bytes(&Q_MERKLE_CRH.1).unwrap(),
+                pallas::Base::from_repr(Q_MERKLE_CRH.0).unwrap(),
+                pallas::Base::from_repr(Q_MERKLE_CRH.1).unwrap(),
             )
             .unwrap(),
         }
@@ -125,10 +112,10 @@ pub enum OrchardCommitDomains {
 }
 
 impl CommitDomains<pallas::Affine, OrchardFixedBases, OrchardHashDomains> for OrchardCommitDomains {
-    fn r(&self) -> OrchardFixedBases {
+    fn r(&self) -> OrchardFixedBasesFull {
         match self {
-            Self::NoteCommit => OrchardFixedBases::NoteCommitR,
-            Self::CommitIvk => OrchardFixedBases::CommitIvkR,
+            Self::NoteCommit => OrchardFixedBasesFull::NoteCommitR,
+            Self::CommitIvk => OrchardFixedBasesFull::CommitIvkR,
         }
     }
 
@@ -143,23 +130,19 @@ impl CommitDomains<pallas::Affine, OrchardFixedBases, OrchardHashDomains> for Or
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::crypto::constants::{
+    use crate::constants::{
         fixed_bases::{COMMIT_IVK_PERSONALIZATION, NOTE_COMMITMENT_PERSONALIZATION},
         sinsemilla::MERKLE_CRH_PERSONALIZATION,
     };
+    use group::{ff::PrimeField, Curve};
     use halo2_gadgets::primitives::sinsemilla::{CommitDomain, HashDomain};
-
-    use pasta_curves::{
-        arithmetic::{CurveAffine, FieldExt},
-        group::{ff::PrimeField, Curve},
-        pallas,
-    };
+    use halo2_proofs::{arithmetic::CurveAffine, pasta::pallas};
     use rand::{self, rngs::OsRng, Rng};
 
     #[test]
     // Nodes in the Merkle tree are Pallas base field elements.
     fn l_orchard_merkle() {
-        assert_eq!(255, pallas::Base::NUM_BITS as usize);
+        assert_eq!(super::L_ORCHARD_MERKLE, pallas::Base::NUM_BITS as usize);
     }
 
     #[test]
@@ -198,14 +181,8 @@ mod tests {
         let point = domain.Q();
         let coords = point.to_affine().coordinates().unwrap();
 
-        assert_eq!(
-            *coords.x(),
-            pallas::Base::from_bytes(&Q_NOTE_COMMITMENT_M_GENERATOR.0).unwrap()
-        );
-        assert_eq!(
-            *coords.y(),
-            pallas::Base::from_bytes(&Q_NOTE_COMMITMENT_M_GENERATOR.1).unwrap()
-        );
+        assert_eq!(*coords.x(), pallas::Base::from_repr(Q_NOTE_COMMITMENT_M_GENERATOR.0).unwrap());
+        assert_eq!(*coords.y(), pallas::Base::from_repr(Q_NOTE_COMMITMENT_M_GENERATOR.1).unwrap());
     }
 
     #[test]
@@ -214,8 +191,8 @@ mod tests {
         let point = domain.Q();
         let coords = point.to_affine().coordinates().unwrap();
 
-        assert_eq!(*coords.x(), pallas::Base::from_bytes(&Q_COMMIT_IVK_M_GENERATOR.0).unwrap());
-        assert_eq!(*coords.y(), pallas::Base::from_bytes(&Q_COMMIT_IVK_M_GENERATOR.1).unwrap());
+        assert_eq!(*coords.x(), pallas::Base::from_repr(Q_COMMIT_IVK_M_GENERATOR.0).unwrap());
+        assert_eq!(*coords.y(), pallas::Base::from_repr(Q_COMMIT_IVK_M_GENERATOR.1).unwrap());
     }
 
     #[test]
@@ -224,14 +201,14 @@ mod tests {
         let point = domain.Q();
         let coords = point.to_affine().coordinates().unwrap();
 
-        assert_eq!(*coords.x(), pallas::Base::from_bytes(&Q_MERKLE_CRH.0).unwrap());
-        assert_eq!(*coords.y(), pallas::Base::from_bytes(&Q_MERKLE_CRH.1).unwrap());
+        assert_eq!(*coords.x(), pallas::Base::from_repr(Q_MERKLE_CRH.0).unwrap());
+        assert_eq!(*coords.y(), pallas::Base::from_repr(Q_MERKLE_CRH.1).unwrap());
     }
 
     #[test]
     fn inv_two_pow_k() {
-        let two_pow_k = pallas::Base::from_u64(1u64 << K);
-        let inv_two_pow_k = pallas::Base::from_bytes(&INV_TWO_POW_K).unwrap();
+        let two_pow_k = pallas::Base::from(1u64 << K);
+        let inv_two_pow_k = pallas::Base::from_repr(INV_TWO_POW_K).unwrap();
 
         assert_eq!(two_pow_k * inv_two_pow_k, pallas::Base::one());
     }

+ 2 - 10
src/crypto/constants/util.rs

@@ -1,11 +1,3 @@
-use pasta_curves::arithmetic::{CurveAffine, Field, FieldExt};
-
-/// Evaluate y = f(x) given the coefficients of f(x)
-pub fn evaluate<C: CurveAffine>(x: u8, coeffs: &[C::Base]) -> C::Base {
-    let x = C::Base::from_u64(x as u64);
-    coeffs.iter().rev().cloned().reduce(|acc, coeff| acc * x + coeff).unwrap_or_else(C::Base::zero)
-}
-
 /// Takes in an FnMut closure and returns a constant-length array with elements of
 /// type `Output`.
 pub fn gen_const_array<Output: Copy + Default, const LEN: usize>(
@@ -16,10 +8,10 @@ pub fn gen_const_array<Output: Copy + Default, const LEN: usize>(
 
 pub(crate) fn gen_const_array_with_default<Output: Copy, const LEN: usize>(
     default_value: Output,
-    closure: impl FnMut(usize) -> Output,
+    mut closure: impl FnMut(usize) -> Output,
 ) -> [Output; LEN] {
     let mut ret: [Output; LEN] = [default_value; LEN];
-    for (bit, val) in ret.iter_mut().zip((0..LEN).map(closure)) {
+    for (bit, val) in ret.iter_mut().zip((0..LEN).map(|idx| closure(idx))) {
         *bit = val;
     }
     ret

+ 17 - 15
src/crypto/keypair.rs

@@ -1,15 +1,17 @@
 use std::{convert::TryFrom, io};
 
-use halo2_gadgets::ecc::FixedPoints;
+use halo2_gadgets::ecc::chip::FixedPoint;
 use pasta_curves::{
-    arithmetic::{Field, FieldExt},
-    group::{Group, GroupEncoding},
+    group::{
+        ff::{Field, PrimeField},
+        Group, GroupEncoding,
+    },
     pallas,
 };
 use rand::RngCore;
 
 use crate::{
-    crypto::{address::Address, constants::OrchardFixedBases, util::mod_r_p},
+    crypto::{address::Address, constants::NullifierK, util::mod_r_p},
     util::serial::{Decodable, Encodable, ReadExt, WriteExt},
     Error, Result,
 };
@@ -42,11 +44,11 @@ impl SecretKey {
     }
 
     pub fn to_bytes(self) -> [u8; 32] {
-        self.0.to_bytes()
+        self.0.to_repr()
     }
 
-    pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self> {
-        match pallas::Base::from_bytes(bytes).into() {
+    pub fn from_bytes(bytes: [u8; 32]) -> Result<Self> {
+        match pallas::Base::from_repr(bytes).into() {
             Some(k) => Ok(Self(k)),
             None => Err(Error::SecretKeyFromBytes),
         }
@@ -63,7 +65,8 @@ impl PublicKey {
     }
 
     pub fn from_secret(s: SecretKey) -> Self {
-        let p = OrchardFixedBases::NullifierK.generator() * mod_r_p(s.0);
+        let nfk = NullifierK;
+        let p = nfk.generator() * mod_r_p(s.0);
         Self(p)
     }
 
@@ -90,7 +93,7 @@ impl TryFrom<Address> for PublicKey {
 
 impl Encodable for pallas::Base {
     fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
-        s.write_slice(&self.to_bytes()[..])?;
+        s.write_slice(&self.to_repr()[..])?;
         Ok(32)
     }
 }
@@ -99,7 +102,7 @@ impl Decodable for pallas::Base {
     fn decode<D: io::Read>(mut d: D) -> Result<Self> {
         let mut bytes = [0u8; 32];
         d.read_slice(&mut bytes)?;
-        let result = pallas::Base::from_bytes(&bytes);
+        let result = pallas::Base::from_repr(bytes);
         if result.is_some().into() {
             Ok(result.unwrap())
         } else {
@@ -110,7 +113,7 @@ impl Decodable for pallas::Base {
 
 impl Encodable for pallas::Scalar {
     fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
-        s.write_slice(&self.to_bytes()[..])?;
+        s.write_slice(&self.to_repr()[..])?;
         Ok(32)
     }
 }
@@ -119,7 +122,7 @@ impl Decodable for pallas::Scalar {
     fn decode<D: io::Read>(mut d: D) -> Result<Self> {
         let mut bytes = [0u8; 32];
         d.read_slice(&mut bytes)?;
-        let result = pallas::Scalar::from_bytes(&bytes);
+        let result = pallas::Scalar::from_repr(bytes);
         if result.is_some().into() {
             Ok(result.unwrap())
         } else {
@@ -150,7 +153,7 @@ impl Decodable for pallas::Point {
 
 impl Encodable for SecretKey {
     fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
-        s.write_slice(&self.0.to_bytes()[..])?;
+        s.write_slice(&self.0.to_repr()[..])?;
         Ok(32)
     }
 }
@@ -159,7 +162,7 @@ impl Decodable for SecretKey {
     fn decode<D: io::Read>(mut d: D) -> Result<Self> {
         let mut bytes = [0u8; 32];
         d.read_slice(&mut bytes)?;
-        let result = pallas::Base::from_bytes(&bytes);
+        let result = pallas::Base::from_repr(bytes);
         if result.is_some().into() {
             Ok(SecretKey(result.unwrap()))
         } else {
@@ -183,7 +186,6 @@ impl Decodable for PublicKey {
         if result.is_some().into() {
             Ok(PublicKey(result.unwrap()))
         } else {
-            log::debug!("Failed decoding PublicKey");
             Err(Error::BadOperationType)
         }
     }

+ 2 - 3
src/crypto/merkle_node.rs

@@ -4,7 +4,6 @@ use halo2_gadgets::primitives::sinsemilla::HashDomain;
 use incrementalmerkletree::{Altitude, Hashable};
 use lazy_static::lazy_static;
 use pasta_curves::{
-    arithmetic::FieldExt,
     group::ff::{PrimeField, PrimeFieldBits},
     pallas,
 };
@@ -28,7 +27,7 @@ use crate::{
 };
 
 lazy_static! {
-    static ref UNCOMMITTED_ORCHARD: pallas::Base = pallas::Base::from_u64(2);
+    static ref UNCOMMITTED_ORCHARD: pallas::Base = pallas::Base::from(2);
     static ref EMPTY_ROOTS: Vec<MerkleNode> = {
         iter::empty()
             .chain(Some(MerkleNode::empty_leaf()))
@@ -85,7 +84,7 @@ impl std::cmp::PartialEq for MerkleNode {
 
 impl std::hash::Hash for MerkleNode {
     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
-        <Option<pallas::Base>>::from(self.0).map(|b| b.to_bytes()).hash(state)
+        <Option<pallas::Base>>::from(self.0).map(|b| b.to_repr()).hash(state)
     }
 }
 

+ 9 - 12
src/crypto/mint_proof.rs

@@ -1,15 +1,12 @@
 use std::{io, time::Instant};
 
-use halo2_gadgets::{
-    primitives,
-    primitives::poseidon::{ConstantLength, P128Pow5T3},
+use halo2_gadgets::primitives::{
+    poseidon,
+    poseidon::{ConstantLength, P128Pow5T3},
 };
 use log::debug;
-use pasta_curves::{
-    arithmetic::{CurveAffine, FieldExt},
-    group::Curve,
-    pallas,
-};
+use pasta_curves::{arithmetic::CurveAffine, group::Curve, pallas};
+use rand::rngs::OsRng;
 
 use crate::{
     crypto::{
@@ -46,9 +43,9 @@ impl MintRevealedValues {
 
         let coords = public_key.0.to_affine().coordinates().unwrap();
         let messages =
-            [*coords.x(), *coords.y(), DrkValue::from_u64(value), token_id, serial, coin_blind];
+            [*coords.x(), *coords.y(), DrkValue::from(value), token_id, serial, coin_blind];
 
-        let coin = primitives::poseidon::Hash::init(P128Pow5T3, ConstantLength::<6>).hash(messages);
+        let coin = poseidon::Hash::<_, P128Pow5T3, ConstantLength<6>, 3, 2>::init().hash(messages);
 
         MintRevealedValues { value_commit, token_commit, coin: Coin(coin) }
     }
@@ -115,7 +112,7 @@ pub fn create_mint_proof(
     let c = MintContract {
         pub_x: Some(*coords.x()),
         pub_y: Some(*coords.y()),
-        value: Some(DrkValue::from_u64(value)),
+        value: Some(DrkValue::from(value)),
         token: Some(token_id),
         serial: Some(serial),
         coin_blind: Some(coin_blind),
@@ -125,7 +122,7 @@ pub fn create_mint_proof(
 
     let start = Instant::now();
     let public_inputs = revealed.make_outputs();
-    let proof = Proof::create(pk, &[c], &public_inputs)?;
+    let proof = Proof::create(pk, &[c], &public_inputs, &mut OsRng)?;
     debug!("Prove: [{:?}]", start.elapsed());
 
     Ok((proof, revealed))

+ 0 - 1
src/crypto/mod.rs

@@ -1,5 +1,4 @@
 pub mod address;
-pub mod arith_chip;
 pub mod coin;
 pub mod constants;
 pub mod diffie_hellman;

+ 7 - 6
src/crypto/nullifier.rs

@@ -4,7 +4,7 @@ use halo2_gadgets::primitives::{
     poseidon,
     poseidon::{ConstantLength, P128Pow5T3},
 };
-use pasta_curves::{arithmetic::FieldExt, pallas};
+use pasta_curves::{group::ff::PrimeField, pallas};
 
 use crate::{
     crypto::keypair::SecretKey,
@@ -18,16 +18,17 @@ pub struct Nullifier(pub(crate) pallas::Base);
 impl Nullifier {
     pub fn new(secret: SecretKey, serial: pallas::Base) -> Self {
         let nullifier = [secret.0, serial];
-        let nullifier = poseidon::Hash::init(P128Pow5T3, ConstantLength::<2>).hash(nullifier);
+        let nullifier =
+            poseidon::Hash::<_, P128Pow5T3, ConstantLength<2>, 3, 2>::init().hash(nullifier);
         Nullifier(nullifier)
     }
 
-    pub fn from_bytes(bytes: &[u8; 32]) -> Self {
-        pallas::Base::from_bytes(bytes).map(Nullifier).unwrap()
+    pub fn from_bytes(bytes: [u8; 32]) -> Self {
+        pallas::Base::from_repr(bytes).map(Nullifier).unwrap()
     }
 
     pub fn to_bytes(self) -> [u8; 32] {
-        self.0.to_bytes()
+        self.0.to_repr()
     }
 
     pub(crate) fn inner(&self) -> pallas::Base {
@@ -46,7 +47,7 @@ impl Decodable for Nullifier {
     fn decode<D: io::Read>(mut d: D) -> Result<Self> {
         let mut bytes = [0u8; 32];
         d.read_slice(&mut bytes)?;
-        let result = Self::from_bytes(&bytes);
+        let result = Self::from_bytes(bytes);
         Ok(result)
     }
 }

+ 17 - 15
src/crypto/proof.rs

@@ -1,13 +1,13 @@
 use std::io;
 
-// TODO: Alias vesta::Affine to something
-use halo2::{
+use halo2_proofs::{
     plonk,
-    plonk::Circuit,
+    plonk::{Circuit, SingleVerifier},
     poly::commitment::Params,
     transcript::{Blake2bRead, Blake2bWrite},
 };
 use pasta_curves::vesta;
+use rand::RngCore;
 
 use crate::{
     crypto::types::*,
@@ -57,11 +57,19 @@ impl Proof {
     pub fn create(
         pk: &ProvingKey,
         circuits: &[impl Circuit<DrkCircuitField>],
-        pubinputs: &[DrkCircuitField],
+        instances: &[DrkCircuitField],
+        mut rng: impl RngCore,
     ) -> std::result::Result<Self, plonk::Error> {
         let mut transcript = Blake2bWrite::<_, vesta::Affine, _>::init(vec![]);
 
-        plonk::create_proof(&pk.params, &pk.pk, circuits, &[&[pubinputs]], &mut transcript)?;
+        plonk::create_proof(
+            &pk.params,
+            &pk.pk,
+            circuits,
+            &[&[instances]],
+            &mut rng,
+            &mut transcript,
+        )?;
 
         Ok(Proof(transcript.finalize()))
     }
@@ -69,18 +77,12 @@ impl Proof {
     pub fn verify(
         &self,
         vk: &VerifyingKey,
-        pubinputs: &[DrkCircuitField],
+        instances: &[DrkCircuitField],
     ) -> std::result::Result<(), plonk::Error> {
-        let msm = vk.params.empty_msm();
+        let strategy = SingleVerifier::new(&vk.params);
         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(plonk::Error::ConstraintSystemFailure)
-        }
+
+        plonk::verify_proof(&vk.params, &vk.vk, strategy, &[&[instances]], &mut transcript)
     }
 
     pub fn new(bytes: Vec<u8>) -> Self {

+ 10 - 6
src/crypto/schnorr.rs

@@ -1,12 +1,15 @@
 use std::io;
 
-use halo2_gadgets::ecc::FixedPoints;
-use pasta_curves::{arithmetic::Field, group::GroupEncoding, pallas};
+use halo2_gadgets::ecc::chip::FixedPoint;
+use pasta_curves::{
+    group::{ff::Field, GroupEncoding},
+    pallas,
+};
 use rand::rngs::OsRng;
 
 use crate::{
     crypto::{
-        constants::{OrchardFixedBases, DRK_SCHNORR_DOMAIN},
+        constants::{NullifierK, DRK_SCHNORR_DOMAIN},
         keypair::{PublicKey, SecretKey},
         util::{hash_to_scalar, mod_r_p},
     },
@@ -31,7 +34,8 @@ pub trait SchnorrPublic {
 impl SchnorrSecret for SecretKey {
     fn sign(&self, message: &[u8]) -> Signature {
         let mask = pallas::Scalar::random(&mut OsRng);
-        let commit = OrchardFixedBases::NullifierK.generator() * mask;
+        let nfk = NullifierK;
+        let commit = nfk.generator() * mask;
 
         let challenge = hash_to_scalar(DRK_SCHNORR_DOMAIN, &commit.to_bytes(), message);
         let response = mask + challenge * mod_r_p(self.0);
@@ -43,8 +47,8 @@ impl SchnorrSecret for SecretKey {
 impl SchnorrPublic for PublicKey {
     fn verify(&self, message: &[u8], signature: &Signature) -> bool {
         let challenge = hash_to_scalar(DRK_SCHNORR_DOMAIN, &signature.commit.to_bytes(), message);
-        OrchardFixedBases::NullifierK.generator() * signature.response - self.0 * challenge ==
-            signature.commit
+        let nfk = NullifierK;
+        nfk.generator() * signature.response - self.0 * challenge == signature.commit
     }
 }
 

+ 10 - 14
src/crypto/spend_proof.rs

@@ -1,16 +1,13 @@
 use std::{io, time::Instant};
 
-use halo2_gadgets::{
-    primitives,
-    primitives::poseidon::{ConstantLength, P128Pow5T3},
+use halo2_gadgets::primitives::{
+    poseidon,
+    poseidon::{ConstantLength, P128Pow5T3},
 };
 use incrementalmerkletree::Hashable;
 use log::debug;
-use pasta_curves::{
-    arithmetic::{CurveAffine, FieldExt},
-    group::Curve,
-    pallas,
-};
+use pasta_curves::{arithmetic::CurveAffine, group::Curve};
+use rand::rngs::OsRng;
 
 use super::{
     nullifier::Nullifier,
@@ -53,15 +50,15 @@ impl SpendRevealedValues {
     ) -> Self {
         let nullifier = [secret.0, serial];
         let nullifier =
-            primitives::poseidon::Hash::init(P128Pow5T3, ConstantLength::<2>).hash(nullifier);
+            poseidon::Hash::<_, P128Pow5T3, ConstantLength<2>, 3, 2>::init().hash(nullifier);
 
         let public_key = PublicKey::from_secret(secret);
         let coords = public_key.0.to_affine().coordinates().unwrap();
 
         let messages =
-            [*coords.x(), *coords.y(), DrkValue::from_u64(value), token_id, serial, coin_blind];
+            [*coords.x(), *coords.y(), DrkValue::from(value), token_id, serial, coin_blind];
 
-        let coin = primitives::poseidon::Hash::init(P128Pow5T3, ConstantLength::<6>).hash(messages);
+        let coin = poseidon::Hash::<_, P128Pow5T3, ConstantLength<6>, 3, 2>::init().hash(messages);
 
         let merkle_root = {
             let position: u64 = leaf_position.into();
@@ -161,13 +158,12 @@ pub fn create_spend_proof(
         signature_secret,
     );
 
-    let merkle_path: Vec<pallas::Base> = merkle_path.iter().map(|node| node.0).collect();
     let leaf_position: u64 = leaf_position.into();
 
     let c = SpendContract {
         secret_key: Some(secret.0),
         serial: Some(serial),
-        value: Some(DrkValue::from_u64(value)),
+        value: Some(DrkValue::from(value)),
         token: Some(token_id),
         coin_blind: Some(coin_blind),
         value_blind: Some(value_blind),
@@ -179,7 +175,7 @@ pub fn create_spend_proof(
 
     let start = Instant::now();
     let public_inputs = revealed.make_outputs();
-    let proof = Proof::create(pk, &[c], &public_inputs)?;
+    let proof = Proof::create(pk, &[c], &public_inputs, &mut OsRng)?;
     debug!("Prove: [{:?}]", start.elapsed());
 
     Ok((proof, revealed))

+ 13 - 2
src/crypto/util.rs

@@ -8,7 +8,7 @@ use pasta_curves::{
 use super::constants::fixed_bases::{
     VALUE_COMMITMENT_PERSONALIZATION, VALUE_COMMITMENT_R_BYTES, VALUE_COMMITMENT_V_BYTES,
 };
-use crate::crypto::types::*;
+use crate::crypto::{constants::util::gen_const_array, types::*};
 
 pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> pallas::Scalar {
     let mut hasher = Params::new().hash_length(64).personal(persona).to_state();
@@ -28,7 +28,7 @@ pub fn pedersen_commitment_scalar(value: pallas::Scalar, blind: DrkValueBlind) -
 }
 
 pub fn pedersen_commitment_u64(value: u64, blind: DrkValueBlind) -> DrkValueCommit {
-    pedersen_commitment_scalar(mod_r_p(DrkValue::from_u64(value)), blind)
+    pedersen_commitment_scalar(mod_r_p(DrkValue::from(value)), blind)
 }
 
 /// Converts from pallas::Base to pallas::Scalar (aka $x \pmod{r_\mathbb{P}}$).
@@ -38,3 +38,14 @@ pub fn pedersen_commitment_u64(value: u64, blind: DrkValueBlind) -> DrkValueComm
 pub fn mod_r_p(x: pallas::Base) -> pallas::Scalar {
     pallas::Scalar::from_repr(x.to_repr()).unwrap()
 }
+
+/// The sequence of bits representing a u64 in little-endian order.
+///
+/// # Panics
+///
+/// Panics if the expected length of the sequence `NUM_BITS` exceeds
+/// 64.
+pub fn i2lebsp<const NUM_BITS: usize>(int: u64) -> [bool; NUM_BITS] {
+    assert!(NUM_BITS <= 64);
+    gen_const_array(|mask: usize| (int & (1 << mask)) != 0)
+}

+ 3 - 10
src/error.rs

@@ -1,6 +1,6 @@
 pub type Result<T> = std::result::Result<T, Error>;
 
-#[derive(Debug, Clone, thiserror::Error)]
+#[derive(Debug, thiserror::Error)]
 pub enum Error {
     #[error("io error: `{0:?}`")]
     Io(std::io::ErrorKind),
@@ -77,8 +77,8 @@ pub enum Error {
     MissingParams,
 
     #[cfg(feature = "crypto")]
-    #[error("PLONK error: `{0}`")]
-    PlonkError(String),
+    #[error(transparent)]
+    PlonkError(#[from] halo2_proofs::plonk::Error),
 
     #[cfg(feature = "crypto")]
     #[error("Unable to decrypt mint note")]
@@ -265,13 +265,6 @@ impl From<tungstenite::Error> for Error {
     }
 }
 
-#[cfg(feature = "crypto")]
-impl From<halo2::plonk::Error> for Error {
-    fn from(err: halo2::plonk::Error) -> Error {
-        Error::PlonkError(format!("{:?}", err))
-    }
-}
-
 #[cfg(feature = "util")]
 impl From<Box<bincode::ErrorKind>> for Error {
     fn from(err: Box<bincode::ErrorKind>) -> Error {

+ 1 - 1
src/net/message.rs

@@ -1,4 +1,4 @@
-use futures::{AsyncRead, AsyncWrite, AsyncReadExt, AsyncWriteExt};
+use futures::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
 use log::debug;
 use std::{io, net::SocketAddr};
 

+ 1 - 1
src/net/mod.rs

@@ -92,6 +92,6 @@ pub use hosts::{Hosts, HostsPtr};
 pub use message::Message;
 pub use message_subscriber::MessageSubscription;
 pub use p2p::{P2p, P2pPtr};
-pub use protocol::{ProtocolJobsManager, ProtocolJobsManagerPtr, ProtocolBasePtr, ProtocolBase};
+pub use protocol::{ProtocolBase, ProtocolBasePtr, ProtocolJobsManager, ProtocolJobsManagerPtr};
 pub use session::{SESSION_ALL, SESSION_INBOUND, SESSION_MANUAL, SESSION_OUTBOUND, SESSION_SEED};
 pub use settings::{Settings, SettingsPtr};

+ 6 - 11
src/net/protocol/protocol_registry.rs

@@ -1,15 +1,12 @@
 use async_std::sync::Mutex;
 use futures::future::BoxFuture;
-use std::future::Future;
 use log::debug;
+use std::future::Future;
 
-use crate::net::{session::SessionBitflag, ChannelPtr, P2pPtr, protocol::ProtocolBasePtr};
+use crate::net::{protocol::ProtocolBasePtr, session::SessionBitflag, ChannelPtr, P2pPtr};
 
-type Constructor = Box<
-    dyn Fn(ChannelPtr, P2pPtr) -> BoxFuture<'static, ProtocolBasePtr>
-        + Send
-        + Sync,
->;
+type Constructor =
+    Box<dyn Fn(ChannelPtr, P2pPtr) -> BoxFuture<'static, ProtocolBasePtr> + Send + Sync>;
 
 pub struct ProtocolRegistry {
     protocol_constructors: Mutex<Vec<(SessionBitflag, Constructor)>>,
@@ -27,8 +24,7 @@ impl ProtocolRegistry {
         F: 'static + Future<Output = ProtocolBasePtr> + Send,
     {
         let constructor = move |channel, p2p| {
-            Box::pin(constructor(channel, p2p))
-                as BoxFuture<'static, ProtocolBasePtr>
+            Box::pin(constructor(channel, p2p)) as BoxFuture<'static, ProtocolBasePtr>
         };
         self.protocol_constructors.lock().await.push((session_flags, Box::new(constructor)));
     }
@@ -46,8 +42,7 @@ impl ProtocolRegistry {
                 continue
             }
 
-            let protocol: ProtocolBasePtr =
-                construct(channel.clone(), p2p.clone()).await;
+            let protocol: ProtocolBasePtr = construct(channel.clone(), p2p.clone()).await;
             debug!(target: "net", "Attached {}", protocol.name());
             protocols.push(protocol)
         }

+ 3 - 3
src/node/service/gateway_p2p.rs

@@ -2,7 +2,7 @@ use async_std::sync::{Arc, Mutex};
 use std::io;
 
 use async_executor::Executor;
-use log::*;
+use log::debug;
 
 use crate::{
     blockchain::{rocks::columns, RocksColumn, Slab, SlabStore},
@@ -22,11 +22,11 @@ pub struct Gateway {
 }
 
 impl Gateway {
-    pub fn new(_settings: Settings, rocks: RocksColumn<columns::Slabs>) -> Result<Self> {
+    pub async fn new(_settings: Settings, rocks: RocksColumn<columns::Slabs>) -> Result<Self> {
         let slabstore = SlabStore::new(rocks)?;
         let settings = Settings::default();
 
-        let p2p = P2p::new(settings);
+        let p2p = P2p::new(settings).await;
         let last_indexes = Arc::new(Mutex::new(vec![0; 10]));
         Ok(Self { p2p, slabstore, _last_indexes: last_indexes })
     }

+ 23 - 18
src/crypto/arith_chip.rs → src/zk/arith_chip.rs

@@ -1,12 +1,11 @@
-use halo2::{
-    circuit::{Chip, Layouter},
+use halo2_proofs::{
+    circuit::{AssignedCell, Chip, Layouter},
     plonk::{Advice, Column, ConstraintSystem, Error, Selector},
     poly::Rotation,
 };
-use halo2_gadgets::utilities::{CellValue, Var};
 use pasta_curves::pallas;
 
-type Variable = CellValue<pallas::Base>;
+type Variable = AssignedCell<pallas::Base, pallas::Base>;
 
 // Replace with use pasta::Fp and pasta::Fq
 type Fp = pallas::Base;
@@ -48,8 +47,8 @@ impl ArithmeticChip {
         let a_col = cs.advice_column();
         let b_col = cs.advice_column();
 
-        cs.enable_equality(a_col.into());
-        cs.enable_equality(b_col.into());
+        cs.enable_equality(a_col);
+        cs.enable_equality(b_col);
 
         //let instance = cs.instance_column();
 
@@ -110,26 +109,29 @@ impl ArithmeticChip {
                     || "lhs",
                     self.config.a_col,
                     0,
-                    || a.value().ok_or(Error::SynthesisError),
+                    || Ok(*a.value().ok_or(Error::Synthesis)?),
                 )?;
+
                 let rhs = region.assign_advice(
                     || "rhs",
                     self.config.b_col,
                     0,
-                    || b.value().ok_or(Error::SynthesisError),
+                    || Ok(*b.value().ok_or(Error::Synthesis)?),
                 )?;
-                region.constrain_equal(a.cell(), lhs)?;
-                region.constrain_equal(b.cell(), rhs)?;
+
+                region.constrain_equal(a.cell(), lhs.cell())?;
+                region.constrain_equal(b.cell(), rhs.cell())?;
 
                 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),
+                    || value.ok_or(Error::Synthesis),
                 )?;
 
-                out = Some(Var::new(cell, value));
+                out = Some(cell);
                 Ok(())
             },
         )?;
@@ -144,6 +146,7 @@ impl ArithmeticChip {
         b: Variable,
     ) -> Result<Variable, Error> {
         let mut out = None;
+
         layouter.assign_region(
             || "mul",
             |mut region| {
@@ -153,26 +156,28 @@ impl ArithmeticChip {
                     || "lhs",
                     self.config.a_col,
                     0,
-                    || a.value().ok_or(Error::SynthesisError),
+                    || Ok(*a.value().ok_or(Error::Synthesis)?),
                 )?;
+
                 let rhs = region.assign_advice(
                     || "rhs",
                     self.config.b_col,
                     0,
-                    || b.value().ok_or(Error::SynthesisError),
+                    || Ok(*b.value().ok_or(Error::Synthesis)?),
                 )?;
-                region.constrain_equal(a.cell(), lhs)?;
-                region.constrain_equal(b.cell(), rhs)?;
+
+                region.constrain_equal(a.cell(), lhs.cell())?;
+                region.constrain_equal(b.cell(), rhs.cell())?;
 
                 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),
+                    || value.ok_or(Error::Synthesis),
                 )?;
 
-                out = Some(Var::new(cell, value));
+                out = Some(cell);
                 Ok(())
             },
         )?;

+ 30 - 32
src/zk/circuit/mint_contract.rs

@@ -1,29 +1,27 @@
-use halo2::{
-    circuit::{Layouter, SimpleFloorPlanner},
-    plonk,
-    plonk::{Advice, Circuit, Column, ConstraintSystem, Instance as InstanceColumn},
-};
 use halo2_gadgets::{
     ecc::{
         chip::{EccChip, EccConfig},
-        FixedPoint,
+        FixedPoint, FixedPointShort,
     },
-    poseidon::{Hash as PoseidonHash, Pow5T3Chip as PoseidonChip, Pow5T3Config as PoseidonConfig},
+    poseidon::{Hash as PoseidonHash, Pow5Chip as PoseidonChip, Pow5Config as PoseidonConfig},
     primitives::poseidon::{ConstantLength, P128Pow5T3},
-    utilities::{
-        lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions, Var,
-    },
+    utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions},
+};
+use halo2_proofs::{
+    circuit::{AssignedCell, Layouter, SimpleFloorPlanner},
+    plonk,
+    plonk::{Advice, Circuit, Column, ConstraintSystem, Instance as InstanceColumn},
 };
-use pasta_curves::pallas;
+use pasta_curves::{pallas, Fp};
 
-use crate::crypto::constants::OrchardFixedBases;
+use crate::crypto::constants::{OrchardFixedBases, OrchardFixedBasesFull, ValueCommitV};
 
 #[derive(Clone, Debug)]
 pub struct MintConfig {
     primary: Column<InstanceColumn>,
     advices: [Column<Advice>; 10],
-    ecc_config: EccConfig,
-    poseidon_config: PoseidonConfig<pallas::Base>,
+    ecc_config: EccConfig<OrchardFixedBases>,
+    poseidon_config: PoseidonConfig<pallas::Base, 3, 2>,
 }
 
 impl MintConfig {
@@ -31,7 +29,7 @@ impl MintConfig {
         EccChip::construct(self.ecc_config.clone())
     }
 
-    fn poseidon_chip(&self) -> PoseidonChip<pallas::Base> {
+    fn poseidon_chip(&self) -> PoseidonChip<pallas::Base, 3, 2> {
         PoseidonChip::construct(self.poseidon_config.clone())
     }
 }
@@ -56,7 +54,7 @@ pub struct MintContract {
 }
 
 impl UtilitiesInstructions<pallas::Base> for MintContract {
-    type Var = CellValue<pallas::Base>;
+    type Var = AssignedCell<pallas::Base, pallas::Base>;
 }
 
 impl Circuit<pallas::Base> for MintContract {
@@ -86,11 +84,11 @@ impl Circuit<pallas::Base> for MintContract {
 
         // Instance column used for public inputs
         let primary = meta.instance_column();
-        meta.enable_equality(primary.into());
+        meta.enable_equality(primary);
 
         // Permutation over all advice columns
         for advice in advices.iter() {
-            meta.enable_equality((*advice).into());
+            meta.enable_equality(*advice);
         }
 
         // Poseidon requires four advice columns, while ECC incomplete addition
@@ -123,9 +121,8 @@ impl Circuit<pallas::Base> for MintContract {
             EccChip::<OrchardFixedBases>::configure(meta, advices, lagrange_coeffs, range_check);
 
         // Configuration for the Poseidon hash
-        let poseidon_config = PoseidonChip::configure(
+        let poseidon_config = PoseidonChip::configure::<P128Pow5T3>(
             meta,
-            P128Pow5T3,
             advices[6..9].try_into().unwrap(),
             advices[5],
             rc_a,
@@ -176,18 +173,17 @@ impl Circuit<pallas::Base> for MintContract {
         // Coin hash
         // =========
         let coin = {
-            let poseidon_message = [pub_x, pub_y, value, token, serial, coin_blind];
+            let poseidon_message = [pub_x, pub_y, value.clone(), token.clone(), serial, coin_blind];
 
-            let poseidon_hasher = PoseidonHash::<_, _, P128Pow5T3, _, 3, 2>::init(
+            let poseidon_hasher = PoseidonHash::<_, _, P128Pow5T3, ConstantLength<6>, 3, 2>::init(
                 config.poseidon_chip(),
                 layouter.namespace(|| "Poseidon init"),
-                ConstantLength::<6>,
             )?;
 
             let poseidon_output =
                 poseidon_hasher.hash(layouter.namespace(|| "Poseidon hash"), poseidon_message)?;
 
-            let poseidon_output: CellValue<pallas::Base> = poseidon_output.inner().into();
+            let poseidon_output: AssignedCell<Fp, Fp> = poseidon_output.into();
             poseidon_output
         };
 
@@ -207,15 +203,16 @@ impl Circuit<pallas::Base> for MintContract {
 
         // 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))?
+            let value_commit_v = ValueCommitV;
+            let value_commit_v = FixedPointShort::from_inner(ecc_chip.clone(), value_commit_v);
+            value_commit_v
+                .mul(layouter.namespace(|| "[value] ValueCommitV"), (value.clone(), one.clone()))?
         };
 
         // r_V * G_2
         let (blind, _rcv) = {
             let rcv = self.value_blind;
-            let value_commit_r = OrchardFixedBases::ValueCommitR;
+            let value_commit_r = OrchardFixedBasesFull::ValueCommitR;
             let value_commit_r = FixedPoint::from_inner(ecc_chip.clone(), value_commit_r);
             value_commit_r.mul(layouter.namespace(|| "[value_blind] ValueCommitR"), rcv)?
         };
@@ -240,15 +237,16 @@ impl Circuit<pallas::Base> for MintContract {
         // ================
         // a * G_1
         let (commitment, _) = {
-            let token_commit_v = OrchardFixedBases::ValueCommitV;
-            let token_commit_v = FixedPoint::from_inner(ecc_chip.clone(), token_commit_v);
-            token_commit_v.mul_short(layouter.namespace(|| "[token] ValueCommitV"), (token, one))?
+            let token_commit_v = ValueCommitV;
+            let token_commit_v = FixedPointShort::from_inner(ecc_chip.clone(), token_commit_v);
+            token_commit_v
+                .mul(layouter.namespace(|| "[token] ValueCommitV"), (token.clone(), one.clone()))?
         };
 
         // r_A * G_2
         let (blind, _rca) = {
             let rca = self.token_blind;
-            let token_commit_r = OrchardFixedBases::ValueCommitR;
+            let token_commit_r = OrchardFixedBasesFull::ValueCommitR;
             let token_commit_r = FixedPoint::from_inner(ecc_chip, token_commit_r);
             token_commit_r.mul(layouter.namespace(|| "[token_blind] ValueCommitR"), rca)?
         };

+ 54 - 55
src/zk/circuit/spend_contract.rs

@@ -1,13 +1,9 @@
-use halo2::{
-    circuit::{Layouter, SimpleFloorPlanner},
-    plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Instance as InstanceColumn},
-};
 use halo2_gadgets::{
     ecc::{
         chip::{EccChip, EccConfig},
-        FixedPoint,
+        FixedPoint, FixedPointBaseField, FixedPointShort,
     },
-    poseidon::{Hash as PoseidonHash, Pow5T3Chip as PoseidonChip, Pow5T3Config as PoseidonConfig},
+    poseidon::{Hash as PoseidonHash, Pow5Chip as PoseidonChip, Pow5Config as PoseidonConfig},
     primitives::poseidon::{ConstantLength, P128Pow5T3},
     sinsemilla::{
         chip::{SinsemillaChip, SinsemillaConfig},
@@ -16,15 +12,21 @@ use halo2_gadgets::{
             MerklePath,
         },
     },
-    utilities::{
-        lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions, Var,
-    },
+    utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions},
+};
+use halo2_proofs::{
+    circuit::{AssignedCell, Layouter, SimpleFloorPlanner},
+    plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Instance as InstanceColumn},
 };
-use pasta_curves::pallas;
+use pasta_curves::{pallas, Fp};
 
-use crate::crypto::constants::{
-    sinsemilla::{OrchardCommitDomains, OrchardHashDomains},
-    OrchardFixedBases,
+use crate::crypto::{
+    constants::{
+        sinsemilla::{OrchardCommitDomains, OrchardHashDomains},
+        util::gen_const_array,
+        NullifierK, OrchardFixedBases, OrchardFixedBasesFull, ValueCommitV, MERKLE_DEPTH_ORCHARD,
+    },
+    merkle_node::MerkleNode,
 };
 
 #[allow(dead_code)]
@@ -32,14 +34,14 @@ use crate::crypto::constants::{
 pub struct SpendConfig {
     primary: Column<InstanceColumn>,
     advices: [Column<Advice>; 10],
-    ecc_config: EccConfig,
+    ecc_config: EccConfig<OrchardFixedBases>,
     merkle_config_1: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
     merkle_config_2: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
     sinsemilla_config_1:
         SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
     sinsemilla_config_2:
         SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
-    poseidon_config: PoseidonConfig<pallas::Base>,
+    poseidon_config: PoseidonConfig<pallas::Base, 3, 2>,
 }
 
 impl SpendConfig {
@@ -73,7 +75,7 @@ impl SpendConfig {
         MerkleChip::construct(self.merkle_config_2.clone())
     }
 
-    fn poseidon_chip(&self) -> PoseidonChip<pallas::Base> {
+    fn poseidon_chip(&self) -> PoseidonChip<pallas::Base, 3, 2> {
         PoseidonChip::construct(self.poseidon_config.clone())
     }
 }
@@ -98,13 +100,13 @@ pub struct SpendContract {
     pub value_blind: Option<pallas::Scalar>,
     pub token_blind: Option<pallas::Scalar>,
     pub leaf_pos: Option<u32>,
-    pub merkle_path: Option<[pallas::Base; 32]>,
+    pub merkle_path: Option<[MerkleNode; MERKLE_DEPTH_ORCHARD]>,
     //pub sig_secret: Option<pallas::Scalar>,
     pub sig_secret: Option<pallas::Base>,
 }
 
 impl UtilitiesInstructions<pallas::Base> for SpendContract {
-    type Var = CellValue<pallas::Base>;
+    type Var = AssignedCell<Fp, Fp>;
 }
 
 impl Circuit<pallas::Base> for SpendContract {
@@ -136,11 +138,11 @@ impl Circuit<pallas::Base> for SpendContract {
 
         // Instance column used for public inputs
         let primary = meta.instance_column();
-        meta.enable_equality(primary.into());
+        meta.enable_equality(primary);
 
         // Permutation over all advice columns
         for advice in advices.iter() {
-            meta.enable_equality((*advice).into());
+            meta.enable_equality(*advice);
         }
 
         // Poseidon requires four advice columns, while ECC incomplete addition
@@ -177,9 +179,8 @@ impl Circuit<pallas::Base> for SpendContract {
         );
 
         // Configuration for the Poseidon hash
-        let poseidon_config = PoseidonChip::configure(
+        let poseidon_config = PoseidonChip::configure::<P128Pow5T3>(
             meta,
-            P128Pow5T3,
             advices[6..9].try_into().unwrap(),
             advices[5],
             rc_a,
@@ -244,10 +245,6 @@ impl Circuit<pallas::Base> for SpendContract {
         // Construct the ECC chip.
         let ecc_chip = config.ecc_chip();
 
-        // Construct the merkle chips
-        let merkle_chip_1 = config.merkle_chip_1();
-        let merkle_chip_2 = config.merkle_chip_2();
-
         // =========
         // Nullifier
         // =========
@@ -264,18 +261,17 @@ impl Circuit<pallas::Base> for SpendContract {
         )?;
 
         let hash = {
-            let poseidon_message = [secret_key, serial];
+            let poseidon_message = [secret_key.clone(), serial.clone()];
 
-            let poseidon_hasher = PoseidonHash::<_, _, P128Pow5T3, _, 3, 2>::init(
+            let poseidon_hasher = PoseidonHash::<_, _, P128Pow5T3, ConstantLength<2>, 3, 2>::init(
                 config.poseidon_chip(),
                 layouter.namespace(|| "Poseidon init"),
-                ConstantLength::<2>,
             )?;
 
             let poseidon_output =
                 poseidon_hasher.hash(layouter.namespace(|| "Poseidon hash"), poseidon_message)?;
 
-            let poseidon_output: CellValue<pallas::Base> = poseidon_output.inner().into();
+            let poseidon_output: AssignedCell<Fp, Fp> = poseidon_output.into();
             poseidon_output
         };
 
@@ -300,9 +296,9 @@ impl Circuit<pallas::Base> for SpendContract {
         )?;
 
         let public_key = {
-            let nullifier_k = OrchardFixedBases::NullifierK;
-            let nullifier_k = FixedPoint::from_inner(ecc_chip.clone(), nullifier_k);
-            nullifier_k.mul_base_field(layouter.namespace(|| "[x_s] Nullifier"), secret_key)?
+            let nullifier_k = NullifierK;
+            let nullifier_k = FixedPointBaseField::from_inner(ecc_chip.clone(), nullifier_k);
+            nullifier_k.mul(layouter.namespace(|| "[x_s] Nullifier"), secret_key)?
         };
 
         let (pub_x, pub_y) = (public_key.inner().x(), public_key.inner().y());
@@ -313,16 +309,15 @@ impl Circuit<pallas::Base> for SpendContract {
         let coin = {
             let poseidon_message = [pub_x, pub_y, value, token, serial, coin_blind];
 
-            let poseidon_hasher = PoseidonHash::<_, _, P128Pow5T3, _, 3, 2>::init(
+            let poseidon_hasher = PoseidonHash::<_, _, P128Pow5T3, ConstantLength<6>, 3, 2>::init(
                 config.poseidon_chip(),
                 layouter.namespace(|| "Poseidon init"),
-                ConstantLength::<6>,
             )?;
 
             let poseidon_output =
                 poseidon_hasher.hash(layouter.namespace(|| "Poseidon hash"), poseidon_message)?;
 
-            let poseidon_output: CellValue<pallas::Base> = poseidon_output.inner().into();
+            let poseidon_output: AssignedCell<Fp, Fp> = poseidon_output.into();
             poseidon_output
         };
 
@@ -330,16 +325,19 @@ impl Circuit<pallas::Base> for SpendContract {
         // Merkle root
         // ===========
 
-        let path = MerklePath {
-            chip_1: merkle_chip_1,
-            chip_2: merkle_chip_2,
-            domain: OrchardHashDomains::MerkleCrh,
-            leaf_pos: self.leaf_pos,
-            path: self.merkle_path,
-        };
+        let path: Option<[pallas::Base; MERKLE_DEPTH_ORCHARD]> =
+            self.merkle_path.map(|typed_path| gen_const_array(|i| typed_path[i].inner()));
+
+        let merkle_inputs = MerklePath::construct(
+            config.merkle_chip_1(),
+            config.merkle_chip_2(),
+            OrchardHashDomains::MerkleCrh,
+            self.leaf_pos,
+            path,
+        );
 
         let computed_final_root =
-            path.calculate_root(layouter.namespace(|| "calculate root"), coin)?;
+            merkle_inputs.calculate_root(layouter.namespace(|| "calculate root"), coin)?;
 
         layouter.constrain_instance(
             computed_final_root.cell(),
@@ -363,15 +361,16 @@ impl Circuit<pallas::Base> for SpendContract {
 
         // 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))?
+            let value_commit_v = ValueCommitV;
+            let value_commit_v = FixedPointShort::from_inner(ecc_chip.clone(), value_commit_v);
+            value_commit_v
+                .mul(layouter.namespace(|| "[value] ValueCommitV"), (value, one.clone()))?
         };
 
         // r_V * G_2
         let (blind, _rcv) = {
             let rcv = self.value_blind;
-            let value_commit_r = OrchardFixedBases::ValueCommitR;
+            let value_commit_r = OrchardFixedBasesFull::ValueCommitR;
             let value_commit_r = FixedPoint::from_inner(ecc_chip.clone(), value_commit_r);
             value_commit_r.mul(layouter.namespace(|| "[value_blind] ValueCommitR"), rcv)?
         };
@@ -398,15 +397,15 @@ impl Circuit<pallas::Base> for SpendContract {
 
         // a * G_1
         let (commitment, _) = {
-            let token_commit_v = OrchardFixedBases::ValueCommitV;
-            let token_commit_v = FixedPoint::from_inner(ecc_chip.clone(), token_commit_v);
-            token_commit_v.mul_short(layouter.namespace(|| "[token] ValueCommitV"), (token, one))?
+            let token_commit_v = ValueCommitV;
+            let token_commit_v = FixedPointShort::from_inner(ecc_chip.clone(), token_commit_v);
+            token_commit_v.mul(layouter.namespace(|| "[token] ValueCommitV"), (token, one))?
         };
 
         // r_A * G_2
         let (blind, _rca) = {
             let rca = self.token_blind;
-            let token_commit_r = OrchardFixedBases::ValueCommitR;
+            let token_commit_r = OrchardFixedBasesFull::ValueCommitR;
             let token_commit_r = FixedPoint::from_inner(ecc_chip.clone(), token_commit_r);
             token_commit_r.mul(layouter.namespace(|| "[token_blind] ValueCommitR"), rca)?
         };
@@ -436,9 +435,9 @@ impl Circuit<pallas::Base> for SpendContract {
         )?;
 
         let sig_pub = {
-            let nullifier_k = OrchardFixedBases::NullifierK;
-            let nullifier_k = FixedPoint::from_inner(ecc_chip, nullifier_k);
-            nullifier_k.mul_base_field(layouter.namespace(|| "[x_s] Nullifier"), sig_secret)?
+            let nullifier_k = NullifierK;
+            let nullifier_k = FixedPointBaseField::from_inner(ecc_chip, nullifier_k);
+            nullifier_k.mul(layouter.namespace(|| "[x_s] Nullifier"), sig_secret)?
         };
 
         layouter.constrain_instance(

+ 5 - 1
src/zk/mod.rs

@@ -1,4 +1,8 @@
-pub mod circuit;
+/// Halo2 arithmetic chip
+pub mod arith_chip;
+
 /// Halo2 zkas virtual machine
 pub mod vm;
 mod vm_stack;
+
+pub mod circuit;

+ 95 - 55
src/zk/vm.rs

@@ -1,14 +1,9 @@
-use halo2::{
-    circuit::{Layouter, SimpleFloorPlanner},
-    plonk,
-    plonk::{Advice, Circuit, Column, ConstraintSystem, Instance as InstanceColumn},
-};
 use halo2_gadgets::{
     ecc::{
         chip::{EccChip, EccConfig},
-        FixedPoint, Point,
+        FixedPoint, FixedPointBaseField, FixedPointShort, Point,
     },
-    poseidon::{Hash as PoseidonHash, Pow5T3Chip as PoseidonChip, Pow5T3Config as PoseidonConfig},
+    poseidon::{Hash as PoseidonHash, Pow5Chip as PoseidonChip, Pow5Config as PoseidonConfig},
     primitives::poseidon::{ConstantLength, P128Pow5T3},
     sinsemilla::{
         chip::{SinsemillaChip, SinsemillaConfig},
@@ -17,19 +12,24 @@ use halo2_gadgets::{
             MerklePath,
         },
     },
-    utilities::{
-        gen_const_array, lookup_range_check::LookupRangeCheckConfig, CellValue,
-        UtilitiesInstructions, Var,
-    },
+    utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions},
+};
+use halo2_proofs::{
+    circuit::{AssignedCell, Layouter, SimpleFloorPlanner},
+    plonk,
+    plonk::{Advice, Circuit, Column, ConstraintSystem, Instance as InstanceColumn},
 };
 use log::debug;
-use pasta_curves::{group::Curve, pallas};
+use pasta_curves::{group::Curve, pallas, Fp};
+
+use super::arith_chip::{ArithmeticChip, ArithmeticChipConfig};
 
 pub use super::vm_stack::{StackVar, Witness};
 use crate::{
     crypto::constants::{
         sinsemilla::{OrchardCommitDomains, OrchardHashDomains},
-        OrchardFixedBases,
+        util::gen_const_array,
+        NullifierK, OrchardFixedBases, OrchardFixedBasesFull, ValueCommitV, MERKLE_DEPTH_ORCHARD,
     },
     zkas::{decoder::ZkBinary, opcode::Opcode},
 };
@@ -38,12 +38,13 @@ use crate::{
 pub struct VmConfig {
     primary: Column<InstanceColumn>,
     advices: [Column<Advice>; 10],
-    ecc_config: EccConfig,
+    ecc_config: EccConfig<OrchardFixedBases>,
     merkle_cfg1: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
     merkle_cfg2: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
     sinsemilla_cfg1: SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
     _sinsemilla_cfg2: SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
-    poseidon_config: PoseidonConfig<pallas::Base>,
+    poseidon_config: PoseidonConfig<pallas::Base, 3, 2>,
+    arith_config: ArithmeticChipConfig,
 }
 
 impl VmConfig {
@@ -77,9 +78,13 @@ impl VmConfig {
         MerkleChip::construct(self.merkle_cfg2.clone())
     }
 
-    fn poseidon_chip(&self) -> PoseidonChip<pallas::Base> {
+    fn poseidon_chip(&self) -> PoseidonChip<pallas::Base, 3, 2> {
         PoseidonChip::construct(self.poseidon_config.clone())
     }
+
+    fn arithmetic_chip(&self) -> ArithmeticChip {
+        ArithmeticChip::construct(self.arith_config.clone())
+    }
 }
 
 #[derive(Clone, Default)]
@@ -97,7 +102,7 @@ impl ZkCircuit {
 }
 
 impl UtilitiesInstructions<pallas::Base> for ZkCircuit {
-    type Var = CellValue<pallas::Base>;
+    type Var = AssignedCell<Fp, Fp>;
 }
 
 impl Circuit<pallas::Base> for ZkCircuit {
@@ -133,11 +138,11 @@ impl Circuit<pallas::Base> for ZkCircuit {
 
         // Instance column used for public inputs
         let primary = meta.instance_column();
-        meta.enable_equality(primary.into());
+        meta.enable_equality(primary);
 
         // Permutation over all advice columns
         for advice in advices.iter() {
-            meta.enable_equality((*advice).into());
+            meta.enable_equality(*advice);
         }
 
         // Poseidon requires four advice columns, while ECC incomplete addition
@@ -174,15 +179,17 @@ impl Circuit<pallas::Base> for ZkCircuit {
         );
 
         // Configuration for the Poseidon hash
-        let poseidon_config = PoseidonChip::configure(
+        let poseidon_config = PoseidonChip::configure::<P128Pow5T3>(
             meta,
-            P128Pow5T3,
             advices[6..9].try_into().unwrap(),
             advices[5],
             rc_a,
             rc_b,
         );
 
+        // Configuration for the Arithmetic chip
+        let arith_config = ArithmeticChip::configure(meta);
+
         // Configuration for a Sinsemilla hash instantiation and a
         // Merkle hash instantiation using this Sinsemilla instance.
         // Since the Sinsemilla config uses only 5 advice columns,
@@ -222,6 +229,7 @@ impl Circuit<pallas::Base> for ZkCircuit {
             sinsemilla_cfg1,
             _sinsemilla_cfg2,
             poseidon_config,
+            arith_config,
         }
     }
 
@@ -244,9 +252,8 @@ impl Circuit<pallas::Base> for ZkCircuit {
         // Construct the ECC chip.
         let ecc_chip = config.ecc_chip();
 
-        // Construct the Merkle chips
-        let merkle_chip_1 = config.merkle_chip_1();
-        let merkle_chip_2 = config.merkle_chip_2();
+        // Construct the Arithmetic chip.
+        let arith_chip = config.arithmetic_chip();
 
         // This constant one is used for short multiplication
         let one = self.load_private(
@@ -260,19 +267,19 @@ impl Circuit<pallas::Base> for ZkCircuit {
             debug!("Pushing constant `{}` to stack index {}", constant.as_str(), stack.len());
             match constant.as_str() {
                 "VALUE_COMMIT_VALUE" => {
-                    let vcv = OrchardFixedBases::ValueCommitV;
-                    let vcv = FixedPoint::from_inner(ecc_chip.clone(), vcv);
-                    stack.push(StackVar::EcFixedPoint(vcv));
+                    let vcv = ValueCommitV;
+                    let vcv = FixedPointShort::from_inner(ecc_chip.clone(), vcv);
+                    stack.push(StackVar::EcFixedPointShort(vcv));
                 }
                 "VALUE_COMMIT_RANDOM" => {
-                    let vcr = OrchardFixedBases::ValueCommitR;
+                    let vcr = OrchardFixedBasesFull::ValueCommitR;
                     let vcr = FixedPoint::from_inner(ecc_chip.clone(), vcr);
                     stack.push(StackVar::EcFixedPoint(vcr));
                 }
                 "NULLIFIER_K" => {
-                    let nfk = OrchardFixedBases::NullifierK;
-                    let nfk = FixedPoint::from_inner(ecc_chip.clone(), nfk);
-                    stack.push(StackVar::EcFixedPoint(nfk));
+                    let nfk = NullifierK;
+                    let nfk = FixedPointBaseField::from_inner(ecc_chip.clone(), nfk);
+                    stack.push(StackVar::EcFixedPointBase(nfk));
                 }
                 _ => unimplemented!(),
             }
@@ -318,7 +325,8 @@ impl Circuit<pallas::Base> for ZkCircuit {
 
                 Witness::MerklePath(w) => {
                     debug!("Witnessing MerklePath into circuit");
-                    let path = w.map(|typed_path| gen_const_array(|i| typed_path[i].inner()));
+                    let path: Option<[pallas::Base; MERKLE_DEPTH_ORCHARD]> =
+                        w.map(|typed_path| gen_const_array(|i| typed_path[i].inner()));
 
                     debug!("Pushing MerklePath to stack index {}", stack.len());
                     stack.push(StackVar::MerklePath(path));
@@ -374,12 +382,12 @@ impl Circuit<pallas::Base> for ZkCircuit {
                     debug!("Executing `EcMulBase{:?}` opcode", opcode.1);
                     let args = &opcode.1;
 
-                    let lhs: FixedPoint<pallas::Affine, EccChip<OrchardFixedBases>> =
+                    let lhs: FixedPointBaseField<pallas::Affine, EccChip<OrchardFixedBases>> =
                         stack[args[1]].clone().into();
 
-                    let rhs: CellValue<pallas::Base> = stack[args[0]].clone().into();
+                    let rhs: AssignedCell<Fp, Fp> = stack[args[0]].clone().into();
 
-                    let ret = lhs.mul_base_field(layouter.namespace(|| "EcMulBase()"), rhs)?;
+                    let ret = lhs.mul(layouter.namespace(|| "EcMulBase()"), rhs)?;
 
                     debug!("Pushing result to stack index {}", stack.len());
                     stack.push(StackVar::EcPoint(ret));
@@ -389,14 +397,13 @@ impl Circuit<pallas::Base> for ZkCircuit {
                     debug!("Executing `EcMulShort{:?}` opcode", opcode.1);
                     let args = &opcode.1;
 
-                    let lhs: FixedPoint<pallas::Affine, EccChip<OrchardFixedBases>> =
+                    let lhs: FixedPointShort<pallas::Affine, EccChip<OrchardFixedBases>> =
                         stack[args[1]].clone().into();
 
-                    let rhs: CellValue<pallas::Base> = stack[args[0]].clone().into();
+                    let rhs: AssignedCell<Fp, Fp> = stack[args[0]].clone().into();
 
                     let (ret, _) =
-                        lhs.mul_short(layouter.namespace(|| "EcMulShort()"), (rhs, one))?;
-
+                        lhs.mul(layouter.namespace(|| "EcMulShort()"), (rhs, one.clone()))?;
                     debug!("Pushing result to stack index {}", stack.len());
                     stack.push(StackVar::EcPoint(ret));
                 }
@@ -431,7 +438,7 @@ impl Circuit<pallas::Base> for ZkCircuit {
                     debug!("Executing `PoseidonHash{:?}` opcode", opcode.1);
                     let args = &opcode.1;
 
-                    let mut poseidon_message: Vec<CellValue<pallas::Base>> =
+                    let mut poseidon_message: Vec<AssignedCell<Fp, Fp>> =
                         Vec::with_capacity(args.len());
 
                     for idx in args {
@@ -440,18 +447,25 @@ impl Circuit<pallas::Base> for ZkCircuit {
 
                     macro_rules! poseidon_hash {
                         ($len:expr, $hasher:ident, $output:ident, $cell:ident) => {
-                            let $hasher = PoseidonHash::<_, _, P128Pow5T3, _, 3, 2>::init(
-                                config.poseidon_chip(),
-                                layouter.namespace(|| "PoseidonHash init"),
-                                ConstantLength::<$len>,
-                            )?;
+                            // let $hasher = PoseidonHash::<_, _, P128Pow5T3, _, 3, 2>::init(
+                            // config.poseidon_chip(),
+                            // layouter.namespace(|| "PoseidonHash init"),
+                            // ConstantLength::<$len>,
+                            // )?;
+
+                            let $hasher =
+                                PoseidonHash::<_, _, P128Pow5T3, ConstantLength<$len>, 3, 2>::init(
+                                    config.poseidon_chip(),
+                                    layouter.namespace(|| "PoseidonHash init"),
+                                )?;
 
                             let $output = $hasher.hash(
                                 layouter.namespace(|| "PoseidonHash hash"),
                                 poseidon_message.try_into().unwrap(),
                             )?;
 
-                            let $cell: CellValue<pallas::Base> = $output.inner().into();
+                            //let $cell: AssignedCell<Fp, Fp> = $output.inner().into();
+                            let $cell: AssignedCell<Fp, Fp> = $output.into();
 
                             debug!("Pushing hash to stack index {}", stack.len());
                             stack.push(StackVar::Base($cell));
@@ -480,26 +494,52 @@ impl Circuit<pallas::Base> for ZkCircuit {
                     let merkle_path = stack[args[1]].clone().into();
                     let leaf = stack[args[2]].clone().into();
 
-                    let path = MerklePath {
-                        chip_1: merkle_chip_1.clone(),
-                        chip_2: merkle_chip_2.clone(),
-                        domain: OrchardHashDomains::MerkleCrh,
+                    let merkle_inputs = MerklePath::construct(
+                        config.merkle_chip_1(),
+                        config.merkle_chip_2(),
+                        OrchardHashDomains::MerkleCrh,
                         leaf_pos,
-                        path: merkle_path,
-                    };
+                        merkle_path,
+                    );
 
-                    let root =
-                        path.calculate_root(layouter.namespace(|| "CalculateMerkleRoot()"), leaf)?;
+                    let root = merkle_inputs
+                        .calculate_root(layouter.namespace(|| "CalculateMerkleRoot()"), leaf)?;
 
                     debug!("Pushing merkle root to stack index {}", stack.len());
                     stack.push(StackVar::Base(root));
                 }
 
+                Opcode::BaseAdd => {
+                    debug!("Executing `BaseAdd{:?}` opcode", opcode.1);
+                    let args = &opcode.1;
+
+                    let lhs = stack[args[0]].clone().into();
+                    let rhs = stack[args[1]].clone().into();
+
+                    let sum = arith_chip.add(layouter.namespace(|| "BaseAdd()"), lhs, rhs)?;
+
+                    debug!("Pushing sum to stack index {}", stack.len());
+                    stack.push(StackVar::Base(sum));
+                }
+
+                Opcode::BaseMul => {
+                    debug!("Executing `BaseMul{:?}` opcode", opcode.1);
+                    let args = &opcode.1;
+
+                    let lhs = stack[args[0]].clone().into();
+                    let rhs = stack[args[1]].clone().into();
+
+                    let product = arith_chip.mul(layouter.namespace(|| "BaseMul()"), lhs, rhs)?;
+
+                    debug!("Pushing product to stack index {}", stack.len());
+                    stack.push(StackVar::Base(product));
+                }
+
                 Opcode::ConstrainInstance => {
                     debug!("Executing `ConstrainInstance{:?}` opcode", opcode.1);
                     let args = &opcode.1;
 
-                    let var: CellValue<pallas::Base> = stack[args[0]].clone().into();
+                    let var: AssignedCell<Fp, Fp> = stack[args[0]].clone().into();
 
                     layouter.constrain_instance(
                         var.cell(),

+ 25 - 7
src/zk/vm_stack.rs

@@ -1,9 +1,7 @@
 //! VM stack type abstractions
-use halo2_gadgets::{
-    ecc::{chip::EccChip, FixedPoint, Point},
-    utilities::CellValue,
-};
-use pasta_curves::pallas;
+use halo2_gadgets::ecc::{chip::EccChip, FixedPoint, FixedPointBaseField, FixedPointShort, Point};
+use halo2_proofs::circuit::AssignedCell;
+use pasta_curves::{pallas, EpAffine};
 
 use crate::crypto::{constants::OrchardFixedBases, merkle_node::MerkleNode};
 
@@ -26,7 +24,9 @@ pub enum Witness {
 pub enum StackVar {
     EcPoint(Point<pallas::Affine, EccChip<OrchardFixedBases>>),
     EcFixedPoint(FixedPoint<pallas::Affine, EccChip<OrchardFixedBases>>),
-    Base(CellValue<pallas::Base>),
+    EcFixedPointShort(FixedPointShort<pallas::Affine, EccChip<OrchardFixedBases>>),
+    EcFixedPointBase(FixedPointBaseField<pallas::Affine, EccChip<OrchardFixedBases>>),
+    Base(AssignedCell<pallas::Base, pallas::Base>),
     Scalar(Option<pallas::Scalar>),
     MerklePath(Option<[pallas::Base; 32]>),
     Uint32(Option<u32>),
@@ -60,7 +60,7 @@ impl From<StackVar> for std::option::Option<pallas::Scalar> {
     }
 }
 
-impl From<StackVar> for CellValue<pallas::Base> {
+impl From<StackVar> for AssignedCell<pallas::Base, pallas::Base> {
     fn from(value: StackVar) -> Self {
         match value {
             StackVar::Base(v) => v,
@@ -86,3 +86,21 @@ impl From<StackVar> for std::option::Option<[pallas::Base; 32]> {
         }
     }
 }
+
+impl From<StackVar> for FixedPointShort<EpAffine, EccChip<OrchardFixedBases>> {
+    fn from(value: StackVar) -> Self {
+        match value {
+            StackVar::EcFixedPointShort(v) => v,
+            _ => unimplemented!(),
+        }
+    }
+}
+
+impl From<StackVar> for FixedPointBaseField<EpAffine, EccChip<OrchardFixedBases>> {
+    fn from(value: StackVar) -> Self {
+        match value {
+            StackVar::EcFixedPointBase(v) => v,
+            _ => unimplemented!(),
+        }
+    }
+}

+ 1 - 1
src/zkas/error.rs

@@ -14,7 +14,7 @@ impl ErrorEmitter {
     }
 
     pub fn emit(&self, msg: String, ln: usize, col: usize) {
-        let err_msg = format!("{} (line{}, column {})", msg, ln, col);
+        let err_msg = format!("{} (line {}, column {})", msg, ln, col);
         let dbg_msg = format!("{}:{}:{}: {}", self.file, ln, col, self.lines[ln - 1]);
         let pad = dbg_msg.split(": ").next().unwrap().len() + col + 2;
         let caret = format!("{:width$}^", "", width = pad);

+ 16 - 2
src/zkas/opcode.rs

@@ -6,15 +6,19 @@ use super::types::Type;
 pub enum Opcode {
     /// Elliptic curve addition
     EcAdd = 0x00,
+
     /// Elliptic curve multiplication
     EcMul = 0x01,
+
     /// Elliptic curve multiplication with a Base field element
     EcMulBase = 0x02,
+
     /// Elliptic curve multiplication with a u64 wrapped in a Scalar element
     EcMulShort = 0x03,
 
     /// Get the x coordinate of an elliptic curve point
     EcGetX = 0x08,
+
     /// Get the y coordinate of an elliptic curve point
     EcGetY = 0x09,
 
@@ -24,6 +28,12 @@ pub enum Opcode {
     /// Calculate merkle root given given a position, Merkle path, and an element
     CalculateMerkleRoot = 0x20,
 
+    /// Base field element addition
+    BaseAdd = 0x30,
+
+    /// Base field element multiplication
+    BaseMul = 0x31,
+
     /// Constrain a Base field element to a circuit's public input
     ConstrainInstance = 0xf0,
 
@@ -39,14 +49,16 @@ impl Opcode {
             // (return_type, opcode_arg_types)
             Opcode::EcAdd => (vec![Type::EcPoint], vec![Type::EcPoint, Type::EcPoint]),
             Opcode::EcMul => (vec![Type::EcPoint], vec![Type::Scalar, Type::EcFixedPoint]),
-            Opcode::EcMulBase => (vec![Type::EcPoint], vec![Type::Base, Type::EcFixedPoint]),
-            Opcode::EcMulShort => (vec![Type::EcPoint], vec![Type::Base, Type::EcFixedPoint]),
+            Opcode::EcMulBase => (vec![Type::EcPoint], vec![Type::Base, Type::EcFixedPointBase]),
+            Opcode::EcMulShort => (vec![Type::EcPoint], vec![Type::Base, Type::EcFixedPointShort]),
             Opcode::EcGetX => (vec![Type::Base], vec![Type::EcPoint]),
             Opcode::EcGetY => (vec![Type::Base], vec![Type::EcPoint]),
             Opcode::PoseidonHash => (vec![Type::Base], vec![Type::BaseArray]),
             Opcode::CalculateMerkleRoot => {
                 (vec![Type::Base], vec![Type::Uint32, Type::MerklePath, Type::Base])
             }
+            Opcode::BaseAdd => (vec![Type::Base], vec![Type::Base, Type::Base]),
+            Opcode::BaseMul => (vec![Type::Base], vec![Type::Base, Type::Base]),
             Opcode::ConstrainInstance => (vec![], vec![Type::Base]),
             Opcode::Noop => (vec![], vec![]),
         }
@@ -62,6 +74,8 @@ impl Opcode {
             0x09 => Self::EcGetY,
             0x10 => Self::PoseidonHash,
             0x20 => Self::CalculateMerkleRoot,
+            0x30 => Self::BaseAdd,
+            0x31 => Self::BaseMul,
             0xf0 => Self::ConstrainInstance,
             _ => unimplemented!(),
         }

+ 38 - 0
src/zkas/parser.rs

@@ -355,6 +355,24 @@ impl Parser {
                     });
                 }
 
+                "EcFixedPointShort" => {
+                    ret.push(Constant {
+                        name: k.to_string(),
+                        typ: Type::EcFixedPointShort,
+                        line: v.0.line,
+                        column: v.0.column,
+                    });
+                }
+
+                "EcFixedPointBase" => {
+                    ret.push(Constant {
+                        name: k.to_string(),
+                        typ: Type::EcFixedPointBase,
+                        line: v.0.line,
+                        column: v.0.column,
+                    });
+                }
+
                 x => {
                     self.error.emit(
                         format!("`{}` is an illegal constant type", x),
@@ -620,6 +638,26 @@ impl Parser {
                         continue
                     }
 
+                    "base_add" => {
+                        stmt.args = self.parse_function_call(token, &mut iter);
+                        stmt.opcode = Opcode::BaseAdd;
+                        stmt.line = token.line;
+                        stmts.push(stmt.clone());
+
+                        parsing = false;
+                        continue
+                    }
+
+                    "base_mul" => {
+                        stmt.args = self.parse_function_call(token, &mut iter);
+                        stmt.opcode = Opcode::BaseMul;
+                        stmt.line = token.line;
+                        stmts.push(stmt.clone());
+
+                        parsing = false;
+                        continue
+                    }
+
                     x => {
                         self.error.emit(
                             format!("Unimplemented function call `{}`", x),

+ 10 - 0
src/zkas/types.rs

@@ -8,13 +8,21 @@ pub enum Type {
     /// Elliptic curve fixed point (a constant)
     EcFixedPoint = 0x01,
 
+    /// Elliptic curve fixed point short
+    EcFixedPointShort = 0x02,
+
+    /// Elliptic curve fixed point in base field
+    EcFixedPointBase = 0x03,
+
     /// Base field element
     Base = 0x10,
+
     /// Array of Base field elements
     BaseArray = 0x11,
 
     /// Scalar field element
     Scalar = 0x12,
+
     /// Array of Scalar field elements
     ScalarArray = 0x13,
 
@@ -36,6 +44,8 @@ impl Type {
         match b {
             0x00 => Self::EcPoint,
             0x01 => Self::EcFixedPoint,
+            0x02 => Self::EcFixedPointShort,
+            0x03 => Self::EcFixedPointBase,
             0x10 => Self::Base,
             0x11 => Self::BaseArray,
             0x12 => Self::Scalar,