What changed, and why it matters
This commit removes a compile-time feature flag called NU6.3 from the Zcash code in the Keystone hardware wallet firmware. Previously, Ironwood (a newer Zcash shielded pool) and v6 transaction support were only compiled when the 'zcash_unstable="nu6.3"' flag was set. The change makes that code always compile and run, effectively enabling Ironwood/v6 support by default. There is no direct evidence in the commit that this fixes a security vulnerability; it appears to be a cleanup that promotes experimental code to stable. However, enabling new consensus code paths always carries some risk that previously-unreachable bugs or parsing differences could now affect real transactions.
Treat this as a routine feature-promotion commit rather than a security patch. Reviewers should verify that the now-unconditionally-compiled Ironwood and v6 code paths have adequate test coverage and that no compiler warnings or unused-code paths were introduced. If this commit is being backported or shipped, consider running the Zcash consensus oracle tests mentioned in the comments to ensure sighash behavior remains bit-exact with upstream.
Security signals we found
Feature flag removal enables previously conditional consensus-critical code (v6 transaction sighash, Ironwood bundle signing)
No logic changes to cryptographic or parsing routines are visible in the diff
No commit message, changelog, or reference describes a security fix or vulnerability
No CVE, advisory, or researcher attribution present in supplied materials
Evidence from the diff
The patch deletes the ‘zcash_unstable=”nu6.3”’ cfg flag from rust/.cargo/config.toml and removes all #[cfg(zcash_unstable = “nu6.3”)] guards in rust/apps/zcash and rust/zcash_vendor. As a result, functions and tests for Ironwood shielded pool handling, v6 transaction parsing/checking/signing, and the associated sighash logic are now compiled unconditionally. The commit also updates the unexpected_cfgs lint entries to remove the nu6.3 value. No logic changes are made to the algorithms themselves; only conditional compilation is removed. The commit message and diff do not describe any security issue, CVE, or researcher attribution.
Changed components
rust/.cargo/config.tomlrust/apps/zcash/Cargo.tomlrust/apps/zcash/src/lib.rsrust/apps/zcash/src/pczt/check.rsrust/apps/zcash/src/pczt/mod.rsrust/apps/zcash/src/pczt/parse.rsrust/apps/zcash/src/pczt/sign.rsrust/zcash_vendor/Cargo.tomlrust/zcash_vendor/src/pczt_ext.rsInspect captured patch +8 / −101
diff --git a/rust/.cargo/config.toml b/rust/.cargo/config.toml
index 4d70cf4..58061e3 100644
--- a/rust/.cargo/config.toml
+++ b/rust/.cargo/config.toml
@@ -2,4 +2,3 @@
## This path is hardcoded into the Makefiles, so make sure a contributor’s
## config hasn’t overridden it.
target-dir = "target"
-rustflags = ["--cfg", "zcash_unstable=\"nu6.3\""]
diff --git a/rust/apps/zcash/Cargo.toml b/rust/apps/zcash/Cargo.toml
index 221e3f6..4e85e88 100644
--- a/rust/apps/zcash/Cargo.toml
+++ b/rust/apps/zcash/Cargo.toml
@@ -38,7 +38,6 @@ orchard = { version = "0.15.0-pre.2", default-features = false }
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = [
'cfg(coverage_nightly)',
- 'cfg(zcash_unstable, values("nu6.3"))',
] }
[features]
diff --git a/rust/apps/zcash/src/lib.rs b/rust/apps/zcash/src/lib.rs
index a3df090..39967b0 100644
--- a/rust/apps/zcash/src/lib.rs
+++ b/rust/apps/zcash/src/lib.rs
@@ -216,7 +216,6 @@ fn transparent_account_pubkey_from_xpub(
#[cfg(feature = "multi_coins")]
fn reject_legacy_check_unsupported_pczt(pczt: &Pczt) -> Result<()> {
- #[cfg(zcash_unstable = "nu6.3")]
{
// The legacy multi-coins check path only verifies transparent data. Reject any
// shielded (Sapling/Orchard/Ironwood) or V6 PCZT so check, parse, and sign
@@ -386,7 +385,6 @@ mod legacy_tests {
);
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn legacy_check_rejects_v6_pczt() {
let pczt = Creator::new(
@@ -431,7 +429,6 @@ fn map_shielded_verifier_error(
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum SignableShieldedPool {
Orchard,
- #[cfg(zcash_unstable = "nu6.3")]
Ironwood,
}
@@ -440,7 +437,6 @@ impl SignableShieldedPool {
fn label(self) -> &'static str {
match self {
SignableShieldedPool::Orchard => "Orchard",
- #[cfg(zcash_unstable = "nu6.3")]
SignableShieldedPool::Ironwood => "Ironwood",
}
}
@@ -448,7 +444,6 @@ impl SignableShieldedPool {
fn shielded_pool(self) -> pczt::ShieldedPool {
match self {
SignableShieldedPool::Orchard => pczt::ShieldedPool::Orchard,
- #[cfg(zcash_unstable = "nu6.3")]
SignableShieldedPool::Ironwood => pczt::ShieldedPool::Ironwood,
}
}
@@ -575,7 +570,6 @@ fn signable_shielded_actions<P: consensus::Parameters>(
reject_unsupported_batch_pczt(&pczt)?;
}
- #[cfg(zcash_unstable = "nu6.3")]
let should_process_ironwood = pczt::pczt_should_process_ironwood(&pczt);
let mut actions = Vec::new();
let verifier = Verifier::new(pczt)
@@ -592,7 +586,6 @@ fn signable_shielded_actions<P: consensus::Parameters>(
})
.map_err(map_shielded_verifier_error)?;
- #[cfg(zcash_unstable = "nu6.3")]
let verifier = if should_process_ironwood {
verifier
.with_ironwood::<ZcashError, _>(|bundle| {
@@ -622,7 +615,6 @@ fn ensure_shielded_actions_are_signed(
) -> Result<Pczt> {
use zcash_vendor::pczt::roles::verifier::Verifier;
- #[cfg(zcash_unstable = "nu6.3")]
let should_process_ironwood = pczt::pczt_should_process_ironwood(&signed_pczt);
let verifier = Verifier::new(signed_pczt)
.with_orchard::<ZcashError, _>(|bundle| {
@@ -630,7 +622,6 @@ fn ensure_shielded_actions_are_signed(
})
.map_err(map_shielded_verifier_error)?;
- #[cfg(zcash_unstable = "nu6.3")]
let verifier = if should_process_ironwood {
verifier
.with_ironwood::<ZcashError, _>(|bundle| {
@@ -794,7 +785,6 @@ mod tests {
derivation_path: Vec<u32>,
}
- #[cfg(zcash_unstable = "nu6.3")]
fn v5_pczt_with_ironwood_actions() -> Vec<u8> {
let sample = pczt::test_support::sample_ironwood_pczt();
let bytes = sample.bytes;
@@ -992,7 +982,6 @@ mod tests {
assert_eq!(address.unwrap(), "u1tqdskj32l9udfp0rysmca6gpz73fdqc2rmeenyhh0nfrq4vgak284ehkxefw5cf9495rdur0tparuntevp6nnetzjkyzv08m524e4swwk94asas7hm2ad5w5c64zz00hmr7nux0yhaz");
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_pczt_ironwood_to_ironwood() {
let sample = pczt::test_support::sample_ironwood_pczt();
@@ -1030,7 +1019,6 @@ mod tests {
);
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_parse_pczt_orchard_decodes_spend_and_change() {
let sample = pczt::test_support::sample_orchard_change_pczt();
@@ -1073,7 +1061,6 @@ mod tests {
.unwrap();
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_parse_and_check_ignore_unsupported_ironwood_spend_zip32_path() {
let sample = pczt::test_support::sample_ironwood_pczt();
@@ -1117,7 +1104,6 @@ mod tests {
}
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_parse_and_check_ignore_dummy_ironwood_spend_zip32_metadata() {
let sample = pczt::test_support::sample_ironwood_pczt();
@@ -1156,7 +1142,6 @@ mod tests {
}
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_parse_check_and_sign_reject_v5_pczt_with_ironwood_actions() {
let sample = pczt::test_support::sample_ironwood_pczt();
@@ -1216,7 +1201,6 @@ mod tests {
assert!(matches!(result.unwrap_err(), ZcashError::InvalidPczt(_)));
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_check_pczt_normalizes_and_is_idempotent() {
let sample = pczt::test_support::sample_orchard_change_pczt();
@@ -1288,7 +1272,6 @@ mod tests {
const BATCH_UNSUPPORTED_SAPLING_ERROR: &str =
"Zcash batch PCZT must not contain Sapling spends or outputs";
- #[cfg(zcash_unstable = "nu6.3")]
fn pczt_with_sapling_output() -> pczt::test_support::SamplePczt {
let mut sample = pczt::test_support::sample_orchard_change_pczt();
let (mut prefix, rest) =
@@ -1335,7 +1318,6 @@ mod tests {
);
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_sign_checked_batch_pczt_signs_ironwood_spend() {
let sample = pczt::test_support::sample_ironwood_pczt();
@@ -1363,7 +1345,6 @@ mod tests {
.any(|action| action.spend().spend_auth_sig().is_some()));
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_sign_checked_pczt_signs_owned_orchard_actions() {
let sample = pczt::test_support::sample_orchard_change_pczt();
@@ -1395,7 +1376,6 @@ mod tests {
assert_eq!(signed_actions, 2);
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_sign_checked_pczt_rejects_foreign_seed() {
let sample = pczt::test_support::sample_orchard_change_pczt();
@@ -1420,7 +1400,6 @@ mod tests {
assert!(matches!(result, Err(ZcashError::PcztNoMyInputs)));
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_sign_checked_batch_pczt_signs_and_rejects_sapling() {
let sample = pczt::test_support::sample_orchard_change_pczt();
@@ -1462,7 +1441,6 @@ mod tests {
));
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_check_batch_pczt_accepts_orchard_and_ironwood_spends() {
for sample in [
@@ -1494,7 +1472,6 @@ mod tests {
}
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_check_resolves_compact_pczt_and_signs() {
use zcash_vendor::pczt::roles::redactor::Redactor;
@@ -1571,7 +1548,6 @@ mod tests {
.any(|action| action.spend().spend_auth_sig().is_some()));
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_check_batch_pczt_rejects_sapling_outputs() {
let sample = pczt_with_sapling_output();
diff --git a/rust/apps/zcash/src/pczt/check.rs b/rust/apps/zcash/src/pczt/check.rs
index b478338..02cde18 100644
--- a/rust/apps/zcash/src/pczt/check.rs
+++ b/rust/apps/zcash/src/pczt/check.rs
@@ -45,7 +45,6 @@ pub fn check_pczt_orchard<P: consensus::Parameters>(
pczt: &Pczt,
) -> Result<(), ZcashError> {
super::validate_supported_pczt(pczt)?;
- #[cfg(zcash_unstable = "nu6.3")]
let should_process_ironwood = super::pczt_should_process_ironwood(pczt);
let verifier = Verifier::new(pczt.clone())
.with_orchard(|bundle| {
@@ -61,7 +60,6 @@ pub fn check_pczt_orchard<P: consensus::Parameters>(
Ok(())
})
.map_err(map_orchard_verifier_error)?;
- #[cfg(zcash_unstable = "nu6.3")]
if should_process_ironwood {
verifier
.with_ironwood(|bundle| {
diff --git a/rust/apps/zcash/src/pczt/mod.rs b/rust/apps/zcash/src/pczt/mod.rs
index dcc39d8..22e61af 100644
--- a/rust/apps/zcash/src/pczt/mod.rs
+++ b/rust/apps/zcash/src/pczt/mod.rs
@@ -20,7 +20,6 @@ pub(crate) fn parse_pczt(bytes: &[u8]) -> Result<Pczt, ZcashError> {
pub(crate) fn validate_supported_pczt(pczt: &Pczt) -> Result<(), ZcashError> {
validate_sapling_bundle_consistency(pczt)?;
- #[cfg(zcash_unstable = "nu6.3")]
{
if pczt_has_ironwood_actions(pczt) && !pczt_is_v6(pczt) {
return Err(ZcashError::InvalidPczt(
@@ -46,18 +45,15 @@ pub(crate) fn validate_supported_pczt(pczt: &Pczt) -> Result<(), ZcashError> {
Ok(())
}
-#[cfg(zcash_unstable = "nu6.3")]
pub(crate) fn pczt_has_ironwood_actions(pczt: &Pczt) -> bool {
!pczt.ironwood().actions().is_empty()
}
-#[cfg(zcash_unstable = "nu6.3")]
pub(crate) fn pczt_is_v6(pczt: &Pczt) -> bool {
*pczt.global().tx_version() == constants::V6_TX_VERSION
&& *pczt.global().version_group_id() == constants::V6_VERSION_GROUP_ID
}
-#[cfg(zcash_unstable = "nu6.3")]
pub(crate) fn pczt_should_process_ironwood(pczt: &Pczt) -> bool {
pczt_is_v6(pczt) || pczt_has_ironwood_actions(pczt)
}
@@ -116,7 +112,6 @@ pub(crate) fn check_transparent_derivation<
#[derive(Clone, Copy)]
pub(crate) enum ShieldedPool {
Orchard,
- #[cfg(zcash_unstable = "nu6.3")]
Ironwood,
}
@@ -125,7 +120,6 @@ impl ShieldedPool {
pub(crate) fn label(self) -> &'static str {
match self {
ShieldedPool::Orchard => "Orchard",
- #[cfg(zcash_unstable = "nu6.3")]
ShieldedPool::Ironwood => "Ironwood",
}
}
@@ -178,10 +172,7 @@ pub(crate) fn matching_seed_supported_orchard_account(
/// Returns whether a PCZT carries anything the transparent-only legacy path
/// cannot handle: a v6+ transaction, or any shielded (Sapling/Orchard/Ironwood)
/// content. These must be checked, parsed, and signed by the cypherpunk build.
-#[cfg(all(
- zcash_unstable = "nu6.3",
- any(feature = "multi_coins", not(feature = "cypherpunk"))
-))]
+#[cfg(any(feature = "multi_coins", not(feature = "cypherpunk")))]
pub(crate) fn pczt_requires_cypherpunk_support(pczt: &zcash_vendor::pczt::Pczt) -> bool {
*pczt.global().tx_version() >= 6
|| !pczt.sapling().spends().is_empty()
@@ -195,20 +186,16 @@ pub(crate) mod test_support {
use alloc::{string::String, vec, vec::Vec};
use ::pczt::roles::{creator::Creator, updater::Updater};
- #[cfg(zcash_unstable = "nu6.3")]
use incrementalmerkletree::Retention;
use keystore::algorithms::zcash::{calculate_seed_fingerprint, derive_ufvk};
use rand_core::OsRng;
- #[cfg(zcash_unstable = "nu6.3")]
use shardtree::{store::memory::MemoryShardStore, ShardTree};
- #[cfg(zcash_unstable = "nu6.3")]
use zcash_note_encryption::try_note_decryption;
use zcash_primitives::transaction::{
builder::{BuildConfig, Builder, PcztParts, PcztResult},
fees::zip317,
TxVersion,
};
- #[cfg(zcash_unstable = "nu6.3")]
use zcash_vendor::zcash_protocol::consensus::{BlockHeight, NetworkType, NetworkUpgrade};
use zcash_vendor::{
orchard,
@@ -229,11 +216,9 @@ pub(crate) mod test_support {
pub(crate) seed_fingerprint: [u8; 32],
}
- #[cfg(zcash_unstable = "nu6.3")]
#[derive(Clone, Copy, Debug)]
pub(crate) struct Nu6_3Network;
- #[cfg(zcash_unstable = "nu6.3")]
impl Parameters for Nu6_3Network {
fn network_type(&self) -> NetworkType {
NetworkType::Main
@@ -247,7 +232,6 @@ pub(crate) mod test_support {
}
}
- #[cfg(zcash_unstable = "nu6.3")]
pub(crate) fn unsupported_orchard_spend_paths() -> Vec<Vec<u32>> {
vec![
vec![
@@ -264,7 +248,6 @@ pub(crate) mod test_support {
]
}
- #[cfg(zcash_unstable = "nu6.3")]
pub(crate) fn orchard_spend_path_for_account(account_index: u32) -> Vec<u32> {
vec![
zip32::ChildIndex::hardened(32).index(),
@@ -273,7 +256,6 @@ pub(crate) mod test_support {
]
}
- #[cfg(zcash_unstable = "nu6.3")]
pub(crate) fn ironwood_pczt_with_spend_derivation(
bytes: &[u8],
seed_fingerprint: [u8; 32],
@@ -298,7 +280,6 @@ pub(crate) mod test_support {
.unwrap()
}
- #[cfg(zcash_unstable = "nu6.3")]
pub(crate) fn ironwood_pczt_with_dummy_spend_derivation(
bytes: &[u8],
seed_fingerprint: [u8; 32],
@@ -335,7 +316,6 @@ pub(crate) mod test_support {
.unwrap()
}
- #[cfg(zcash_unstable = "nu6.3")]
pub(crate) fn sample_ironwood_pczt() -> SamplePczt {
let params = Nu6_3Network;
let seed = [7u8; 32];
@@ -446,7 +426,6 @@ pub(crate) mod test_support {
// Orchard spend -> Ironwood output: a cross-pool migration, the message type
// the real batch uses (and the one never exercised on-device). Mirrors
// sample_ironwood_pczt but the *spent* note is an Orchard note.
- #[cfg(zcash_unstable = "nu6.3")]
pub(crate) fn sample_migration_pczt() -> SamplePczt {
let params = Nu6_3Network;
let seed = [7u8; 32];
@@ -556,7 +535,6 @@ pub(crate) mod test_support {
}
}
- #[cfg(zcash_unstable = "nu6.3")]
pub(crate) fn sample_orchard_change_pczt() -> SamplePczt {
let params = MainNetwork;
let seed = [7u8; 32];
diff --git a/rust/apps/zcash/src/pczt/parse.rs b/rust/apps/zcash/src/pczt/parse.rs
index 248afb6..53bac0f 100644
--- a/rust/apps/zcash/src/pczt/parse.rs
+++ b/rust/apps/zcash/src/pczt/parse.rs
@@ -208,9 +208,7 @@ pub fn parse_pczt_cypherpunk<P: consensus::Parameters>(
) -> Result<ParsedPczt, ZcashError> {
super::validate_supported_pczt(pczt)?;
let mut parsed_orchard = None;
- #[cfg(zcash_unstable = "nu6.3")]
let mut parsed_ironwood = None;
- #[cfg(zcash_unstable = "nu6.3")]
let should_process_ironwood = super::pczt_should_process_ironwood(pczt);
let mut parsed_transparent = None;
@@ -227,7 +225,6 @@ pub fn parse_pczt_cypherpunk<P: consensus::Parameters>(
Ok(())
})
.map_err(map_orchard_verifier_error)?;
- #[cfg(zcash_unstable = "nu6.3")]
let verifier = if should_process_ironwood {
verifier
.with_ironwood(|bundle| {
@@ -274,7 +271,6 @@ pub fn parse_pczt_cypherpunk<P: consensus::Parameters>(
.iter()
.fold(0, |acc, to| acc + to.get_amount());
}
- #[cfg(zcash_unstable = "nu6.3")]
if let Some(ironwood) = &parsed_ironwood {
total_change_value += ironwood
.get_to()
@@ -332,11 +328,6 @@ pub fn parse_pczt_cypherpunk<P: consensus::Parameters>(
let has_sapling = !pczt.sapling().spends().is_empty() || !pczt.sapling().outputs().is_empty();
- #[cfg(zcash_unstable = "nu6.3")]
- let parsed_ironwood = parsed_ironwood;
- #[cfg(not(zcash_unstable = "nu6.3"))]
- let parsed_ironwood = None;
-
Ok(ParsedPczt::new(
parsed_transparent,
parsed_orchard,
@@ -424,7 +415,6 @@ pub fn parse_pczt_multi_coins<P: consensus::Parameters>(
#[cfg(feature = "multi_coins")]
fn reject_legacy_parse_unsupported_pczt(pczt: &Pczt) -> Result<(), ZcashError> {
- #[cfg(zcash_unstable = "nu6.3")]
{
// The legacy multi-coins parser only displays transparent data. Reject any
// shielded (Sapling/Orchard/Ironwood) or V6 PCZT instead of showing an
@@ -822,7 +812,6 @@ mod legacy_tests {
zcash_protocol::consensus::{BranchId, MainNetwork, NetworkConstants},
};
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn legacy_parse_rejects_v6_pczt() {
let pczt = Creator::new(
diff --git a/rust/apps/zcash/src/pczt/sign.rs b/rust/apps/zcash/src/pczt/sign.rs
index e5a2783..f087fea 100644
--- a/rust/apps/zcash/src/pczt/sign.rs
+++ b/rust/apps/zcash/src/pczt/sign.rs
@@ -90,7 +90,6 @@ pub fn sign_pczt(pczt: Pczt, seed: &[u8]) -> crate::Result<Vec<u8>> {
#[cfg(not(feature = "cypherpunk"))]
fn reject_legacy_unsupported_pczt(pczt: &Pczt) -> Result<(), ZcashError> {
- #[cfg(zcash_unstable = "nu6.3")]
{
// The legacy helper below carries the pre-NU6.3 transparent sighash implementation.
// It must not be used for shielded (Sapling/Orchard/Ironwood) or V6 PCZTs.
@@ -265,7 +264,6 @@ pub fn sign_and_redact_pczt(pczt: Pczt, seed: &[u8]) -> crate::Result<Pczt> {
let seed_fingerprint =
calculate_seed_fingerprint(seed).map_err(|e| ZcashError::SigningError(e.to_string()))?;
- #[cfg(zcash_unstable = "nu6.3")]
let process_ironwood = super::pczt_should_process_ironwood(&pczt);
// The orchard signer handles both the transparent inputs and the Orchard bundle
@@ -279,9 +277,7 @@ pub fn sign_and_redact_pczt(pczt: Pczt, seed: &[u8]) -> crate::Result<Pczt> {
let signer = pczt_ext::sign_transparent(signer, &orchard_signer)?;
let signer = pczt_ext::sign_orchard(signer, &orchard_signer)?;
- #[cfg(zcash_unstable = "nu6.3")]
let ironwood_signer = SeedSigner::new(seed, seed_fingerprint, ShieldedPool::Ironwood);
- #[cfg(zcash_unstable = "nu6.3")]
let signer = if process_ironwood {
pczt_ext::sign_ironwood(signer, &ironwood_signer)?
} else {
@@ -289,7 +285,6 @@ pub fn sign_and_redact_pczt(pczt: Pczt, seed: &[u8]) -> crate::Result<Pczt> {
};
let mut signed = orchard_signer.signed.get();
- #[cfg(zcash_unstable = "nu6.3")]
{
signed += ironwood_signer.signed.get();
}
@@ -318,7 +313,6 @@ fn stamp_and_redact(pczt: Pczt) -> Pczt {
// signing response does not need. This keeps the QR round trip small while
// preserving signatures and global proprietary fields for the wallet.
let redactor = Redactor::new(stamped_pczt).redact_orchard_with(redact_orchard_bundle);
- #[cfg(zcash_unstable = "nu6.3")]
let redactor = redactor.redact_ironwood_with(redact_orchard_bundle);
redactor
@@ -446,12 +440,10 @@ mod tests {
}
}
- #[cfg(zcash_unstable = "nu6.3")]
fn signable_sample_pczt() -> crate::pczt::test_support::SamplePczt {
crate::pczt::test_support::sample_ironwood_pczt()
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_sign_pczt_invalid_seed_fingerprint() {
let sample = signable_sample_pczt();
@@ -467,7 +459,6 @@ mod tests {
// bit-exact for an Orchard-only tx, a dual-pool Orchard->Ironwood migration, and an
// Ironwood spend, so any upstream sighash change turns CI red instead of silently
// producing wrong signatures on-device.
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_lean_sighash_control_orchard_only() {
let sample = crate::pczt::test_support::sample_orchard_change_pczt();
@@ -483,7 +474,6 @@ mod tests {
);
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_lean_sighash_migration_dualpool() {
let sample = crate::pczt::test_support::sample_migration_pczt();
@@ -499,7 +489,6 @@ mod tests {
);
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_lean_sighash_ironwood_spend() {
// Exercises a populated Ironwood bundle with a real spend action.
@@ -518,7 +507,6 @@ mod tests {
// End-to-end: an Orchard->Ironwood migration signs the Orchard spend and leaves the
// output-only Ironwood bundle unsigned.
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_sign_pczt_migration_signs_orchard_only() {
let sample = crate::pczt::test_support::sample_migration_pczt();
@@ -543,7 +531,6 @@ mod tests {
);
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_sign_pczt_ironwood_spend() {
let sample = crate::pczt::test_support::sample_ironwood_pczt();
@@ -609,7 +596,6 @@ mod tests {
);
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_sign_pczt_ironwood_spend_rejects_unsupported_zip32_path() {
let sample = crate::pczt::test_support::sample_ironwood_pczt();
@@ -627,7 +613,6 @@ mod tests {
}
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_sign_pczt_ironwood_spend_ignores_dummy_zip32_metadata() {
let sample = crate::pczt::test_support::sample_ironwood_pczt();
@@ -650,7 +635,6 @@ mod tests {
);
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn test_sign_pczt_orchard_change_output_spend() {
let sample = crate::pczt::test_support::sample_orchard_change_pczt();
@@ -671,7 +655,6 @@ mod tests {
);
}
- #[cfg(zcash_unstable = "nu6.3")]
fn pczt_with_min_version(min_version: &[u8]) -> Pczt {
let sample = signable_sample_pczt();
let base = Pczt::parse(&sample.bytes).unwrap();
@@ -683,12 +666,10 @@ mod tests {
.finish()
}
- #[cfg(zcash_unstable = "nu6.3")]
fn test_seed() -> Vec<u8> {
[7u8; 32].to_vec()
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn firmware_equal_version_stamps_response() {
let pczt = pczt_with_min_version(&KEYSTONE_FW_VERSION.encode());
@@ -710,7 +691,6 @@ mod tests {
assert_eq!(request_min, &KEYSTONE_FW_VERSION.encode().to_vec());
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn firmware_older_min_version_still_stamps_response() {
let pczt = pczt_with_min_version(&[1, 0, 0]);
@@ -725,7 +705,6 @@ mod tests {
assert_eq!(stamp, &KEYSTONE_FW_VERSION.encode().to_vec());
}
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn malformed_min_version_round_trips_and_stamps() {
let pczt = pczt_with_min_version(&[1, 2]);
@@ -757,7 +736,6 @@ mod legacy_tests {
zcash_protocol::consensus::{BranchId, MainNetwork, NetworkConstants},
};
- #[cfg(zcash_unstable = "nu6.3")]
#[test]
fn legacy_signing_rejects_v6_pczt() {
let pczt = Creator::new(
diff --git a/rust/zcash_vendor/Cargo.toml b/rust/zcash_vendor/Cargo.toml
index 0dc6b3f..f16ad23 100644
--- a/rust/zcash_vendor/Cargo.toml
+++ b/rust/zcash_vendor/Cargo.toml
@@ -61,7 +61,7 @@ rust_tools = { workspace = true }
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = [
- 'cfg(zcash_unstable, values("nu6.3", "zfuture"))',
+ 'cfg(zcash_unstable, values("zfuture"))',
] }
[dev-dependencies]
diff --git a/rust/zcash_vendor/src/pczt_ext.rs b/rust/zcash_vendor/src/pczt_ext.rs
index 301c97a..196e975 100644
--- a/rust/zcash_vendor/src/pczt_ext.rs
+++ b/rust/zcash_vendor/src/pczt_ext.rs
@@ -337,24 +337,17 @@ fn hash_orchard_txid_empty() -> Hash {
// This is consensus-critical and must stay bit-exact with upstream. The
// `shielded_sig_commitment == RoleSigner::shielded_sighash` oracle tests in
// apps/zcash/src/pczt/sign.rs guard it (red CI on any upstream drift).
-#[cfg(zcash_unstable = "nu6.3")]
const ZCASH_ORCHARD_V6_HASH_PERSONALIZATION: &[u8; 16] = b"ZTxIdOrchardH_v6";
-#[cfg(zcash_unstable = "nu6.3")]
const ZCASH_IRONWOOD_HASH_PERSONALIZATION: &[u8; 16] = b"ZTxIdIronwd_H_v6";
-#[cfg(zcash_unstable = "nu6.3")]
const ZCASH_IRONWOOD_ACTIONS_COMPACT_HASH_PERSONALIZATION: &[u8; 16] = b"ZTxIdIrnActCH_v6";
-#[cfg(zcash_unstable = "nu6.3")]
const ZCASH_IRONWOOD_ACTIONS_MEMOS_HASH_PERSONALIZATION: &[u8; 16] = b"ZTxIdIrnActMH_v6";
-#[cfg(zcash_unstable = "nu6.3")]
const ZCASH_IRONWOOD_ACTIONS_NONCOMPACT_HASH_PERSONALIZATION: &[u8; 16] = b"ZTxIdIrnActNH_v6";
-#[cfg(zcash_unstable = "nu6.3")]
fn is_v6(pczt: &Pczt) -> bool {
*pczt.global().tx_version() == zcash_protocol::constants::V6_TX_VERSION
&& *pczt.global().version_group_id() == zcash_protocol::constants::V6_VERSION_GROUP_ID
}
-#[cfg(zcash_unstable = "nu6.3")]
fn has_ironwood(pczt: &Pczt) -> bool {
!pczt.ironwood().actions().is_empty()
}
@@ -363,7 +356,6 @@ fn has_ironwood(pczt: &Pczt) -> bool {
/// upstream `orchard::bundle::commitments::hash_bundle_txid_data_with_domain` for the
/// `ORCHARD_V6` / `IRONWOOD_V6` domains: the three ZIP-244 action sub-hashes, the flag
/// byte, the value balance, and — unlike v5 — NO anchor (`effects_anchor = Omit`).
-#[cfg(zcash_unstable = "nu6.3")]
fn digest_orchard_shaped_v6(
bundle: &pczt::orchard::Bundle,
bundle_personalization: &[u8; 16],
@@ -406,7 +398,6 @@ fn digest_orchard_shaped_v6(
h.finalize()
}
-#[cfg(zcash_unstable = "nu6.3")]
fn digest_orchard_v6(pczt: &Pczt) -> Hash {
digest_orchard_shaped_v6(
pczt.orchard(),
@@ -417,7 +408,6 @@ fn digest_orchard_v6(pczt: &Pczt) -> Hash {
)
}
-#[cfg(zcash_unstable = "nu6.3")]
fn digest_ironwood_v6(pczt: &Pczt) -> Hash {
digest_orchard_shaped_v6(
pczt.ironwood(),
@@ -428,17 +418,14 @@ fn digest_ironwood_v6(pczt: &Pczt) -> Hash {
)
}
-#[cfg(zcash_unstable = "nu6.3")]
fn hash_orchard_v6_txid_empty() -> Hash {
hasher(ZCASH_ORCHARD_V6_HASH_PERSONALIZATION).finalize()
}
-#[cfg(zcash_unstable = "nu6.3")]
fn hash_ironwood_v6_txid_empty() -> Hash {
hasher(ZCASH_IRONWOOD_HASH_PERSONALIZATION).finalize()
}
-#[cfg(zcash_unstable = "nu6.3")]
fn shielded_sig_commitment_v6(
pczt: &Pczt,
lock_time: u32,
@@ -487,8 +474,11 @@ fn shielded_sig_commitment_v6(
/// `pub` so the `app_zcash` consensus oracle tests can assert it stays bit-exact against
/// the upstream RoleSigner sighash (any divergence turns CI red rather than producing
/// wrong on-device signatures).
-pub fn shielded_sig_commitment(pczt: &Pczt, lock_time: u32, input_info: Option<SignableInput>) -> Hash {
- #[cfg(zcash_unstable = "nu6.3")]
+pub fn shielded_sig_commitment(
+ pczt: &Pczt,
+ lock_time: u32,
+ input_info: Option<SignableInput>,
+) -> Hash {
if is_v6(pczt) {
return shielded_sig_commitment_v6(pczt, lock_time, input_info);
}
@@ -680,7 +670,7 @@ where
/// is the one parsed and mutated. Dummy/output-only actions (value 0 or absent) are
/// skipped, so an Orchard→Ironwood migration (Ironwood output-only) produces no
/// Ironwood signature here.
-#[cfg(all(feature = "orchard", zcash_unstable = "nu6.3"))]
+#[cfg(feature = "orchard")]
pub fn sign_ironwood<T>(llsigner: Signer, signer: &T) -> Result<Signer, T::Error>
where
T: PcztSigner,
Why this scored 28/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.