diff --git a/ironfish-rust/src/keys/mod.rs b/ironfish-rust/src/keys/mod.rs index 9e4313cda6..24287cf681 100644 --- a/ironfish-rust/src/keys/mod.rs +++ b/ironfish-rust/src/keys/mod.rs @@ -13,6 +13,7 @@ use group::GroupEncoding; use ironfish_zkp::constants::{ CRH_IVK_PERSONALIZATION, PROOF_GENERATION_KEY_GENERATOR, SPENDING_KEY_GENERATOR, }; +pub use ironfish_zkp::ProofGenerationKey; use jubjub::SubgroupPoint; use rand::prelude::*; @@ -26,8 +27,6 @@ mod view_keys; pub use view_keys::*; mod util; pub use util::*; -pub mod proof_generation_key; -pub use proof_generation_key::*; #[cfg(test)] mod test; @@ -210,10 +209,7 @@ impl SaplingKey { /// Adapter to convert this key to a proof generation key for use in /// sapling functions pub fn sapling_proof_generation_key(&self) -> ProofGenerationKey { - ProofGenerationKey { - ak: self.view_key.authorizing_key, - nsk: self.proof_authorizing_key, - } + ProofGenerationKey::new(self.view_key.authorizing_key, self.proof_authorizing_key) } /// Convert the spending key to another value using a pseudorandom hash diff --git a/ironfish-rust/src/keys/proof_generation_key.rs b/ironfish-rust/src/keys/proof_generation_key.rs deleted file mode 100644 index ac19cf0119..0000000000 --- a/ironfish-rust/src/keys/proof_generation_key.rs +++ /dev/null @@ -1,170 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ - -use group::GroupEncoding; -pub use ironfish_zkp::ProofGenerationKey; -use jubjub::{Fr, SubgroupPoint}; - -use crate::{ - errors::{IronfishError, IronfishErrorKind}, - serializing::{bytes_to_hex, hex_to_bytes}, -}; - -pub trait ProofGenerationKeySerializable { - fn serialize(&self) -> [u8; 64]; - fn deserialize(bytes: [u8; 64]) -> Result; - fn hex_key(&self) -> String; - fn from_hex(hex_key: &str) -> Result; -} - -impl ProofGenerationKeySerializable for ProofGenerationKey { - fn serialize(&self) -> [u8; 64] { - let mut proof_generation_key_bytes: [u8; 64] = [0; 64]; - proof_generation_key_bytes[0..32].copy_from_slice(&self.ak.to_bytes()); - proof_generation_key_bytes[32..].copy_from_slice(&self.nsk.to_bytes()); - proof_generation_key_bytes - } - - fn deserialize(proof_generation_key_bytes: [u8; 64]) -> Result { - let mut ak_bytes: [u8; 32] = [0; 32]; - let mut nsk_bytes: [u8; 32] = [0; 32]; - - ak_bytes[0..32].copy_from_slice(&proof_generation_key_bytes[0..32]); - nsk_bytes[0..32].copy_from_slice(&proof_generation_key_bytes[32..64]); - - let ak = match SubgroupPoint::from_bytes(&ak_bytes).into() { - Some(ak) => ak, - None => return Err(IronfishError::new(IronfishErrorKind::InvalidAuthorizingKey)), - }; - - let nsk = match Fr::from_bytes(&nsk_bytes).into() { - Some(nsk) => nsk, - None => { - return Err(IronfishError::new( - IronfishErrorKind::InvalidNullifierDerivingKey, - )) - } - }; - - Ok(ProofGenerationKey { ak, nsk }) - } - - fn hex_key(&self) -> String { - let serialized_bytes = self.serialize(); - bytes_to_hex(&serialized_bytes[..]) - } - - fn from_hex(hex_key: &str) -> Result { - let bytes = hex_to_bytes(hex_key)?; - ProofGenerationKey::deserialize(bytes) - } -} - -#[cfg(test)] -mod test { - use crate::errors::IronfishErrorKind; - use ff::Field; - use group::{Group, GroupEncoding}; - use ironfish_zkp::ProofGenerationKey; - - use super::ProofGenerationKeySerializable; - use jubjub; - use rand::{rngs::StdRng, SeedableRng}; - - #[test] - fn test_serialize() { - let mut rng = StdRng::seed_from_u64(0); - - let proof_generation_key = ProofGenerationKey { - ak: jubjub::SubgroupPoint::random(&mut rng), - nsk: jubjub::Fr::random(&mut rng), - }; - - let serialized_bytes = proof_generation_key.serialize(); - - assert_eq!(serialized_bytes.len(), 64); - } - - #[test] - fn test_deserialize_ak_error() { - let mut proof_generation_key_bytes: [u8; 64] = [0; 64]; - proof_generation_key_bytes[0..32].fill(0xFF); - - let result = ProofGenerationKey::deserialize(proof_generation_key_bytes); - - assert!(result.is_err()); - - let err = result.err().unwrap(); - - assert!(matches!(err.kind, IronfishErrorKind::InvalidAuthorizingKey)); - } - - #[test] - fn test_deserialize_nsk_error() { - let mut proof_generation_key_bytes: [u8; 64] = [0; 64]; - // Populate with valid bytes for ak and invalid bytes for nsk - let valid_ak = jubjub::SubgroupPoint::random(&mut StdRng::seed_from_u64(0)); - proof_generation_key_bytes[0..32].copy_from_slice(&valid_ak.to_bytes()); // Assuming these are valid bytes for ak - proof_generation_key_bytes[32..64].fill(0xFF); // Invalid bytes for nsk - - let result = ProofGenerationKey::deserialize(proof_generation_key_bytes); - - assert!(result.is_err()); - - let err = result.err().unwrap(); - - assert!(matches!( - err.kind, - IronfishErrorKind::InvalidNullifierDerivingKey - )); - } - - #[test] - fn test_deserialize() { - let mut rng = StdRng::seed_from_u64(0); - - let proof_generation_key = ProofGenerationKey { - ak: jubjub::SubgroupPoint::random(&mut rng), - nsk: jubjub::Fr::random(&mut rng), - }; - - let serialized_bytes = proof_generation_key.serialize(); - - let deserialized_proof_generation_key = - ProofGenerationKey::deserialize(serialized_bytes).expect("deserialization successful"); - - assert_eq!( - proof_generation_key.ak, - deserialized_proof_generation_key.ak - ); - assert_eq!( - proof_generation_key.nsk, - deserialized_proof_generation_key.nsk - ); - } - - #[test] - fn test_hex() { - let mut rng = StdRng::seed_from_u64(0); - - let proof_generation_key = ProofGenerationKey { - ak: jubjub::SubgroupPoint::random(&mut rng), - nsk: jubjub::Fr::random(&mut rng), - }; - - let hex_key = proof_generation_key.hex_key(); - - let deserialized_proof_generation_key = - ProofGenerationKey::from_hex(&hex_key).expect("deserialization successful"); - - assert_eq!( - proof_generation_key.ak, - deserialized_proof_generation_key.ak - ); - assert_eq!( - proof_generation_key.nsk, - deserialized_proof_generation_key.nsk - ); - } -} diff --git a/ironfish-rust/src/transaction/mod.rs b/ironfish-rust/src/transaction/mod.rs index dbbab6a8e8..dff9699a2a 100644 --- a/ironfish-rust/src/transaction/mod.rs +++ b/ironfish-rust/src/transaction/mod.rs @@ -239,10 +239,8 @@ impl ProposedTransaction { ) -> Result { let public_address = view_key.public_address()?; - let proof_generation_key = ProofGenerationKey { - ak: view_key.authorizing_key, - nsk: proof_authorizing_key, - }; + let proof_generation_key = + ProofGenerationKey::new(view_key.authorizing_key, proof_authorizing_key); // skip adding change notes if this is special case of a miners fee transaction let is_miners_fee = self.outputs.iter().any(|output| output.get_is_miners_fee()); diff --git a/ironfish-zkp/src/circuits/mint_asset.rs b/ironfish-zkp/src/circuits/mint_asset.rs index 92e1a23b13..f9f9de6fc3 100644 --- a/ironfish-zkp/src/circuits/mint_asset.rs +++ b/ironfish-zkp/src/circuits/mint_asset.rs @@ -3,13 +3,15 @@ use bellperson::{ Circuit, }; use ff::PrimeField; -use zcash_primitives::sapling::ProofGenerationKey; use zcash_proofs::{ circuit::ecc, constants::{PROOF_GENERATION_KEY_GENERATOR, SPENDING_KEY_GENERATOR}, }; -use crate::constants::{proof::PUBLIC_KEY_GENERATOR, CRH_IVK_PERSONALIZATION}; +use crate::{ + constants::{proof::PUBLIC_KEY_GENERATOR, CRH_IVK_PERSONALIZATION}, + ProofGenerationKey, +}; pub struct MintAsset { /// Key required to construct proofs for a particular spending key @@ -122,9 +124,8 @@ mod test { use group::{Curve, Group}; use jubjub::ExtendedPoint; use rand::{rngs::StdRng, SeedableRng}; - use zcash_primitives::sapling::ProofGenerationKey; - use crate::constants::PUBLIC_KEY_GENERATOR; + use crate::{constants::PUBLIC_KEY_GENERATOR, ProofGenerationKey}; use super::MintAsset; @@ -135,10 +136,10 @@ mod test { let mut cs = TestConstraintSystem::new(); - let proof_generation_key = ProofGenerationKey { - ak: jubjub::SubgroupPoint::random(&mut rng), - nsk: jubjub::Fr::random(&mut rng), - }; + let proof_generation_key = ProofGenerationKey::new( + jubjub::SubgroupPoint::random(&mut rng), + jubjub::Fr::random(&mut rng), + ); let incoming_view_key = proof_generation_key.to_viewing_key(); let public_address = *PUBLIC_KEY_GENERATOR * incoming_view_key.ivk().0; let public_address_point = ExtendedPoint::from(public_address).to_affine(); diff --git a/ironfish-zkp/src/circuits/output.rs b/ironfish-zkp/src/circuits/output.rs index 527d1aa88c..d7bb97760a 100644 --- a/ironfish-zkp/src/circuits/output.rs +++ b/ironfish-zkp/src/circuits/output.rs @@ -5,7 +5,6 @@ use bellperson::{gadgets::blake2s, Circuit, ConstraintSystem, SynthesisError}; use group::Curve; use jubjub::SubgroupPoint; -use zcash_primitives::sapling::ProofGenerationKey; use zcash_proofs::{ circuit::{ecc, pedersen_hash}, constants::{ @@ -18,6 +17,7 @@ use crate::{ circuits::util::assert_valid_asset_generator, constants::{proof::PUBLIC_KEY_GENERATOR, ASSET_ID_LENGTH, CRH_IVK_PERSONALIZATION}, primitives::ValueCommitment, + ProofGenerationKey, }; use super::util::expose_value_commitment; @@ -260,9 +260,9 @@ mod test { use group::{Curve, Group}; use rand::rngs::StdRng; use rand::{Rng, RngCore, SeedableRng}; - use zcash_primitives::sapling::ProofGenerationKey; use crate::util::asset_hash_to_point; + use crate::ProofGenerationKey; use crate::{ circuits::output::Output, constants::PUBLIC_KEY_GENERATOR, primitives::ValueCommitment, util::commitment_full_point, @@ -296,7 +296,7 @@ mod test { let esk = jubjub::Fr::random(&mut rng); let ar = jubjub::Fr::random(&mut rng); - let proof_generation_key = ProofGenerationKey { ak, nsk }; + let proof_generation_key = ProofGenerationKey::new(ak, nsk); let viewing_key = proof_generation_key.to_viewing_key(); diff --git a/ironfish-zkp/src/circuits/spend.rs b/ironfish-zkp/src/circuits/spend.rs index 7546711dad..82065ecec6 100644 --- a/ironfish-zkp/src/circuits/spend.rs +++ b/ironfish-zkp/src/circuits/spend.rs @@ -3,6 +3,7 @@ use ff::{Field, PrimeField}; use jubjub::SubgroupPoint; use crate::constants::{CRH_IVK_PERSONALIZATION, PRF_NF_PERSONALIZATION}; +use crate::ProofGenerationKey; use crate::{constants::proof::PUBLIC_KEY_GENERATOR, primitives::ValueCommitment}; use super::util::expose_value_commitment; @@ -11,7 +12,6 @@ use bellperson::gadgets::boolean; use bellperson::gadgets::multipack; use bellperson::gadgets::num; use bellperson::gadgets::Assignment; -use zcash_primitives::sapling::ProofGenerationKey; use zcash_proofs::{ circuit::{ecc, pedersen_hash}, constants::{ @@ -342,15 +342,17 @@ mod test { use ff::{Field, PrimeField, PrimeFieldBits}; use group::{Curve, Group, GroupEncoding}; use rand::{rngs::StdRng, RngCore, SeedableRng}; - use zcash_primitives::sapling::{pedersen_hash, Note, ProofGenerationKey, Rseed}; + use zcash_primitives::sapling::{pedersen_hash, Note, Rseed}; use zcash_primitives::{constants::NULLIFIER_POSITION_GENERATOR, sapling::Nullifier}; use crate::{ circuits::spend::Spend, - constants::PUBLIC_KEY_GENERATOR, - constants::{PRF_NF_PERSONALIZATION, VALUE_COMMITMENT_VALUE_GENERATOR}, + constants::{ + PRF_NF_PERSONALIZATION, PUBLIC_KEY_GENERATOR, VALUE_COMMITMENT_VALUE_GENERATOR, + }, primitives::ValueCommitment, util::commitment_full_point, + ProofGenerationKey, }; #[test] @@ -367,10 +369,10 @@ mod test { asset_generator: (*VALUE_COMMITMENT_VALUE_GENERATOR).into(), }; - let proof_generation_key = ProofGenerationKey { - ak: jubjub::SubgroupPoint::random(&mut rng), - nsk: jubjub::Fr::random(&mut rng), - }; + let proof_generation_key = ProofGenerationKey::new( + jubjub::SubgroupPoint::random(&mut rng), + jubjub::Fr::random(&mut rng), + ); let viewing_key = proof_generation_key.to_viewing_key(); @@ -524,10 +526,10 @@ mod test { asset_generator: (*VALUE_COMMITMENT_VALUE_GENERATOR).into(), }; - let proof_generation_key = ProofGenerationKey { - ak: jubjub::SubgroupPoint::random(&mut rng), - nsk: jubjub::Fr::random(&mut rng), - }; + let proof_generation_key = ProofGenerationKey::new( + jubjub::SubgroupPoint::random(&mut rng), + jubjub::Fr::random(&mut rng), + ); let viewing_key = proof_generation_key.to_viewing_key(); diff --git a/ironfish-zkp/src/lib.rs b/ironfish-zkp/src/lib.rs index 3ea6dd5b85..b0ddf82de1 100644 --- a/ironfish-zkp/src/lib.rs +++ b/ironfish-zkp/src/lib.rs @@ -6,9 +6,10 @@ pub mod util; pub use zcash_primitives::sapling::{ group_hash::group_hash, pedersen_hash, redjubjub, Diversifier, Note as SaplingNote, Nullifier, - PaymentAddress, ProofGenerationKey, Rseed, ViewingKey, + PaymentAddress, Rseed, ViewingKey, }; +pub use primitives::proof_generation_key::ProofGenerationKey; pub mod proofs { pub use crate::circuits::mint_asset::MintAsset; pub use crate::circuits::{output::Output, spend::Spend}; diff --git a/ironfish-zkp/src/primitives/mod.rs b/ironfish-zkp/src/primitives/mod.rs index 1c9e55b29d..49c82e57d1 100644 --- a/ironfish-zkp/src/primitives/mod.rs +++ b/ironfish-zkp/src/primitives/mod.rs @@ -1,2 +1,3 @@ +pub mod proof_generation_key; mod value_commitment; pub use value_commitment::ValueCommitment; diff --git a/ironfish-zkp/src/primitives/proof_generation_key.rs b/ironfish-zkp/src/primitives/proof_generation_key.rs new file mode 100644 index 0000000000..6df8350751 --- /dev/null +++ b/ironfish-zkp/src/primitives/proof_generation_key.rs @@ -0,0 +1,204 @@ +use group::GroupEncoding; +use jubjub::{Fr, SubgroupPoint}; +use std::error::Error; +use std::fmt; +use std::ops::Deref; +use zcash_primitives::sapling::ProofGenerationKey as ZcashProofGenerationKey; + +use crate::hex::{bytes_to_hex, hex_to_bytes}; + +#[derive(Debug)] +pub enum ProofGenerationKeyError { + InvalidAuthorizingKey, + InvalidLength, + InvalidNullifierDerivingKey, + HexConversionError, +} + +impl fmt::Display for ProofGenerationKeyError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ProofGenerationKeyError::InvalidAuthorizingKey => write!(f, "Invalid authorizing key"), + ProofGenerationKeyError::InvalidNullifierDerivingKey => { + write!(f, "Invalid nullifier deriving key") + } + ProofGenerationKeyError::HexConversionError => write!(f, "Hex conversion error"), + ProofGenerationKeyError::InvalidLength => write!(f, "Invalid length"), + } + } +} + +impl Error for ProofGenerationKeyError {} + +#[derive(Clone)] +pub struct ProofGenerationKey(ZcashProofGenerationKey); + +impl ProofGenerationKey { + pub fn new(ak: SubgroupPoint, nsk: Fr) -> Self { + ProofGenerationKey(ZcashProofGenerationKey { ak, nsk }) + } + + pub fn to_bytes(&self) -> [u8; 64] { + let mut proof_generation_key_bytes: [u8; 64] = [0; 64]; + proof_generation_key_bytes[0..32].copy_from_slice(&self.0.ak.to_bytes()); + proof_generation_key_bytes[32..].copy_from_slice(&self.0.nsk.to_bytes()); + proof_generation_key_bytes + } + + pub fn from_bytes(proof_generation_key_bytes: &[u8]) -> Result { + if proof_generation_key_bytes.len() != 64 { + return Err(ProofGenerationKeyError::InvalidLength); + } + let mut ak_bytes: [u8; 32] = [0; 32]; + let mut nsk_bytes: [u8; 32] = [0; 32]; + + ak_bytes[0..32].copy_from_slice(&proof_generation_key_bytes[0..32]); + nsk_bytes[0..32].copy_from_slice(&proof_generation_key_bytes[32..64]); + + let ak = match SubgroupPoint::from_bytes(&ak_bytes).into() { + Some(ak) => ak, + None => return Err(ProofGenerationKeyError::InvalidAuthorizingKey), + }; + + let nsk = match Fr::from_bytes(&nsk_bytes).into() { + Some(nsk) => nsk, + None => return Err(ProofGenerationKeyError::InvalidNullifierDerivingKey), + }; + + Ok(ProofGenerationKey(ZcashProofGenerationKey { ak, nsk })) + } + + pub fn hex_key(&self) -> String { + bytes_to_hex(&self.to_bytes()) + } + + pub fn from_hex(hex_key: &str) -> Result { + let bytes: [u8; 64] = + hex_to_bytes(hex_key).map_err(|_| ProofGenerationKeyError::HexConversionError)?; + ProofGenerationKey::from_bytes(&bytes) + } +} + +impl Deref for ProofGenerationKey { + type Target = ZcashProofGenerationKey; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From for ProofGenerationKey { + fn from(key: ZcashProofGenerationKey) -> Self { + ProofGenerationKey(key) + } +} + +#[cfg(test)] +mod test { + use ff::Field; + use group::{Group, GroupEncoding}; + + use jubjub; + use rand::{rngs::StdRng, SeedableRng}; + + use crate::primitives::proof_generation_key::{ProofGenerationKey, ProofGenerationKeyError}; + + #[test] + fn test_serialize() { + let mut rng = StdRng::seed_from_u64(0); + + let proof_generation_key = ProofGenerationKey::new( + jubjub::SubgroupPoint::random(&mut rng), + jubjub::Fr::random(&mut rng), + ); + + let serialized_bytes = proof_generation_key.to_bytes(); + + assert_eq!(serialized_bytes.len(), 64); + } + + #[test] + fn test_deserialize_ak_error() { + let mut proof_generation_key_bytes: [u8; 64] = [0; 64]; + proof_generation_key_bytes[0..32].fill(0xFF); + + let result = ProofGenerationKey::from_bytes(&proof_generation_key_bytes); + + assert!(result.is_err()); + + let err = result.err().unwrap(); + + assert!(matches!( + err, + ProofGenerationKeyError::InvalidAuthorizingKey + )); + } + + #[test] + fn test_deserialize_nsk_error() { + let mut proof_generation_key_bytes: [u8; 64] = [0; 64]; + // Populate with valid bytes for ak and invalid bytes for nsk + let valid_ak = jubjub::SubgroupPoint::random(&mut StdRng::seed_from_u64(0)); + proof_generation_key_bytes[0..32].copy_from_slice(&valid_ak.to_bytes()); // Assuming these are valid bytes for ak + proof_generation_key_bytes[32..64].fill(0xFF); // Invalid bytes for nsk + + let result = ProofGenerationKey::from_bytes(&proof_generation_key_bytes); + + assert!(result.is_err()); + + let err = result.err().unwrap(); + + assert!(matches!( + err, + ProofGenerationKeyError::InvalidNullifierDerivingKey + )); + } + + #[test] + fn test_deserialize() { + let mut rng = StdRng::seed_from_u64(0); + + let proof_generation_key = ProofGenerationKey::new( + jubjub::SubgroupPoint::random(&mut rng), + jubjub::Fr::random(&mut rng), + ); + + let serialized_bytes = proof_generation_key.to_bytes(); + + let deserialized_proof_generation_key = + ProofGenerationKey::from_bytes(&serialized_bytes).expect("deserialization successful"); + + assert_eq!( + proof_generation_key.ak, + deserialized_proof_generation_key.ak + ); + assert_eq!( + proof_generation_key.nsk, + deserialized_proof_generation_key.nsk + ); + } + + #[test] + fn test_hex() { + let mut rng = StdRng::seed_from_u64(0); + + let proof_generation_key = ProofGenerationKey::new( + jubjub::SubgroupPoint::random(&mut rng), + jubjub::Fr::random(&mut rng), + ); + + let hex_key = proof_generation_key.hex_key(); + + let deserialized_proof_generation_key = + ProofGenerationKey::from_hex(&hex_key).expect("deserialization successful"); + + assert_eq!( + proof_generation_key.ak, + deserialized_proof_generation_key.ak + ); + assert_eq!( + proof_generation_key.nsk, + deserialized_proof_generation_key.nsk + ); + } +}