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

Port codebase to latest halo2 revision.

parazyd 4 лет назад
Родитель
Сommit
3238530003

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

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

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

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