diff --git a/Cargo.lock b/Cargo.lock index 2bcea96fc..84f3f9310 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -460,9 +460,8 @@ dependencies = [ [[package]] name = "bip32" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e141fb0f8be1c7b45887af94c88b182472b57c96b56773250ae00cd6a14a164" +version = "0.5.2" +source = "git+https://github.com/KeystoneHQ/crates.git?rev=9873e8fd56007d792fa60d6e844fdb75d527c858#9873e8fd56007d792fa60d6e844fdb75d527c858" dependencies = [ "bs58", "hmac", @@ -2609,9 +2608,9 @@ dependencies = [ [[package]] name = "nonempty" -version = "0.7.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7" +checksum = "549e471b99ccaf2f89101bec68f4d244457d5a95a9c3d0672e9564124397741d" [[package]] name = "notify" @@ -2789,8 +2788,7 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "orchard" version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02f7152474406422f572de163e0bc63b2126cdbfe17bc849efbbde36fcfe647e" +source = "git+https://github.com/zcash/orchard.git?rev=cd3e0901ccac2c630dd7fd03eb496d5030c1bbfe#cd3e0901ccac2c630dd7fd03eb496d5030c1bbfe" dependencies = [ "aes", "bitvec", @@ -3911,9 +3909,9 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.27.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ "rand", "secp256k1-sys", @@ -3921,9 +3919,9 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.8.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" dependencies = [ "cc", ] diff --git a/Cargo.toml b/Cargo.toml index 4e37a9fe4..6b8920d93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,18 +65,18 @@ redjubjub = "0.7" sapling = { package = "sapling-crypto", version = "0.4", default-features = false } # - Orchard -nonempty = "0.7" orchard = { version = "0.10.1", default-features = false } pasta_curves = "0.5" # - Transparent bip32 = { version = "0.5", default-features = false } ripemd = { version = "0.1", default-features = false } -secp256k1 = { version = "0.27", default-features = false, features = ["alloc"] } +secp256k1 = { version = "0.29", default-features = false, features = ["alloc"] } transparent = { package = "zcash_transparent", version = "0.1", path = "zcash_transparent", default-features = false } # Boilerplate & missing stdlib getset = "0.1" +nonempty = { version = "0.11", default-features = false } # CSPRNG rand = { version = "0.8", default-features = false } @@ -193,3 +193,7 @@ debug = true [workspace.lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ['cfg(zcash_unstable, values("zfuture"))'] } + +[patch.crates-io] +bip32 = { git = "https://github.com/KeystoneHQ/crates.git", rev = "9873e8fd56007d792fa60d6e844fdb75d527c858" } +orchard = { git = "https://github.com/zcash/orchard.git", rev = "cd3e0901ccac2c630dd7fd03eb496d5030c1bbfe" } diff --git a/components/zcash_encoding/CHANGELOG.md b/components/zcash_encoding/CHANGELOG.md index c7253c84c..5aca6da70 100644 --- a/components/zcash_encoding/CHANGELOG.md +++ b/components/zcash_encoding/CHANGELOG.md @@ -6,6 +6,10 @@ and this library adheres to Rust's notion of [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] + +### Changed +- Migrated to `nonempty 0.11` + ## [0.2.2] - 2024-12-13 ### Added - `no-std` support, via a default-enabled `std` feature flag. diff --git a/devtools/Cargo.toml b/devtools/Cargo.toml index 56917a21a..dea1aefe8 100644 --- a/devtools/Cargo.toml +++ b/devtools/Cargo.toml @@ -27,7 +27,7 @@ zcash_protocol = {workspace = true, features = ["local-consensus"] } # Transparent secp256k1.workspace = true -transparent.workspace = true +transparent = { workspace = true, features = ["test-dependencies"] } # Sprout ed25519-zebra = "4" diff --git a/devtools/src/bin/inspect/transaction.rs b/devtools/src/bin/inspect/transaction.rs index bfb8bbc3a..8f6c970b7 100644 --- a/devtools/src/bin/inspect/transaction.rs +++ b/devtools/src/bin/inspect/transaction.rs @@ -325,8 +325,9 @@ pub(crate) fn inspect( ), txid_parts, ); - let msg = secp256k1::Message::from_slice(sighash.as_ref()) - .expect("signature_hash() returns correct length"); + let msg = + secp256k1::Message::from_digest_slice(sighash.as_ref()) + .expect("signature_hash() returns correct length"); if let Err(e) = ctx.verify_ecdsa(&msg, &sig, &pubkey) { eprintln!(" ⚠️ Spend {} is invalid: {}", i, e); diff --git a/pczt/CHANGELOG.md b/pczt/CHANGELOG.md index ba186f614..09850a109 100644 --- a/pczt/CHANGELOG.md +++ b/pczt/CHANGELOG.md @@ -7,5 +7,8 @@ and this library adheres to Rust's notion of ## [Unreleased] +### Changed +- Migrated to `nonempty 0.11` + ## [0.1.0] - 2024-12-16 Initial release supporting the PCZT v1 format. diff --git a/pczt/src/common.rs b/pczt/src/common.rs index bcf808aab..577cd2722 100644 --- a/pczt/src/common.rs +++ b/pczt/src/common.rs @@ -21,13 +21,16 @@ pub struct Global { // These are required fields that are part of the final transaction, and are filled in // by the Creator when initializing the PCZT. // + #[getset(get = "pub")] pub(crate) tx_version: u32, + #[getset(get = "pub")] pub(crate) version_group_id: u32, /// The consensus branch ID for the chain in which this transaction will be mined. /// /// Non-optional because this commits to the set of consensus rules that will apply to /// the transaction; differences therein can affect every role. + #[getset(get = "pub")] pub(crate) consensus_branch_id: u32, /// The transaction locktime to use if no inputs specify a required locktime. @@ -36,6 +39,7 @@ pub struct Global { /// - If omitted, the fallback locktime is assumed to be 0. pub(crate) fallback_lock_time: Option, + #[getset(get = "pub")] pub(crate) expiry_height: u32, /// The [SLIP 44] coin type, indicating the network for which this transaction is @@ -181,9 +185,10 @@ impl Global { } } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Getters)] pub(crate) struct Zip32Derivation { /// The [ZIP 32 seed fingerprint](https://zips.z.cash/zip-0032#seed-fingerprints). + #[getset(get = "pub")] pub(crate) seed_fingerprint: [u8; 32], /// The sequence of indices corresponding to the shielded HD path. @@ -196,9 +201,94 @@ pub(crate) struct Zip32Derivation { /// /// [BIP 44]: https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki /// [ZIP 320]: https://zips.z.cash/zip-0320 + #[getset(get = "pub")] pub(crate) derivation_path: Vec, } +/// Determines the lock time for the transaction. +/// +/// Implemented following the specification in [BIP 370], with the rationale that this +/// makes integration of PCZTs simpler for codebases that already support PSBTs. +/// +/// [BIP 370]: https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki#determining-lock-time +pub fn determine_lock_time( + global: &crate::common::Global, + inputs: &[L], +) -> Result { + // The nLockTime field of a transaction is determined by inspecting the + // `Global.fallback_lock_time` and each input's `required_time_lock_time` and + // `required_height_lock_time` fields. + + // If one or more inputs have a `required_time_lock_time` or `required_height_lock_time`, + let have_required_lock_time = inputs.iter().any(|input| { + input.required_time_lock_time().is_some() || input.required_height_lock_time().is_some() + }); + // then the field chosen is the one which is supported by all of the inputs. This can + // be determined by looking at all of the inputs which specify a locktime in either of + // those fields, and choosing the field which is present in all of those inputs. + // Inputs not specifying a lock time field can take both types of lock times, as can + // those that specify both. + let time_lock_time_unsupported = inputs + .iter() + .any(|input| input.required_height_lock_time().is_some()); + let height_lock_time_unsupported = inputs + .iter() + .any(|input| input.required_time_lock_time().is_some()); + + // The lock time chosen is then the maximum value of the chosen type of lock time. + match ( + have_required_lock_time, + time_lock_time_unsupported, + height_lock_time_unsupported, + ) { + (true, true, true) => Err(()), + (true, false, true) => Ok(inputs + .iter() + .filter_map(|input| input.required_time_lock_time()) + .max() + .expect("iterator is non-empty because have_required_lock_time is true")), + // If a PSBT has both types of locktimes possible because one or more inputs + // specify both `required_time_lock_time` and `required_height_lock_time`, then a + // locktime determined by looking at the `required_height_lock_time` fields of the + // inputs must be chosen. + (true, _, false) => Ok(inputs + .iter() + .filter_map(|input| input.required_height_lock_time()) + .max() + .expect("iterator is non-empty because have_required_lock_time is true")), + // If none of the inputs have a `required_time_lock_time` and + // `required_height_lock_time`, then `Global.fallback_lock_time` must be used. If + // `Global.fallback_lock_time` is not provided, then it is assumed to be 0. + (false, _, _) => Ok(global.fallback_lock_time.unwrap_or(0)), + } +} + +pub trait LockTimeInput { + fn required_time_lock_time(&self) -> Option; + fn required_height_lock_time(&self) -> Option; +} + +impl LockTimeInput for crate::transparent::Input { + fn required_time_lock_time(&self) -> Option { + self.required_time_lock_time + } + + fn required_height_lock_time(&self) -> Option { + self.required_height_lock_time + } +} + +#[cfg(feature = "transparent")] +impl LockTimeInput for ::transparent::pczt::Input { + fn required_time_lock_time(&self) -> Option { + *self.required_time_lock_time() + } + + fn required_height_lock_time(&self) -> Option { + *self.required_height_lock_time() + } +} + #[cfg(test)] mod tests { use alloc::collections::BTreeMap; diff --git a/pczt/src/orchard.rs b/pczt/src/orchard.rs index 2e610a466..59abdec1a 100644 --- a/pczt/src/orchard.rs +++ b/pczt/src/orchard.rs @@ -33,6 +33,7 @@ pub struct Bundle { /// /// This is set by the Creator. The Constructor MUST only add spends and outputs that /// are consistent with these flags (i.e. are dummies as appropriate). + #[getset(get = "pub")] pub(crate) flags: u8, /// The net value of Orchard spends minus outputs. @@ -40,11 +41,13 @@ pub struct Bundle { /// This is initialized by the Creator, and updated by the Constructor as spends or /// outputs are added to the PCZT. It enables per-spend and per-output values to be /// redacted from the PCZT after they are no longer necessary. + #[getset(get = "pub")] pub(crate) value_sum: (u64, bool), /// The Orchard anchor for this transaction. /// /// Set by the Creator. + #[getset(get = "pub")] pub(crate) anchor: [u8; 32], /// The Orchard bundle proof. @@ -67,6 +70,7 @@ pub struct Action { // These are required fields that are part of the final transaction, and are filled in // by the Constructor when adding an output. // + #[getset(get = "pub")] pub(crate) cv_net: [u8; 32], #[getset(get = "pub")] pub(crate) spend: Spend, @@ -97,6 +101,7 @@ pub struct Spend { // #[getset(get = "pub")] pub(crate) nullifier: [u8; 32], + #[getset(get = "pub")] pub(crate) rk: [u8; 32], /// The spend authorization signature. @@ -183,7 +188,9 @@ pub struct Output { // These are required fields that are part of the final transaction, and are filled in // by the Constructor when adding an output. // + #[getset(get = "pub")] pub(crate) cmx: [u8; 32], + #[getset(get = "pub")] pub(crate) ephemeral_key: [u8; 32], /// The encrypted note plaintext for the output. /// @@ -191,10 +198,12 @@ pub struct Output { /// /// Once we have memo bundles, we will be able to set memos independently of Outputs. /// For now, the Constructor sets both at the same time. + #[getset(get = "pub")] pub(crate) enc_ciphertext: Vec, /// The encrypted note plaintext for the output. /// /// Encoded as a `Vec` because its length depends on the transaction version. + #[getset(get = "pub")] pub(crate) out_ciphertext: Vec, /// The [raw encoding] of the Orchard payment address that will receive the output. diff --git a/pczt/src/roles.rs b/pczt/src/roles.rs index 8361fd9ba..807164d97 100644 --- a/pczt/src/roles.rs +++ b/pczt/src/roles.rs @@ -13,6 +13,8 @@ pub mod prover; #[cfg(feature = "signer")] pub mod signer; +pub mod low_level_signer; + pub mod combiner; #[cfg(feature = "spend-finalizer")] diff --git a/pczt/src/roles/low_level_signer/mod.rs b/pczt/src/roles/low_level_signer/mod.rs new file mode 100644 index 000000000..61816681a --- /dev/null +++ b/pczt/src/roles/low_level_signer/mod.rs @@ -0,0 +1,80 @@ +use crate::Pczt; + +pub struct Signer { + pczt: Pczt, +} + +impl Signer { + /// Instantiates the low-level Signer role with the given PCZT. + pub fn new(pczt: Pczt) -> Self { + Self { pczt } + } + + /// Exposes the capability to sign the Orchard spends. + #[cfg(feature = "orchard")] + pub fn sign_orchard_with(self, f: F) -> Result + where + E: From, + F: FnOnce(&Pczt, &mut orchard::pczt::Bundle, &mut u8) -> Result<(), E>, + { + let mut pczt = self.pczt; + + let mut tx_modifiable = pczt.global.tx_modifiable; + + let mut bundle = pczt.orchard.clone().into_parsed()?; + + f(&pczt, &mut bundle, &mut tx_modifiable)?; + + pczt.global.tx_modifiable = tx_modifiable; + pczt.orchard = crate::orchard::Bundle::serialize_from(bundle); + + Ok(Self { pczt }) + } + + /// Exposes the capability to sign the Sapling spends. + #[cfg(feature = "sapling")] + pub fn sign_sapling_with(self, f: F) -> Result + where + E: From, + F: FnOnce(&Pczt, &mut sapling::pczt::Bundle, &mut u8) -> Result<(), E>, + { + let mut pczt = self.pczt; + + let mut tx_modifiable = pczt.global.tx_modifiable; + + let mut bundle = pczt.sapling.clone().into_parsed()?; + + f(&pczt, &mut bundle, &mut tx_modifiable)?; + + pczt.global.tx_modifiable = tx_modifiable; + pczt.sapling = crate::sapling::Bundle::serialize_from(bundle); + + Ok(Self { pczt }) + } + + /// Exposes the capability to sign the transparent spends. + #[cfg(feature = "transparent")] + pub fn sign_transparent_with(self, f: F) -> Result + where + E: From, + F: FnOnce(&Pczt, &mut transparent::pczt::Bundle, &mut u8) -> Result<(), E>, + { + let mut pczt = self.pczt; + + let mut tx_modifiable = pczt.global.tx_modifiable; + + let mut bundle = pczt.transparent.clone().into_parsed()?; + + f(&pczt, &mut bundle, &mut tx_modifiable)?; + + pczt.global.tx_modifiable = tx_modifiable; + pczt.transparent = crate::transparent::Bundle::serialize_from(bundle); + + Ok(Self { pczt }) + } + + /// Finishes the low-level Signer role, returning the updated PCZT. + pub fn finish(self) -> Pczt { + self.pczt + } +} diff --git a/pczt/src/roles/signer/mod.rs b/pczt/src/roles/signer/mod.rs index b929e5464..402dad0f0 100644 --- a/pczt/src/roles/signer/mod.rs +++ b/pczt/src/roles/signer/mod.rs @@ -16,7 +16,7 @@ use crate::{ Pczt, }; -use super::tx_extractor::determine_lock_time; +use crate::common::determine_lock_time; const V5_TX_VERSION: u32 = 5; const V5_VERSION_GROUP_ID: u32 = 0x26A7270A; diff --git a/pczt/src/roles/tx_extractor/mod.rs b/pczt/src/roles/tx_extractor/mod.rs index bb104b233..9248ef9fd 100644 --- a/pczt/src/roles/tx_extractor/mod.rs +++ b/pczt/src/roles/tx_extractor/mod.rs @@ -10,7 +10,7 @@ use zcash_primitives::{ }, }; -use crate::{Pczt, V5_TX_VERSION, V5_VERSION_GROUP_ID}; +use crate::{common::determine_lock_time, Pczt, V5_TX_VERSION, V5_VERSION_GROUP_ID}; mod orchard; pub use self::orchard::OrchardError; @@ -175,87 +175,3 @@ pub enum GlobalError { UnknownConsensusBranchId, UnsupportedTxVersion { version: u32, version_group_id: u32 }, } - -/// Determines the lock time for the transaction. -/// -/// Implemented following the specification in [BIP 370], with the rationale that this -/// makes integration of PCZTs simpler for codebases that already support PSBTs. -/// -/// [BIP 370]: https://github.com/bitcoin/bips/blob/master/bip-0370.mediawiki#determining-lock-time -pub(crate) fn determine_lock_time( - global: &crate::common::Global, - inputs: &[L], -) -> Result { - // The nLockTime field of a transaction is determined by inspecting the - // `Global.fallback_lock_time` and each input's `required_time_lock_time` and - // `required_height_lock_time` fields. - - // If one or more inputs have a `required_time_lock_time` or `required_height_lock_time`, - let have_required_lock_time = inputs.iter().any(|input| { - input.required_time_lock_time().is_some() || input.required_height_lock_time().is_some() - }); - // then the field chosen is the one which is supported by all of the inputs. This can - // be determined by looking at all of the inputs which specify a locktime in either of - // those fields, and choosing the field which is present in all of those inputs. - // Inputs not specifying a lock time field can take both types of lock times, as can - // those that specify both. - let time_lock_time_unsupported = inputs - .iter() - .any(|input| input.required_height_lock_time().is_some()); - let height_lock_time_unsupported = inputs - .iter() - .any(|input| input.required_time_lock_time().is_some()); - - // The lock time chosen is then the maximum value of the chosen type of lock time. - match ( - have_required_lock_time, - time_lock_time_unsupported, - height_lock_time_unsupported, - ) { - (true, true, true) => Err(()), - (true, false, true) => Ok(inputs - .iter() - .filter_map(|input| input.required_time_lock_time()) - .max() - .expect("iterator is non-empty because have_required_lock_time is true")), - // If a PSBT has both types of locktimes possible because one or more inputs - // specify both `required_time_lock_time` and `required_height_lock_time`, then a - // locktime determined by looking at the `required_height_lock_time` fields of the - // inputs must be chosen. - (true, _, false) => Ok(inputs - .iter() - .filter_map(|input| input.required_height_lock_time()) - .max() - .expect("iterator is non-empty because have_required_lock_time is true")), - // If none of the inputs have a `required_time_lock_time` and - // `required_height_lock_time`, then `Global.fallback_lock_time` must be used. If - // `Global.fallback_lock_time` is not provided, then it is assumed to be 0. - (false, _, _) => Ok(global.fallback_lock_time.unwrap_or(0)), - } -} - -pub(crate) trait LockTimeInput { - fn required_time_lock_time(&self) -> Option; - fn required_height_lock_time(&self) -> Option; -} - -impl LockTimeInput for crate::transparent::Input { - fn required_time_lock_time(&self) -> Option { - self.required_time_lock_time - } - - fn required_height_lock_time(&self) -> Option { - self.required_height_lock_time - } -} - -#[cfg(feature = "transparent")] -impl LockTimeInput for ::transparent::pczt::Input { - fn required_time_lock_time(&self) -> Option { - *self.required_time_lock_time() - } - - fn required_height_lock_time(&self) -> Option { - *self.required_height_lock_time() - } -} diff --git a/pczt/src/sapling.rs b/pczt/src/sapling.rs index c6b752721..edf52d345 100644 --- a/pczt/src/sapling.rs +++ b/pczt/src/sapling.rs @@ -27,11 +27,13 @@ pub struct Bundle { /// This is initialized by the Creator, and updated by the Constructor as spends or /// outputs are added to the PCZT. It enables per-spend and per-output values to be /// redacted from the PCZT after they are no longer necessary. + #[getset(get = "pub")] pub(crate) value_sum: i128, /// The Sapling anchor for this transaction. /// /// Set by the Creator. + #[getset(get = "pub")] pub(crate) anchor: [u8; 32], /// The Sapling binding signature signing key. @@ -51,8 +53,11 @@ pub struct Spend { // These are required fields that are part of the final transaction, and are filled in // by the Constructor when adding an output. // + #[getset(get = "pub")] pub(crate) cv: [u8; 32], + #[getset(get = "pub")] pub(crate) nullifier: [u8; 32], + #[getset(get = "pub")] pub(crate) rk: [u8; 32], /// The Spend proof. @@ -161,8 +166,11 @@ pub struct Output { // These are required fields that are part of the final transaction, and are filled in // by the Constructor when adding an output. // + #[getset(get = "pub")] pub(crate) cv: [u8; 32], + #[getset(get = "pub")] pub(crate) cmu: [u8; 32], + #[getset(get = "pub")] pub(crate) ephemeral_key: [u8; 32], /// The encrypted note plaintext for the output. /// @@ -172,10 +180,12 @@ pub struct Output { /// Outputs. For now, the Constructor sets both at the same time. /// /// [memo bundles]: https://zips.z.cash/zip-0231 + #[getset(get = "pub")] pub(crate) enc_ciphertext: Vec, /// The encrypted note plaintext for the output. /// /// Encoded as a `Vec` because its length depends on the transaction version. + #[getset(get = "pub")] pub(crate) out_ciphertext: Vec, /// The Output proof. diff --git a/pczt/src/transparent.rs b/pczt/src/transparent.rs index db86357b5..b7f7ff68e 100644 --- a/pczt/src/transparent.rs +++ b/pczt/src/transparent.rs @@ -41,6 +41,7 @@ pub struct Input { /// - This is set by the Constructor. /// - If omitted, the sequence number is assumed to be the final sequence number /// (`0xffffffff`). + #[getset(get = "pub")] pub(crate) sequence: Option, /// The minimum Unix timstamp that this input requires to be set as the transaction's @@ -66,6 +67,7 @@ pub struct Input { // needed for computing the binding signatures. #[getset(get = "pub")] pub(crate) value: u64, + #[getset(get = "pub")] pub(crate) script_pubkey: Vec, /// The script required to spend this output, if it is P2SH. @@ -88,6 +90,7 @@ pub struct Input { /// cannot produce signatures for this sighash type must not provide a signature. /// - Spend Finalizers must fail to finalize inputs which have signatures not matching /// this sighash type. + #[getset(get = "pub")] pub(crate) sighash_type: u8, /// A map from a pubkey to the BIP 32 derivation path at which its corresponding @@ -98,6 +101,7 @@ pub struct Input { /// - Individual entries may be required by a Signer. /// - It is not required that the map include entries for all of the used pubkeys. /// In particular, it is not possible to include entries for non-BIP-32 pubkeys. + #[getset(get = "pub")] #[serde_as(as = "BTreeMap<[_; 33], _>")] pub(crate) bip32_derivation: BTreeMap<[u8; 33], Zip32Derivation>, @@ -139,7 +143,9 @@ pub struct Output { // These are required fields that are part of the final transaction, and are filled in // by the Constructor when adding an output. // + #[getset(get = "pub")] pub(crate) value: u64, + #[getset(get = "pub")] pub(crate) script_pubkey: Vec, /// The script required to spend this output, if it is P2SH. @@ -155,6 +161,7 @@ pub struct Output { /// - Individual entries may be required by a Signer. /// - It is not required that the map include entries for all of the used pubkeys. /// In particular, it is not possible to include entries for non-BIP-32 pubkeys. + #[getset(get = "pub")] #[serde_as(as = "BTreeMap<[_; 33], _>")] pub(crate) bip32_derivation: BTreeMap<[u8; 33], Zip32Derivation>, diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index c93f2275b..b4611bbcf 100644 --- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -254,6 +254,26 @@ who = "Jack Grigg " criteria = "safe-to-deploy" delta = "2.11.2 -> 2.12.0" +[[audits.nonempty]] +who = "Kris Nuttycombe " +criteria = "safe-to-deploy" +version = "0.11.0" +notes = """ +Additional use of `unsafe` to wrap `NonZeroUsize::new_unchecked`; in both cases +the argument to this method is ` + 1`; in general this +is safe with the exception that if an existing `Vec` has length or capacity +`usize::MAX` this could wrap into zero; it would be better to use the safe +operation and then `expect` to generate a panic, rather than risk undefined +behavior. + +Additions are: +- no_std support +- sorting +- `nonzero` module (just wrappers +- `serde` support +- `nonempty macro` (trivial, verified safe) +""" + [[audits.num-bigint]] who = "Daira-Emma Hopwood " criteria = "safe-to-deploy" diff --git a/supply-chain/config.toml b/supply-chain/config.toml index 9b91b97fa..068db66d2 100644 --- a/supply-chain/config.toml +++ b/supply-chain/config.toml @@ -765,10 +765,6 @@ criteria = "safe-to-deploy" version = "0.8.3" criteria = "safe-to-deploy" -[[exemptions.nonempty]] -version = "0.7.0" -criteria = "safe-to-deploy" - [[exemptions.notify]] version = "6.1.1" criteria = "safe-to-deploy" diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock index 961de26e3..418274054 100644 --- a/supply-chain/imports.lock +++ b/supply-chain/imports.lock @@ -77,13 +77,6 @@ user-id = 6289 user-login = "str4d" user-name = "Jack Grigg" -[[publisher.orchard]] -version = "0.10.1" -when = "2024-12-17" -user-id = 169181 -user-login = "nuttycom" -user-name = "Kris Nuttycombe" - [[publisher.pczt]] version = "0.1.0" when = "2024-12-17" diff --git a/zcash_client_backend/CHANGELOG.md b/zcash_client_backend/CHANGELOG.md index b88727242..b58d96399 100644 --- a/zcash_client_backend/CHANGELOG.md +++ b/zcash_client_backend/CHANGELOG.md @@ -7,6 +7,9 @@ and this library adheres to Rust's notion of ## [Unreleased] +### Changed +- Migrated to `nonempty 0.11` + ## [0.16.0] - 2024-12-16 ### Added diff --git a/zcash_client_sqlite/CHANGELOG.md b/zcash_client_sqlite/CHANGELOG.md index c77dc9c8a..22b31c43d 100644 --- a/zcash_client_sqlite/CHANGELOG.md +++ b/zcash_client_sqlite/CHANGELOG.md @@ -7,6 +7,9 @@ and this library adheres to Rust's notion of ## [Unreleased] +### Changed +- Migrated to `nonempty 0.11` + ## [0.14.0] - 2024-12-16 ### Added diff --git a/zcash_keys/CHANGELOG.md b/zcash_keys/CHANGELOG.md index d7e33fb8d..33b00bb7c 100644 --- a/zcash_keys/CHANGELOG.md +++ b/zcash_keys/CHANGELOG.md @@ -6,6 +6,13 @@ and this library adheres to Rust's notion of ## [Unreleased] +### Added +- `no-std` compatibility (`alloc` is required). A default-enabled `std` feature + flag has been added gating the `std::error::Error` usage. + +### Changed +- Migrated to `nonempty 0.11` + ## [0.6.0] - 2024-12-16 ### Changed diff --git a/zcash_keys/Cargo.toml b/zcash_keys/Cargo.toml index f950bcbf7..851e122ea 100644 --- a/zcash_keys/Cargo.toml +++ b/zcash_keys/Cargo.toml @@ -59,7 +59,7 @@ proptest = { workspace = true, optional = true } # Dependencies used internally: # (Breaking upgrades to these are usually backwards-compatible, but check MSRVs.) # - Documentation -document-features.workspace = true +document-features = { workspace = true, optional = true } # - Encodings byteorder = { workspace = true, optional = true } @@ -76,6 +76,9 @@ orchard = { workspace = true, features = ["circuit"] } zcash_address = { workspace = true, features = ["test-dependencies"] } [features] +default = ["std"] +std = ["dep:document-features"] + ## Enables use of transparent key parts and addresses transparent-inputs = [ "dep:bip32", diff --git a/zcash_keys/src/encoding.rs b/zcash_keys/src/encoding.rs index 50270fc28..7be07a3d4 100644 --- a/zcash_keys/src/encoding.rs +++ b/zcash_keys/src/encoding.rs @@ -76,7 +76,7 @@ impl fmt::Display for Bech32DecodeError { } } -#[cfg(feature = "sapling")] +#[cfg(all(feature = "sapling", feature = "std"))] impl std::error::Error for Bech32DecodeError {} #[cfg(feature = "sapling")] @@ -135,6 +135,7 @@ impl fmt::Display for TransparentCodecError { } } +#[cfg(feature = "std")] impl std::error::Error for TransparentCodecError {} impl AddressCodec

for TransparentAddress { diff --git a/zcash_keys/src/keys.rs b/zcash_keys/src/keys.rs index 140e2cc58..123dd20aa 100644 --- a/zcash_keys/src/keys.rs +++ b/zcash_keys/src/keys.rs @@ -113,6 +113,7 @@ impl Display for DerivationError { } } +#[cfg(feature = "std")] impl std::error::Error for DerivationError {} /// A version identifier for the encoding of unified spending keys. @@ -180,6 +181,7 @@ impl core::fmt::Display for DecodingError { } } +#[cfg(feature = "std")] impl std::error::Error for DecodingError {} #[cfg(feature = "unstable")] @@ -547,6 +549,7 @@ impl fmt::Display for AddressGenerationError { } } +#[cfg(feature = "std")] impl std::error::Error for AddressGenerationError {} /// Specification for how a unified address should be generated from a unified viewing key. @@ -1308,7 +1311,6 @@ pub mod testing { #[cfg(test)] mod tests { - use proptest::prelude::proptest; use zcash_protocol::consensus::MAIN_NETWORK; diff --git a/zcash_keys/src/lib.rs b/zcash_keys/src/lib.rs index 28c9c98b1..48830ebd0 100644 --- a/zcash_keys/src/lib.rs +++ b/zcash_keys/src/lib.rs @@ -4,7 +4,8 @@ //! and viewing keys and addresses. //! //! ## Feature flags -#![doc = document_features::document_features!()] +#![cfg_attr(feature = "std", doc = "## Feature flags")] +#![cfg_attr(feature = "std", doc = document_features::document_features!())] //! #![no_std] @@ -18,6 +19,7 @@ #[macro_use] extern crate alloc; +#[cfg(feature = "std")] extern crate std; pub mod address; diff --git a/zcash_primitives/CHANGELOG.md b/zcash_primitives/CHANGELOG.md index fc811d14e..bb7d255a5 100644 --- a/zcash_primitives/CHANGELOG.md +++ b/zcash_primitives/CHANGELOG.md @@ -7,6 +7,9 @@ and this library adheres to Rust's notion of ## [Unreleased] +### Changed +- Migrated to `nonempty 0.11` + ## [0.21.0] - 2024-12-16 ### Added diff --git a/zcash_transparent/CHANGELOG.md b/zcash_transparent/CHANGELOG.md index 8dc130e2b..35cc8874e 100644 --- a/zcash_transparent/CHANGELOG.md +++ b/zcash_transparent/CHANGELOG.md @@ -7,6 +7,10 @@ and this library adheres to Rust's notion of ## [Unreleased] +### Fixed +- `zcash_transparent::keys::AccountPubKey::derive_pubkey_at_bip32_path` now + returns the correct result for valid paths instead of an error or panic. + ## [0.1.0] - 2024-12-16 The entries below are relative to the `zcash_primitives` crate as of the tag diff --git a/zcash_transparent/Cargo.toml b/zcash_transparent/Cargo.toml index cb93f05ff..45c575db0 100644 --- a/zcash_transparent/Cargo.toml +++ b/zcash_transparent/Cargo.toml @@ -58,6 +58,10 @@ hex.workspace = true # - Transparent protocol ripemd.workspace = true +[dev-dependencies] +proptest.workspace = true +zcash_protocol = { workspace = true, features = ["test-dependencies"] } + [features] default = ["std"] std = [ diff --git a/zcash_transparent/src/builder.rs b/zcash_transparent/src/builder.rs index 420091089..2c94c7b38 100644 --- a/zcash_transparent/src/builder.rs +++ b/zcash_transparent/src/builder.rs @@ -351,7 +351,8 @@ impl Bundle { value: info.coin.value, }); - let msg = secp256k1::Message::from_slice(sighash.as_ref()).expect("32 bytes"); + let msg = + secp256k1::Message::from_digest_slice(sighash.as_ref()).expect("32 bytes"); let sig = signing_set.secp.sign_ecdsa(&msg, sk); // Signature has to have "SIGHASH_ALL" appended to it diff --git a/zcash_transparent/src/keys.rs b/zcash_transparent/src/keys.rs index 03b82e4a2..7bd310448 100644 --- a/zcash_transparent/src/keys.rs +++ b/zcash_transparent/src/keys.rs @@ -273,17 +273,17 @@ impl AccountPubKey { expected_account_index: AccountId, path: &[ChildNumber], ) -> Result { - if path.len() > 3 { + if path.len() < 3 { Err(bip32::Error::ChildNumber) } else { match path.split_at(3) { - ( - [ChildNumber(44 | ChildNumber::HARDENED_FLAG), coin_type, account_index], - sub_path, - ) if coin_type.is_hardened() - && coin_type.index() == params.network_type().coin_type() - && account_index.is_hardened() - && account_index.index() == expected_account_index.into() => + ([purpose, coin_type, account_index], sub_path) + if purpose.is_hardened() + && purpose.index() == 44 + && coin_type.is_hardened() + && coin_type.index() == params.network_type().coin_type() + && account_index.is_hardened() + && account_index.index() == expected_account_index.into() => { sub_path .iter() @@ -522,244 +522,118 @@ impl ExternalOvk { mod tests { use bip32::ChildNumber; use subtle::ConstantTimeEq; + use zcash_protocol::consensus::{NetworkConstants, MAIN_NETWORK}; use super::AccountPubKey; use super::NonHardenedChildIndex; + #[allow(deprecated)] + use crate::keys::pubkey_to_address; + use crate::{ + address::TransparentAddress, + keys::{AccountPrivKey, IncomingViewingKey, TransparentKeyScope}, + test_vectors, + }; #[test] - fn check_ovk_test_vectors() { - struct TestVector { - c: [u8; 32], - pk: [u8; 33], - external_ovk: [u8; 32], - internal_ovk: [u8; 32], + #[allow(deprecated)] + fn address_derivation() { + let seed = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + ]; + + for account_index in 0..5 { + let account_index = zip32::AccountId::try_from(account_index).unwrap(); + let account_sk = + AccountPrivKey::from_seed(&MAIN_NETWORK, &seed, account_index).unwrap(); + let account_pubkey = account_sk.to_account_pubkey(); + + let external_ivk = account_pubkey.derive_external_ivk().unwrap(); + let (address, address_index) = external_ivk.default_address(); + + let address_pubkey = account_pubkey + .derive_address_pubkey(TransparentKeyScope::EXTERNAL, address_index) + .unwrap(); + assert_eq!(pubkey_to_address(&address_pubkey), address); + + let expected_path = [ + ChildNumber::new(44, true).unwrap(), + ChildNumber::new(MAIN_NETWORK.coin_type(), true).unwrap(), + ChildNumber::new(account_index.into(), true).unwrap(), + TransparentKeyScope::EXTERNAL.into(), + address_index.into(), + ]; + + // For short paths, we get an error. + for i in 0..3 { + assert_eq!( + account_pubkey.derive_pubkey_at_bip32_path( + &MAIN_NETWORK, + account_index, + &expected_path[..i] + ), + Err(bip32::Error::ChildNumber), + ); + } + + // The truncated-by-one path gives the external IVK. + assert_eq!( + account_pubkey.derive_pubkey_at_bip32_path( + &MAIN_NETWORK, + account_index, + &expected_path[..4], + ), + Ok(*external_ivk.0.public_key()), + ); + + // The full path gives the correct pubkey. + assert_eq!( + account_pubkey.derive_pubkey_at_bip32_path( + &MAIN_NETWORK, + account_index, + &expected_path, + ), + Ok(address_pubkey), + ); } + } - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/zip_0316.py - let test_vectors = vec![ - TestVector { - c: [ - 0x5d, 0x7a, 0x8f, 0x73, 0x9a, 0x2d, 0x9e, 0x94, 0x5b, 0x0c, 0xe1, 0x52, 0xa8, - 0x04, 0x9e, 0x29, 0x4c, 0x4d, 0x6e, 0x66, 0xb1, 0x64, 0x93, 0x9d, 0xaf, 0xfa, - 0x2e, 0xf6, 0xee, 0x69, 0x21, 0x48, - ], - pk: [ - 0x02, 0x16, 0x88, 0x4f, 0x1d, 0xbc, 0x92, 0x90, 0x89, 0xa4, 0x17, 0x6e, 0x84, - 0x0b, 0xb5, 0x81, 0xc8, 0x0e, 0x16, 0xe9, 0xb1, 0xab, 0xd6, 0x54, 0xe6, 0x2c, - 0x8b, 0x0b, 0x95, 0x70, 0x20, 0xb7, 0x48, - ], - external_ovk: [ - 0xdc, 0xe7, 0xfb, 0x7f, 0x20, 0xeb, 0x77, 0x64, 0xd5, 0x12, 0x4f, 0xbd, 0x23, - 0xc4, 0xd7, 0xca, 0x8c, 0x32, 0x19, 0xec, 0x1d, 0xb3, 0xff, 0x1e, 0x08, 0x13, - 0x50, 0xad, 0x03, 0x9b, 0x40, 0x79, - ], - internal_ovk: [ - 0x4d, 0x46, 0xc7, 0x14, 0xed, 0xda, 0xd9, 0x4a, 0x40, 0xac, 0x21, 0x28, 0x6a, - 0xff, 0x32, 0x7d, 0x7e, 0xbf, 0x11, 0x9e, 0x86, 0x85, 0x10, 0x9b, 0x44, 0xe8, - 0x02, 0x83, 0xd8, 0xc8, 0xa4, 0x00, - ], - }, - TestVector { - c: [ - 0xbf, 0x69, 0xb8, 0x25, 0x0c, 0x18, 0xef, 0x41, 0x29, 0x4c, 0xa9, 0x79, 0x93, - 0xdb, 0x54, 0x6c, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, 0xa5, 0xe2, - 0x9d, 0x4e, 0x30, 0xa7, 0x35, 0x94, - ], - pk: [ - 0x03, 0x72, 0x73, 0xb6, 0x57, 0xd9, 0x71, 0xa4, 0x5e, 0x72, 0x24, 0x0c, 0x7a, - 0xaa, 0xa7, 0xd0, 0x68, 0x5d, 0x06, 0xd7, 0x99, 0x9b, 0x0a, 0x19, 0xc4, 0xce, - 0xa3, 0x27, 0x88, 0xa6, 0xab, 0x51, 0x3d, - ], - external_ovk: [ - 0x8d, 0x31, 0x53, 0x7b, 0x38, 0x8f, 0x40, 0x23, 0xe6, 0x48, 0x70, 0x8b, 0xfb, - 0xde, 0x2b, 0xa1, 0xff, 0x1a, 0x4e, 0xe1, 0x12, 0xea, 0x67, 0x0a, 0xd1, 0x67, - 0x44, 0xf4, 0x58, 0x3e, 0x95, 0x52, - ], - internal_ovk: [ - 0x16, 0x77, 0x49, 0x00, 0x76, 0x9d, 0x9c, 0x03, 0xbe, 0x06, 0x32, 0x45, 0xcf, - 0x1c, 0x22, 0x44, 0xa9, 0x2e, 0x48, 0x51, 0x01, 0x54, 0x73, 0x61, 0x3f, 0xbf, - 0x38, 0xd2, 0x42, 0xd7, 0x54, 0xf6, - ], - }, - TestVector { - c: [ - 0x3d, 0xc1, 0x66, 0xd5, 0x6a, 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x55, 0x1d, 0xb5, - 0xfd, 0x93, 0x13, 0xe8, 0xc7, 0x20, 0x3d, 0x99, 0x6a, 0xf7, 0xd4, 0x77, 0x08, - 0x37, 0x56, 0xd5, 0x9a, 0xf8, 0x0d, - ], - pk: [ - 0x03, 0xec, 0x05, 0xbb, 0x7f, 0x06, 0x5e, 0x25, 0x6f, 0xf4, 0x54, 0xf8, 0xa8, - 0xdf, 0x6f, 0x2f, 0x9b, 0x8a, 0x8c, 0x95, 0x08, 0xca, 0xac, 0xfe, 0xe9, 0x52, - 0x1c, 0xbe, 0x68, 0x9d, 0xd1, 0x12, 0x0f, - ], - external_ovk: [ - 0xdb, 0x97, 0x52, 0x0e, 0x2f, 0xe3, 0x68, 0xad, 0x50, 0x2d, 0xef, 0xf8, 0x42, - 0xf0, 0xc0, 0xee, 0x5d, 0x20, 0x3b, 0x48, 0x33, 0x7a, 0x0f, 0xff, 0x75, 0xbe, - 0x24, 0x52, 0x59, 0x77, 0xf3, 0x7e, - ], - internal_ovk: [ - 0xbc, 0x4a, 0xcb, 0x5f, 0x52, 0xb8, 0xae, 0x21, 0xe3, 0x32, 0xb1, 0x7c, 0x29, - 0x63, 0x1f, 0x68, 0xe9, 0x68, 0x2a, 0x46, 0xc4, 0xa7, 0xab, 0xc8, 0xed, 0xf9, - 0x0d, 0x37, 0xae, 0xea, 0xd3, 0x6c, - ], - }, - TestVector { - c: [ - 0x49, 0x5c, 0x22, 0x2f, 0x7f, 0xba, 0x1e, 0x31, 0xde, 0xfa, 0x3d, 0x5a, 0x57, - 0xef, 0xc2, 0xe1, 0xe9, 0xb0, 0x1a, 0x03, 0x55, 0x87, 0xd5, 0xfb, 0x1a, 0x38, - 0xe0, 0x1d, 0x94, 0x90, 0x3d, 0x3c, - ], - pk: [ - 0x02, 0x81, 0x8f, 0x50, 0xce, 0x47, 0x10, 0xf4, 0xeb, 0x11, 0xe7, 0x43, 0xe6, - 0x40, 0x85, 0x44, 0xaa, 0x3c, 0x12, 0x3c, 0x7f, 0x07, 0xe2, 0xaa, 0xbb, 0x91, - 0xaf, 0xc4, 0xec, 0x48, 0x78, 0x8d, 0xe9, - ], - external_ovk: [ - 0xb8, 0xa3, 0x6d, 0x62, 0xa6, 0x3f, 0x69, 0x36, 0x7b, 0xe3, 0xf4, 0xbe, 0xd4, - 0x20, 0x26, 0x4a, 0xdb, 0x63, 0x7b, 0xbb, 0x47, 0x0e, 0x1f, 0x56, 0xe0, 0x33, - 0x8b, 0x38, 0xe2, 0xa6, 0x90, 0x97, - ], - internal_ovk: [ - 0x4f, 0xf6, 0xfa, 0xf2, 0x06, 0x63, 0x1e, 0xcb, 0x01, 0xf9, 0x57, 0x30, 0xf7, - 0xe5, 0x5b, 0xfc, 0xff, 0x8b, 0x02, 0xa3, 0x14, 0x88, 0x5a, 0x6d, 0x24, 0x8e, - 0x6e, 0xbe, 0xb7, 0x4d, 0x3e, 0x50, - ], - }, - TestVector { - c: [ - 0xa7, 0xaf, 0x9d, 0xb6, 0x99, 0x0e, 0xd8, 0x3d, 0xd6, 0x4a, 0xf3, 0x59, 0x7c, - 0x04, 0x32, 0x3e, 0xa5, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, 0xb9, 0xda, - 0x94, 0x8d, 0x32, 0x0d, 0xad, 0xd6, - ], - pk: [ - 0x02, 0xae, 0x36, 0xb6, 0x1a, 0x3d, 0x10, 0xf1, 0xaa, 0x75, 0x2a, 0xb1, 0xdc, - 0x16, 0xe3, 0xe4, 0x9b, 0x6a, 0xc0, 0xd2, 0xae, 0x19, 0x07, 0xd2, 0xe6, 0x94, - 0x25, 0xec, 0x12, 0xc9, 0x3a, 0xae, 0xbc, - ], - external_ovk: [ - 0xda, 0x6f, 0x47, 0x0f, 0x42, 0x5b, 0x3d, 0x27, 0xf4, 0x28, 0x6e, 0xf0, 0x3b, - 0x7e, 0x87, 0x01, 0x7c, 0x20, 0xa7, 0x10, 0xb3, 0xff, 0xb9, 0xc1, 0xb6, 0x6c, - 0x71, 0x60, 0x92, 0xe3, 0xd9, 0xbc, - ], - internal_ovk: [ - 0x09, 0xb5, 0x4f, 0x75, 0xcb, 0x70, 0x32, 0x67, 0x1d, 0xc6, 0x8a, 0xaa, 0x07, - 0x30, 0x5f, 0x38, 0xcd, 0xbc, 0x87, 0x9e, 0xe1, 0x5b, 0xec, 0x04, 0x71, 0x3c, - 0x24, 0xdc, 0xe3, 0xca, 0x70, 0x26, - ], - }, - TestVector { - c: [ - 0xe0, 0x0c, 0x7a, 0x1d, 0x48, 0xaf, 0x04, 0x68, 0x27, 0x59, 0x1e, 0x97, 0x33, - 0xa9, 0x7f, 0xa6, 0xb6, 0x79, 0xf3, 0xdc, 0x60, 0x1d, 0x00, 0x82, 0x85, 0xed, - 0xcb, 0xda, 0xe6, 0x9c, 0xe8, 0xfc, - ], - pk: [ - 0x02, 0x49, 0x26, 0x53, 0x80, 0xd2, 0xb0, 0x2e, 0x0a, 0x1d, 0x98, 0x8f, 0x3d, - 0xe3, 0x45, 0x8b, 0x6e, 0x00, 0x29, 0x1d, 0xb0, 0xe6, 0x2e, 0x17, 0x47, 0x91, - 0xd0, 0x09, 0x29, 0x9f, 0x61, 0xfe, 0xc4, - ], - external_ovk: [ - 0x60, 0xa7, 0xa0, 0x8e, 0xef, 0xa2, 0x4e, 0x75, 0xcc, 0xbb, 0x29, 0xdc, 0x84, - 0x94, 0x67, 0x2d, 0x73, 0x0f, 0xb3, 0x88, 0x7c, 0xb2, 0x6e, 0xf5, 0x1c, 0x6a, - 0x1a, 0x78, 0xe8, 0x8a, 0x78, 0x39, - ], - internal_ovk: [ - 0x3b, 0xab, 0x40, 0x98, 0x08, 0x10, 0x8b, 0xa9, 0xe5, 0xa1, 0xbb, 0x6a, 0x42, - 0x24, 0x59, 0x9d, 0x62, 0xcc, 0xee, 0x63, 0xff, 0x2f, 0x38, 0x15, 0x4c, 0x7f, - 0xb0, 0xc9, 0xa9, 0xa5, 0x79, 0x0f, - ], - }, - TestVector { - c: [ - 0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, 0x79, - 0x0f, 0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, 0x32, 0xb4, - 0xf4, 0x73, 0xf4, 0x68, 0xa0, 0x08, - ], - pk: [ - 0x03, 0x9a, 0x0e, 0x46, 0x39, 0xb4, 0x69, 0x1f, 0x02, 0x7c, 0x0d, 0xb7, 0xfe, - 0xf1, 0xbb, 0x5e, 0xf9, 0x0a, 0xcd, 0xb7, 0x08, 0x62, 0x6d, 0x2e, 0x1f, 0x3e, - 0x38, 0x3e, 0xe7, 0x5b, 0x31, 0xcf, 0x57, - ], - external_ovk: [ - 0xbb, 0x47, 0x87, 0x2c, 0x25, 0x09, 0xbf, 0x3c, 0x72, 0xde, 0xdf, 0x4f, 0xc1, - 0x77, 0x0f, 0x91, 0x93, 0xe2, 0xc1, 0x90, 0xd7, 0xaa, 0x8e, 0x9e, 0x88, 0x1a, - 0xd2, 0xf1, 0x73, 0x48, 0x4e, 0xf2, - ], - internal_ovk: [ - 0x5f, 0x36, 0xdf, 0xa3, 0x6c, 0xa7, 0x65, 0x74, 0x50, 0x29, 0x4e, 0xaa, 0xdd, - 0xad, 0x78, 0xaf, 0xf2, 0xb3, 0xdc, 0x38, 0x5a, 0x57, 0x73, 0x5a, 0xc0, 0x0d, - 0x3d, 0x9a, 0x29, 0x2b, 0x8c, 0x77, - ], - }, - TestVector { - c: [ - 0xed, 0x94, 0x94, 0xc6, 0xac, 0x89, 0x3c, 0x49, 0x72, 0x38, 0x33, 0xec, 0x89, - 0x26, 0xc1, 0x03, 0x95, 0x86, 0xa7, 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, 0x73, 0x1e, - 0x98, 0x5d, 0x99, 0x58, 0x9c, 0x8b, - ], - pk: [ - 0x03, 0xbb, 0xf4, 0x49, 0x82, 0xf1, 0xba, 0x3a, 0x2b, 0x9d, 0xd3, 0xc1, 0x77, - 0x4d, 0x71, 0xce, 0x33, 0x60, 0x59, 0x9b, 0x07, 0xf2, 0x11, 0xc8, 0x16, 0xb8, - 0xc4, 0x3b, 0x98, 0x42, 0x23, 0x09, 0x24, - ], - external_ovk: [ - 0xed, 0xe8, 0xfb, 0x11, 0x37, 0x9b, 0x15, 0xae, 0xc4, 0xfa, 0x4e, 0xc5, 0x12, - 0x4c, 0x95, 0x00, 0xad, 0xf4, 0x0e, 0xb6, 0xf7, 0xca, 0xa5, 0xe9, 0xce, 0x80, - 0xf6, 0xbd, 0x9e, 0x73, 0xd0, 0xe7, - ], - internal_ovk: [ - 0x25, 0x0b, 0x4d, 0xfc, 0x34, 0xdd, 0x57, 0x76, 0x74, 0x51, 0x57, 0xf3, 0x82, - 0xce, 0x6d, 0xe4, 0xf6, 0xfe, 0x22, 0xd7, 0x98, 0x02, 0xf3, 0x9f, 0xe1, 0x34, - 0x77, 0x8b, 0x79, 0x40, 0x42, 0xd3, - ], - }, - TestVector { - c: [ - 0x92, 0x47, 0x69, 0x30, 0xd0, 0x69, 0x89, 0x6c, 0xff, 0x30, 0xeb, 0x41, 0x4f, - 0x72, 0x7b, 0x89, 0xe0, 0x01, 0xaf, 0xa2, 0xfb, 0x8d, 0xc3, 0x43, 0x6d, 0x75, - 0xa4, 0xa6, 0xf2, 0x65, 0x72, 0x50, - ], - pk: [ - 0x03, 0xff, 0x63, 0xc7, 0x89, 0x25, 0x1c, 0x10, 0x43, 0xc6, 0xf9, 0x6c, 0x66, - 0xbf, 0x5b, 0x0f, 0x61, 0xc9, 0xd6, 0x5f, 0xef, 0x5a, 0xaf, 0x42, 0x84, 0xa6, - 0xa5, 0x69, 0x94, 0x94, 0x1c, 0x05, 0xfa, - ], - external_ovk: [ - 0xb3, 0x11, 0x52, 0x06, 0x42, 0x71, 0x01, 0x01, 0xbb, 0xc8, 0x1b, 0xbe, 0x92, - 0x85, 0x1f, 0x9e, 0x65, 0x36, 0x22, 0x3e, 0xd6, 0xe6, 0xa1, 0x28, 0x59, 0x06, - 0x62, 0x1e, 0xfa, 0xe6, 0x41, 0x10, - ], - internal_ovk: [ - 0xf4, 0x46, 0xc0, 0xc1, 0x74, 0x1c, 0x94, 0x42, 0x56, 0x8e, 0x12, 0xf0, 0x55, - 0xef, 0xd5, 0x0c, 0x1e, 0xfe, 0x4d, 0x71, 0x53, 0x3d, 0x97, 0x6b, 0x08, 0xe9, - 0x94, 0x41, 0x44, 0x49, 0xc4, 0xac, - ], - }, - TestVector { - c: [ - 0x7d, 0x41, 0x7a, 0xdb, 0x3d, 0x15, 0xcc, 0x54, 0xdc, 0xb1, 0xfc, 0xe4, 0x67, - 0x50, 0x0c, 0x6b, 0x8f, 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, 0x82, 0x85, - 0x7d, 0xee, 0xcc, 0x40, 0xa9, 0x8d, - ], - pk: [ - 0x02, 0xbf, 0x39, 0x20, 0xce, 0x2e, 0x9e, 0x95, 0xb0, 0xee, 0xce, 0x13, 0x0a, - 0x50, 0xba, 0x7d, 0xcc, 0x6f, 0x26, 0x51, 0x2a, 0x9f, 0xc7, 0xb8, 0x04, 0xaf, - 0xf0, 0x89, 0xf5, 0x0c, 0xbc, 0xff, 0xf7, - ], - external_ovk: [ - 0xae, 0x63, 0x84, 0xf8, 0x07, 0x72, 0x1c, 0x5f, 0x46, 0xc8, 0xaa, 0x83, 0x3b, - 0x66, 0x9b, 0x01, 0xc4, 0x22, 0x7c, 0x00, 0x18, 0xcb, 0x27, 0x29, 0xa9, 0x79, - 0x91, 0x01, 0xea, 0xb8, 0x5a, 0xb9, - ], - internal_ovk: [ - 0xef, 0x70, 0x8e, 0xb8, 0x26, 0xd8, 0xbf, 0xcd, 0x7f, 0xaa, 0x4f, 0x90, 0xdf, - 0x46, 0x1d, 0xed, 0x08, 0xd1, 0x6e, 0x19, 0x1b, 0x4e, 0x51, 0xb8, 0xa3, 0xa9, - 0x1c, 0x02, 0x0b, 0x32, 0xcc, 0x07, - ], - }, + #[test] + #[allow(deprecated)] + fn bip_32_test_vectors() { + let seed = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, ]; - for tv in test_vectors { + for tv in test_vectors::bip_32() { + let account_sk = AccountPrivKey::from_seed( + &MAIN_NETWORK, + &seed, + zip32::AccountId::try_from(tv.account).unwrap(), + ) + .unwrap(); + let account_pubkey = account_sk.to_account_pubkey(); + + let mut key_bytes = [0u8; 65]; + key_bytes[..32].copy_from_slice(&tv.c); + key_bytes[32..].copy_from_slice(&tv.pk); + assert_eq!(account_pubkey.serialize(), key_bytes); + + let (internal_ovk, external_ovk) = account_pubkey.ovks_for_shielding(); + assert_eq!(internal_ovk.as_bytes(), tv.internal_ovk); + assert_eq!(external_ovk.as_bytes(), tv.external_ovk); + + // The test vectors are broken here: they should be deriving an address at the + // address level, but instead use the account pubkey as an address. + let address = TransparentAddress::PublicKeyHash(tv.address); + assert_eq!(pubkey_to_address(account_pubkey.0.public_key()), address); + } + } + + #[test] + fn check_ovk_test_vectors() { + for tv in test_vectors::transparent_ovk() { let mut key_bytes = [0u8; 65]; key_bytes[..32].copy_from_slice(&tv.c); key_bytes[32..].copy_from_slice(&tv.pk); diff --git a/zcash_transparent/src/lib.rs b/zcash_transparent/src/lib.rs index 96f614440..7b93d735c 100644 --- a/zcash_transparent/src/lib.rs +++ b/zcash_transparent/src/lib.rs @@ -15,5 +15,8 @@ pub mod sighash; #[cfg(feature = "transparent-inputs")] pub mod keys; +#[cfg(test)] +mod test_vectors; + #[macro_use] extern crate alloc; diff --git a/zcash_transparent/src/pczt/signer.rs b/zcash_transparent/src/pczt/signer.rs index ab682d404..4f92016fa 100644 --- a/zcash_transparent/src/pczt/signer.rs +++ b/zcash_transparent/src/pczt/signer.rs @@ -32,7 +32,7 @@ impl super::Input { value: self.value, }); - let msg = secp256k1::Message::from_slice(&sighash).expect("32 bytes"); + let msg = secp256k1::Message::from_digest_slice(&sighash).expect("32 bytes"); let sig = secp.sign_ecdsa(&msg, sk); // Signature has to have the SighashType appended to it. diff --git a/zcash_transparent/src/test_vectors.rs b/zcash_transparent/src/test_vectors.rs new file mode 100644 index 000000000..30a21805a --- /dev/null +++ b/zcash_transparent/src/test_vectors.rs @@ -0,0 +1,523 @@ +use alloc::vec::Vec; + +pub struct TransparentOvkTestVector { + pub c: [u8; 32], + pub pk: [u8; 33], + pub external_ovk: [u8; 32], + pub internal_ovk: [u8; 32], +} + +pub fn transparent_ovk() -> Vec { + use TransparentOvkTestVector as TestVector; + + // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/zip_0316.py + vec![ + TestVector { + c: [ + 0x5d, 0x7a, 0x8f, 0x73, 0x9a, 0x2d, 0x9e, 0x94, 0x5b, 0x0c, 0xe1, 0x52, 0xa8, 0x04, + 0x9e, 0x29, 0x4c, 0x4d, 0x6e, 0x66, 0xb1, 0x64, 0x93, 0x9d, 0xaf, 0xfa, 0x2e, 0xf6, + 0xee, 0x69, 0x21, 0x48, + ], + pk: [ + 0x02, 0x16, 0x88, 0x4f, 0x1d, 0xbc, 0x92, 0x90, 0x89, 0xa4, 0x17, 0x6e, 0x84, 0x0b, + 0xb5, 0x81, 0xc8, 0x0e, 0x16, 0xe9, 0xb1, 0xab, 0xd6, 0x54, 0xe6, 0x2c, 0x8b, 0x0b, + 0x95, 0x70, 0x20, 0xb7, 0x48, + ], + external_ovk: [ + 0xdc, 0xe7, 0xfb, 0x7f, 0x20, 0xeb, 0x77, 0x64, 0xd5, 0x12, 0x4f, 0xbd, 0x23, 0xc4, + 0xd7, 0xca, 0x8c, 0x32, 0x19, 0xec, 0x1d, 0xb3, 0xff, 0x1e, 0x08, 0x13, 0x50, 0xad, + 0x03, 0x9b, 0x40, 0x79, + ], + internal_ovk: [ + 0x4d, 0x46, 0xc7, 0x14, 0xed, 0xda, 0xd9, 0x4a, 0x40, 0xac, 0x21, 0x28, 0x6a, 0xff, + 0x32, 0x7d, 0x7e, 0xbf, 0x11, 0x9e, 0x86, 0x85, 0x10, 0x9b, 0x44, 0xe8, 0x02, 0x83, + 0xd8, 0xc8, 0xa4, 0x00, + ], + }, + TestVector { + c: [ + 0xbf, 0x69, 0xb8, 0x25, 0x0c, 0x18, 0xef, 0x41, 0x29, 0x4c, 0xa9, 0x79, 0x93, 0xdb, + 0x54, 0x6c, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, 0xa5, 0xe2, 0x9d, 0x4e, + 0x30, 0xa7, 0x35, 0x94, + ], + pk: [ + 0x03, 0x72, 0x73, 0xb6, 0x57, 0xd9, 0x71, 0xa4, 0x5e, 0x72, 0x24, 0x0c, 0x7a, 0xaa, + 0xa7, 0xd0, 0x68, 0x5d, 0x06, 0xd7, 0x99, 0x9b, 0x0a, 0x19, 0xc4, 0xce, 0xa3, 0x27, + 0x88, 0xa6, 0xab, 0x51, 0x3d, + ], + external_ovk: [ + 0x8d, 0x31, 0x53, 0x7b, 0x38, 0x8f, 0x40, 0x23, 0xe6, 0x48, 0x70, 0x8b, 0xfb, 0xde, + 0x2b, 0xa1, 0xff, 0x1a, 0x4e, 0xe1, 0x12, 0xea, 0x67, 0x0a, 0xd1, 0x67, 0x44, 0xf4, + 0x58, 0x3e, 0x95, 0x52, + ], + internal_ovk: [ + 0x16, 0x77, 0x49, 0x00, 0x76, 0x9d, 0x9c, 0x03, 0xbe, 0x06, 0x32, 0x45, 0xcf, 0x1c, + 0x22, 0x44, 0xa9, 0x2e, 0x48, 0x51, 0x01, 0x54, 0x73, 0x61, 0x3f, 0xbf, 0x38, 0xd2, + 0x42, 0xd7, 0x54, 0xf6, + ], + }, + TestVector { + c: [ + 0x3d, 0xc1, 0x66, 0xd5, 0x6a, 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x55, 0x1d, 0xb5, 0xfd, + 0x93, 0x13, 0xe8, 0xc7, 0x20, 0x3d, 0x99, 0x6a, 0xf7, 0xd4, 0x77, 0x08, 0x37, 0x56, + 0xd5, 0x9a, 0xf8, 0x0d, + ], + pk: [ + 0x03, 0xec, 0x05, 0xbb, 0x7f, 0x06, 0x5e, 0x25, 0x6f, 0xf4, 0x54, 0xf8, 0xa8, 0xdf, + 0x6f, 0x2f, 0x9b, 0x8a, 0x8c, 0x95, 0x08, 0xca, 0xac, 0xfe, 0xe9, 0x52, 0x1c, 0xbe, + 0x68, 0x9d, 0xd1, 0x12, 0x0f, + ], + external_ovk: [ + 0xdb, 0x97, 0x52, 0x0e, 0x2f, 0xe3, 0x68, 0xad, 0x50, 0x2d, 0xef, 0xf8, 0x42, 0xf0, + 0xc0, 0xee, 0x5d, 0x20, 0x3b, 0x48, 0x33, 0x7a, 0x0f, 0xff, 0x75, 0xbe, 0x24, 0x52, + 0x59, 0x77, 0xf3, 0x7e, + ], + internal_ovk: [ + 0xbc, 0x4a, 0xcb, 0x5f, 0x52, 0xb8, 0xae, 0x21, 0xe3, 0x32, 0xb1, 0x7c, 0x29, 0x63, + 0x1f, 0x68, 0xe9, 0x68, 0x2a, 0x46, 0xc4, 0xa7, 0xab, 0xc8, 0xed, 0xf9, 0x0d, 0x37, + 0xae, 0xea, 0xd3, 0x6c, + ], + }, + TestVector { + c: [ + 0x49, 0x5c, 0x22, 0x2f, 0x7f, 0xba, 0x1e, 0x31, 0xde, 0xfa, 0x3d, 0x5a, 0x57, 0xef, + 0xc2, 0xe1, 0xe9, 0xb0, 0x1a, 0x03, 0x55, 0x87, 0xd5, 0xfb, 0x1a, 0x38, 0xe0, 0x1d, + 0x94, 0x90, 0x3d, 0x3c, + ], + pk: [ + 0x02, 0x81, 0x8f, 0x50, 0xce, 0x47, 0x10, 0xf4, 0xeb, 0x11, 0xe7, 0x43, 0xe6, 0x40, + 0x85, 0x44, 0xaa, 0x3c, 0x12, 0x3c, 0x7f, 0x07, 0xe2, 0xaa, 0xbb, 0x91, 0xaf, 0xc4, + 0xec, 0x48, 0x78, 0x8d, 0xe9, + ], + external_ovk: [ + 0xb8, 0xa3, 0x6d, 0x62, 0xa6, 0x3f, 0x69, 0x36, 0x7b, 0xe3, 0xf4, 0xbe, 0xd4, 0x20, + 0x26, 0x4a, 0xdb, 0x63, 0x7b, 0xbb, 0x47, 0x0e, 0x1f, 0x56, 0xe0, 0x33, 0x8b, 0x38, + 0xe2, 0xa6, 0x90, 0x97, + ], + internal_ovk: [ + 0x4f, 0xf6, 0xfa, 0xf2, 0x06, 0x63, 0x1e, 0xcb, 0x01, 0xf9, 0x57, 0x30, 0xf7, 0xe5, + 0x5b, 0xfc, 0xff, 0x8b, 0x02, 0xa3, 0x14, 0x88, 0x5a, 0x6d, 0x24, 0x8e, 0x6e, 0xbe, + 0xb7, 0x4d, 0x3e, 0x50, + ], + }, + TestVector { + c: [ + 0xa7, 0xaf, 0x9d, 0xb6, 0x99, 0x0e, 0xd8, 0x3d, 0xd6, 0x4a, 0xf3, 0x59, 0x7c, 0x04, + 0x32, 0x3e, 0xa5, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, 0xb9, 0xda, 0x94, 0x8d, + 0x32, 0x0d, 0xad, 0xd6, + ], + pk: [ + 0x02, 0xae, 0x36, 0xb6, 0x1a, 0x3d, 0x10, 0xf1, 0xaa, 0x75, 0x2a, 0xb1, 0xdc, 0x16, + 0xe3, 0xe4, 0x9b, 0x6a, 0xc0, 0xd2, 0xae, 0x19, 0x07, 0xd2, 0xe6, 0x94, 0x25, 0xec, + 0x12, 0xc9, 0x3a, 0xae, 0xbc, + ], + external_ovk: [ + 0xda, 0x6f, 0x47, 0x0f, 0x42, 0x5b, 0x3d, 0x27, 0xf4, 0x28, 0x6e, 0xf0, 0x3b, 0x7e, + 0x87, 0x01, 0x7c, 0x20, 0xa7, 0x10, 0xb3, 0xff, 0xb9, 0xc1, 0xb6, 0x6c, 0x71, 0x60, + 0x92, 0xe3, 0xd9, 0xbc, + ], + internal_ovk: [ + 0x09, 0xb5, 0x4f, 0x75, 0xcb, 0x70, 0x32, 0x67, 0x1d, 0xc6, 0x8a, 0xaa, 0x07, 0x30, + 0x5f, 0x38, 0xcd, 0xbc, 0x87, 0x9e, 0xe1, 0x5b, 0xec, 0x04, 0x71, 0x3c, 0x24, 0xdc, + 0xe3, 0xca, 0x70, 0x26, + ], + }, + TestVector { + c: [ + 0xe0, 0x0c, 0x7a, 0x1d, 0x48, 0xaf, 0x04, 0x68, 0x27, 0x59, 0x1e, 0x97, 0x33, 0xa9, + 0x7f, 0xa6, 0xb6, 0x79, 0xf3, 0xdc, 0x60, 0x1d, 0x00, 0x82, 0x85, 0xed, 0xcb, 0xda, + 0xe6, 0x9c, 0xe8, 0xfc, + ], + pk: [ + 0x02, 0x49, 0x26, 0x53, 0x80, 0xd2, 0xb0, 0x2e, 0x0a, 0x1d, 0x98, 0x8f, 0x3d, 0xe3, + 0x45, 0x8b, 0x6e, 0x00, 0x29, 0x1d, 0xb0, 0xe6, 0x2e, 0x17, 0x47, 0x91, 0xd0, 0x09, + 0x29, 0x9f, 0x61, 0xfe, 0xc4, + ], + external_ovk: [ + 0x60, 0xa7, 0xa0, 0x8e, 0xef, 0xa2, 0x4e, 0x75, 0xcc, 0xbb, 0x29, 0xdc, 0x84, 0x94, + 0x67, 0x2d, 0x73, 0x0f, 0xb3, 0x88, 0x7c, 0xb2, 0x6e, 0xf5, 0x1c, 0x6a, 0x1a, 0x78, + 0xe8, 0x8a, 0x78, 0x39, + ], + internal_ovk: [ + 0x3b, 0xab, 0x40, 0x98, 0x08, 0x10, 0x8b, 0xa9, 0xe5, 0xa1, 0xbb, 0x6a, 0x42, 0x24, + 0x59, 0x9d, 0x62, 0xcc, 0xee, 0x63, 0xff, 0x2f, 0x38, 0x15, 0x4c, 0x7f, 0xb0, 0xc9, + 0xa9, 0xa5, 0x79, 0x0f, + ], + }, + TestVector { + c: [ + 0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, 0x79, 0x0f, + 0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, 0x32, 0xb4, 0xf4, 0x73, + 0xf4, 0x68, 0xa0, 0x08, + ], + pk: [ + 0x03, 0x9a, 0x0e, 0x46, 0x39, 0xb4, 0x69, 0x1f, 0x02, 0x7c, 0x0d, 0xb7, 0xfe, 0xf1, + 0xbb, 0x5e, 0xf9, 0x0a, 0xcd, 0xb7, 0x08, 0x62, 0x6d, 0x2e, 0x1f, 0x3e, 0x38, 0x3e, + 0xe7, 0x5b, 0x31, 0xcf, 0x57, + ], + external_ovk: [ + 0xbb, 0x47, 0x87, 0x2c, 0x25, 0x09, 0xbf, 0x3c, 0x72, 0xde, 0xdf, 0x4f, 0xc1, 0x77, + 0x0f, 0x91, 0x93, 0xe2, 0xc1, 0x90, 0xd7, 0xaa, 0x8e, 0x9e, 0x88, 0x1a, 0xd2, 0xf1, + 0x73, 0x48, 0x4e, 0xf2, + ], + internal_ovk: [ + 0x5f, 0x36, 0xdf, 0xa3, 0x6c, 0xa7, 0x65, 0x74, 0x50, 0x29, 0x4e, 0xaa, 0xdd, 0xad, + 0x78, 0xaf, 0xf2, 0xb3, 0xdc, 0x38, 0x5a, 0x57, 0x73, 0x5a, 0xc0, 0x0d, 0x3d, 0x9a, + 0x29, 0x2b, 0x8c, 0x77, + ], + }, + TestVector { + c: [ + 0xed, 0x94, 0x94, 0xc6, 0xac, 0x89, 0x3c, 0x49, 0x72, 0x38, 0x33, 0xec, 0x89, 0x26, + 0xc1, 0x03, 0x95, 0x86, 0xa7, 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, 0x73, 0x1e, 0x98, 0x5d, + 0x99, 0x58, 0x9c, 0x8b, + ], + pk: [ + 0x03, 0xbb, 0xf4, 0x49, 0x82, 0xf1, 0xba, 0x3a, 0x2b, 0x9d, 0xd3, 0xc1, 0x77, 0x4d, + 0x71, 0xce, 0x33, 0x60, 0x59, 0x9b, 0x07, 0xf2, 0x11, 0xc8, 0x16, 0xb8, 0xc4, 0x3b, + 0x98, 0x42, 0x23, 0x09, 0x24, + ], + external_ovk: [ + 0xed, 0xe8, 0xfb, 0x11, 0x37, 0x9b, 0x15, 0xae, 0xc4, 0xfa, 0x4e, 0xc5, 0x12, 0x4c, + 0x95, 0x00, 0xad, 0xf4, 0x0e, 0xb6, 0xf7, 0xca, 0xa5, 0xe9, 0xce, 0x80, 0xf6, 0xbd, + 0x9e, 0x73, 0xd0, 0xe7, + ], + internal_ovk: [ + 0x25, 0x0b, 0x4d, 0xfc, 0x34, 0xdd, 0x57, 0x76, 0x74, 0x51, 0x57, 0xf3, 0x82, 0xce, + 0x6d, 0xe4, 0xf6, 0xfe, 0x22, 0xd7, 0x98, 0x02, 0xf3, 0x9f, 0xe1, 0x34, 0x77, 0x8b, + 0x79, 0x40, 0x42, 0xd3, + ], + }, + TestVector { + c: [ + 0x92, 0x47, 0x69, 0x30, 0xd0, 0x69, 0x89, 0x6c, 0xff, 0x30, 0xeb, 0x41, 0x4f, 0x72, + 0x7b, 0x89, 0xe0, 0x01, 0xaf, 0xa2, 0xfb, 0x8d, 0xc3, 0x43, 0x6d, 0x75, 0xa4, 0xa6, + 0xf2, 0x65, 0x72, 0x50, + ], + pk: [ + 0x03, 0xff, 0x63, 0xc7, 0x89, 0x25, 0x1c, 0x10, 0x43, 0xc6, 0xf9, 0x6c, 0x66, 0xbf, + 0x5b, 0x0f, 0x61, 0xc9, 0xd6, 0x5f, 0xef, 0x5a, 0xaf, 0x42, 0x84, 0xa6, 0xa5, 0x69, + 0x94, 0x94, 0x1c, 0x05, 0xfa, + ], + external_ovk: [ + 0xb3, 0x11, 0x52, 0x06, 0x42, 0x71, 0x01, 0x01, 0xbb, 0xc8, 0x1b, 0xbe, 0x92, 0x85, + 0x1f, 0x9e, 0x65, 0x36, 0x22, 0x3e, 0xd6, 0xe6, 0xa1, 0x28, 0x59, 0x06, 0x62, 0x1e, + 0xfa, 0xe6, 0x41, 0x10, + ], + internal_ovk: [ + 0xf4, 0x46, 0xc0, 0xc1, 0x74, 0x1c, 0x94, 0x42, 0x56, 0x8e, 0x12, 0xf0, 0x55, 0xef, + 0xd5, 0x0c, 0x1e, 0xfe, 0x4d, 0x71, 0x53, 0x3d, 0x97, 0x6b, 0x08, 0xe9, 0x94, 0x41, + 0x44, 0x49, 0xc4, 0xac, + ], + }, + TestVector { + c: [ + 0x7d, 0x41, 0x7a, 0xdb, 0x3d, 0x15, 0xcc, 0x54, 0xdc, 0xb1, 0xfc, 0xe4, 0x67, 0x50, + 0x0c, 0x6b, 0x8f, 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, 0x82, 0x85, 0x7d, 0xee, + 0xcc, 0x40, 0xa9, 0x8d, + ], + pk: [ + 0x02, 0xbf, 0x39, 0x20, 0xce, 0x2e, 0x9e, 0x95, 0xb0, 0xee, 0xce, 0x13, 0x0a, 0x50, + 0xba, 0x7d, 0xcc, 0x6f, 0x26, 0x51, 0x2a, 0x9f, 0xc7, 0xb8, 0x04, 0xaf, 0xf0, 0x89, + 0xf5, 0x0c, 0xbc, 0xff, 0xf7, + ], + external_ovk: [ + 0xae, 0x63, 0x84, 0xf8, 0x07, 0x72, 0x1c, 0x5f, 0x46, 0xc8, 0xaa, 0x83, 0x3b, 0x66, + 0x9b, 0x01, 0xc4, 0x22, 0x7c, 0x00, 0x18, 0xcb, 0x27, 0x29, 0xa9, 0x79, 0x91, 0x01, + 0xea, 0xb8, 0x5a, 0xb9, + ], + internal_ovk: [ + 0xef, 0x70, 0x8e, 0xb8, 0x26, 0xd8, 0xbf, 0xcd, 0x7f, 0xaa, 0x4f, 0x90, 0xdf, 0x46, + 0x1d, 0xed, 0x08, 0xd1, 0x6e, 0x19, 0x1b, 0x4e, 0x51, 0xb8, 0xa3, 0xa9, 0x1c, 0x02, + 0x0b, 0x32, 0xcc, 0x07, + ], + }, + ] +} + +pub struct Bip32TestVector { + pub c: [u8; 32], + pub pk: [u8; 33], + pub address: [u8; 20], + pub external_ovk: [u8; 32], + pub internal_ovk: [u8; 32], + pub account: u32, +} + +pub fn bip_32() -> Vec { + use Bip32TestVector as TestVector; + + // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/bip_0032.py + vec![ + TestVector { + c: [ + 0x9b, 0xa0, 0x43, 0x9c, 0x6a, 0x2d, 0x3d, 0x90, 0x38, 0x83, 0xd4, 0x53, 0x7c, 0x36, + 0x22, 0x88, 0x62, 0x6d, 0xa6, 0x2c, 0x62, 0x99, 0x01, 0x2e, 0x36, 0x2d, 0x8f, 0xb6, + 0xef, 0xeb, 0xab, 0x47, + ], + pk: [ + 0x02, 0xed, 0x63, 0x85, 0x32, 0xc4, 0x75, 0xf6, 0x74, 0x00, 0x35, 0x0f, 0xb1, 0xd6, + 0xed, 0xa5, 0x59, 0xcd, 0xc2, 0x89, 0xa1, 0x9b, 0x43, 0x19, 0xeb, 0x17, 0x51, 0x40, + 0xaa, 0x86, 0x89, 0x38, 0x36, + ], + address: [ + 0x67, 0x25, 0xf2, 0x62, 0xbb, 0xa6, 0x42, 0x2f, 0xd4, 0x7c, 0x30, 0x5b, 0x83, 0x78, + 0xc4, 0x99, 0x42, 0x41, 0xc4, 0x42, + ], + external_ovk: [ + 0xd4, 0x86, 0x35, 0x2d, 0xd1, 0xd6, 0x66, 0x98, 0xa6, 0x16, 0x34, 0xab, 0x21, 0x9a, + 0x2a, 0x6e, 0xa3, 0xc2, 0xee, 0x98, 0x79, 0xcc, 0x82, 0x84, 0x03, 0xba, 0x99, 0x69, + 0x50, 0x57, 0x74, 0xdd, + ], + internal_ovk: [ + 0x73, 0x90, 0xae, 0x2d, 0xf3, 0x1c, 0xee, 0xb2, 0x64, 0xcf, 0xbb, 0xcb, 0xbf, 0xfd, + 0x2d, 0x97, 0x3d, 0xb6, 0x8c, 0xf5, 0x72, 0xa7, 0x56, 0xd3, 0x2d, 0x5b, 0xd3, 0xec, + 0x00, 0x46, 0x59, 0x7f, + ], + account: 0, + }, + TestVector { + c: [ + 0xfa, 0x92, 0x91, 0xb3, 0x53, 0xbe, 0x21, 0xac, 0x45, 0x2f, 0x85, 0xcb, 0x96, 0xe4, + 0xfc, 0x97, 0x8d, 0x35, 0x2e, 0x34, 0xc5, 0xc0, 0x25, 0x9a, 0xc2, 0x8d, 0x0b, 0xea, + 0xb1, 0xb8, 0xe2, 0x98, + ], + pk: [ + 0x03, 0xfc, 0x39, 0x9e, 0x61, 0x3d, 0x01, 0x08, 0x65, 0xd5, 0xa1, 0xfa, 0x87, 0x65, + 0xb7, 0x10, 0x9f, 0x9d, 0xb1, 0xed, 0x56, 0x21, 0x89, 0x83, 0xf9, 0xbd, 0x54, 0xb8, + 0xc7, 0x12, 0x47, 0x88, 0x29, + ], + address: [ + 0x04, 0x63, 0x1a, 0xd8, 0x90, 0x2a, 0xd2, 0xfc, 0x56, 0x41, 0xbb, 0xe9, 0x35, 0xde, + 0xa6, 0x79, 0x50, 0xbb, 0x9c, 0x59, + ], + external_ovk: [ + 0xd2, 0xbd, 0x69, 0xa3, 0xd3, 0xe8, 0x25, 0xe3, 0x63, 0x3f, 0x49, 0x7f, 0xc1, 0xb5, + 0x04, 0xba, 0xf6, 0x73, 0x29, 0xa9, 0x16, 0x74, 0x87, 0xd0, 0xfd, 0x98, 0xca, 0xe5, + 0xd1, 0xa9, 0x66, 0x13, + ], + internal_ovk: [ + 0xc8, 0x01, 0x85, 0x9b, 0xd2, 0xfb, 0x9f, 0x09, 0x0d, 0x65, 0x18, 0xe1, 0xfe, 0x19, + 0x27, 0x84, 0xe7, 0x5a, 0xb7, 0x69, 0xc8, 0xec, 0x66, 0x21, 0xf7, 0xbc, 0x0c, 0x13, + 0x20, 0x82, 0x0b, 0x0a, + ], + account: 1, + }, + TestVector { + c: [ + 0xf6, 0xa7, 0x04, 0xfc, 0x09, 0x38, 0x82, 0x16, 0x6a, 0x88, 0xee, 0xb2, 0x43, 0xe2, + 0x65, 0x8f, 0x0e, 0xb7, 0xb5, 0xb7, 0x94, 0x3c, 0xe4, 0x7c, 0x39, 0x24, 0xc6, 0x7c, + 0x96, 0x47, 0x4c, 0xea, + ], + pk: [ + 0x02, 0x9f, 0x17, 0x94, 0x89, 0x55, 0x62, 0x43, 0x0d, 0x5d, 0xc8, 0xbe, 0x5e, 0x88, + 0xcf, 0xee, 0xe3, 0x26, 0x1d, 0x6b, 0xe4, 0xe6, 0xeb, 0x5b, 0x23, 0x8e, 0xcc, 0x9e, + 0x7e, 0xbd, 0xeb, 0x1b, 0xf0, + ], + address: [ + 0x0b, 0xec, 0x65, 0xaa, 0x3c, 0xf1, 0xaf, 0x84, 0xa9, 0x5d, 0xa1, 0xe6, 0xb9, 0xe4, + 0xa5, 0x2b, 0x74, 0x42, 0x8f, 0xf6, + ], + external_ovk: [ + 0xa6, 0x0c, 0xaa, 0x83, 0x0f, 0x08, 0xd4, 0xa5, 0x4c, 0x39, 0x80, 0x2c, 0x0a, 0xdc, + 0x1c, 0x2b, 0xa4, 0x22, 0xce, 0xb8, 0x09, 0x7c, 0xd1, 0x26, 0xa2, 0x08, 0x13, 0xf5, + 0x7e, 0x4d, 0x2f, 0x82, + ], + internal_ovk: [ + 0x14, 0xf5, 0x95, 0x92, 0x21, 0x33, 0x8f, 0x3a, 0xdb, 0x60, 0xdf, 0x69, 0x04, 0x2d, + 0xea, 0x7c, 0xfb, 0xd8, 0x72, 0x0c, 0x3f, 0xad, 0x1d, 0xeb, 0xaa, 0x0b, 0xea, 0x81, + 0x74, 0xce, 0xa5, 0x6e, + ], + account: 2, + }, + TestVector { + c: [ + 0x3e, 0xbe, 0x46, 0xd6, 0x20, 0x4f, 0xee, 0xb4, 0x3b, 0xd8, 0x35, 0x11, 0xcd, 0x81, + 0x61, 0x34, 0xc2, 0xf0, 0x3d, 0x85, 0x82, 0xc6, 0x64, 0x31, 0x8c, 0xc6, 0x00, 0x63, + 0xec, 0xa3, 0x8a, 0x04, + ], + pk: [ + 0x02, 0x0f, 0x8a, 0xed, 0x76, 0x90, 0xbc, 0x84, 0xe3, 0xfa, 0x65, 0x10, 0xc3, 0x62, + 0xbb, 0x92, 0x90, 0x90, 0x4b, 0x6f, 0xf5, 0xb7, 0x5e, 0x4e, 0x5c, 0xa6, 0xde, 0x82, + 0x1b, 0xf3, 0x38, 0x9f, 0xae, + ], + address: [ + 0x75, 0x2c, 0x53, 0xa4, 0x3b, 0x8a, 0x44, 0x18, 0x25, 0x50, 0xed, 0x66, 0x8d, 0x49, + 0x94, 0x1c, 0x4f, 0xef, 0x55, 0x02, + ], + external_ovk: [ + 0x00, 0x96, 0xdd, 0xb9, 0xce, 0xa0, 0x3e, 0x17, 0xf2, 0x43, 0x0c, 0xe3, 0xf6, 0x1d, + 0xf8, 0xcd, 0x43, 0x30, 0x94, 0x50, 0xf0, 0x1e, 0xfd, 0x6f, 0x5b, 0x33, 0xae, 0xc7, + 0xac, 0xe1, 0x65, 0xbd, + ], + internal_ovk: [ + 0x23, 0xb2, 0xef, 0x2b, 0x1e, 0xe4, 0x8a, 0xf6, 0x45, 0x9c, 0xe7, 0xf0, 0x61, 0x25, + 0x14, 0x3d, 0xc9, 0x5c, 0xbe, 0x1e, 0xbf, 0x49, 0xd4, 0x11, 0xdb, 0x91, 0xe8, 0x8b, + 0x59, 0x34, 0x14, 0x06, + ], + account: 3, + }, + TestVector { + c: [ + 0x93, 0x4d, 0x5c, 0x7b, 0x67, 0xec, 0xeb, 0xc7, 0xfe, 0x71, 0x7f, 0xfb, 0xa0, 0x6f, + 0x30, 0x97, 0x3e, 0xcd, 0xb4, 0x73, 0x5d, 0xd8, 0xc8, 0x17, 0x35, 0x28, 0xc3, 0x57, + 0xec, 0x23, 0x31, 0x1f, + ], + pk: [ + 0x03, 0x9e, 0xfd, 0xdc, 0x9c, 0xc1, 0xbf, 0x9f, 0x42, 0x14, 0xa0, 0x9a, 0x7f, 0x01, + 0x88, 0x54, 0x07, 0x89, 0xb2, 0x61, 0x97, 0xcd, 0xed, 0xed, 0xc9, 0x93, 0xbe, 0x53, + 0x81, 0x58, 0x7f, 0x79, 0xde, + ], + address: [ + 0x1a, 0x8f, 0xaa, 0x82, 0xb6, 0xfe, 0x12, 0x85, 0x53, 0xc2, 0xf3, 0xf3, 0x8b, 0x22, + 0x51, 0xd8, 0x88, 0x80, 0x48, 0xab, + ], + external_ovk: [ + 0xed, 0x3e, 0xc5, 0xb6, 0x23, 0x27, 0x62, 0xb0, 0xda, 0x1b, 0x1c, 0xc4, 0xc6, 0x2e, + 0x1e, 0x4f, 0x30, 0x29, 0x27, 0x40, 0x48, 0xe3, 0xf1, 0x80, 0x81, 0x46, 0x40, 0x1f, + 0xc4, 0xd1, 0xf6, 0x1c, + ], + internal_ovk: [ + 0x19, 0xd7, 0xd9, 0x37, 0xae, 0x9a, 0x49, 0xb1, 0xa5, 0x23, 0x7a, 0x06, 0xc5, 0xef, + 0x3c, 0x7d, 0xa8, 0xde, 0x44, 0xe6, 0xcd, 0x64, 0x3b, 0xe3, 0xfd, 0xe7, 0x09, 0x14, + 0x68, 0xcc, 0x24, 0x9c, + ], + account: 4, + }, + TestVector { + c: [ + 0x03, 0xeb, 0x45, 0x2d, 0xae, 0x94, 0xc4, 0xee, 0xa9, 0x07, 0x7f, 0x24, 0x5d, 0x72, + 0xb1, 0xa1, 0xe0, 0x8f, 0xa7, 0xd4, 0x96, 0x70, 0x2e, 0x6d, 0x45, 0xb9, 0xf5, 0xb3, + 0xd4, 0x93, 0xb6, 0x94, + ], + pk: [ + 0x03, 0xe0, 0x32, 0x02, 0x9b, 0xfe, 0x0a, 0xbd, 0xf0, 0x0e, 0x26, 0xee, 0xe7, 0x7e, + 0x4c, 0x3b, 0x55, 0x67, 0x44, 0x86, 0xc9, 0x03, 0x42, 0x86, 0x48, 0xb2, 0x6a, 0xdb, + 0x5c, 0x11, 0xce, 0xd5, 0xb3, + ], + address: [ + 0xe5, 0x9b, 0x1c, 0x45, 0xcf, 0xda, 0x3f, 0x6f, 0x2d, 0xf7, 0x8d, 0x04, 0xbd, 0x0d, + 0xf8, 0xa5, 0x93, 0x17, 0x88, 0x36, + ], + external_ovk: [ + 0xc7, 0x3c, 0xd3, 0x90, 0xf8, 0xf4, 0x7d, 0xba, 0x4c, 0x87, 0x4c, 0x12, 0xc2, 0x23, + 0xea, 0x47, 0x8e, 0x2b, 0x40, 0xc4, 0xfc, 0x8f, 0x5e, 0xcf, 0xc5, 0xa1, 0xda, 0x10, + 0x38, 0xec, 0x45, 0x29, + ], + internal_ovk: [ + 0x4b, 0x15, 0x90, 0x4c, 0x8c, 0x31, 0xea, 0x27, 0x22, 0x80, 0xeb, 0x75, 0xfb, 0xfa, + 0x5e, 0xbd, 0xfa, 0x31, 0x60, 0x70, 0x83, 0xac, 0x56, 0x0d, 0x8f, 0x6e, 0x6e, 0xe3, + 0x69, 0x0c, 0x00, 0xa4, + ], + account: 5, + }, + TestVector { + c: [ + 0xde, 0xcf, 0x85, 0x43, 0x0d, 0xb4, 0x84, 0x89, 0xcd, 0xd8, 0x94, 0xaa, 0x29, 0xa7, + 0x8b, 0x33, 0x15, 0xd2, 0x3b, 0xb6, 0x25, 0x88, 0x27, 0x57, 0xe3, 0x39, 0x6d, 0xf6, + 0xe3, 0xba, 0xd6, 0xca, + ], + pk: [ + 0x02, 0x8e, 0xfe, 0x8f, 0xa9, 0xb8, 0x82, 0x7f, 0x87, 0x48, 0x4a, 0xa1, 0x86, 0x87, + 0x33, 0x72, 0xa4, 0x6e, 0x53, 0x8a, 0x1c, 0x3f, 0x34, 0x1a, 0xdb, 0x9c, 0x33, 0x69, + 0xac, 0x4d, 0x4f, 0x70, 0x7a, + ], + address: [ + 0x3a, 0x9c, 0x2a, 0xd9, 0x50, 0x09, 0x8f, 0x11, 0x1c, 0x3e, 0xdd, 0x0d, 0x3e, 0xb3, + 0x09, 0x1c, 0x96, 0xea, 0x83, 0x56, + ], + external_ovk: [ + 0x5c, 0x49, 0xa5, 0x6a, 0xdf, 0xff, 0x55, 0xb7, 0xfb, 0xa2, 0x8f, 0x52, 0xf2, 0x0e, + 0x30, 0x64, 0xde, 0xdb, 0x2a, 0x65, 0xb3, 0x0f, 0x19, 0xf6, 0x8a, 0xed, 0x58, 0x89, + 0xcd, 0xd7, 0xe4, 0x30, + ], + internal_ovk: [ + 0x4d, 0x55, 0xd6, 0xdd, 0x28, 0x70, 0xc2, 0xf6, 0x29, 0x48, 0x68, 0x5d, 0x0e, 0x70, + 0x27, 0x1a, 0x45, 0xe4, 0x90, 0xf6, 0xb8, 0xc3, 0x65, 0x02, 0x83, 0x5a, 0xbc, 0x92, + 0xca, 0x92, 0x5f, 0xf3, + ], + account: 6, + }, + TestVector { + c: [ + 0x69, 0x4c, 0xc0, 0x9d, 0xd2, 0x42, 0xe4, 0xa7, 0xb7, 0x4e, 0x3b, 0x3c, 0xd7, 0x95, + 0xfe, 0x69, 0x59, 0xfa, 0x57, 0x7b, 0xa5, 0x6f, 0xde, 0xb5, 0xfc, 0xf4, 0xc1, 0xa4, + 0x50, 0x2d, 0xec, 0x75, + ], + pk: [ + 0x02, 0x14, 0x15, 0x8d, 0xc4, 0x63, 0x1f, 0x2a, 0x37, 0x84, 0xbf, 0xb4, 0x2b, 0x9a, + 0xd4, 0x4d, 0xcb, 0x77, 0x9d, 0xcf, 0x0f, 0x26, 0xa1, 0xde, 0xf9, 0x12, 0x0f, 0x81, + 0xc9, 0x83, 0x6b, 0xf4, 0xb5, + ], + address: [ + 0x0f, 0xf6, 0xc3, 0xeb, 0xc6, 0x25, 0x38, 0xff, 0x1d, 0x69, 0x0d, 0xc8, 0xe0, 0x7a, + 0x91, 0x3b, 0x15, 0xfe, 0xe1, 0xc5, + ], + external_ovk: [ + 0xa2, 0x61, 0x04, 0x00, 0x35, 0x27, 0xbb, 0xf9, 0x39, 0xb6, 0x00, 0x26, 0xd7, 0x28, + 0xd5, 0x6c, 0xda, 0xa5, 0xcd, 0xed, 0x07, 0x20, 0x9a, 0x2c, 0x62, 0xf8, 0x6d, 0xe7, + 0x29, 0x86, 0x18, 0xad, + ], + internal_ovk: [ + 0x91, 0x7f, 0x76, 0x7b, 0x53, 0x4b, 0xd8, 0x21, 0xb2, 0x46, 0x39, 0x86, 0x00, 0x49, + 0xef, 0x4c, 0x8e, 0xf8, 0xa2, 0xec, 0xfb, 0x62, 0x91, 0xdc, 0x15, 0xa8, 0xbd, 0xa2, + 0xf6, 0x5b, 0x8c, 0x23, + ], + account: 7, + }, + TestVector { + c: [ + 0x3e, 0xea, 0x14, 0x08, 0xbf, 0xfa, 0x9c, 0x4c, 0x02, 0xdf, 0x5d, 0xd1, 0x74, 0xe8, + 0xb5, 0x6e, 0x45, 0x06, 0xca, 0xad, 0xe7, 0x83, 0x92, 0x67, 0x76, 0x12, 0x27, 0xe4, + 0xda, 0x25, 0x06, 0xa5, + ], + pk: [ + 0x03, 0x5d, 0x0d, 0x72, 0x24, 0xc3, 0xbe, 0xb7, 0x8b, 0xc6, 0x7c, 0x21, 0x4f, 0x56, + 0x73, 0x1b, 0x3f, 0xfb, 0x27, 0xb0, 0x63, 0x10, 0xa1, 0xe6, 0x09, 0x33, 0x84, 0xf6, + 0xeb, 0x72, 0xb6, 0xc5, 0xf6, + ], + address: [ + 0x9f, 0xf4, 0x3f, 0x3f, 0x01, 0x21, 0xbf, 0x05, 0x4c, 0x14, 0xea, 0x0d, 0x9d, 0x84, + 0x9e, 0x0b, 0x02, 0xe9, 0x46, 0x87, + ], + external_ovk: [ + 0x7a, 0xa8, 0xb1, 0xf6, 0x6d, 0xa9, 0xfe, 0xbf, 0x1a, 0x8c, 0xa9, 0x2f, 0xaa, 0x4b, + 0x3f, 0x83, 0x8a, 0xb4, 0x50, 0x3e, 0xa4, 0x18, 0x3d, 0xcf, 0x05, 0xf6, 0x7c, 0x1b, + 0x13, 0x58, 0x79, 0x10, + ], + internal_ovk: [ + 0x77, 0xd1, 0x93, 0x54, 0xbd, 0xc0, 0xea, 0xf3, 0xb4, 0x00, 0x65, 0xb9, 0xc7, 0xfa, + 0xc8, 0xc2, 0xf7, 0x04, 0x08, 0x17, 0x74, 0xab, 0xde, 0x2d, 0x15, 0x13, 0x1f, 0x80, + 0x96, 0x4d, 0x76, 0xfd, + ], + account: 8, + }, + TestVector { + c: [ + 0xb6, 0x08, 0x95, 0x76, 0x6b, 0xda, 0xd0, 0x50, 0xed, 0x93, 0x2d, 0x00, 0x99, 0x83, + 0x22, 0x55, 0xdc, 0x09, 0x66, 0xea, 0xb8, 0xf9, 0x8a, 0x3b, 0x15, 0x77, 0xf4, 0x50, + 0xf2, 0x26, 0xa9, 0x41, + ], + pk: [ + 0x02, 0x95, 0x59, 0x9f, 0xc0, 0x48, 0xf2, 0x18, 0x11, 0x56, 0xf9, 0xe4, 0x53, 0x73, + 0x5d, 0x98, 0x9e, 0xb6, 0x16, 0x23, 0xf6, 0xee, 0xe8, 0xa0, 0x60, 0xb8, 0xf3, 0xfa, + 0x59, 0x66, 0x6c, 0xdf, 0xe1, + ], + address: [ + 0xda, 0xeb, 0xdd, 0x95, 0x7b, 0xe5, 0x47, 0x02, 0xdb, 0x56, 0xdd, 0x0d, 0x1c, 0x19, + 0xa7, 0x76, 0x06, 0xdf, 0xec, 0xd5, + ], + external_ovk: [ + 0xa5, 0x30, 0x77, 0x62, 0x06, 0x17, 0xc1, 0xd1, 0xce, 0xad, 0xa1, 0x21, 0x2e, 0xe5, + 0x48, 0x3e, 0x1c, 0xd3, 0x10, 0x34, 0x82, 0x1c, 0x59, 0x8c, 0x04, 0x90, 0xe8, 0x97, + 0xa9, 0x60, 0xe8, 0xcb, + ], + internal_ovk: [ + 0x48, 0x16, 0x20, 0x80, 0xf8, 0x57, 0x4d, 0x87, 0xab, 0x71, 0x41, 0x45, 0x06, 0x46, + 0xe2, 0x83, 0x79, 0x17, 0xdf, 0xd8, 0x38, 0xda, 0xac, 0x0b, 0x59, 0x32, 0xd1, 0x56, + 0xdc, 0xec, 0xbb, 0x2f, + ], + account: 9, + }, + ] +}