فهرست منبع

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

lunar-mining 4 سال پیش
والد
کامیت
04d986c1f4
61فایلهای تغییر یافته به همراه2097 افزوده شده و 763 حذف شده
  1. 79 109
      Cargo.lock
  2. 11 9
      Cargo.toml
  3. 9 14
      bin/cashierd/src/main.rs
  4. 7 16
      bin/darkfid/src/main.rs
  5. 7 16
      bin/drk/src/main.rs
  6. 7 16
      bin/gatewayd/src/main.rs
  7. 2 2
      bin/ircd/Cargo.toml
  8. 9 6
      bin/ircd/src/main.rs
  9. 1 1
      bin/ircd/src/protocol_privmsg.rs
  10. 2 2
      bin/map/src/lib.rs
  11. 1 1
      bin/map/src/main.rs
  12. 110 0
      example/dao.rs
  13. BIN
      lc.file
  14. 516 0
      proof/dao.rs
  15. 46 0
      proof/dao.zk
  16. 45 0
      script/research/PoS-blockchain/ouroboros/beacon.py
  17. 91 0
      script/research/PoS-blockchain/ouroboros/block.py
  18. 39 0
      script/research/PoS-blockchain/ouroboros/blockchain.py
  19. 46 0
      script/research/PoS-blockchain/ouroboros/clock.py
  20. 68 0
      script/research/PoS-blockchain/ouroboros/environment.py
  21. 53 0
      script/research/PoS-blockchain/ouroboros/epoch.py
  22. 14 0
      script/research/PoS-blockchain/ouroboros/kes.py
  23. 13 0
      script/research/PoS-blockchain/ouroboros/logger.py
  24. 70 0
      script/research/PoS-blockchain/ouroboros/stakeholder.py
  25. 56 0
      script/research/PoS-blockchain/ouroboros/utils.py
  26. 27 16
      script/research/PoS-blockchain/ouroboros/vrf.py
  27. 29 1
      src/cli/cli_config.rs
  28. 9 0
      src/cli/cli_parser.rs
  29. 1 1
      src/cli/mod.rs
  30. 2 2
      src/crypto/arith_chip.rs
  31. 5 5
      src/crypto/coin.rs
  32. 10 1
      src/crypto/constants.rs
  33. 100 153
      src/crypto/constants/fixed_bases.rs
  34. 11 13
      src/crypto/constants/fixed_bases/commit_ivk_r.rs
  35. 13 16
      src/crypto/constants/fixed_bases/note_commit_r.rs
  36. 9 13
      src/crypto/constants/fixed_bases/nullifier_k.rs
  37. 9 10
      src/crypto/constants/fixed_bases/spend_auth_g.rs
  38. 9 12
      src/crypto/constants/fixed_bases/value_commit_r.rs
  39. 11 15
      src/crypto/constants/fixed_bases/value_commit_v.rs
  40. 257 0
      src/crypto/constants/load.rs
  41. 31 56
      src/crypto/constants/sinsemilla.rs
  42. 2 10
      src/crypto/constants/util.rs
  43. 17 15
      src/crypto/keypair.rs
  44. 2 3
      src/crypto/merkle_node.rs
  45. 9 12
      src/crypto/mint_proof.rs
  46. 2 1
      src/crypto/mod.rs
  47. 7 6
      src/crypto/nullifier.rs
  48. 17 15
      src/crypto/proof.rs
  49. 10 6
      src/crypto/schnorr.rs
  50. 11 14
      src/crypto/spend_proof.rs
  51. 13 2
      src/crypto/util.rs
  52. 3 10
      src/error.rs
  53. 1 1
      src/net/message.rs
  54. 1 1
      src/net/mod.rs
  55. 6 11
      src/net/protocol/protocol_registry.rs
  56. 3 3
      src/node/service/gateway_p2p.rs
  57. 30 32
      src/zk/circuit/mint_contract.rs
  58. 54 51
      src/zk/circuit/spend_contract.rs
  59. 57 56
      src/zk/vm.rs
  60. 16 7
      src/zk/vm_stack.rs
  61. 1 1
      src/zkas/error.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"

+ 11 - 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",
@@ -253,3 +250,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"]

+ 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"
 

+ 9 - 6
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},
@@ -218,12 +220,13 @@ impl JsonRpcInterface {
 }
 
 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};

+ 1 - 1
bin/map/src/main.rs

@@ -222,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();

+ 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(())
+}

BIN
lc.file


+ 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);
+}

+ 45 - 0
script/research/PoS-blockchain/ouroboros/beacon.py

@@ -0,0 +1,45 @@
+from clock import SynchedNTPClock
+from vrf import VRF
+import threading
+import time 
+
+'''
+\class TrustedBeacon
+
+the trusted beacon is decentralized, such that at the onset of the Epoch,
+the leader of the first slot generated the signed seed, and release the signature, 
+proof, and base to the genesis block.
+
+#TODO implement trustedbeacon as a node
+'''
+class TrustedBeacon(SynchedNTPClock, threading.Thread):
+    def __init__(self, node, epoch_length):
+        SynchedNTPClock.__init__(self.epoch_length)
+        threading.Thread.__init__(self)
+        self.daemon=True
+        self.epoch_length=epoch_length # how many slots in a a block
+        self.node = node #stakeholder
+        self.vrf = VRF(self.node.vrf_pk, self.node.vrf_sk, self.node.vrk_base)
+        self.current_slot = self.slot
+
+    def run(self):
+        self.__background()
+
+    def __background(self):
+        current_epoch = self.slot
+        while True:
+            if self.slot != current_epoch:
+                current_epoch = self.slot
+                self.__callback()
+
+    def __callback(self):
+        self.current_slot = self.slot
+        sigma, proof = self.vrf.sign(self.current_slot)
+        if self.slot%self.epoch_length==0:
+            self.node.new_slot(self.current_slot, sigma, proof)
+        else:
+            self.node.new_slot(self.current_slot, sigma, proof, True)
+
+    def verify(self, y, pi, pk_raw, g):
+        return VRF.verify(self.current_slot, y, pi, pk_raw, g)
+    

+ 91 - 0
script/research/PoS-blockchain/ouroboros/block.py

@@ -0,0 +1,91 @@
+import json
+from utils import encode_genesis_data, decode_gensis_data, state_hash
+
+'''
+single block B_i for slot i in the system live time L,
+assigned to stakeholder U_j, with propability P_j_i,
+in the chain C, should be signed by U_j keys.
+'''
+class Block(object):
+    '''
+    @param previous_block: parent block to the current block
+    @param data: is the transaction, or contracts in the leadger, or gensis block data, 
+        data is expected to be binary, no format is enforced
+    @param slot_uid: the block corresponding slot monotonically increasing index, 
+        it's one-based
+    @param gensis: boolean, True for gensis block
+    '''
+    def __init__(self, previous_block, data, slot_uid, genesis=False):
+        # state is hte hash of the previous block in the blockchain
+        self.state=''
+        if slot_uid>1:
+            self.state=state_hash(previous_block)
+        self.tx = data
+        self.sl = slot_uid
+        self.is_genesis=genesis
+
+    def __repr__(self):
+        if self.is_genesis:
+            return "GensisBlock at {slot:"+self.sl+",data:"+self.tx+",state:"+self.state+"}\n"+\
+                decode_gensis_data(self.data)
+        return "Block at {slot:"+self.sl+",data:"+self.tx+",state:"+self.state+"}"
+    
+    def __eq__(self, block):
+        return self.state==block.state and \
+            self.tx == block.tx and \
+            self.sl == block.sl
+
+    def to_json(self):
+        d = {'state':self.state, \
+            'data': self.tx, \
+            'sl': self.sl}
+        return json.encoder(d)
+
+    @property
+    def state(self):
+        return self.st
+    
+    @property
+    def data(self):
+        return self.tx
+
+    @property
+    def slot(self):
+        return self.sl
+
+    @property
+    def empty(self):
+        return (self.data=='' or self.slot<0) and self.state==''
+
+class GensisBlock(Block):
+    '''
+    @param data: data is dictionary of  list of (pk_i, s_i) public key,
+        and stake respectively of the corresponding stakeholder U_i,
+        seed of the leader election function.
+    '''
+    def __init__(self, previous_block, data, slot_uid):
+        # stakeholders is list of tuple (pk_i, s_i) for the ith stakeholder
+        self.stakeholders = data['stakeholders']
+        self.seed = data['seed']
+        data = encode_genesis_data(self.stakeholders, self.seed)
+        super.__init__(previous_block, data, slot_uid, True)
+    '''
+    @return: the number of participating stakeholders in the blockchain
+    '''
+    @property
+    def length(self):
+        return len(self.stakeholders)
+
+    def __getitem__(self, i):
+        if i<0 or i>=self.length:
+            raise "index is out of range!"
+        return self.stakeholders[i]
+
+'''
+block lead by an adversary, or 
+lead by offline leader
+is an empty Block
+'''
+class EmptyBlock(Block):
+    def __init__(self):
+        super.__init__(None, '', -1, False)

+ 39 - 0
script/research/PoS-blockchain/ouroboros/blockchain.py

@@ -0,0 +1,39 @@
+from logger import Logger
+'''
+Non-forkable Blockchain for simplicity
+#TODO consider forkable property
+'''
+class Blockchain(object):
+    def __init__(self, R):
+        self.blocks = []
+        self.log = Logger(self)
+        self.R = R # how many slots in single epoch
+    
+    @property
+    def epoch_length(self):
+        return self.R
+
+    def __repr__(self):
+        buff=''
+        for i in range(len(self.blocks)):
+            buff+=self.blocks[i]
+        return buff
+    
+    def __getitem__(self, i):
+        return self.blocks[i]
+
+    def __len__(self):
+        return len(self.blocks)
+
+    def __add_block(self, block):
+        self.blocks.append(block)
+
+    def add_epoch(self, epoch):
+        for idx, block in enumerate(epoch):
+            if not block.empty:
+                self.__add_block(block)
+            else:
+                self.log.info(f"met an empty block at index of index: {block.index},\nrelative slot:{idx}\nabsolute slot: {self.length*idx+block.slot}")
+
+
+    

+ 46 - 0
script/research/PoS-blockchain/ouroboros/clock.py

@@ -0,0 +1,46 @@
+'''
+synchronized NTP clock
+'''
+
+import ntplib
+from time import ctime
+import math
+
+class SynchedNTPClock(object):
+
+    def __init__(self, slot_length=180, ntp_server='europe.pool.ntp.org'):
+        #TODO how long should be the slot length
+        self.slot_length=slot_length
+        self.ntp_server = ntp_server
+        self.ntp_client = ntplib.NTPClient()
+        #TODO validate the server
+        # when was darkfi birthday? as seconds since the epoch 
+        self.darkfi_epoch=0
+        
+    def __repr__(self):
+        return 'darkfi time: '+ ctime(self.darkfi_time) + ', current synched time: ' + ctime(self.synched_time)
+
+    def __get_time_stat(self):
+        response=None
+        success=True
+        while not success:
+            try:
+                response = self.ntp_client.request(self.ntp_server, version=3)
+                success=True
+            except ntplib.NTPException as e:
+                 print("connection failed: {}".format(e.what()))
+        return response
+
+    @property
+    def synched_time(self):
+        state = self.__get_time_stat()
+        synched_time = state.tx_time
+        return synched_time
+
+    @property
+    def darkfi_time(self):
+        return self.synched_time - self.darkfi_epoch
+
+    @property
+    def slot(self):   
+        return math.floor(self.darkfi_time/self.slot_length)

+ 68 - 0
script/research/PoS-blockchain/ouroboros/environment.py

@@ -0,0 +1,68 @@
+import numpy as np
+import math
+import random
+'''
+\class Z is the environment
+'''
+class Z(object):
+    def __init__(self, stakeholdes, epoch_length=100):
+        self.epoch_length=epoch_length
+        self.stakeholders = np.array(stakeholdes)
+        self.adversary_mask=np.array([True]*len(stakeholdes))
+    '''
+        return genesis data of the current epoch
+    '''
+    def get_genesis_data(self):
+        #TODO implement    
+        pass
+    
+    @property
+    def current_leader_vrf_pk(self):
+        #TODO implement
+        pass
+    
+    @property
+    def current_leader_vrf_g(self):
+        #TODO implement
+        pass
+
+    #TODO complete
+    def obfuscate_idx(self, i):
+        return i
+
+    #TODO complete
+    def deobfuscate_idx(self, i):
+        return i
+
+    def corrupt(self, i):
+        if i<0 or i>len(self.adversary_mask):
+            return False
+        self.adversary_mask[self.deobfuscate_idx(i)]=False
+        return True
+    
+    '''
+    return the length of all parties
+    '''
+    def __len__(self):
+        return len(self.stakeholders)
+
+    @property
+    def length(self):
+        return len(self.stakeholders)
+    @property
+    def honest(self):
+        return len(self.stakeholders[self.adversary_mask])
+
+    def select_epoch_leaders(self, sigma):
+        def leader_selection_hash(sigma):
+            Y = np.array(sigma)
+            y_hypotenuse2 = math.ceil(np.sum(Y[1]**2+Y[2]**2))
+            return y_hypotenuse2
+        seed = leader_selection_hash(sigma)
+        random.seed(seed)
+        leader_idx=seed%self.length
+        leader = self.stakeholders[leader_idx]
+        while not self.adversary_mask[leader_idx]:
+            leader_idx=random.randint(0,self.length)
+        #TODO select the following leader for this epoch, note, 
+        # under a single condition that no one is able to predict who is next

+ 53 - 0
script/research/PoS-blockchain/ouroboros/epoch.py

@@ -0,0 +1,53 @@
+from utils import state_hash
+
+class Epoch(object):
+    '''
+    epoch spans R slots, 
+    maximum number of block in Epoch is R
+    epoch must start with gensis block B0
+    '''
+    def __init__(self, gensis_block, R, epoch_idx):
+        self.gensis_block=gensis_block
+        self.blocks = []
+        self.R = R #maximum epoch legnth, and it's a fixed property of the system
+        self.e = epoch_idx
+        self.index=0
+    @property
+    def slot(self):
+        return self.gensis_block.sl
+    
+    @property
+    def length(self):
+        return len(self.blocks)
+
+    @property
+    def index(self):
+        return self.e
+
+    @property
+    def genesis(self):
+        if self.length==0:
+            return None
+        return self.blocks[0]
+
+    def add_block(self, block):
+        if len(self.blocks)>0 and not block.state==state_hash(self.block[-1]):
+            #TODO we dealing with corrupt stakeholder,
+            # action to be taken
+            # the caller of the add_block should execute (corrupt,U)
+            pass
+        if self.length==self.R:
+            raise f"can't exceed Epoch's length: {self.length}"
+        self.blocks.append(block)
+    
+    def __iter__(self):
+        return self
+    
+    def __next__(self):
+        for i in range(self.length):
+            try:
+                res=self.blocks[self.index]
+            except IndexError:
+                raise StopIteration
+            self.index+=1
+            return res

+ 14 - 0
script/research/PoS-blockchain/ouroboros/kes.py

@@ -0,0 +1,14 @@
+'''
+forward secure signature scheme by key evolving
+'''
+class KES(object):
+    def __init__(sefl):
+        pass
+    def gen(self):
+        pk=None
+        sk=None
+        return pk, sk
+    def verify(self, sigma, message, pk):
+        return True
+    def update(self):
+        pass

+ 13 - 0
script/research/PoS-blockchain/ouroboros/logger.py

@@ -0,0 +1,13 @@
+class Logger(object):
+    def __init__(self, obj):
+        self.obj = obj
+
+    def info(self, payload):
+        print(f"\t[{self.obj}]:\n{payload}")
+    
+    def warn(self, payload):
+        print(f"\t[{self.obj}]:\n{payload}")
+    
+    def error(self, pyaload):
+        print(f"\t[{self.obj}]:\n{payload}")
+        exit()

+ 70 - 0
script/research/PoS-blockchain/ouroboros/stakeholder.py

@@ -0,0 +1,70 @@
+from block import Block, GensisBlock, EmptyBlock
+from blockchain import Blockchain
+from epoch import Epoch
+from beacon import TrustedBeacon
+from vrf import generate_vrf_keys
+from utils import *
+import numpy as np
+import math
+
+'''
+\class Stakeholder
+'''
+class Stakeholder(object):
+    def __init__(self, env, epoch_length=100, passwd='password'):
+        self.passwd=passwd
+        self.epoch_length=epoch_length
+        self.blockchain = Blockchain(self.epoch_length)
+        self.beacon = TrustedBeacon(self, self.epoch_length)
+        self.beacon.start()
+        pk, sk, g = generate_vrf_keys(self.passwd)
+        self.vrf_pk = pk
+        self.vrf_sk = sk
+        self.vrf_base = g
+        self.current_block = None
+        self.uncommited_tx=''
+        self.tx=''
+        self.current_slot_uid = self.beacon.slot
+        self.current_epoch = None
+        self.env = env
+        
+    @property
+    def epoch_index(self):
+        return round(self.current_slot_uid/self.epoch_length)
+
+    '''
+    it's a callback function, and called by the diffuser
+    '''
+    def new_slot(self, slot, sigma, proof, new_epoch=False):
+        '''
+        #TODO implement praos
+        for this implementation we assume synchrony,
+        and at this point, and no delay is considered (for simplicity)
+        '''
+
+        if not self.beacon.verify(sigma, proof, self.env.current_leader_vrf_pk, self.env.current_leader_vrf_g):
+            #TODO the leader is corrupted, action to be taken against the corrupt stakeholder
+            #in this case this slot is empty
+            self.current_block=EmptyBlock() 
+            self.current_epoch.add_block(self.current_block)
+            return
+        self.current_slot_uid = slot
+        if new_epoch:
+            # add epoch to the ledger
+            if self.current_slot_uid > 1:
+                self.blockchain.add_epoch(self.current_epoch)
+            #kickoff gensis block
+            self.tx = self.env.get_genesis_data()
+            self.current_block=GensisBlock(self.current_block, self.tx, self.current_slot_uid)
+            self.current_epoch=Epoch(self.current_block, self.epoch_length, self.epoch_index)
+            #TODO elect leaders
+            self.select_leader(slot, sigma, proof)
+
+        else:
+            self.current_block=Block(self.current_block, self.tx, self.current_slot_uid)
+            self.current_epoch.add_block(self.current_block)
+
+
+    def select_leader(self, slot, sigma, proof):
+        #TODO implement
+        pass

+ 56 - 0
script/research/PoS-blockchain/ouroboros/utils.py

@@ -1,3 +1,7 @@
+import random
+import joblib
+import pickle
+
 def extended_euclidean_algorithm(a, b):
     """
     Returns a three-tuple (gcd, x, y) such that
@@ -38,3 +42,55 @@ def inverse_of(n, p):
             'modulo {}'.format(n, p))
     else:
         return x % p
+
+'''
+@param nums: list of weight
+@param true_rnd_fn: truely random function
+@return zero-based index of the truely selected element
+'''
+def weighted_random(nums, true_rnd_fn=random.random):
+    """
+    nums is list of weight, it return the truely random
+    weighted value.
+    """
+    L = len(nums)
+    pair = [(i, nums[i]) for i in range(L)]
+    pair.sort(key=lambda p: p[1])
+    tot = sum([pair[i][1] for i in range(L)])
+    frequency = [pair[i][1]/tot for i in range(L)]
+    acc_prop = [sum(frequency[:i+1]) for i in range(L)]
+    rnd = true_rnd_fn()
+    for elected in range(L):
+        if rnd<=acc_prop[elected]:
+            break
+    return pair[elected][0]
+
+
+'''
+@param data: data is dictionary of  list of (pk_i, s_i) public key,
+        and stake respectively of the corresponding stakeholder U_i,
+        seed of the leader election function.
+'''
+def encode_genesis_data(data):
+    return pickle.dumps(data)
+
+def decode_gensis_data(encoded_data):
+    return pickle.loads(encoded_data)
+
+'''
+TODO this is a  adhoc solution
+this has is used to compute the state of block from the previous block
+'''
+def state_hash(obj):
+    return hash(obj)
+
+
+'''
+TODO this is a  adhoc solution
+this is used to generate VRF's sk from some seed
+note there is a need for nounce to be concatenated with the seed,
+just in case two stakeholders started with the same seed
+(for the time being the seed is provided by the stakeholder, it's stakeholder passowrd)
+'''
+def vrf_hash(seed):
+    return hash(seed)

+ 27 - 16
script/research/PoS-blockchain/ouroboros/vrf.py

@@ -2,37 +2,48 @@ from streamlet.logger import Logger
 import random as rnd
 from  tate_bilinear_pairing import eta, ecc
 from ouroboros.utils import inverse_of
+from utils import vrf_hash
 eta.init(369)
 
+'''
+gernate vrf keys for stakeholder
+@param sk_seed: this is suppoed to be the password of the stakeholder
+'''
+def generate_vrf_keys(sk_seed):
+    '''
+        generate pk/sk
+    return: list of pk (public key), sk(secret key), base(field base)
+    '''
+    sk = vrf_hash(sk_seed)
+    base = ecc.gen()
+    pk = ecc.scalar_mult(sk, base)
+    return (pk, sk, base)
+
 class VRF(object):
     '''
     verifiable random function implementation
     '''
-    def __init__(self):
-        self.pk = None
-        self.sk = None
+    def __init__(self, pk, sk, base):
+        self.pk = pk
+        self.sk = sk
+        self.g=base
         self.log = Logger(self)
-        #TODO (res) adhoc temporary
-        self.g = ecc.gen()
-        self.__gen()
         self.order = ecc.order()
 
-    def __gen(self):
-        '''
-        generate pk/sk
-        '''
-        # TODO implement that is simple sk choosing mechanism for poc; 
-        self.sk = rnd.randint(0,1000)
-        self.pk = ecc.scalar_mult(self.sk, self.g)
-
     '''
     short signature without random oracle
     @param x: message to be signed
+    @return y (the signature), pi (the proof)
     '''
     def sign(self, x):
         pi = ecc.scalar_mult(inverse_of(x+self.sk, self.order), self.g)
         y = eta.pairing(*self.g[1:], *pi[1:])
-        return (y, pi, self.g)
+        return (y, pi)
+
+    def update(self, pk, sk, g):
+        self.pk = pk
+        self.sk = sk
+        self.g = g
     
     '''
     verify signature
@@ -56,4 +67,4 @@ class VRF(object):
             print(f"proposed {x}, {y}, {pi}, {pk_raw}, {g}")
             print(f"lhs: {lhs},\nrhs: {rhs}")
             return False
-        return True
+        return True

+ 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};

+ 2 - 2
src/crypto/arith_chip.rs

@@ -1,9 +1,9 @@
-use halo2::{
+use halo2_gadgets::utilities::Var;
+use halo2_proofs::{
     circuit::{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>;

+ 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))
     }
 }

+ 10 - 1
src/crypto/constants.rs

@@ -2,10 +2,19 @@ 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;
+
+/// $\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()
+    }
+}

+ 31 - 56
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,12 @@ pub const INV_TWO_POW_K: [u8; 32] = [
 /// of Pallas.
 pub const C: usize = 253;
 
+/// $\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 +61,14 @@ 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 +85,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 +110,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 +128,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 +179,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 +189,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 +199,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))

+ 2 - 1
src/crypto/mod.rs

@@ -1,5 +1,5 @@
 pub mod address;
-pub mod arith_chip;
+//pub mod arith_chip;
 pub mod coin;
 pub mod constants;
 pub mod diffie_hellman;
@@ -10,6 +10,7 @@ pub mod mint_proof;
 pub mod note;
 pub mod nullifier;
 pub mod proof;
+//pub mod redpallas;
 pub mod schnorr;
 pub mod spend_proof;
 pub mod token_id;

+ 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
     }
 }
 

+ 11 - 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, pallas};
+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,13 @@ pub fn create_spend_proof(
         signature_secret,
     );
 
-    let merkle_path: Vec<pallas::Base> = merkle_path.iter().map(|node| node.0).collect();
+    //let merkle_path: Vec<MerkleNode> = 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 +176,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 })
     }

+ 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 - 51
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,
@@ -264,18 +265,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 +300,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 +313,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 +329,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 +365,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 +401,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 +439,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(

+ 57 - 56
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,22 @@ 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};
 
 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 +36,12 @@ 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>,
 }
 
 impl VmConfig {
@@ -77,7 +75,7 @@ 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())
     }
 }
@@ -97,7 +95,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 +131,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,9 +172,8 @@ 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,
@@ -244,10 +241,6 @@ 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();
-
         // This constant one is used for short multiplication
         let one = self.load_private(
             layouter.namespace(|| "Load constant one"),
@@ -260,19 +253,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::FixedPointShort(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 +311,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 +368,13 @@ 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: 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_base_field(layouter.namespace(|| "EcMulBase()"), rhs)?;
+                    let (ret, _) =
+                        lhs.mul(layouter.namespace(|| "EcMulBase()"), (rhs, one.clone()))?;
 
                     debug!("Pushing result to stack index {}", stack.len());
                     stack.push(StackVar::EcPoint(ret));
@@ -389,14 +384,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 +425,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 +434,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,16 +481,16 @@ 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));
@@ -499,7 +500,7 @@ impl Circuit<pallas::Base> for ZkCircuit {
                     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(),

+ 16 - 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,11 +24,13 @@ pub enum Witness {
 pub enum StackVar {
     EcPoint(Point<pallas::Affine, EccChip<OrchardFixedBases>>),
     EcFixedPoint(FixedPoint<pallas::Affine, EccChip<OrchardFixedBases>>),
-    Base(CellValue<pallas::Base>),
+    EcFixedPointBase(FixedPointBaseField<pallas::Affine, EccChip<OrchardFixedBases>>),
+    Base(AssignedCell<pallas::Base, pallas::Base>),
     Scalar(Option<pallas::Scalar>),
     MerklePath(Option<[pallas::Base; 32]>),
     Uint32(Option<u32>),
     Uint64(Option<u64>),
+    FixedPointShort(FixedPointShort<EpAffine, EccChip<OrchardFixedBases>>),
 }
 
 impl From<StackVar> for Point<pallas::Affine, EccChip<OrchardFixedBases>> {
@@ -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,12 @@ 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::FixedPointShort(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);