diff --git a/Cargo.lock b/Cargo.lock index 770a4093e..1fcac9c7e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2085,6 +2085,37 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "sapling-crypto" +version = "0.0.1" +source = "git+https://github.com/zcash/sapling-crypto.git?rev=df6681c1046bd28073befd7d42224e4a4c70032a#df6681c1046bd28073befd7d42224e4a4c70032a" +dependencies = [ + "aes", + "bellman", + "bitvec", + "blake2b_simd", + "blake2s_simd", + "bls12_381", + "byteorder", + "ff", + "fpe", + "group", + "hex", + "incrementalmerkletree", + "jubjub", + "lazy_static", + "memuse", + "proptest", + "rand", + "rand_core", + "redjubjub", + "subtle", + "tracing", + "zcash_note_encryption", + "zcash_spec", + "zip32", +] + [[package]] name = "schemer" version = "0.2.1" @@ -3079,12 +3110,8 @@ version = "0.13.0" dependencies = [ "aes", "assert_matches", - "bellman", "bip0039", - "bitvec", "blake2b_simd", - "blake2s_simd", - "bls12_381", "byteorder", "chacha20poly1305", "criterion", @@ -3096,7 +3123,6 @@ dependencies = [ "hex", "incrementalmerkletree", "jubjub", - "lazy_static", "memuse", "nonempty", "orchard", @@ -3107,6 +3133,7 @@ dependencies = [ "rand_xorshift", "redjubjub", "ripemd", + "sapling-crypto", "secp256k1", "sha2", "subtle", diff --git a/Cargo.toml b/Cargo.toml index 83421e4bd..c3975c3a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ bitvec = "1" blake2s_simd = "1" bls12_381 = "0.8" jubjub = "0.10" +sapling = { package = "sapling-crypto", version = "0.0" } # - Orchard nonempty = "0.7" @@ -109,3 +110,6 @@ zip32 = "0.1" lto = true panic = 'abort' codegen-units = 1 + +[patch.crates-io] +sapling = { package = "sapling-crypto", git = "https://github.com/zcash/sapling-crypto.git", rev = "df6681c1046bd28073befd7d42224e4a4c70032a" } diff --git a/zcash_primitives/Cargo.toml b/zcash_primitives/Cargo.toml index cffe94683..c57412dc9 100644 --- a/zcash_primitives/Cargo.toml +++ b/zcash_primitives/Cargo.toml @@ -41,21 +41,17 @@ tracing.workspace = true subtle.workspace = true # - Shielded protocols -bellman = { version = "0.14", default-features = false, features = ["groth16"] } -bls12_381.workspace = true ff.workspace = true group = { workspace = true, features = ["wnaf-memuse"] } jubjub.workspace = true nonempty.workspace = true orchard.workspace = true +sapling.workspace = true zcash_spec.workspace = true # - Note Commitment Trees incrementalmerkletree = { workspace = true, features = ["legacy-api"] } -# - Static constants -lazy_static.workspace = true - # - Test dependencies proptest = { workspace = true, optional = true } @@ -75,8 +71,6 @@ byteorder.workspace = true hex.workspace = true # - Shielded protocols -bitvec.workspace = true -blake2s_simd.workspace = true redjubjub = "0.7" # - Transparent inputs @@ -104,10 +98,14 @@ pprof = { version = "0.11", features = ["criterion", "flamegraph"] } # MSRV 1.56 [features] default = ["multicore"] -multicore = ["bellman/multicore", "orchard/multicore"] +multicore = ["orchard/multicore", "sapling/multicore"] transparent-inputs = ["hdwallet", "ripemd", "secp256k1"] temporary-zcashd = [] -test-dependencies = ["proptest", "orchard/test-dependencies"] +test-dependencies = [ + "proptest", + "orchard/test-dependencies", + "sapling/test-dependencies", +] unstable-nu6 = [] zfuture = [] diff --git a/zcash_primitives/src/lib.rs b/zcash_primitives/src/lib.rs index fba2103f9..20c91ceb0 100644 --- a/zcash_primitives/src/lib.rs +++ b/zcash_primitives/src/lib.rs @@ -16,13 +16,10 @@ pub mod keys; pub mod legacy; pub mod memo; pub mod merkle_tree; -pub mod sapling; +pub use sapling; pub mod transaction; pub use zip32; pub mod zip339; #[cfg(feature = "zfuture")] pub mod extensions; - -#[cfg(test)] -mod test_vectors; diff --git a/zcash_primitives/src/sapling.rs b/zcash_primitives/src/sapling.rs deleted file mode 100644 index 03e019f3b..000000000 --- a/zcash_primitives/src/sapling.rs +++ /dev/null @@ -1,39 +0,0 @@ -//! Structs and constants specific to the Sapling shielded pool. - -mod address; -pub mod builder; -pub mod bundle; -pub mod circuit; -pub mod constants; -pub mod group_hash; -pub mod keys; -pub mod note; -pub mod note_encryption; -pub mod pedersen_hash; -pub mod prover; -mod spec; -mod tree; -pub mod util; -pub mod value; -mod verifier; -pub mod zip32; - -pub use address::PaymentAddress; -pub use bundle::Bundle; -pub use keys::{Diversifier, NullifierDerivingKey, ProofGenerationKey, SaplingIvk, ViewingKey}; -pub use note::{nullifier::Nullifier, Note, Rseed}; -pub use tree::{ - merkle_hash, CommitmentTree, IncrementalWitness, MerklePath, Node, NOTE_COMMITMENT_TREE_DEPTH, -}; -pub use verifier::{BatchValidator, SaplingVerificationContext}; - -#[cfg(any(test, feature = "test-dependencies"))] -pub mod testing { - pub use super::{ - address::testing::arb_payment_address, keys::testing::arb_incoming_viewing_key, - note::testing::arb_note, tree::testing::arb_node, - }; -} - -#[cfg(test)] -mod test_vectors; diff --git a/zcash_primitives/src/sapling/address.rs b/zcash_primitives/src/sapling/address.rs deleted file mode 100644 index fa71c2d66..000000000 --- a/zcash_primitives/src/sapling/address.rs +++ /dev/null @@ -1,118 +0,0 @@ -use super::{ - keys::{DiversifiedTransmissionKey, Diversifier}, - note::{Note, Rseed}, - value::NoteValue, -}; - -/// A Sapling payment address. -/// -/// # Invariants -/// -/// - `diversifier` is guaranteed to be valid for Sapling (only 50% of diversifiers are). -/// - `pk_d` is guaranteed to be prime-order (i.e. in the prime-order subgroup of Jubjub, -/// and not the identity). -#[derive(Clone, Copy, Debug)] -pub struct PaymentAddress { - pk_d: DiversifiedTransmissionKey, - diversifier: Diversifier, -} - -impl PartialEq for PaymentAddress { - fn eq(&self, other: &Self) -> bool { - self.pk_d == other.pk_d && self.diversifier == other.diversifier - } -} - -impl Eq for PaymentAddress {} - -impl PaymentAddress { - /// Constructs a PaymentAddress from a diversifier and a Jubjub point. - /// - /// Returns None if `diversifier` is not valid for Sapling, or `pk_d` is the identity. - /// Note that we cannot verify in this constructor that `pk_d` is derived from - /// `diversifier`, so addresses for which these values have no known relationship - /// (and therefore no-one can receive funds at them) can still be constructed. - pub fn from_parts(diversifier: Diversifier, pk_d: DiversifiedTransmissionKey) -> Option { - // Check that the diversifier is valid - diversifier.g_d()?; - - Self::from_parts_unchecked(diversifier, pk_d) - } - - /// Constructs a PaymentAddress from a diversifier and a Jubjub point. - /// - /// Returns None if `pk_d` is the identity. The caller must check that `diversifier` - /// is valid for Sapling. - pub(crate) fn from_parts_unchecked( - diversifier: Diversifier, - pk_d: DiversifiedTransmissionKey, - ) -> Option { - if pk_d.is_identity() { - None - } else { - Some(PaymentAddress { pk_d, diversifier }) - } - } - - /// Parses a PaymentAddress from bytes. - pub fn from_bytes(bytes: &[u8; 43]) -> Option { - let diversifier = { - let mut tmp = [0; 11]; - tmp.copy_from_slice(&bytes[0..11]); - Diversifier(tmp) - }; - - let pk_d = DiversifiedTransmissionKey::from_bytes(bytes[11..43].try_into().unwrap()); - if pk_d.is_some().into() { - // The remaining invariants are checked here. - PaymentAddress::from_parts(diversifier, pk_d.unwrap()) - } else { - None - } - } - - /// Returns the byte encoding of this `PaymentAddress`. - pub fn to_bytes(&self) -> [u8; 43] { - let mut bytes = [0; 43]; - bytes[0..11].copy_from_slice(&self.diversifier.0); - bytes[11..].copy_from_slice(&self.pk_d.to_bytes()); - bytes - } - - /// Returns the [`Diversifier`] for this `PaymentAddress`. - pub fn diversifier(&self) -> &Diversifier { - &self.diversifier - } - - /// Returns `pk_d` for this `PaymentAddress`. - pub fn pk_d(&self) -> &DiversifiedTransmissionKey { - &self.pk_d - } - - pub(crate) fn g_d(&self) -> jubjub::SubgroupPoint { - self.diversifier.g_d().expect("checked at construction") - } - - pub fn create_note(&self, value: NoteValue, rseed: Rseed) -> Note { - Note::from_parts(*self, value, rseed) - } -} - -#[cfg(any(test, feature = "test-dependencies"))] -pub(super) mod testing { - use proptest::prelude::*; - - use super::{ - super::keys::{testing::arb_incoming_viewing_key, Diversifier, SaplingIvk}, - PaymentAddress, - }; - - pub fn arb_payment_address() -> impl Strategy { - arb_incoming_viewing_key().prop_flat_map(|ivk: SaplingIvk| { - any::<[u8; 11]>().prop_filter_map( - "Sampled diversifier must generate a valid Sapling payment address.", - move |d| ivk.to_payment_address(Diversifier(d)), - ) - }) - } -} diff --git a/zcash_primitives/src/sapling/builder.rs b/zcash_primitives/src/sapling/builder.rs deleted file mode 100644 index 5b3e70fe4..000000000 --- a/zcash_primitives/src/sapling/builder.rs +++ /dev/null @@ -1,937 +0,0 @@ -//! Types and functions for building Sapling transaction components. - -use core::fmt; -use std::marker::PhantomData; - -use group::ff::Field; -use rand::{seq::SliceRandom, RngCore}; -use rand_core::CryptoRng; -use redjubjub::{Binding, SpendAuth}; - -use crate::sapling::{ - self, - bundle::{ - Authorization, Authorized, Bundle, GrothProofBytes, MapAuth, OutputDescription, - SpendDescription, - }, - keys::{OutgoingViewingKey, SpendAuthorizingKey, SpendValidatingKey}, - note_encryption::{sapling_note_encryption, Zip212Enforcement}, - prover::{OutputProver, SpendProver}, - util::generate_random_rseed_internal, - value::{ - CommitmentSum, NoteValue, TrapdoorSum, ValueCommitTrapdoor, ValueCommitment, ValueSum, - }, - zip32::ExtendedSpendingKey, - Diversifier, MerklePath, Node, Note, PaymentAddress, ProofGenerationKey, SaplingIvk, -}; - -/// If there are any shielded inputs, always have at least two shielded outputs, padding -/// with dummy outputs if necessary. See . -const MIN_SHIELDED_OUTPUTS: usize = 2; - -#[derive(Debug, PartialEq, Eq)] -pub enum Error { - AnchorMismatch, - BindingSig, - /// A signature is valid for more than one input. This should never happen if `alpha` - /// is sampled correctly, and indicates a critical failure in randomness generation. - DuplicateSignature, - InvalidAddress, - InvalidAmount, - /// External signature is not valid. - InvalidExternalSignature, - /// A bundle could not be built because required signatures were missing. - MissingSignatures, - SpendProof, -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Error::AnchorMismatch => { - write!(f, "Anchor mismatch (anchors for all spends must be equal)") - } - Error::BindingSig => write!(f, "Failed to create bindingSig"), - Error::DuplicateSignature => write!(f, "Signature valid for more than one input"), - Error::InvalidAddress => write!(f, "Invalid address"), - Error::InvalidAmount => write!(f, "Invalid amount"), - Error::InvalidExternalSignature => write!(f, "External signature was invalid"), - Error::MissingSignatures => write!(f, "Required signatures were missing during build"), - Error::SpendProof => write!(f, "Failed to create Sapling spend proof"), - } - } -} - -#[derive(Debug, Clone)] -pub struct SpendDescriptionInfo { - proof_generation_key: ProofGenerationKey, - note: Note, - alpha: jubjub::Fr, - merkle_path: MerklePath, - rcv: ValueCommitTrapdoor, -} - -impl SpendDescriptionInfo { - fn new_internal( - mut rng: &mut R, - extsk: &ExtendedSpendingKey, - note: Note, - merkle_path: MerklePath, - ) -> Self { - SpendDescriptionInfo { - proof_generation_key: extsk.expsk.proof_generation_key(), - note, - alpha: jubjub::Fr::random(&mut rng), - merkle_path, - rcv: ValueCommitTrapdoor::random(rng), - } - } - - pub fn value(&self) -> NoteValue { - self.note.value() - } - - fn build( - self, - anchor: Option, - ) -> Result>, Error> { - let anchor = anchor.expect("Sapling anchor must be set if Sapling spends are present."); - - // Construct the value commitment. - let cv = ValueCommitment::derive(self.note.value(), self.rcv.clone()); - - let ak = self.proof_generation_key.ak.clone(); - - // This is the result of the re-randomization, we compute it for the caller - let rk = ak.randomize(&self.alpha); - - let nullifier = self.note.nf( - &self.proof_generation_key.to_viewing_key().nk, - u64::try_from(self.merkle_path.position()) - .expect("Sapling note commitment tree position must fit into a u64"), - ); - - let zkproof = Pr::prepare_circuit( - self.proof_generation_key, - *self.note.recipient().diversifier(), - *self.note.rseed(), - self.note.value(), - self.alpha, - self.rcv, - anchor, - self.merkle_path.clone(), - ) - .ok_or(Error::SpendProof)?; - - Ok(SpendDescription::from_parts( - cv, - anchor, - nullifier, - rk, - zkproof, - SigningParts { - ak, - alpha: self.alpha, - }, - )) - } -} - -/// A struct containing the information required in order to construct a -/// Sapling output to a transaction. -#[derive(Clone)] -pub struct SaplingOutputInfo { - /// `None` represents the `ovk = ⊥` case. - ovk: Option, - note: Note, - memo: Option<[u8; 512]>, - rcv: ValueCommitTrapdoor, -} - -impl SaplingOutputInfo { - fn dummy(mut rng: &mut R, zip212_enforcement: Zip212Enforcement) -> Self { - // This is a dummy output - let dummy_to = { - let mut diversifier = Diversifier([0; 11]); - loop { - rng.fill_bytes(&mut diversifier.0); - let dummy_ivk = SaplingIvk(jubjub::Fr::random(&mut rng)); - if let Some(addr) = dummy_ivk.to_payment_address(diversifier) { - break addr; - } - } - }; - - Self::new_internal( - rng, - None, - dummy_to, - NoteValue::from_raw(0), - None, - zip212_enforcement, - ) - } - - fn new_internal( - rng: &mut R, - ovk: Option, - to: PaymentAddress, - value: NoteValue, - memo: Option<[u8; 512]>, - zip212_enforcement: Zip212Enforcement, - ) -> Self { - let rseed = generate_random_rseed_internal(zip212_enforcement, rng); - - let note = Note::from_parts(to, value, rseed); - - SaplingOutputInfo { - ovk, - note, - memo, - rcv: ValueCommitTrapdoor::random(rng), - } - } - - fn build( - self, - rng: &mut R, - ) -> OutputDescription { - let encryptor = sapling_note_encryption::( - self.ovk, - self.note.clone(), - self.memo.unwrap_or_else(|| { - let mut memo = [0; 512]; - memo[0] = 0xf6; - memo - }), - rng, - ); - - // Construct the value commitment. - let cv = ValueCommitment::derive(self.note.value(), self.rcv.clone()); - - // Prepare the circuit that will be used to construct the proof. - let zkproof = Pr::prepare_circuit( - encryptor.esk().0, - self.note.recipient(), - self.note.rcm(), - self.note.value(), - self.rcv, - ); - - let cmu = self.note.cmu(); - - let enc_ciphertext = encryptor.encrypt_note_plaintext(); - let out_ciphertext = encryptor.encrypt_outgoing_plaintext(&cv, &cmu, rng); - - let epk = encryptor.epk(); - - OutputDescription::from_parts( - cv, - cmu, - epk.to_bytes(), - enc_ciphertext, - out_ciphertext, - zkproof, - ) - } - - pub fn recipient(&self) -> PaymentAddress { - self.note.recipient() - } - - pub fn value(&self) -> NoteValue { - self.note.value() - } -} - -/// Metadata about a transaction created by a [`SaplingBuilder`]. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct SaplingMetadata { - spend_indices: Vec, - output_indices: Vec, -} - -impl SaplingMetadata { - pub fn empty() -> Self { - SaplingMetadata { - spend_indices: vec![], - output_indices: vec![], - } - } - - /// Returns the index within the transaction of the [`SpendDescription`] corresponding - /// to the `n`-th call to [`SaplingBuilder::add_spend`]. - /// - /// Note positions are randomized when building transactions for indistinguishability. - /// This means that the transaction consumer cannot assume that e.g. the first spend - /// they added (via the first call to [`SaplingBuilder::add_spend`]) is the first - /// [`SpendDescription`] in the transaction. - pub fn spend_index(&self, n: usize) -> Option { - self.spend_indices.get(n).copied() - } - - /// Returns the index within the transaction of the [`OutputDescription`] corresponding - /// to the `n`-th call to [`SaplingBuilder::add_output`]. - /// - /// Note positions are randomized when building transactions for indistinguishability. - /// This means that the transaction consumer cannot assume that e.g. the first output - /// they added (via the first call to [`SaplingBuilder::add_output`]) is the first - /// [`OutputDescription`] in the transaction. - pub fn output_index(&self, n: usize) -> Option { - self.output_indices.get(n).copied() - } -} - -pub struct SaplingBuilder { - anchor: Option, - value_balance: ValueSum, - spends: Vec, - outputs: Vec, - zip212_enforcement: Zip212Enforcement, -} - -impl SaplingBuilder { - pub fn new(zip212_enforcement: Zip212Enforcement) -> Self { - SaplingBuilder { - anchor: None, - value_balance: ValueSum::zero(), - spends: vec![], - outputs: vec![], - zip212_enforcement, - } - } - - /// Returns the list of Sapling inputs that will be consumed by the transaction being - /// constructed. - pub fn inputs(&self) -> &[SpendDescriptionInfo] { - &self.spends - } - - /// Returns the Sapling outputs that will be produced by the transaction being constructed - pub fn outputs(&self) -> &[SaplingOutputInfo] { - &self.outputs - } - - /// Returns the number of outputs that will be present in the Sapling bundle built by - /// this builder. - /// - /// This may be larger than the number of outputs that have been added to the builder, - /// depending on whether padding is going to be applied. - pub(crate) fn bundle_output_count(&self) -> usize { - // This matches the padding behaviour in `Self::build`. - match self.spends.len() { - 0 => self.outputs.len(), - _ => std::cmp::max(MIN_SHIELDED_OUTPUTS, self.outputs.len()), - } - } - - /// Returns the net value represented by the spends and outputs added to this builder, - /// or an error if the values added to this builder overflow the range of a Zcash - /// monetary amount. - fn try_value_balance>(&self) -> Result { - self.value_balance - .try_into() - .map_err(|_| ()) - .and_then(|vb| V::try_from(vb).map_err(|_| ())) - .map_err(|()| Error::InvalidAmount) - } - - /// Returns the net value represented by the spends and outputs added to this builder. - pub fn value_balance>(&self) -> V { - self.try_value_balance() - .expect("we check this when mutating self.value_balance") - } - - /// Adds a Sapling note to be spent in this transaction. - /// - /// Returns an error if the given Merkle path does not have the same anchor as the - /// paths for previous Sapling notes. - pub fn add_spend( - &mut self, - mut rng: R, - extsk: &ExtendedSpendingKey, - note: Note, - merkle_path: MerklePath, - ) -> Result<(), Error> { - // Consistency check: all anchors must equal the first one - let node = Node::from_cmu(¬e.cmu()); - if let Some(anchor) = self.anchor { - let path_root: bls12_381::Scalar = merkle_path.root(node).into(); - if path_root != anchor { - return Err(Error::AnchorMismatch); - } - } else { - self.anchor = Some(merkle_path.root(node).into()) - } - - self.value_balance = (self.value_balance + note.value()).ok_or(Error::InvalidAmount)?; - self.try_value_balance::()?; - - let spend = SpendDescriptionInfo::new_internal(&mut rng, extsk, note, merkle_path); - - self.spends.push(spend); - - Ok(()) - } - - /// Adds a Sapling address to send funds to. - #[allow(clippy::too_many_arguments)] - pub fn add_output( - &mut self, - mut rng: R, - ovk: Option, - to: PaymentAddress, - value: NoteValue, - memo: Option<[u8; 512]>, - ) -> Result<(), Error> { - let output = SaplingOutputInfo::new_internal( - &mut rng, - ovk, - to, - value, - memo, - self.zip212_enforcement, - ); - - self.value_balance = (self.value_balance - value).ok_or(Error::InvalidAddress)?; - self.try_value_balance::()?; - - self.outputs.push(output); - - Ok(()) - } - - pub fn build>( - self, - mut rng: R, - ) -> Result, SaplingMetadata)>, Error> { - let value_balance = self.try_value_balance()?; - - // Record initial positions of spends and outputs - let mut indexed_spends: Vec<_> = self.spends.into_iter().enumerate().collect(); - let mut indexed_outputs: Vec<_> = self - .outputs - .into_iter() - .enumerate() - .map(|(i, o)| Some((i, o))) - .collect(); - - // Set up the transaction metadata that will be used to record how - // inputs and outputs are shuffled. - let mut tx_metadata = SaplingMetadata::empty(); - tx_metadata.spend_indices.resize(indexed_spends.len(), 0); - tx_metadata.output_indices.resize(indexed_outputs.len(), 0); - - // Pad Sapling outputs - if !indexed_spends.is_empty() { - while indexed_outputs.len() < MIN_SHIELDED_OUTPUTS { - indexed_outputs.push(None); - } - } - - // Randomize order of inputs and outputs - indexed_spends.shuffle(&mut rng); - indexed_outputs.shuffle(&mut rng); - - // Record the transaction metadata and create dummy outputs. - let spend_infos = indexed_spends - .into_iter() - .enumerate() - .map(|(i, (pos, spend))| { - // Record the post-randomized spend location - tx_metadata.spend_indices[pos] = i; - - spend - }) - .collect::>(); - let output_infos = indexed_outputs - .into_iter() - .enumerate() - .map(|(i, output)| { - if let Some((pos, output)) = output { - // Record the post-randomized output location - tx_metadata.output_indices[pos] = i; - - output - } else { - // This is a dummy output - SaplingOutputInfo::dummy(&mut rng, self.zip212_enforcement) - } - }) - .collect::>(); - - // Compute the transaction binding signing key. - let bsk = { - let spends: TrapdoorSum = spend_infos.iter().map(|spend| &spend.rcv).sum(); - let outputs: TrapdoorSum = output_infos.iter().map(|output| &output.rcv).sum(); - (spends - outputs).into_bsk() - }; - - // Create the unauthorized Spend and Output descriptions. - let shielded_spends = spend_infos - .into_iter() - .map(|a| a.build::(self.anchor)) - .collect::, _>>()?; - let shielded_outputs = output_infos - .into_iter() - .map(|a| a.build::(&mut rng)) - .collect::>(); - - // Verify that bsk and bvk are consistent. - let bvk = { - let spends = shielded_spends - .iter() - .map(|spend| spend.cv()) - .sum::(); - let outputs = shielded_outputs - .iter() - .map(|output| output.cv()) - .sum::(); - (spends - outputs) - .into_bvk(i64::try_from(self.value_balance).map_err(|_| Error::InvalidAmount)?) - }; - assert_eq!(redjubjub::VerificationKey::from(&bsk), bvk); - - let bundle = if shielded_spends.is_empty() && shielded_outputs.is_empty() { - None - } else { - Some(( - Bundle::from_parts( - shielded_spends, - shielded_outputs, - value_balance, - InProgress { - sigs: Unsigned { bsk }, - _proof_state: PhantomData::default(), - }, - ), - tx_metadata, - )) - }; - - Ok(bundle) - } -} - -/// Type alias for an in-progress bundle that has no proofs or signatures. -/// -/// This is returned by [`SaplingBuilder::build`]. -pub type UnauthorizedBundle = Bundle, V>; - -/// Marker trait representing bundle proofs in the process of being created. -pub trait InProgressProofs: fmt::Debug { - /// The proof type of a Sapling spend in the process of being proven. - type SpendProof: Clone + fmt::Debug; - /// The proof type of a Sapling output in the process of being proven. - type OutputProof: Clone + fmt::Debug; -} - -/// Marker trait representing bundle signatures in the process of being created. -pub trait InProgressSignatures: fmt::Debug { - /// The authorization type of a Sapling spend or output in the process of being - /// authorized. - type AuthSig: Clone + fmt::Debug; -} - -/// Marker for a bundle in the process of being built. -#[derive(Clone, Debug)] -pub struct InProgress { - sigs: S, - _proof_state: PhantomData

, -} - -impl Authorization for InProgress { - type SpendProof = P::SpendProof; - type OutputProof = P::OutputProof; - type AuthSig = S::AuthSig; -} - -/// Marker for a [`Bundle`] without proofs. -/// -/// The [`SpendDescription`]s and [`OutputDescription`]s within the bundle contain the -/// private data needed to create proofs. -#[derive(Clone, Copy, Debug)] -pub struct Unproven; - -impl InProgressProofs for Unproven { - type SpendProof = sapling::circuit::Spend; - type OutputProof = sapling::circuit::Output; -} - -/// Marker for a [`Bundle`] with proofs. -#[derive(Clone, Copy, Debug)] -pub struct Proven; - -impl InProgressProofs for Proven { - type SpendProof = GrothProofBytes; - type OutputProof = GrothProofBytes; -} - -/// Reports on the progress made towards creating proofs for a bundle. -pub trait ProverProgress { - /// Updates the progress instance with the number of steps completed and the total - /// number of steps. - fn update(&mut self, cur: u32, end: u32); -} - -impl ProverProgress for () { - fn update(&mut self, _: u32, _: u32) {} -} - -impl> ProverProgress for std::sync::mpsc::Sender { - fn update(&mut self, cur: u32, end: u32) { - // If the send fails, we should ignore the error, not crash. - self.send(U::from((cur, end))).unwrap_or(()); - } -} - -impl ProverProgress for &mut U { - fn update(&mut self, cur: u32, end: u32) { - (*self).update(cur, end); - } -} - -struct CreateProofs<'a, SP: SpendProver, OP: OutputProver, R: RngCore, U: ProverProgress> { - spend_prover: &'a SP, - output_prover: &'a OP, - rng: R, - progress_notifier: U, - total_progress: u32, - progress: u32, -} - -impl<'a, SP: SpendProver, OP: OutputProver, R: RngCore, U: ProverProgress> - CreateProofs<'a, SP, OP, R, U> -{ - fn new( - spend_prover: &'a SP, - output_prover: &'a OP, - rng: R, - progress_notifier: U, - total_progress: u32, - ) -> Self { - // Keep track of the total number of steps computed - Self { - spend_prover, - output_prover, - rng, - progress_notifier, - total_progress, - progress: 0u32, - } - } - - fn update_progress(&mut self) { - // Update progress and send a notification on the channel - self.progress += 1; - self.progress_notifier - .update(self.progress, self.total_progress); - } -} - -impl< - 'a, - S: InProgressSignatures, - SP: SpendProver, - OP: OutputProver, - R: RngCore, - U: ProverProgress, - > MapAuth, InProgress> for CreateProofs<'a, SP, OP, R, U> -{ - fn map_spend_proof(&mut self, spend: sapling::circuit::Spend) -> GrothProofBytes { - let proof = self.spend_prover.create_proof(spend, &mut self.rng); - self.update_progress(); - SP::encode_proof(proof) - } - - fn map_output_proof(&mut self, output: sapling::circuit::Output) -> GrothProofBytes { - let proof = self.output_prover.create_proof(output, &mut self.rng); - self.update_progress(); - OP::encode_proof(proof) - } - - fn map_auth_sig(&mut self, s: S::AuthSig) -> S::AuthSig { - s - } - - fn map_authorization(&mut self, a: InProgress) -> InProgress { - InProgress { - sigs: a.sigs, - _proof_state: PhantomData::default(), - } - } -} - -impl Bundle, V> { - /// Creates the proofs for this bundle. - pub fn create_proofs( - self, - spend_prover: &SP, - output_prover: &OP, - rng: impl RngCore, - progress_notifier: impl ProverProgress, - ) -> Bundle, V> { - let total_progress = - self.shielded_spends().len() as u32 + self.shielded_outputs().len() as u32; - self.map_authorization(CreateProofs::new( - spend_prover, - output_prover, - rng, - progress_notifier, - total_progress, - )) - } -} - -/// Marker for an unauthorized bundle with no signatures. -#[derive(Clone)] -pub struct Unsigned { - bsk: redjubjub::SigningKey, -} - -impl fmt::Debug for Unsigned { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Unsigned").finish_non_exhaustive() - } -} - -impl InProgressSignatures for Unsigned { - type AuthSig = SigningParts; -} - -/// The parts needed to sign a [`SpendDescription`]. -#[derive(Clone, Debug)] -pub struct SigningParts { - /// The spend validating key for this spend description. Used to match spend - /// authorizing keys to spend descriptions they can create signatures for. - ak: SpendValidatingKey, - /// The randomization needed to derive the actual signing key for this note. - alpha: jubjub::Scalar, -} - -/// Marker for a partially-authorized bundle, in the process of being signed. -#[derive(Clone, Debug)] -pub struct PartiallyAuthorized { - binding_signature: redjubjub::Signature, - sighash: [u8; 32], -} - -impl InProgressSignatures for PartiallyAuthorized { - type AuthSig = MaybeSigned; -} - -/// A heisen[`Signature`] for a particular [`SpendDescription`]. -/// -/// [`Signature`]: redjubjub::Signature -#[derive(Clone, Debug)] -pub enum MaybeSigned { - /// The information needed to sign this [`SpendDescription`]. - SigningMetadata(SigningParts), - /// The signature for this [`SpendDescription`]. - Signature(redjubjub::Signature), -} - -impl MaybeSigned { - fn finalize(self) -> Result, Error> { - match self { - Self::Signature(sig) => Ok(sig), - _ => Err(Error::MissingSignatures), - } - } -} - -impl Bundle, V> { - /// Loads the sighash into this bundle, preparing it for signing. - /// - /// This API ensures that all signatures are created over the same sighash. - pub fn prepare( - self, - mut rng: R, - sighash: [u8; 32], - ) -> Bundle, V> { - self.map_authorization(( - |proof| proof, - |proof| proof, - MaybeSigned::SigningMetadata, - |auth: InProgress| InProgress { - sigs: PartiallyAuthorized { - binding_signature: auth.sigs.bsk.sign(&mut rng, &sighash), - sighash, - }, - _proof_state: PhantomData::default(), - }, - )) - } -} - -impl Bundle, V> { - /// Applies signatures to this bundle, in order to authorize it. - /// - /// This is a helper method that wraps [`Bundle::prepare`], [`Bundle::sign`], and - /// [`Bundle::finalize`]. - pub fn apply_signatures( - self, - mut rng: R, - sighash: [u8; 32], - signing_keys: &[SpendAuthorizingKey], - ) -> Result, Error> { - signing_keys - .iter() - .fold(self.prepare(&mut rng, sighash), |partial, ask| { - partial.sign(&mut rng, ask) - }) - .finalize() - } -} - -impl Bundle, V> { - /// Signs this bundle with the given [`redjubjub::SigningKey`]. - /// - /// This will apply signatures for all notes controlled by this spending key. - pub fn sign(self, mut rng: R, ask: &SpendAuthorizingKey) -> Self { - let expected_ak = ask.into(); - let sighash = self.authorization().sigs.sighash; - self.map_authorization(( - |proof| proof, - |proof| proof, - |maybe| match maybe { - MaybeSigned::SigningMetadata(parts) if parts.ak == expected_ak => { - MaybeSigned::Signature(ask.randomize(&parts.alpha).sign(&mut rng, &sighash)) - } - s => s, - }, - |partial| partial, - )) - } - - /// Appends externally computed [`redjubjub::Signature`]s. - /// - /// Each signature will be applied to the one input for which it is valid. An error - /// will be returned if the signature is not valid for any inputs, or if it is valid - /// for more than one input. - pub fn append_signatures( - self, - signatures: &[redjubjub::Signature], - ) -> Result { - signatures.iter().try_fold(self, Self::append_signature) - } - - fn append_signature(self, signature: &redjubjub::Signature) -> Result { - let sighash = self.authorization().sigs.sighash; - let mut signature_valid_for = 0usize; - let bundle = self.map_authorization(( - |proof| proof, - |proof| proof, - |maybe| match maybe { - MaybeSigned::SigningMetadata(parts) => { - let rk = parts.ak.randomize(&parts.alpha); - if rk.verify(&sighash, signature).is_ok() { - signature_valid_for += 1; - MaybeSigned::Signature(*signature) - } else { - // Signature isn't for this input. - MaybeSigned::SigningMetadata(parts) - } - } - s => s, - }, - |partial| partial, - )); - match signature_valid_for { - 0 => Err(Error::InvalidExternalSignature), - 1 => Ok(bundle), - _ => Err(Error::DuplicateSignature), - } - } -} - -impl Bundle, V> { - /// Finalizes this bundle, enabling it to be included in a transaction. - /// - /// Returns an error if any signatures are missing. - pub fn finalize(self) -> Result, Error> { - self.try_map_authorization(( - Ok, - Ok, - |maybe: MaybeSigned| maybe.finalize(), - |partial: InProgress| { - Ok(Authorized { - binding_sig: partial.sigs.binding_signature, - }) - }, - )) - } -} - -#[cfg(any(test, feature = "test-dependencies"))] -pub mod testing { - use std::fmt; - - use proptest::collection::vec; - use proptest::prelude::*; - use rand::{rngs::StdRng, SeedableRng}; - - use crate::sapling::{ - bundle::{Authorized, Bundle}, - note_encryption::Zip212Enforcement, - prover::mock::{MockOutputProver, MockSpendProver}, - testing::{arb_node, arb_note}, - value::testing::arb_positive_note_value, - zip32::testing::arb_extended_spending_key, - }; - use incrementalmerkletree::{ - frontier::testing::arb_commitment_tree, witness::IncrementalWitness, - }; - - use super::SaplingBuilder; - - #[allow(dead_code)] - fn arb_bundle>( - max_money: u64, - zip212_enforcement: Zip212Enforcement, - ) -> impl Strategy> { - (1..30usize) - .prop_flat_map(move |n_notes| { - ( - arb_extended_spending_key(), - vec( - arb_positive_note_value(max_money / 10000).prop_flat_map(arb_note), - n_notes, - ), - vec( - arb_commitment_tree::<_, _, 32>(n_notes, arb_node()) - .prop_map(|t| IncrementalWitness::from_tree(t).path().unwrap()), - n_notes, - ), - prop::array::uniform32(any::()), - prop::array::uniform32(any::()), - ) - }) - .prop_map( - move |(extsk, spendable_notes, commitment_trees, rng_seed, fake_sighash_bytes)| { - let mut builder = SaplingBuilder::new(zip212_enforcement); - let mut rng = StdRng::from_seed(rng_seed); - - for (note, path) in spendable_notes - .into_iter() - .zip(commitment_trees.into_iter()) - { - builder.add_spend(&mut rng, &extsk, note, path).unwrap(); - } - - let (bundle, _) = builder - .build::(&mut rng) - .unwrap() - .unwrap(); - - let bundle = - bundle.create_proofs(&MockSpendProver, &MockOutputProver, &mut rng, ()); - - bundle - .apply_signatures(&mut rng, fake_sighash_bytes, &[extsk.expsk.ask]) - .unwrap() - }, - ) - } -} diff --git a/zcash_primitives/src/sapling/bundle.rs b/zcash_primitives/src/sapling/bundle.rs deleted file mode 100644 index d6b02c960..000000000 --- a/zcash_primitives/src/sapling/bundle.rs +++ /dev/null @@ -1,747 +0,0 @@ -use core::fmt::Debug; - -use memuse::DynamicUsage; -use redjubjub::{Binding, SpendAuth}; - -use zcash_note_encryption::{ - EphemeralKeyBytes, ShieldedOutput, COMPACT_NOTE_SIZE, ENC_CIPHERTEXT_SIZE, OUT_CIPHERTEXT_SIZE, -}; - -use crate::sapling::{ - circuit::GROTH_PROOF_SIZE, - note::ExtractedNoteCommitment, - note_encryption::{CompactOutputDescription, SaplingDomain}, - value::ValueCommitment, - Nullifier, -}; - -pub type GrothProofBytes = [u8; GROTH_PROOF_SIZE]; - -/// Defines the authorization type of a Sapling bundle. -pub trait Authorization: Debug { - type SpendProof: Clone + Debug; - type OutputProof: Clone + Debug; - type AuthSig: Clone + Debug; -} - -/// Authorizing data for a bundle of Sapling spends and outputs, ready to be committed to -/// the ledger. -#[derive(Debug, Copy, Clone)] -pub struct Authorized { - // TODO: Make this private. - pub binding_sig: redjubjub::Signature, -} - -impl Authorization for Authorized { - type SpendProof = GrothProofBytes; - type OutputProof = GrothProofBytes; - type AuthSig = redjubjub::Signature; -} - -/// A map from one bundle authorization to another. -/// -/// For use with [`Bundle::map_authorization`]. -pub trait MapAuth { - fn map_spend_proof(&mut self, p: A::SpendProof) -> B::SpendProof; - fn map_output_proof(&mut self, p: A::OutputProof) -> B::OutputProof; - fn map_auth_sig(&mut self, s: A::AuthSig) -> B::AuthSig; - fn map_authorization(&mut self, a: A) -> B; -} - -/// The identity map. -/// -/// This can be used with [`TransactionData::map_authorization`] when you want to map the -/// authorization of a subset of the transaction's bundles. -/// -/// [`TransactionData::map_authorization`]: crate::transaction::TransactionData::map_authorization -impl MapAuth for () { - fn map_spend_proof( - &mut self, - p: ::SpendProof, - ) -> ::SpendProof { - p - } - - fn map_output_proof( - &mut self, - p: ::OutputProof, - ) -> ::OutputProof { - p - } - - fn map_auth_sig( - &mut self, - s: ::AuthSig, - ) -> ::AuthSig { - s - } - - fn map_authorization(&mut self, a: Authorized) -> Authorized { - a - } -} - -/// A helper for implementing `MapAuth` with a set of closures. -impl MapAuth for (F, G, H, I) -where - A: Authorization, - B: Authorization, - F: FnMut(A::SpendProof) -> B::SpendProof, - G: FnMut(A::OutputProof) -> B::OutputProof, - H: FnMut(A::AuthSig) -> B::AuthSig, - I: FnMut(A) -> B, -{ - fn map_spend_proof(&mut self, p: A::SpendProof) -> B::SpendProof { - self.0(p) - } - - fn map_output_proof(&mut self, p: A::OutputProof) -> B::OutputProof { - self.1(p) - } - - fn map_auth_sig(&mut self, s: A::AuthSig) -> B::AuthSig { - self.2(s) - } - - fn map_authorization(&mut self, a: A) -> B { - self.3(a) - } -} - -/// A fallible map from one bundle authorization to another. -/// -/// For use with [`Bundle::try_map_authorization`]. -pub trait TryMapAuth { - type Error; - fn try_map_spend_proof(&mut self, p: A::SpendProof) -> Result; - fn try_map_output_proof(&mut self, p: A::OutputProof) -> Result; - fn try_map_auth_sig(&mut self, s: A::AuthSig) -> Result; - fn try_map_authorization(&mut self, a: A) -> Result; -} - -/// A helper for implementing `TryMapAuth` with a set of closures. -impl TryMapAuth for (F, G, H, I) -where - A: Authorization, - B: Authorization, - F: FnMut(A::SpendProof) -> Result, - G: FnMut(A::OutputProof) -> Result, - H: FnMut(A::AuthSig) -> Result, - I: FnMut(A) -> Result, -{ - type Error = E; - - fn try_map_spend_proof(&mut self, p: A::SpendProof) -> Result { - self.0(p) - } - - fn try_map_output_proof(&mut self, p: A::OutputProof) -> Result { - self.1(p) - } - - fn try_map_auth_sig(&mut self, s: A::AuthSig) -> Result { - self.2(s) - } - - fn try_map_authorization(&mut self, a: A) -> Result { - self.3(a) - } -} - -#[derive(Debug, Clone)] -pub struct Bundle { - shielded_spends: Vec>, - shielded_outputs: Vec>, - value_balance: V, - authorization: A, -} - -impl Bundle { - /// Constructs a `Bundle` from its constituent parts. - #[cfg(feature = "temporary-zcashd")] - pub fn temporary_zcashd_from_parts( - shielded_spends: Vec>, - shielded_outputs: Vec>, - value_balance: V, - authorization: A, - ) -> Self { - Self::from_parts( - shielded_spends, - shielded_outputs, - value_balance, - authorization, - ) - } - - /// Constructs a `Bundle` from its constituent parts. - pub(crate) fn from_parts( - shielded_spends: Vec>, - shielded_outputs: Vec>, - value_balance: V, - authorization: A, - ) -> Self { - Bundle { - shielded_spends, - shielded_outputs, - value_balance, - authorization, - } - } - - /// Returns the list of spends in this bundle. - pub fn shielded_spends(&self) -> &[SpendDescription] { - &self.shielded_spends - } - - /// Returns the list of outputs in this bundle. - pub fn shielded_outputs(&self) -> &[OutputDescription] { - &self.shielded_outputs - } - - /// Returns the net value moved into or out of the Sapling shielded pool. - /// - /// This is the sum of Sapling spends minus the sum of Sapling outputs. - pub fn value_balance(&self) -> &V { - &self.value_balance - } - - /// Returns the authorization for this bundle. - /// - /// In the case of a `Bundle`, this is the binding signature. - pub fn authorization(&self) -> &A { - &self.authorization - } - - /// Transitions this bundle from one authorization state to another. - pub fn map_authorization>(self, mut f: F) -> Bundle { - Bundle { - shielded_spends: self - .shielded_spends - .into_iter() - .map(|d| SpendDescription { - cv: d.cv, - anchor: d.anchor, - nullifier: d.nullifier, - rk: d.rk, - zkproof: f.map_spend_proof(d.zkproof), - spend_auth_sig: f.map_auth_sig(d.spend_auth_sig), - }) - .collect(), - shielded_outputs: self - .shielded_outputs - .into_iter() - .map(|o| OutputDescription { - cv: o.cv, - cmu: o.cmu, - ephemeral_key: o.ephemeral_key, - enc_ciphertext: o.enc_ciphertext, - out_ciphertext: o.out_ciphertext, - zkproof: f.map_output_proof(o.zkproof), - }) - .collect(), - value_balance: self.value_balance, - authorization: f.map_authorization(self.authorization), - } - } - - /// Transitions this bundle from one authorization state to another. - pub fn try_map_authorization>( - self, - mut f: F, - ) -> Result, F::Error> { - Ok(Bundle { - shielded_spends: self - .shielded_spends - .into_iter() - .map(|d| { - Ok(SpendDescription { - cv: d.cv, - anchor: d.anchor, - nullifier: d.nullifier, - rk: d.rk, - zkproof: f.try_map_spend_proof(d.zkproof)?, - spend_auth_sig: f.try_map_auth_sig(d.spend_auth_sig)?, - }) - }) - .collect::>()?, - shielded_outputs: self - .shielded_outputs - .into_iter() - .map(|o| { - Ok(OutputDescription { - cv: o.cv, - cmu: o.cmu, - ephemeral_key: o.ephemeral_key, - enc_ciphertext: o.enc_ciphertext, - out_ciphertext: o.out_ciphertext, - zkproof: f.try_map_output_proof(o.zkproof)?, - }) - }) - .collect::>()?, - value_balance: self.value_balance, - authorization: f.try_map_authorization(self.authorization)?, - }) - } -} - -impl DynamicUsage for Bundle { - fn dynamic_usage(&self) -> usize { - self.shielded_spends.dynamic_usage() - + self.shielded_outputs.dynamic_usage() - + self.value_balance.dynamic_usage() - } - - fn dynamic_usage_bounds(&self) -> (usize, Option) { - let bounds = ( - self.shielded_spends.dynamic_usage_bounds(), - self.shielded_outputs.dynamic_usage_bounds(), - self.value_balance.dynamic_usage_bounds(), - ); - - ( - bounds.0 .0 + bounds.1 .0 + bounds.2 .0, - bounds - .0 - .1 - .zip(bounds.1 .1) - .zip(bounds.2 .1) - .map(|((a, b), c)| a + b + c), - ) - } -} - -#[derive(Clone)] -pub struct SpendDescription { - cv: ValueCommitment, - anchor: bls12_381::Scalar, - nullifier: Nullifier, - rk: redjubjub::VerificationKey, - zkproof: A::SpendProof, - spend_auth_sig: A::AuthSig, -} - -impl std::fmt::Debug for SpendDescription { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - write!( - f, - "SpendDescription(cv = {:?}, anchor = {:?}, nullifier = {:?}, rk = {:?}, spend_auth_sig = {:?})", - self.cv, self.anchor, self.nullifier, self.rk, self.spend_auth_sig - ) - } -} - -impl SpendDescription { - #[cfg(feature = "temporary-zcashd")] - pub fn temporary_zcashd_from_parts( - cv: ValueCommitment, - anchor: bls12_381::Scalar, - nullifier: Nullifier, - rk: redjubjub::VerificationKey, - zkproof: A::SpendProof, - spend_auth_sig: A::AuthSig, - ) -> Self { - Self::from_parts(cv, anchor, nullifier, rk, zkproof, spend_auth_sig) - } - - pub(crate) fn from_parts( - cv: ValueCommitment, - anchor: bls12_381::Scalar, - nullifier: Nullifier, - rk: redjubjub::VerificationKey, - zkproof: A::SpendProof, - spend_auth_sig: A::AuthSig, - ) -> Self { - Self { - cv, - anchor, - nullifier, - rk, - zkproof, - spend_auth_sig, - } - } - - /// Returns the commitment to the value consumed by this spend. - pub fn cv(&self) -> &ValueCommitment { - &self.cv - } - - /// Returns the root of the Sapling commitment tree that this spend commits to. - pub fn anchor(&self) -> &bls12_381::Scalar { - &self.anchor - } - - /// Returns the nullifier of the note being spent. - pub fn nullifier(&self) -> &Nullifier { - &self.nullifier - } - - /// Returns the randomized verification key for the note being spent. - pub fn rk(&self) -> &redjubjub::VerificationKey { - &self.rk - } - - /// Returns the proof for this spend. - pub fn zkproof(&self) -> &A::SpendProof { - &self.zkproof - } - - /// Returns the authorization signature for this spend. - pub fn spend_auth_sig(&self) -> &A::AuthSig { - &self.spend_auth_sig - } -} - -impl DynamicUsage for SpendDescription { - fn dynamic_usage(&self) -> usize { - self.zkproof.dynamic_usage() - } - - fn dynamic_usage_bounds(&self) -> (usize, Option) { - self.zkproof.dynamic_usage_bounds() - } -} - -#[derive(Clone)] -pub struct SpendDescriptionV5 { - cv: ValueCommitment, - nullifier: Nullifier, - rk: redjubjub::VerificationKey, -} - -impl SpendDescriptionV5 { - pub(crate) fn from_parts( - cv: ValueCommitment, - nullifier: Nullifier, - rk: redjubjub::VerificationKey, - ) -> Self { - Self { cv, nullifier, rk } - } - - pub fn into_spend_description( - self, - anchor: bls12_381::Scalar, - zkproof: GrothProofBytes, - spend_auth_sig: redjubjub::Signature, - ) -> SpendDescription { - SpendDescription { - cv: self.cv, - anchor, - nullifier: self.nullifier, - rk: self.rk, - zkproof, - spend_auth_sig, - } - } -} - -#[derive(Clone)] -pub struct OutputDescription { - cv: ValueCommitment, - cmu: ExtractedNoteCommitment, - ephemeral_key: EphemeralKeyBytes, - enc_ciphertext: [u8; ENC_CIPHERTEXT_SIZE], - out_ciphertext: [u8; OUT_CIPHERTEXT_SIZE], - zkproof: Proof, -} - -impl OutputDescription { - /// Returns the commitment to the value consumed by this output. - pub fn cv(&self) -> &ValueCommitment { - &self.cv - } - - /// Returns the commitment to the new note being created. - pub fn cmu(&self) -> &ExtractedNoteCommitment { - &self.cmu - } - - pub fn ephemeral_key(&self) -> &EphemeralKeyBytes { - &self.ephemeral_key - } - - /// Returns the encrypted note ciphertext. - pub fn enc_ciphertext(&self) -> &[u8; ENC_CIPHERTEXT_SIZE] { - &self.enc_ciphertext - } - - /// Returns the output recovery ciphertext. - pub fn out_ciphertext(&self) -> &[u8; OUT_CIPHERTEXT_SIZE] { - &self.out_ciphertext - } - - /// Returns the proof for this output. - pub fn zkproof(&self) -> &Proof { - &self.zkproof - } - - #[cfg(feature = "temporary-zcashd")] - pub fn temporary_zcashd_from_parts( - cv: ValueCommitment, - cmu: ExtractedNoteCommitment, - ephemeral_key: EphemeralKeyBytes, - enc_ciphertext: [u8; ENC_CIPHERTEXT_SIZE], - out_ciphertext: [u8; OUT_CIPHERTEXT_SIZE], - zkproof: Proof, - ) -> Self { - Self::from_parts( - cv, - cmu, - ephemeral_key, - enc_ciphertext, - out_ciphertext, - zkproof, - ) - } - - pub(crate) fn from_parts( - cv: ValueCommitment, - cmu: ExtractedNoteCommitment, - ephemeral_key: EphemeralKeyBytes, - enc_ciphertext: [u8; ENC_CIPHERTEXT_SIZE], - out_ciphertext: [u8; OUT_CIPHERTEXT_SIZE], - zkproof: Proof, - ) -> Self { - OutputDescription { - cv, - cmu, - ephemeral_key, - enc_ciphertext, - out_ciphertext, - zkproof, - } - } -} - -#[cfg(test)] -impl OutputDescription { - pub(crate) fn cv_mut(&mut self) -> &mut ValueCommitment { - &mut self.cv - } - pub(crate) fn cmu_mut(&mut self) -> &mut ExtractedNoteCommitment { - &mut self.cmu - } - pub(crate) fn ephemeral_key_mut(&mut self) -> &mut EphemeralKeyBytes { - &mut self.ephemeral_key - } - pub(crate) fn enc_ciphertext_mut(&mut self) -> &mut [u8; ENC_CIPHERTEXT_SIZE] { - &mut self.enc_ciphertext - } - pub(crate) fn out_ciphertext_mut(&mut self) -> &mut [u8; OUT_CIPHERTEXT_SIZE] { - &mut self.out_ciphertext - } -} - -impl DynamicUsage for OutputDescription { - fn dynamic_usage(&self) -> usize { - self.zkproof.dynamic_usage() - } - - fn dynamic_usage_bounds(&self) -> (usize, Option) { - self.zkproof.dynamic_usage_bounds() - } -} - -impl ShieldedOutput for OutputDescription { - fn ephemeral_key(&self) -> EphemeralKeyBytes { - self.ephemeral_key.clone() - } - - fn cmstar_bytes(&self) -> [u8; 32] { - self.cmu.to_bytes() - } - - fn enc_ciphertext(&self) -> &[u8; ENC_CIPHERTEXT_SIZE] { - &self.enc_ciphertext - } -} - -impl std::fmt::Debug for OutputDescription { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - write!( - f, - "OutputDescription(cv = {:?}, cmu = {:?}, ephemeral_key = {:?})", - self.cv, self.cmu, self.ephemeral_key - ) - } -} - -#[derive(Clone)] -pub struct OutputDescriptionV5 { - cv: ValueCommitment, - cmu: ExtractedNoteCommitment, - ephemeral_key: EphemeralKeyBytes, - enc_ciphertext: [u8; ENC_CIPHERTEXT_SIZE], - out_ciphertext: [u8; OUT_CIPHERTEXT_SIZE], -} - -memuse::impl_no_dynamic_usage!(OutputDescriptionV5); - -impl OutputDescriptionV5 { - pub(crate) fn from_parts( - cv: ValueCommitment, - cmu: ExtractedNoteCommitment, - ephemeral_key: EphemeralKeyBytes, - enc_ciphertext: [u8; ENC_CIPHERTEXT_SIZE], - out_ciphertext: [u8; OUT_CIPHERTEXT_SIZE], - ) -> Self { - Self { - cv, - cmu, - ephemeral_key, - enc_ciphertext, - out_ciphertext, - } - } - - pub fn into_output_description( - self, - zkproof: GrothProofBytes, - ) -> OutputDescription { - OutputDescription { - cv: self.cv, - cmu: self.cmu, - ephemeral_key: self.ephemeral_key, - enc_ciphertext: self.enc_ciphertext, - out_ciphertext: self.out_ciphertext, - zkproof, - } - } -} - -impl From> for CompactOutputDescription { - fn from(out: OutputDescription) -> CompactOutputDescription { - CompactOutputDescription { - ephemeral_key: out.ephemeral_key, - cmu: out.cmu, - enc_ciphertext: out.enc_ciphertext[..COMPACT_NOTE_SIZE].try_into().unwrap(), - } - } -} - -#[cfg(any(test, feature = "test-dependencies"))] -pub mod testing { - use std::fmt; - - use ff::Field; - use group::{Group, GroupEncoding}; - use proptest::collection::vec; - use proptest::prelude::*; - use rand::{rngs::StdRng, SeedableRng}; - - use crate::{ - sapling::{ - note::testing::arb_cmu, - value::{ - testing::{arb_note_value_bounded, arb_trapdoor}, - ValueCommitment, MAX_NOTE_VALUE, - }, - Nullifier, - }, - transaction::components::GROTH_PROOF_SIZE, - }; - - use super::{ - Authorized, Bundle, GrothProofBytes, OutputDescription, SpendDescription, - ENC_CIPHERTEXT_SIZE, OUT_CIPHERTEXT_SIZE, - }; - - prop_compose! { - fn arb_extended_point()(rng_seed in prop::array::uniform32(any::())) -> jubjub::ExtendedPoint { - let mut rng = StdRng::from_seed(rng_seed); - let scalar = jubjub::Scalar::random(&mut rng); - jubjub::ExtendedPoint::generator() * scalar - } - } - - prop_compose! { - /// produce a spend description with invalid data (useful only for serialization - /// roundtrip testing). - fn arb_spend_description(n_spends: usize)( - value in arb_note_value_bounded(MAX_NOTE_VALUE.checked_div(n_spends as u64).unwrap_or(0)), - rcv in arb_trapdoor(), - anchor in vec(any::(), 64) - .prop_map(|v| <[u8;64]>::try_from(v.as_slice()).unwrap()) - .prop_map(|v| bls12_381::Scalar::from_bytes_wide(&v)), - nullifier in prop::array::uniform32(any::()) - .prop_map(|v| Nullifier::from_slice(&v).unwrap()), - zkproof in vec(any::(), GROTH_PROOF_SIZE) - .prop_map(|v| <[u8;GROTH_PROOF_SIZE]>::try_from(v.as_slice()).unwrap()), - rng_seed in prop::array::uniform32(prop::num::u8::ANY), - fake_sighash_bytes in prop::array::uniform32(prop::num::u8::ANY), - ) -> SpendDescription { - let mut rng = StdRng::from_seed(rng_seed); - let sk1 = redjubjub::SigningKey::new(&mut rng); - let rk = redjubjub::VerificationKey::from(&sk1); - let cv = ValueCommitment::derive(value, rcv); - SpendDescription { - cv, - anchor, - nullifier, - rk, - zkproof, - spend_auth_sig: sk1.sign(&mut rng, &fake_sighash_bytes), - } - } - } - - prop_compose! { - /// produce an output description with invalid data (useful only for serialization - /// roundtrip testing). - pub fn arb_output_description(n_outputs: usize)( - value in arb_note_value_bounded(MAX_NOTE_VALUE.checked_div(n_outputs as u64).unwrap_or(0)), - rcv in arb_trapdoor(), - cmu in arb_cmu(), - enc_ciphertext in vec(any::(), ENC_CIPHERTEXT_SIZE) - .prop_map(|v| <[u8; ENC_CIPHERTEXT_SIZE]>::try_from(v.as_slice()).unwrap()), - epk in arb_extended_point(), - out_ciphertext in vec(any::(), OUT_CIPHERTEXT_SIZE) - .prop_map(|v| <[u8; OUT_CIPHERTEXT_SIZE]>::try_from(v.as_slice()).unwrap()), - zkproof in vec(any::(), GROTH_PROOF_SIZE) - .prop_map(|v| <[u8; GROTH_PROOF_SIZE]>::try_from(v.as_slice()).unwrap()), - ) -> OutputDescription { - let cv = ValueCommitment::derive(value, rcv); - OutputDescription { - cv, - cmu, - ephemeral_key: epk.to_bytes().into(), - enc_ciphertext, - out_ciphertext, - zkproof, - } - } - } - - pub fn arb_bundle( - value_balance: V, - ) -> impl Strategy>> { - (0usize..30, 0usize..30) - .prop_flat_map(|(n_spends, n_outputs)| { - ( - vec(arb_spend_description(n_spends), n_spends), - vec(arb_output_description(n_outputs), n_outputs), - prop::array::uniform32(prop::num::u8::ANY), - prop::array::uniform32(prop::num::u8::ANY), - ) - }) - .prop_map( - move |(shielded_spends, shielded_outputs, rng_seed, fake_bvk_bytes)| { - if shielded_spends.is_empty() && shielded_outputs.is_empty() { - None - } else { - let mut rng = StdRng::from_seed(rng_seed); - let bsk = redjubjub::SigningKey::new(&mut rng); - - Some(Bundle { - shielded_spends, - shielded_outputs, - value_balance, - authorization: Authorized { - binding_sig: bsk.sign(&mut rng, &fake_bvk_bytes), - }, - }) - } - }, - ) - } -} diff --git a/zcash_primitives/src/sapling/circuit.rs b/zcash_primitives/src/sapling/circuit.rs deleted file mode 100644 index cbdf0573e..000000000 --- a/zcash_primitives/src/sapling/circuit.rs +++ /dev/null @@ -1,1073 +0,0 @@ -//! The Sapling circuits. - -use core::fmt; -use std::io; - -use group::{ff::PrimeField, Curve}; - -use bellman::{groth16, Circuit, ConstraintSystem, SynthesisError}; -use bls12_381::Bls12; - -use super::{value::NoteValue, PaymentAddress, ProofGenerationKey}; - -use bellman::gadgets::blake2s; -use bellman::gadgets::boolean; -use bellman::gadgets::multipack; -use bellman::gadgets::num; -use bellman::gadgets::Assignment; - -use self::constants::{ - NOTE_COMMITMENT_RANDOMNESS_GENERATOR, NULLIFIER_POSITION_GENERATOR, - PROOF_GENERATION_KEY_GENERATOR, SPENDING_KEY_GENERATOR, VALUE_COMMITMENT_RANDOMNESS_GENERATOR, - VALUE_COMMITMENT_VALUE_GENERATOR, -}; - -#[cfg(test)] -use group::ff::PrimeFieldBits; - -mod constants; -mod ecc; -mod pedersen_hash; - -// π_A + π_B + π_C -pub(crate) const GROTH_PROOF_SIZE: usize = 48 + 96 + 48; - -/// The opening (value and randomness) of a Sapling value commitment. -#[derive(Clone)] -pub struct ValueCommitmentOpening { - pub value: NoteValue, - pub randomness: jubjub::Scalar, -} - -#[cfg(test)] -impl ValueCommitmentOpening { - fn commitment(&self) -> jubjub::ExtendedPoint { - let cv = (super::constants::VALUE_COMMITMENT_VALUE_GENERATOR - * jubjub::Fr::from(self.value.inner())) - + (super::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR * self.randomness); - cv.into() - } -} - -/// This is an instance of the `Spend` circuit. -#[derive(Clone)] -pub struct Spend { - /// The opening of a Pedersen commitment to the value being spent. - pub value_commitment_opening: Option, - - /// Key required to construct proofs for spending notes - /// for a particular spending key - pub proof_generation_key: Option, - - /// The payment address associated with the note - pub payment_address: Option, - - /// The randomness of the note commitment - pub commitment_randomness: Option, - - /// Re-randomization of the public key - pub ar: Option, - - /// The authentication path of the commitment in the tree - pub auth_path: Vec>, - - /// The anchor; the root of the tree. If the note being - /// spent is zero-value, this can be anything. - pub anchor: Option, -} - -impl fmt::Debug for Spend { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Spend") - .field("anchor", &self.anchor) - .finish_non_exhaustive() - } -} - -/// This is an output circuit instance. -#[derive(Clone)] -pub struct Output { - /// The opening of a Pedersen commitment to the value being spent. - pub value_commitment_opening: Option, - - /// The payment address of the recipient - pub payment_address: Option, - - /// The randomness used to hide the note commitment data - pub commitment_randomness: Option, - - /// The ephemeral secret key for DH with recipient - pub esk: Option, -} - -impl fmt::Debug for Output { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Output").finish_non_exhaustive() - } -} - -/// Exposes a Pedersen commitment to the value as an -/// input to the circuit -fn expose_value_commitment( - mut cs: CS, - value_commitment_opening: Option, -) -> Result, SynthesisError> -where - CS: ConstraintSystem, -{ - // Booleanize the value into little-endian bit order - let value_bits = boolean::u64_into_boolean_vec_le( - cs.namespace(|| "value"), - value_commitment_opening.as_ref().map(|c| c.value.inner()), - )?; - - // Compute the note value in the exponent - let value = ecc::fixed_base_multiplication( - cs.namespace(|| "compute the value in the exponent"), - &VALUE_COMMITMENT_VALUE_GENERATOR, - &value_bits, - )?; - - // Booleanize the randomness. This does not ensure - // the bit representation is "in the field" because - // it doesn't matter for security. - let rcv = boolean::field_into_boolean_vec_le( - cs.namespace(|| "rcv"), - value_commitment_opening.as_ref().map(|c| c.randomness), - )?; - - // Compute the randomness in the exponent - let rcv = ecc::fixed_base_multiplication( - cs.namespace(|| "computation of rcv"), - &VALUE_COMMITMENT_RANDOMNESS_GENERATOR, - &rcv, - )?; - - // Compute the Pedersen commitment to the value - let cv = value.add(cs.namespace(|| "computation of cv"), &rcv)?; - - // Expose the commitment as an input to the circuit - cv.inputize(cs.namespace(|| "commitment point"))?; - - Ok(value_bits) -} - -impl Circuit for Spend { - fn synthesize>( - self, - cs: &mut CS, - ) -> Result<(), SynthesisError> { - // Prover witnesses ak (ensures that it's on the curve) - let ak = ecc::EdwardsPoint::witness( - cs.namespace(|| "ak"), - self.proof_generation_key.as_ref().map(|k| (&k.ak).into()), - )?; - - // There are no sensible attacks on small order points - // of ak (that we're aware of!) but it's a cheap check, - // so we do it. - ak.assert_not_small_order(cs.namespace(|| "ak not small order"))?; - - // Rerandomize ak and expose it as an input to the circuit - { - let ar = boolean::field_into_boolean_vec_le(cs.namespace(|| "ar"), self.ar)?; - - // Compute the randomness in the exponent - let ar = ecc::fixed_base_multiplication( - cs.namespace(|| "computation of randomization for the signing key"), - &SPENDING_KEY_GENERATOR, - &ar, - )?; - - let rk = ak.add(cs.namespace(|| "computation of rk"), &ar)?; - - rk.inputize(cs.namespace(|| "rk"))?; - } - - // Compute nk = [nsk] ProofGenerationKey - let nk; - { - // Witness nsk as bits - let nsk = boolean::field_into_boolean_vec_le( - cs.namespace(|| "nsk"), - self.proof_generation_key.as_ref().map(|k| k.nsk), - )?; - - // NB: We don't ensure that the bit representation of nsk - // is "in the field" (jubjub::Fr) because it's not used - // except to demonstrate the prover knows it. If they know - // a congruency then that's equivalent. - - // Compute nk = [nsk] ProvingPublicKey - nk = ecc::fixed_base_multiplication( - cs.namespace(|| "computation of nk"), - &PROOF_GENERATION_KEY_GENERATOR, - &nsk, - )?; - } - - // This is the "viewing key" preimage for CRH^ivk - let mut ivk_preimage = vec![]; - - // Place ak in the preimage for CRH^ivk - ivk_preimage.extend(ak.repr(cs.namespace(|| "representation of ak"))?); - - // This is the nullifier preimage for PRF^nf - let mut nf_preimage = vec![]; - - // Extend ivk and nf preimages with the representation of - // nk. - { - let repr_nk = nk.repr(cs.namespace(|| "representation of nk"))?; - - ivk_preimage.extend(repr_nk.iter().cloned()); - nf_preimage.extend(repr_nk); - } - - assert_eq!(ivk_preimage.len(), 512); - assert_eq!(nf_preimage.len(), 256); - - // Compute the incoming viewing key ivk - let mut ivk = blake2s::blake2s( - cs.namespace(|| "computation of ivk"), - &ivk_preimage, - super::constants::CRH_IVK_PERSONALIZATION, - )?; - - // drop_5 to ensure it's in the field - ivk.truncate(jubjub::Fr::CAPACITY as usize); - - // Witness g_d, checking that it's on the curve. - let g_d = { - ecc::EdwardsPoint::witness( - cs.namespace(|| "witness g_d"), - self.payment_address.as_ref().map(|a| { - a.diversifier() - .g_d() - .expect("checked at construction") - .into() - }), - )? - }; - - // Check that g_d is not small order. Technically, this check - // is already done in the Output circuit, and this proof ensures - // g_d is bound to a product of that check, but for defense in - // depth let's check it anyway. It's cheap. - g_d.assert_not_small_order(cs.namespace(|| "g_d not small order"))?; - - // Compute pk_d = g_d^ivk - let pk_d = g_d.mul(cs.namespace(|| "compute pk_d"), &ivk)?; - - // Compute note contents: - // value (in big endian) followed by g_d and pk_d - let mut note_contents = vec![]; - - // Handle the value; we'll need it later for the - // dummy input check. - let mut value_num = num::Num::zero(); - { - // Get the value in little-endian bit order - let value_bits = expose_value_commitment( - cs.namespace(|| "value commitment"), - self.value_commitment_opening, - )?; - - // Compute the note's value as a linear combination - // of the bits. - let mut coeff = bls12_381::Scalar::one(); - for bit in &value_bits { - value_num = value_num.add_bool_with_coeff(CS::one(), bit, coeff); - coeff = coeff.double(); - } - - // Place the value in the note - note_contents.extend(value_bits); - } - - // Place g_d in the note - note_contents.extend(g_d.repr(cs.namespace(|| "representation of g_d"))?); - - // Place pk_d in the note - note_contents.extend(pk_d.repr(cs.namespace(|| "representation of pk_d"))?); - - assert_eq!( - note_contents.len(), - 64 + // value - 256 + // g_d - 256 // p_d - ); - - // Compute the hash of the note contents - let mut cm = pedersen_hash::pedersen_hash( - cs.namespace(|| "note content hash"), - pedersen_hash::Personalization::NoteCommitment, - ¬e_contents, - )?; - - { - // Booleanize the randomness for the note commitment - let rcm = boolean::field_into_boolean_vec_le( - cs.namespace(|| "rcm"), - self.commitment_randomness, - )?; - - // Compute the note commitment randomness in the exponent - let rcm = ecc::fixed_base_multiplication( - cs.namespace(|| "computation of commitment randomness"), - &NOTE_COMMITMENT_RANDOMNESS_GENERATOR, - &rcm, - )?; - - // Randomize the note commitment. Pedersen hashes are not - // themselves hiding commitments. - cm = cm.add(cs.namespace(|| "randomization of note commitment"), &rcm)?; - } - - // This will store (least significant bit first) - // the position of the note in the tree, for use - // in nullifier computation. - let mut position_bits = vec![]; - - // This is an injective encoding, as cur is a - // point in the prime order subgroup. - let mut cur = cm.get_u().clone(); - - // Ascend the merkle tree authentication path - for (i, e) in self.auth_path.into_iter().enumerate() { - let cs = &mut cs.namespace(|| format!("merkle tree hash {}", i)); - - // Determines if the current subtree is the "right" leaf at this - // depth of the tree. - let cur_is_right = boolean::Boolean::from(boolean::AllocatedBit::alloc( - cs.namespace(|| "position bit"), - e.map(|e| e.1), - )?); - - // Push this boolean for nullifier computation later - position_bits.push(cur_is_right.clone()); - - // Witness the authentication path element adjacent - // at this depth. - let path_element = - num::AllocatedNum::alloc(cs.namespace(|| "path element"), || Ok(e.get()?.0))?; - - // Swap the two if the current subtree is on the right - let (ul, ur) = num::AllocatedNum::conditionally_reverse( - cs.namespace(|| "conditional reversal of preimage"), - &cur, - &path_element, - &cur_is_right, - )?; - - // We don't need to be strict, because the function is - // collision-resistant. If the prover witnesses a congruency, - // they will be unable to find an authentication path in the - // tree with high probability. - let mut preimage = vec![]; - preimage.extend(ul.to_bits_le(cs.namespace(|| "ul into bits"))?); - preimage.extend(ur.to_bits_le(cs.namespace(|| "ur into bits"))?); - - // Compute the new subtree value - cur = pedersen_hash::pedersen_hash( - cs.namespace(|| "computation of pedersen hash"), - pedersen_hash::Personalization::MerkleTree(i), - &preimage, - )? - .get_u() - .clone(); // Injective encoding - } - - { - let real_anchor_value = self.anchor; - - // Allocate the "real" anchor that will be exposed. - let rt = num::AllocatedNum::alloc(cs.namespace(|| "conditional anchor"), || { - Ok(*real_anchor_value.get()?) - })?; - - // (cur - rt) * value = 0 - // if value is zero, cur and rt can be different - // if value is nonzero, they must be equal - cs.enforce( - || "conditionally enforce correct root", - |lc| lc + cur.get_variable() - rt.get_variable(), - |lc| lc + &value_num.lc(bls12_381::Scalar::one()), - |lc| lc, - ); - - // Expose the anchor - rt.inputize(cs.namespace(|| "anchor"))?; - } - - // Compute the cm + g^position for preventing - // faerie gold attacks - let mut rho = cm; - { - // Compute the position in the exponent - let position = ecc::fixed_base_multiplication( - cs.namespace(|| "g^position"), - &NULLIFIER_POSITION_GENERATOR, - &position_bits, - )?; - - // Add the position to the commitment - rho = rho.add(cs.namespace(|| "faerie gold prevention"), &position)?; - } - - // Let's compute nf = BLAKE2s(nk || rho) - nf_preimage.extend(rho.repr(cs.namespace(|| "representation of rho"))?); - - assert_eq!(nf_preimage.len(), 512); - - // Compute nf - let nf = blake2s::blake2s( - cs.namespace(|| "nf computation"), - &nf_preimage, - super::constants::PRF_NF_PERSONALIZATION, - )?; - - multipack::pack_into_inputs(cs.namespace(|| "pack nullifier"), &nf) - } -} - -impl Circuit for Output { - fn synthesize>( - self, - cs: &mut CS, - ) -> Result<(), SynthesisError> { - // Let's start to construct our note, which contains - // value (big endian) - let mut note_contents = vec![]; - - // Expose the value commitment and place the value - // in the note. - note_contents.extend(expose_value_commitment( - cs.namespace(|| "value commitment"), - self.value_commitment_opening, - )?); - - // Let's deal with g_d - { - // Prover witnesses g_d, ensuring it's on the - // curve. - let g_d = ecc::EdwardsPoint::witness( - cs.namespace(|| "witness g_d"), - self.payment_address.as_ref().map(|a| { - a.diversifier() - .g_d() - .expect("checked at construction") - .into() - }), - )?; - - // g_d is ensured to be large order. The relationship - // between g_d and pk_d ultimately binds ivk to the - // note. If this were a small order point, it would - // not do this correctly, and the prover could - // double-spend by finding random ivk's that satisfy - // the relationship. - // - // Further, if it were small order, epk would be - // small order too! - g_d.assert_not_small_order(cs.namespace(|| "g_d not small order"))?; - - // Extend our note contents with the representation of - // g_d. - note_contents.extend(g_d.repr(cs.namespace(|| "representation of g_d"))?); - - // Booleanize our ephemeral secret key - let esk = boolean::field_into_boolean_vec_le(cs.namespace(|| "esk"), self.esk)?; - - // Create the ephemeral public key from g_d. - let epk = g_d.mul(cs.namespace(|| "epk computation"), &esk)?; - - // Expose epk publicly. - epk.inputize(cs.namespace(|| "epk"))?; - } - - // Now let's deal with pk_d. We don't do any checks and - // essentially allow the prover to witness any 256 bits - // they would like. - { - // Just grab pk_d from the witness - let pk_d = self - .payment_address - .as_ref() - .map(|e| jubjub::ExtendedPoint::from(e.pk_d().inner()).to_affine()); - - // Witness the v-coordinate, encoded as little - // endian bits (to match the representation) - let v_contents = boolean::field_into_boolean_vec_le( - cs.namespace(|| "pk_d bits of v"), - pk_d.map(|e| e.get_v()), - )?; - - // Witness the sign bit - let sign_bit = boolean::Boolean::from(boolean::AllocatedBit::alloc( - cs.namespace(|| "pk_d bit of u"), - pk_d.map(|e| e.get_u().is_odd().into()), - )?); - - // Extend the note with pk_d representation - note_contents.extend(v_contents); - note_contents.push(sign_bit); - } - - assert_eq!( - note_contents.len(), - 64 + // value - 256 + // g_d - 256 // pk_d - ); - - // Compute the hash of the note contents - let mut cm = pedersen_hash::pedersen_hash( - cs.namespace(|| "note content hash"), - pedersen_hash::Personalization::NoteCommitment, - ¬e_contents, - )?; - - { - // Booleanize the randomness - let rcm = boolean::field_into_boolean_vec_le( - cs.namespace(|| "rcm"), - self.commitment_randomness, - )?; - - // Compute the note commitment randomness in the exponent - let rcm = ecc::fixed_base_multiplication( - cs.namespace(|| "computation of commitment randomness"), - &NOTE_COMMITMENT_RANDOMNESS_GENERATOR, - &rcm, - )?; - - // Randomize our note commitment - cm = cm.add(cs.namespace(|| "randomization of note commitment"), &rcm)?; - } - - // Only the u-coordinate of the output is revealed, - // since we know it is prime order, and we know that - // the u-coordinate is an injective encoding for - // elements in the prime-order subgroup. - cm.get_u().inputize(cs.namespace(|| "commitment"))?; - - Ok(()) - } -} - -/// The parameters for the Sapling Spend circuit. -pub struct SpendParameters(pub(crate) groth16::Parameters); - -impl SpendParameters { - /// Reads the parameters from their encoding. - /// - /// Only set `verify_point_encodings` to false if you are verifying the parameters in - /// another way (such as checking the hash of the parameters file on disk). - pub fn read(reader: R, verify_point_encodings: bool) -> io::Result { - groth16::Parameters::::read(reader, verify_point_encodings).map(Self) - } - - /// Returns the verifying key for the Sapling Spend circuit. - pub fn verifying_key(&self) -> SpendVerifyingKey { - SpendVerifyingKey(self.0.vk.clone()) - } - - /// Returns the verifying key for the Sapling Spend circuit, with precomputations - /// optimized for verifying individual proofs. - pub fn prepared_verifying_key(&self) -> PreparedSpendVerifyingKey { - PreparedSpendVerifyingKey(groth16::prepare_verifying_key(&self.0.vk)) - } -} - -/// The verifying key for the Sapling Spend circuit. -pub struct SpendVerifyingKey(pub(crate) groth16::VerifyingKey); - -impl SpendVerifyingKey { - /// Performs precomputations optimized for verifying individual proofs. - pub fn prepare(&self) -> PreparedSpendVerifyingKey { - PreparedSpendVerifyingKey(groth16::prepare_verifying_key(&self.0)) - } -} - -/// The verifying key for the Sapling Spend circuit, with precomputations optimized for -/// verifying individual proofs. -pub struct PreparedSpendVerifyingKey(pub(crate) groth16::PreparedVerifyingKey); - -/// The parameters for the Sapling Output circuit. -pub struct OutputParameters(pub(crate) groth16::Parameters); - -impl OutputParameters { - /// Reads the parameters from their encoding. - /// - /// Only set `verify_point_encodings` to false if you are verifying the parameters in - /// another way (such as checking the hash of the parameters file on disk). - pub fn read(reader: R, verify_point_encodings: bool) -> io::Result { - groth16::Parameters::::read(reader, verify_point_encodings).map(Self) - } - - /// Returns the verifying key for the Sapling Output circuit. - pub fn verifying_key(&self) -> OutputVerifyingKey { - OutputVerifyingKey(self.0.vk.clone()) - } - - /// Returns the verifying key for the Sapling Output circuit, with precomputations - /// optimized for verifying individual proofs. - pub fn prepared_verifying_key(&self) -> PreparedOutputVerifyingKey { - PreparedOutputVerifyingKey(groth16::prepare_verifying_key(&self.0.vk)) - } -} - -/// The verifying key for the Sapling Output circuit. -pub struct OutputVerifyingKey(pub(crate) groth16::VerifyingKey); - -impl OutputVerifyingKey { - /// Performs precomputations optimized for verifying individual proofs. - pub fn prepare(&self) -> PreparedOutputVerifyingKey { - PreparedOutputVerifyingKey(groth16::prepare_verifying_key(&self.0)) - } -} - -/// The verifying key for the Sapling Output circuit, with precomputations optimized for -/// verifying individual proofs. -pub struct PreparedOutputVerifyingKey(pub(crate) groth16::PreparedVerifyingKey); - -#[test] -fn test_input_circuit_with_bls12_381() { - use crate::sapling::{ - keys::SpendValidatingKey, pedersen_hash, Diversifier, Note, ProofGenerationKey, Rseed, - }; - - use bellman::gadgets::test::*; - use group::ff::Field; - use rand_core::{RngCore, SeedableRng}; - use rand_xorshift::XorShiftRng; - - let mut rng = XorShiftRng::from_seed([ - 0x58, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let tree_depth = 32; - - for _ in 0..10 { - let value_commitment = ValueCommitmentOpening { - value: NoteValue::from_raw(rng.next_u64()), - randomness: jubjub::Fr::random(&mut rng), - }; - - let proof_generation_key = ProofGenerationKey { - ak: SpendValidatingKey::fake_random(&mut rng), - nsk: jubjub::Fr::random(&mut rng), - }; - - let viewing_key = proof_generation_key.to_viewing_key(); - - let payment_address; - - loop { - let diversifier = { - let mut d = [0; 11]; - rng.fill_bytes(&mut d); - Diversifier(d) - }; - - if let Some(p) = viewing_key.to_payment_address(diversifier) { - payment_address = p; - break; - } - } - - let commitment_randomness = jubjub::Fr::random(&mut rng); - let auth_path = - vec![Some((bls12_381::Scalar::random(&mut rng), rng.next_u32() % 2 != 0)); tree_depth]; - let ar = jubjub::Fr::random(&mut rng); - - { - let rk = jubjub::AffinePoint::from_bytes(viewing_key.rk(ar).into()).unwrap(); - let expected_value_commitment = value_commitment.commitment().to_affine(); - let note = Note::from_parts( - payment_address, - value_commitment.value, - Rseed::BeforeZip212(commitment_randomness), - ); - - let mut position = 0u64; - let cmu = note.cmu(); - let mut cur = bls12_381::Scalar::from_bytes(&cmu.to_bytes()).unwrap(); - - for (i, val) in auth_path.clone().into_iter().enumerate() { - let (uncle, b) = val.unwrap(); - - let mut lhs = cur; - let mut rhs = uncle; - - if b { - ::std::mem::swap(&mut lhs, &mut rhs); - } - - let lhs = lhs.to_le_bits(); - let rhs = rhs.to_le_bits(); - - cur = jubjub::ExtendedPoint::from(pedersen_hash::pedersen_hash( - pedersen_hash::Personalization::MerkleTree(i), - lhs.iter() - .by_vals() - .take(bls12_381::Scalar::NUM_BITS as usize) - .chain( - rhs.iter() - .by_vals() - .take(bls12_381::Scalar::NUM_BITS as usize), - ), - )) - .to_affine() - .get_u(); - - if b { - position |= 1 << i; - } - } - - let expected_nf = note.nf(&viewing_key.nk, position); - let expected_nf = multipack::bytes_to_bits_le(&expected_nf.0); - let expected_nf = multipack::compute_multipacking(&expected_nf); - assert_eq!(expected_nf.len(), 2); - - let mut cs = TestConstraintSystem::new(); - - let instance = Spend { - value_commitment_opening: Some(value_commitment.clone()), - proof_generation_key: Some(proof_generation_key.clone()), - payment_address: Some(payment_address), - commitment_randomness: Some(commitment_randomness), - ar: Some(ar), - auth_path: auth_path.clone(), - anchor: Some(cur), - }; - - instance.synthesize(&mut cs).unwrap(); - - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 98777); - assert_eq!( - cs.hash(), - "d37c738e83df5d9b0bb6495ac96abf21bcb2697477e2c15c2c7916ff7a3b6a89" - ); - - assert_eq!( - cs.get("randomization of note commitment/u3/num").to_repr(), - cmu.to_bytes() - ); - - assert_eq!(cs.num_inputs(), 8); - assert_eq!(cs.get_input(0, "ONE"), bls12_381::Scalar::one()); - assert_eq!(cs.get_input(1, "rk/u/input variable"), rk.get_u()); - assert_eq!(cs.get_input(2, "rk/v/input variable"), rk.get_v()); - assert_eq!( - cs.get_input(3, "value commitment/commitment point/u/input variable"), - expected_value_commitment.get_u() - ); - assert_eq!( - cs.get_input(4, "value commitment/commitment point/v/input variable"), - expected_value_commitment.get_v() - ); - assert_eq!( - cs.get_input(5, "anchor/input variable").to_repr(), - cur.to_bytes() - ); - assert_eq!(cs.get_input(6, "pack nullifier/input 0"), expected_nf[0]); - assert_eq!(cs.get_input(7, "pack nullifier/input 1"), expected_nf[1]); - } - } -} - -#[test] -fn test_input_circuit_with_bls12_381_external_test_vectors() { - use crate::sapling::{ - keys::SpendValidatingKey, pedersen_hash, Diversifier, Note, ProofGenerationKey, Rseed, - }; - - use bellman::gadgets::test::*; - use group::ff::Field; - use rand_core::{RngCore, SeedableRng}; - use rand_xorshift::XorShiftRng; - - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let tree_depth = 32; - - let expected_commitment_us = vec![ - "43821661663052659750276289184181083197337192946256245809816728673021647664276", - "7220807656052227578299730541645543434083158611414003423211850718229633594616", - "13239753550660714843257636471668037031928211668773449453628093339627668081697", - "10900524635678389360790699587556574797582192824300145558807405770494079767974", - "1411013767457690636461779630023011774660680126764323588543800715293173598850", - "32334206652383066267661379202183359608706535021387905923603014648832344657662", - "20206750741605167608500278423400565295188703622528437817438897624149653579380", - "46716485782200334735478719487356079850582051575003452698983255860512578229998", - "31221372899739042781372142393132358519434268512685538373976981051223051220367", - "18269767207277008186871145355531741929166733260352590789136389380124992250945", - ]; - - let expected_commitment_vs = vec![ - "27630722367128086497290371604583225252915685718989450292520883698391703910", - "23310648738313092772044712773481584369462075017189681529702825235349449805260", - "25709635353183537915646348052945798827495141780341329896098121888376871589480", - "10516315852014492141081718791576479298042117442649432716255936672048164184691", - "23970713991179488695004801139667700217127937225554773561645815034212389459772", - "3256052161046564597126736968199320852691566092694819239485673781545479548450", - "18887250722195819674378865377623103071236046274361890247643850134985809137409", - "36501156873031641173054592888886902104303750771545647842488588827138867116570", - "21927526310070011864833939629345235038589128172309792087590183778192091594775", - "32959334601512756708397683646222389414681003290313255304927423560477040775488", - ]; - - for i in 0..10 { - let value_commitment = ValueCommitmentOpening { - value: NoteValue::from_raw(i), - randomness: jubjub::Fr::from(1000 * (i + 1)), - }; - - let proof_generation_key = ProofGenerationKey { - ak: SpendValidatingKey::fake_random(&mut rng), - nsk: jubjub::Fr::random(&mut rng), - }; - - let viewing_key = proof_generation_key.to_viewing_key(); - - let payment_address; - - loop { - let diversifier = { - let mut d = [0; 11]; - rng.fill_bytes(&mut d); - Diversifier(d) - }; - - if let Some(p) = viewing_key.to_payment_address(diversifier) { - payment_address = p; - break; - } - } - - let commitment_randomness = jubjub::Fr::random(&mut rng); - let auth_path = - vec![Some((bls12_381::Scalar::random(&mut rng), rng.next_u32() % 2 != 0)); tree_depth]; - let ar = jubjub::Fr::random(&mut rng); - - { - let rk = jubjub::AffinePoint::from_bytes(viewing_key.rk(ar).into()).unwrap(); - let expected_value_commitment = value_commitment.commitment().to_affine(); - assert_eq!( - expected_value_commitment.get_u(), - bls12_381::Scalar::from_str_vartime(expected_commitment_us[i as usize]).unwrap() - ); - assert_eq!( - expected_value_commitment.get_v(), - bls12_381::Scalar::from_str_vartime(expected_commitment_vs[i as usize]).unwrap() - ); - let note = Note::from_parts( - payment_address, - value_commitment.value, - Rseed::BeforeZip212(commitment_randomness), - ); - - let mut position = 0u64; - let cmu = note.cmu(); - let mut cur = bls12_381::Scalar::from_bytes(&cmu.to_bytes()).unwrap(); - - for (i, val) in auth_path.clone().into_iter().enumerate() { - let (uncle, b) = val.unwrap(); - - let mut lhs = cur; - let mut rhs = uncle; - - if b { - ::std::mem::swap(&mut lhs, &mut rhs); - } - - let lhs = lhs.to_le_bits(); - let rhs = rhs.to_le_bits(); - - cur = jubjub::ExtendedPoint::from(pedersen_hash::pedersen_hash( - pedersen_hash::Personalization::MerkleTree(i), - lhs.iter() - .by_vals() - .take(bls12_381::Scalar::NUM_BITS as usize) - .chain( - rhs.iter() - .by_vals() - .take(bls12_381::Scalar::NUM_BITS as usize), - ), - )) - .to_affine() - .get_u(); - - if b { - position |= 1 << i; - } - } - - let expected_nf = note.nf(&viewing_key.nk, position); - let expected_nf = multipack::bytes_to_bits_le(&expected_nf.0); - let expected_nf = multipack::compute_multipacking(&expected_nf); - assert_eq!(expected_nf.len(), 2); - - let mut cs = TestConstraintSystem::new(); - - let instance = Spend { - value_commitment_opening: Some(value_commitment.clone()), - proof_generation_key: Some(proof_generation_key.clone()), - payment_address: Some(payment_address), - commitment_randomness: Some(commitment_randomness), - ar: Some(ar), - auth_path: auth_path.clone(), - anchor: Some(cur), - }; - - instance.synthesize(&mut cs).unwrap(); - - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 98777); - assert_eq!( - cs.hash(), - "d37c738e83df5d9b0bb6495ac96abf21bcb2697477e2c15c2c7916ff7a3b6a89" - ); - - assert_eq!( - cs.get("randomization of note commitment/u3/num").to_repr(), - cmu.to_bytes() - ); - - assert_eq!(cs.num_inputs(), 8); - assert_eq!(cs.get_input(0, "ONE"), bls12_381::Scalar::one()); - assert_eq!(cs.get_input(1, "rk/u/input variable"), rk.get_u()); - assert_eq!(cs.get_input(2, "rk/v/input variable"), rk.get_v()); - assert_eq!( - cs.get_input(3, "value commitment/commitment point/u/input variable"), - expected_value_commitment.get_u() - ); - assert_eq!( - cs.get_input(4, "value commitment/commitment point/v/input variable"), - expected_value_commitment.get_v() - ); - assert_eq!( - cs.get_input(5, "anchor/input variable").to_repr(), - cur.to_bytes() - ); - assert_eq!(cs.get_input(6, "pack nullifier/input 0"), expected_nf[0]); - assert_eq!(cs.get_input(7, "pack nullifier/input 1"), expected_nf[1]); - } - } -} - -#[test] -fn test_output_circuit_with_bls12_381() { - use crate::sapling::{keys::SpendValidatingKey, Diversifier, ProofGenerationKey, Rseed}; - - use bellman::gadgets::test::*; - use group::ff::Field; - use rand_core::{RngCore, SeedableRng}; - use rand_xorshift::XorShiftRng; - - let mut rng = XorShiftRng::from_seed([ - 0x58, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..100 { - let value_commitment = ValueCommitmentOpening { - value: NoteValue::from_raw(rng.next_u64()), - randomness: jubjub::Fr::random(&mut rng), - }; - - let nsk = jubjub::Fr::random(&mut rng); - let ak = SpendValidatingKey::fake_random(&mut rng); - - let proof_generation_key = ProofGenerationKey { ak, nsk }; - - let viewing_key = proof_generation_key.to_viewing_key(); - - let payment_address; - - loop { - let diversifier = { - let mut d = [0; 11]; - rng.fill_bytes(&mut d); - Diversifier(d) - }; - - if let Some(p) = viewing_key.to_payment_address(diversifier) { - payment_address = p; - break; - } - } - - let commitment_randomness = jubjub::Fr::random(&mut rng); - let esk = jubjub::Fr::random(&mut rng); - - { - let mut cs = TestConstraintSystem::new(); - - let instance = Output { - value_commitment_opening: Some(value_commitment.clone()), - payment_address: Some(payment_address), - commitment_randomness: Some(commitment_randomness), - esk: Some(esk), - }; - - instance.synthesize(&mut cs).unwrap(); - - assert!(cs.is_satisfied()); - assert_eq!(cs.num_constraints(), 7827); - assert_eq!( - cs.hash(), - "c26d5cdfe6ccd65c03390902c02e11393ea6bb96aae32a7f2ecb12eb9103faee" - ); - - let expected_cmu = payment_address - .create_note( - value_commitment.value, - Rseed::BeforeZip212(commitment_randomness), - ) - .cmu(); - - let expected_value_commitment = value_commitment.commitment().to_affine(); - - let expected_epk = jubjub::ExtendedPoint::from( - payment_address - .diversifier() - .g_d() - .expect("should be valid") - * esk, - ) - .to_affine(); - - assert_eq!(cs.num_inputs(), 6); - assert_eq!(cs.get_input(0, "ONE"), bls12_381::Scalar::one()); - assert_eq!( - cs.get_input(1, "value commitment/commitment point/u/input variable"), - expected_value_commitment.get_u() - ); - assert_eq!( - cs.get_input(2, "value commitment/commitment point/v/input variable"), - expected_value_commitment.get_v() - ); - assert_eq!( - cs.get_input(3, "epk/u/input variable"), - expected_epk.get_u() - ); - assert_eq!( - cs.get_input(4, "epk/v/input variable"), - expected_epk.get_v() - ); - assert_eq!( - cs.get_input(5, "commitment/input variable").to_repr(), - expected_cmu.to_bytes() - ); - } - } -} diff --git a/zcash_primitives/src/sapling/circuit/constants.rs b/zcash_primitives/src/sapling/circuit/constants.rs deleted file mode 100644 index d7afaeaa3..000000000 --- a/zcash_primitives/src/sapling/circuit/constants.rs +++ /dev/null @@ -1,195 +0,0 @@ -//! Various constants used for the Zcash proofs. - -use crate::sapling::constants::{PEDERSEN_HASH_CHUNKS_PER_GENERATOR, PEDERSEN_HASH_GENERATORS}; -use bls12_381::Scalar; -use group::{ff::Field, Curve, Group}; -use jubjub::ExtendedPoint; -use lazy_static::lazy_static; - -/// The `d` constant of the twisted Edwards curve. -pub(crate) const EDWARDS_D: Scalar = Scalar::from_raw([ - 0x0106_5fd6_d634_3eb1, - 0x292d_7f6d_3757_9d26, - 0xf5fd_9207_e6bd_7fd4, - 0x2a93_18e7_4bfa_2b48, -]); - -/// The `A` constant of the birationally equivalent Montgomery curve. -pub(crate) const MONTGOMERY_A: Scalar = Scalar::from_raw([ - 0x0000_0000_0000_a002, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, -]); - -/// The scaling factor used for conversion to and from the Montgomery form. -pub(crate) const MONTGOMERY_SCALE: Scalar = Scalar::from_raw([ - 0x8f45_35f7_cf82_b8d9, - 0xce40_6970_3da8_8abd, - 0x31de_341e_77d7_64e5, - 0x2762_de61_e862_645e, -]); - -/// The number of chunks needed to represent a full scalar during fixed-base -/// exponentiation. -const FIXED_BASE_CHUNKS_PER_GENERATOR: usize = 84; - -/// Reference to a circuit version of a generator for fixed-base salar multiplication. -pub type FixedGenerator = &'static [Vec<(Scalar, Scalar)>]; - -/// Circuit version of a generator for fixed-base salar multiplication. -pub type FixedGeneratorOwned = Vec>; - -lazy_static! { - pub static ref PROOF_GENERATION_KEY_GENERATOR: FixedGeneratorOwned = - generate_circuit_generator(crate::sapling::constants::PROOF_GENERATION_KEY_GENERATOR); - - pub static ref NOTE_COMMITMENT_RANDOMNESS_GENERATOR: FixedGeneratorOwned = - generate_circuit_generator(crate::sapling::constants::NOTE_COMMITMENT_RANDOMNESS_GENERATOR); - - pub static ref NULLIFIER_POSITION_GENERATOR: FixedGeneratorOwned = - generate_circuit_generator(crate::sapling::constants::NULLIFIER_POSITION_GENERATOR); - - pub static ref VALUE_COMMITMENT_VALUE_GENERATOR: FixedGeneratorOwned = - generate_circuit_generator(crate::sapling::constants::VALUE_COMMITMENT_VALUE_GENERATOR); - - pub static ref VALUE_COMMITMENT_RANDOMNESS_GENERATOR: FixedGeneratorOwned = - generate_circuit_generator(crate::sapling::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR); - - pub static ref SPENDING_KEY_GENERATOR: FixedGeneratorOwned = - generate_circuit_generator(crate::sapling::constants::SPENDING_KEY_GENERATOR); - - /// The pre-computed window tables `[-4, 3, 2, 1, 1, 2, 3, 4]` of different magnitudes - /// of the Pedersen hash segment generators. - pub(crate) static ref PEDERSEN_CIRCUIT_GENERATORS: Vec>> = - generate_pedersen_circuit_generators(); -} - -/// Creates the 3-bit window table `[0, 1, ..., 8]` for different magnitudes of a fixed -/// generator. -pub fn generate_circuit_generator(mut gen: jubjub::SubgroupPoint) -> FixedGeneratorOwned { - let mut windows = vec![]; - - for _ in 0..FIXED_BASE_CHUNKS_PER_GENERATOR { - let mut coeffs = vec![(Scalar::zero(), Scalar::one())]; - let mut g = gen; - for _ in 0..7 { - let g_affine = jubjub::ExtendedPoint::from(g).to_affine(); - coeffs.push((g_affine.get_u(), g_affine.get_v())); - g += gen; - } - windows.push(coeffs); - - // gen = gen * 8 - gen = g; - } - - windows -} - -/// Returns the coordinates of this point's Montgomery curve representation, or `None` if -/// it is the point at infinity. -#[allow(clippy::many_single_char_names)] -pub(crate) fn to_montgomery_coords(g: ExtendedPoint) -> Option<(Scalar, Scalar)> { - let g = g.to_affine(); - let (x, y) = (g.get_u(), g.get_v()); - - if y == Scalar::one() { - // The only solution for y = 1 is x = 0. (0, 1) is the neutral element, so we map - // this to the point at infinity. - None - } else { - // The map from a twisted Edwards curve is defined as - // (x, y) -> (u, v) where - // u = (1 + y) / (1 - y) - // v = u / x - // - // This mapping is not defined for y = 1 and for x = 0. - // - // We have that y != 1 above. If x = 0, the only - // solutions for y are 1 (contradiction) or -1. - if x.is_zero_vartime() { - // (0, -1) is the point of order two which is not - // the neutral element, so we map it to (0, 0) which is - // the only affine point of order 2. - Some((Scalar::zero(), Scalar::zero())) - } else { - // The mapping is defined as above. - // - // (x, y) -> (u, v) where - // u = (1 + y) / (1 - y) - // v = u / x - - let u = (Scalar::one() + y) * (Scalar::one() - y).invert().unwrap(); - let v = u * x.invert().unwrap(); - - // Scale it into the correct curve constants - // scaling factor = sqrt(4 / (a - d)) - Some((u, v * MONTGOMERY_SCALE)) - } - } -} - -/// Creates the 2-bit window table lookups for each 4-bit "chunk" in each segment of the -/// Pedersen hash. -fn generate_pedersen_circuit_generators() -> Vec>> { - // Process each segment - PEDERSEN_HASH_GENERATORS - .iter() - .cloned() - .map(|mut gen| { - let mut windows = vec![]; - - for _ in 0..PEDERSEN_HASH_CHUNKS_PER_GENERATOR { - // Create (x, y) coeffs for this chunk - let mut coeffs = vec![]; - let mut g = gen; - - // coeffs = g, g*2, g*3, g*4 - for _ in 0..4 { - coeffs.push( - to_montgomery_coords(g.into()) - .expect("we never encounter the point at infinity"), - ); - g += gen; - } - windows.push(coeffs); - - // Our chunks are separated by 2 bits to prevent overlap. - for _ in 0..4 { - gen = gen.double(); - } - } - - windows - }) - .collect() -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn edwards_d() { - // d = -(10240/10241) - assert_eq!( - -Scalar::from(10240) * Scalar::from(10241).invert().unwrap(), - EDWARDS_D - ); - } - - #[test] - fn montgomery_a() { - assert_eq!(Scalar::from(40962), MONTGOMERY_A); - } - - #[test] - fn montgomery_scale() { - // scaling factor = sqrt(4 / (a - d)) - assert_eq!( - MONTGOMERY_SCALE.square() * (-Scalar::one() - EDWARDS_D), - Scalar::from(4), - ); - } -} diff --git a/zcash_primitives/src/sapling/circuit/ecc.rs b/zcash_primitives/src/sapling/circuit/ecc.rs deleted file mode 100644 index b61f5e222..000000000 --- a/zcash_primitives/src/sapling/circuit/ecc.rs +++ /dev/null @@ -1,1117 +0,0 @@ -//! Gadgets implementing Jubjub elliptic curve operations. - -use std::ops::{AddAssign, MulAssign, Neg, SubAssign}; - -use bellman::{ConstraintSystem, SynthesisError}; - -use bellman::gadgets::Assignment; - -use bellman::gadgets::num::{AllocatedNum, Num}; - -use bellman::gadgets::lookup::lookup3_xy; - -use bellman::gadgets::boolean::Boolean; - -use group::Curve; - -use super::constants::{FixedGenerator, EDWARDS_D, MONTGOMERY_A, MONTGOMERY_SCALE}; - -#[derive(Clone)] -pub struct EdwardsPoint { - u: AllocatedNum, - v: AllocatedNum, -} - -/// Perform a fixed-base scalar multiplication with -/// `by` being in little-endian bit order. -pub fn fixed_base_multiplication( - mut cs: CS, - base: FixedGenerator, - by: &[Boolean], -) -> Result -where - CS: ConstraintSystem, -{ - // Represents the result of the multiplication - let mut result = None; - - for (i, (chunk, window)) in by.chunks(3).zip(base.iter()).enumerate() { - let chunk_a = chunk - .get(0) - .cloned() - .unwrap_or_else(|| Boolean::constant(false)); - let chunk_b = chunk - .get(1) - .cloned() - .unwrap_or_else(|| Boolean::constant(false)); - let chunk_c = chunk - .get(2) - .cloned() - .unwrap_or_else(|| Boolean::constant(false)); - - // TODO: rename to lookup3_uv - let (u, v) = lookup3_xy( - cs.namespace(|| format!("window table lookup {}", i)), - &[chunk_a, chunk_b, chunk_c], - window, - )?; - - let p = EdwardsPoint { u, v }; - - if result.is_none() { - result = Some(p); - } else { - result = Some( - result - .unwrap() - .add(cs.namespace(|| format!("addition {}", i)), &p)?, - ); - } - } - - Ok(result.get()?.clone()) -} - -impl EdwardsPoint { - pub fn get_u(&self) -> &AllocatedNum { - &self.u - } - - #[cfg(test)] - pub fn get_v(&self) -> &AllocatedNum { - &self.v - } - - pub fn assert_not_small_order(&self, mut cs: CS) -> Result<(), SynthesisError> - where - CS: ConstraintSystem, - { - let tmp = self.double(cs.namespace(|| "first doubling"))?; - let tmp = tmp.double(cs.namespace(|| "second doubling"))?; - let tmp = tmp.double(cs.namespace(|| "third doubling"))?; - - // (0, -1) is a small order point, but won't ever appear here - // because cofactor is 2^3, and we performed three doublings. - // (0, 1) is the neutral element, so checking if u is nonzero - // is sufficient to prevent small order points here. - tmp.u.assert_nonzero(cs.namespace(|| "check u != 0"))?; - - Ok(()) - } - - pub fn inputize(&self, mut cs: CS) -> Result<(), SynthesisError> - where - CS: ConstraintSystem, - { - self.u.inputize(cs.namespace(|| "u"))?; - self.v.inputize(cs.namespace(|| "v"))?; - - Ok(()) - } - - /// This converts the point into a representation. - pub fn repr(&self, mut cs: CS) -> Result, SynthesisError> - where - CS: ConstraintSystem, - { - let mut tmp = vec![]; - - let u = self.u.to_bits_le_strict(cs.namespace(|| "unpack u"))?; - - let v = self.v.to_bits_le_strict(cs.namespace(|| "unpack v"))?; - - tmp.extend(v); - tmp.push(u[0].clone()); - - Ok(tmp) - } - - /// This 'witnesses' a point inside the constraint system. - /// It guarantees the point is on the curve. - pub fn witness(mut cs: CS, p: Option) -> Result - where - CS: ConstraintSystem, - { - let p = p.map(|p| p.to_affine()); - - // Allocate u - let u = AllocatedNum::alloc(cs.namespace(|| "u"), || Ok(p.get()?.get_u()))?; - - // Allocate v - let v = AllocatedNum::alloc(cs.namespace(|| "v"), || Ok(p.get()?.get_v()))?; - - Self::interpret(cs.namespace(|| "point interpretation"), &u, &v) - } - - /// Returns `self` if condition is true, and the neutral - /// element (0, 1) otherwise. - pub fn conditionally_select( - &self, - mut cs: CS, - condition: &Boolean, - ) -> Result - where - CS: ConstraintSystem, - { - // Compute u' = self.u if condition, and 0 otherwise - let u_prime = AllocatedNum::alloc(cs.namespace(|| "u'"), || { - if *condition.get_value().get()? { - Ok(*self.u.get_value().get()?) - } else { - Ok(bls12_381::Scalar::zero()) - } - })?; - - // condition * u = u' - // if condition is 0, u' must be 0 - // if condition is 1, u' must be u - let one = CS::one(); - cs.enforce( - || "u' computation", - |lc| lc + self.u.get_variable(), - |_| condition.lc(one, bls12_381::Scalar::one()), - |lc| lc + u_prime.get_variable(), - ); - - // Compute v' = self.v if condition, and 1 otherwise - let v_prime = AllocatedNum::alloc(cs.namespace(|| "v'"), || { - if *condition.get_value().get()? { - Ok(*self.v.get_value().get()?) - } else { - Ok(bls12_381::Scalar::one()) - } - })?; - - // condition * v = v' - (1 - condition) - // if condition is 0, v' must be 1 - // if condition is 1, v' must be v - cs.enforce( - || "v' computation", - |lc| lc + self.v.get_variable(), - |_| condition.lc(one, bls12_381::Scalar::one()), - |lc| lc + v_prime.get_variable() - &condition.not().lc(one, bls12_381::Scalar::one()), - ); - - Ok(EdwardsPoint { - u: u_prime, - v: v_prime, - }) - } - - /// Performs a scalar multiplication of this twisted Edwards - /// point by a scalar represented as a sequence of booleans - /// in little-endian bit order. - pub fn mul(&self, mut cs: CS, by: &[Boolean]) -> Result - where - CS: ConstraintSystem, - { - // Represents the current "magnitude" of the base - // that we're operating over. Starts at self, - // then 2*self, then 4*self, ... - let mut curbase = None; - - // Represents the result of the multiplication - let mut result = None; - - for (i, bit) in by.iter().enumerate() { - if curbase.is_none() { - curbase = Some(self.clone()); - } else { - // Double the previous value - curbase = Some( - curbase - .unwrap() - .double(cs.namespace(|| format!("doubling {}", i)))?, - ); - } - - // Represents the select base. If the bit for this magnitude - // is true, this will return `curbase`. Otherwise it will - // return the neutral element, which will have no effect on - // the result. - let thisbase = curbase - .as_ref() - .unwrap() - .conditionally_select(cs.namespace(|| format!("selection {}", i)), bit)?; - - if result.is_none() { - result = Some(thisbase); - } else { - result = Some( - result - .unwrap() - .add(cs.namespace(|| format!("addition {}", i)), &thisbase)?, - ); - } - } - - Ok(result.get()?.clone()) - } - - pub fn interpret( - mut cs: CS, - u: &AllocatedNum, - v: &AllocatedNum, - ) -> Result - where - CS: ConstraintSystem, - { - // -u^2 + v^2 = 1 + du^2v^2 - - let u2 = u.square(cs.namespace(|| "u^2"))?; - let v2 = v.square(cs.namespace(|| "v^2"))?; - let u2v2 = u2.mul(cs.namespace(|| "u^2 v^2"), &v2)?; - - let one = CS::one(); - cs.enforce( - || "on curve check", - |lc| lc - u2.get_variable() + v2.get_variable(), - |lc| lc + one, - |lc| lc + one + (EDWARDS_D, u2v2.get_variable()), - ); - - Ok(EdwardsPoint { - u: u.clone(), - v: v.clone(), - }) - } - - pub fn double(&self, mut cs: CS) -> Result - where - CS: ConstraintSystem, - { - // Compute T = (u + v) * (v - EDWARDS_A*u) - // = (u + v) * (u + v) - let t = AllocatedNum::alloc(cs.namespace(|| "T"), || { - let mut t0 = *self.u.get_value().get()?; - t0.add_assign(self.v.get_value().get()?); - - let mut t1 = *self.u.get_value().get()?; - t1.add_assign(self.v.get_value().get()?); - - t0.mul_assign(&t1); - - Ok(t0) - })?; - - cs.enforce( - || "T computation", - |lc| lc + self.u.get_variable() + self.v.get_variable(), - |lc| lc + self.u.get_variable() + self.v.get_variable(), - |lc| lc + t.get_variable(), - ); - - // Compute A = u * v - let a = self.u.mul(cs.namespace(|| "A computation"), &self.v)?; - - // Compute C = d*A*A - let c = AllocatedNum::alloc(cs.namespace(|| "C"), || { - let mut t0 = a.get_value().get()?.square(); - t0.mul_assign(EDWARDS_D); - - Ok(t0) - })?; - - cs.enforce( - || "C computation", - |lc| lc + (EDWARDS_D, a.get_variable()), - |lc| lc + a.get_variable(), - |lc| lc + c.get_variable(), - ); - - // Compute u3 = (2.A) / (1 + C) - let u3 = AllocatedNum::alloc(cs.namespace(|| "u3"), || { - let mut t0 = *a.get_value().get()?; - t0 = t0.double(); - - let mut t1 = bls12_381::Scalar::one(); - t1.add_assign(c.get_value().get()?); - - let res = t1.invert().map(|t1| t0 * t1); - if bool::from(res.is_some()) { - Ok(res.unwrap()) - } else { - Err(SynthesisError::DivisionByZero) - } - })?; - - let one = CS::one(); - cs.enforce( - || "u3 computation", - |lc| lc + one + c.get_variable(), - |lc| lc + u3.get_variable(), - |lc| lc + a.get_variable() + a.get_variable(), - ); - - // Compute v3 = (T + (EDWARDS_A-1)*A) / (1 - C) - // = (T - 2.A) / (1 - C) - let v3 = AllocatedNum::alloc(cs.namespace(|| "v3"), || { - let mut t0 = *a.get_value().get()?; - t0 = t0.double().neg(); - t0.add_assign(t.get_value().get()?); - - let mut t1 = bls12_381::Scalar::one(); - t1.sub_assign(c.get_value().get()?); - - let res = t1.invert().map(|t1| t0 * t1); - if bool::from(res.is_some()) { - Ok(res.unwrap()) - } else { - Err(SynthesisError::DivisionByZero) - } - })?; - - cs.enforce( - || "v3 computation", - |lc| lc + one - c.get_variable(), - |lc| lc + v3.get_variable(), - |lc| lc + t.get_variable() - a.get_variable() - a.get_variable(), - ); - - Ok(EdwardsPoint { u: u3, v: v3 }) - } - - /// Perform addition between any two points - pub fn add(&self, mut cs: CS, other: &Self) -> Result - where - CS: ConstraintSystem, - { - // Compute U = (u1 + v1) * (v2 - EDWARDS_A*u2) - // = (u1 + v1) * (u2 + v2) - // (In hindsight, U was a poor choice of name.) - let uppercase_u = AllocatedNum::alloc(cs.namespace(|| "U"), || { - let mut t0 = *self.u.get_value().get()?; - t0.add_assign(self.v.get_value().get()?); - - let mut t1 = *other.u.get_value().get()?; - t1.add_assign(other.v.get_value().get()?); - - t0.mul_assign(&t1); - - Ok(t0) - })?; - - cs.enforce( - || "U computation", - |lc| lc + self.u.get_variable() + self.v.get_variable(), - |lc| lc + other.u.get_variable() + other.v.get_variable(), - |lc| lc + uppercase_u.get_variable(), - ); - - // Compute A = v2 * u1 - let a = other.v.mul(cs.namespace(|| "A computation"), &self.u)?; - - // Compute B = u2 * v1 - let b = other.u.mul(cs.namespace(|| "B computation"), &self.v)?; - - // Compute C = d*A*B - let c = AllocatedNum::alloc(cs.namespace(|| "C"), || { - let mut t0 = *a.get_value().get()?; - t0.mul_assign(b.get_value().get()?); - t0.mul_assign(EDWARDS_D); - - Ok(t0) - })?; - - cs.enforce( - || "C computation", - |lc| lc + (EDWARDS_D, a.get_variable()), - |lc| lc + b.get_variable(), - |lc| lc + c.get_variable(), - ); - - // Compute u3 = (A + B) / (1 + C) - let u3 = AllocatedNum::alloc(cs.namespace(|| "u3"), || { - let mut t0 = *a.get_value().get()?; - t0.add_assign(b.get_value().get()?); - - let mut t1 = bls12_381::Scalar::one(); - t1.add_assign(c.get_value().get()?); - - let ret = t1.invert().map(|t1| t0 * t1); - if bool::from(ret.is_some()) { - Ok(ret.unwrap()) - } else { - Err(SynthesisError::DivisionByZero) - } - })?; - - let one = CS::one(); - cs.enforce( - || "u3 computation", - |lc| lc + one + c.get_variable(), - |lc| lc + u3.get_variable(), - |lc| lc + a.get_variable() + b.get_variable(), - ); - - // Compute v3 = (U - A - B) / (1 - C) - let v3 = AllocatedNum::alloc(cs.namespace(|| "v3"), || { - let mut t0 = *uppercase_u.get_value().get()?; - t0.sub_assign(a.get_value().get()?); - t0.sub_assign(b.get_value().get()?); - - let mut t1 = bls12_381::Scalar::one(); - t1.sub_assign(c.get_value().get()?); - - let ret = t1.invert().map(|t1| t0 * t1); - if bool::from(ret.is_some()) { - Ok(ret.unwrap()) - } else { - Err(SynthesisError::DivisionByZero) - } - })?; - - cs.enforce( - || "v3 computation", - |lc| lc + one - c.get_variable(), - |lc| lc + v3.get_variable(), - |lc| lc + uppercase_u.get_variable() - a.get_variable() - b.get_variable(), - ); - - Ok(EdwardsPoint { u: u3, v: v3 }) - } -} - -pub struct MontgomeryPoint { - x: Num, - y: Num, -} - -impl MontgomeryPoint { - /// Converts an element in the prime order subgroup into - /// a point in the birationally equivalent twisted - /// Edwards curve. - pub fn into_edwards(self, mut cs: CS) -> Result - where - CS: ConstraintSystem, - { - // Compute u = (scale*x) / y - let u = AllocatedNum::alloc(cs.namespace(|| "u"), || { - let mut t0 = *self.x.get_value().get()?; - t0.mul_assign(MONTGOMERY_SCALE); - - let ret = self.y.get_value().get()?.invert().map(|invy| t0 * invy); - if bool::from(ret.is_some()) { - Ok(ret.unwrap()) - } else { - Err(SynthesisError::DivisionByZero) - } - })?; - - cs.enforce( - || "u computation", - |lc| lc + &self.y.lc(bls12_381::Scalar::one()), - |lc| lc + u.get_variable(), - |lc| lc + &self.x.lc(MONTGOMERY_SCALE), - ); - - // Compute v = (x - 1) / (x + 1) - let v = AllocatedNum::alloc(cs.namespace(|| "v"), || { - let mut t0 = *self.x.get_value().get()?; - let mut t1 = t0; - t0.sub_assign(&bls12_381::Scalar::one()); - t1.add_assign(&bls12_381::Scalar::one()); - - let ret = t1.invert().map(|t1| t0 * t1); - if bool::from(ret.is_some()) { - Ok(ret.unwrap()) - } else { - Err(SynthesisError::DivisionByZero) - } - })?; - - let one = CS::one(); - cs.enforce( - || "v computation", - |lc| lc + &self.x.lc(bls12_381::Scalar::one()) + one, - |lc| lc + v.get_variable(), - |lc| lc + &self.x.lc(bls12_381::Scalar::one()) - one, - ); - - Ok(EdwardsPoint { u, v }) - } - - /// Interprets an (x, y) pair as a point - /// in Montgomery, does not check that it's - /// on the curve. Useful for constants and - /// window table lookups. - pub fn interpret_unchecked(x: Num, y: Num) -> Self { - MontgomeryPoint { x, y } - } - - /// Performs an affine point addition, not defined for - /// points with the same x-coordinate. - pub fn add(&self, mut cs: CS, other: &Self) -> Result - where - CS: ConstraintSystem, - { - // Compute lambda = (y' - y) / (x' - x) - let lambda = AllocatedNum::alloc(cs.namespace(|| "lambda"), || { - let mut n = *other.y.get_value().get()?; - n.sub_assign(self.y.get_value().get()?); - - let mut d = *other.x.get_value().get()?; - d.sub_assign(self.x.get_value().get()?); - - let ret = d.invert().map(|d| n * d); - if bool::from(ret.is_some()) { - Ok(ret.unwrap()) - } else { - Err(SynthesisError::DivisionByZero) - } - })?; - - cs.enforce( - || "evaluate lambda", - |lc| lc + &other.x.lc(bls12_381::Scalar::one()) - &self.x.lc(bls12_381::Scalar::one()), - |lc| lc + lambda.get_variable(), - |lc| lc + &other.y.lc(bls12_381::Scalar::one()) - &self.y.lc(bls12_381::Scalar::one()), - ); - - // Compute x'' = lambda^2 - A - x - x' - let xprime = AllocatedNum::alloc(cs.namespace(|| "xprime"), || { - let mut t0 = lambda.get_value().get()?.square(); - t0.sub_assign(MONTGOMERY_A); - t0.sub_assign(self.x.get_value().get()?); - t0.sub_assign(other.x.get_value().get()?); - - Ok(t0) - })?; - - // (lambda) * (lambda) = (A + x + x' + x'') - let one = CS::one(); - cs.enforce( - || "evaluate xprime", - |lc| lc + lambda.get_variable(), - |lc| lc + lambda.get_variable(), - |lc| { - lc + (MONTGOMERY_A, one) - + &self.x.lc(bls12_381::Scalar::one()) - + &other.x.lc(bls12_381::Scalar::one()) - + xprime.get_variable() - }, - ); - - // Compute y' = -(y + lambda(x' - x)) - let yprime = AllocatedNum::alloc(cs.namespace(|| "yprime"), || { - let mut t0 = *xprime.get_value().get()?; - t0.sub_assign(self.x.get_value().get()?); - t0.mul_assign(lambda.get_value().get()?); - t0.add_assign(self.y.get_value().get()?); - t0 = t0.neg(); - - Ok(t0) - })?; - - // y' + y = lambda(x - x') - cs.enforce( - || "evaluate yprime", - |lc| lc + &self.x.lc(bls12_381::Scalar::one()) - xprime.get_variable(), - |lc| lc + lambda.get_variable(), - |lc| lc + yprime.get_variable() + &self.y.lc(bls12_381::Scalar::one()), - ); - - Ok(MontgomeryPoint { - x: xprime.into(), - y: yprime.into(), - }) - } -} - -#[cfg(test)] -mod test { - use bellman::ConstraintSystem; - use group::{ - ff::{Field, PrimeField, PrimeFieldBits}, - Curve, Group, - }; - use rand_core::{RngCore, SeedableRng}; - use rand_xorshift::XorShiftRng; - - use bellman::gadgets::test::*; - - use super::{fixed_base_multiplication, AllocatedNum, EdwardsPoint, MontgomeryPoint}; - use crate::sapling::circuit::constants::{ - to_montgomery_coords, NOTE_COMMITMENT_RANDOMNESS_GENERATOR, - }; - use bellman::gadgets::boolean::{AllocatedBit, Boolean}; - - #[test] - #[allow(clippy::many_single_char_names)] - fn test_into_edwards() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, - 0xbc, 0xe5, - ]); - - for _ in 0..100 { - let mut cs = TestConstraintSystem::new(); - - let p = jubjub::ExtendedPoint::random(&mut rng); - let (x, y) = to_montgomery_coords(p).unwrap(); - let p = p.to_affine(); - let (u, v) = (p.get_u(), p.get_v()); - - let numx = AllocatedNum::alloc(cs.namespace(|| "mont x"), || Ok(x)).unwrap(); - let numy = AllocatedNum::alloc(cs.namespace(|| "mont y"), || Ok(y)).unwrap(); - - let p = MontgomeryPoint::interpret_unchecked(numx.into(), numy.into()); - - let q = p.into_edwards(&mut cs).unwrap(); - - assert!(cs.is_satisfied()); - assert!(q.u.get_value().unwrap() == u); - assert!(q.v.get_value().unwrap() == v); - - cs.set("u/num", bls12_381::Scalar::random(&mut rng)); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "u computation"); - cs.set("u/num", u); - assert!(cs.is_satisfied()); - - cs.set("v/num", bls12_381::Scalar::random(&mut rng)); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "v computation"); - cs.set("v/num", v); - assert!(cs.is_satisfied()); - } - } - - #[test] - fn test_interpret() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, - 0xbc, 0xe5, - ]); - - for _ in 0..100 { - let p = jubjub::ExtendedPoint::random(&mut rng); - - let mut cs = TestConstraintSystem::new(); - let q = EdwardsPoint::witness(&mut cs, Some(p)).unwrap(); - - let p = p.to_affine(); - - assert!(cs.is_satisfied()); - assert_eq!(q.u.get_value().unwrap(), p.get_u()); - assert_eq!(q.v.get_value().unwrap(), p.get_v()); - } - - for _ in 0..100 { - let p = jubjub::ExtendedPoint::random(&mut rng).to_affine(); - let (u, v) = (p.get_u(), p.get_v()); - - let mut cs = TestConstraintSystem::new(); - let numu = AllocatedNum::alloc(cs.namespace(|| "u"), || Ok(u)).unwrap(); - let numv = AllocatedNum::alloc(cs.namespace(|| "v"), || Ok(v)).unwrap(); - - let p = EdwardsPoint::interpret(&mut cs, &numu, &numv).unwrap(); - - assert!(cs.is_satisfied()); - assert_eq!(p.u.get_value().unwrap(), u); - assert_eq!(p.v.get_value().unwrap(), v); - } - - // Random (u, v) are unlikely to be on the curve. - for _ in 0..100 { - let u = bls12_381::Scalar::random(&mut rng); - let v = bls12_381::Scalar::random(&mut rng); - - let mut cs = TestConstraintSystem::new(); - let numu = AllocatedNum::alloc(cs.namespace(|| "u"), || Ok(u)).unwrap(); - let numv = AllocatedNum::alloc(cs.namespace(|| "v"), || Ok(v)).unwrap(); - - EdwardsPoint::interpret(&mut cs, &numu, &numv).unwrap(); - - assert_eq!(cs.which_is_unsatisfied().unwrap(), "on curve check"); - } - } - - #[test] - fn test_edwards_fixed_base_multiplication() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, - 0xbc, 0xe5, - ]); - - for _ in 0..100 { - let mut cs = TestConstraintSystem::::new(); - - let p = crate::sapling::constants::NOTE_COMMITMENT_RANDOMNESS_GENERATOR; - let s = jubjub::Fr::random(&mut rng); - let q = jubjub::ExtendedPoint::from(p * s).to_affine(); - let (u1, v1) = (q.get_u(), q.get_v()); - - let s_bits = s - .to_le_bits() - .iter() - .by_vals() - .take(jubjub::Fr::NUM_BITS as usize) - .enumerate() - .map(|(i, b)| { - AllocatedBit::alloc(cs.namespace(|| format!("scalar bit {}", i)), Some(b)) - .unwrap() - }) - .map(Boolean::from) - .collect::>(); - - let q = fixed_base_multiplication( - cs.namespace(|| "multiplication"), - &NOTE_COMMITMENT_RANDOMNESS_GENERATOR, - &s_bits, - ) - .unwrap(); - - assert_eq!(q.u.get_value().unwrap(), u1); - assert_eq!(q.v.get_value().unwrap(), v1); - } - } - - #[test] - fn test_edwards_multiplication() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, - 0xbc, 0xe5, - ]); - - for _ in 0..100 { - let mut cs = TestConstraintSystem::new(); - - let p = jubjub::ExtendedPoint::random(&mut rng); - let s = jubjub::Fr::random(&mut rng); - let q = (p * s).to_affine(); - let p = p.to_affine(); - - let (u0, v0) = (p.get_u(), p.get_v()); - let (u1, v1) = (q.get_u(), q.get_v()); - - let num_u0 = AllocatedNum::alloc(cs.namespace(|| "u0"), || Ok(u0)).unwrap(); - let num_v0 = AllocatedNum::alloc(cs.namespace(|| "v0"), || Ok(v0)).unwrap(); - - let p = EdwardsPoint { - u: num_u0, - v: num_v0, - }; - - let s_bits = s - .to_le_bits() - .iter() - .by_vals() - .take(jubjub::Fr::NUM_BITS as usize) - .enumerate() - .map(|(i, b)| { - AllocatedBit::alloc(cs.namespace(|| format!("scalar bit {}", i)), Some(b)) - .unwrap() - }) - .map(Boolean::from) - .collect::>(); - - let q = p.mul(cs.namespace(|| "scalar mul"), &s_bits).unwrap(); - - assert!(cs.is_satisfied()); - - assert_eq!(q.u.get_value().unwrap(), u1); - - assert_eq!(q.v.get_value().unwrap(), v1); - } - } - - #[test] - fn test_conditionally_select() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, - 0xbc, 0xe5, - ]); - - for _ in 0..1000 { - let mut cs = TestConstraintSystem::new(); - - let p = jubjub::ExtendedPoint::random(&mut rng).to_affine(); - - let (u0, v0) = (p.get_u(), p.get_v()); - - let num_u0 = AllocatedNum::alloc(cs.namespace(|| "u0"), || Ok(u0)).unwrap(); - let num_v0 = AllocatedNum::alloc(cs.namespace(|| "v0"), || Ok(v0)).unwrap(); - - let p = EdwardsPoint { - u: num_u0, - v: num_v0, - }; - - let mut should_we_select = rng.next_u32() % 2 != 0; - - // Conditionally allocate - let mut b = if rng.next_u32() % 2 != 0 { - Boolean::from( - AllocatedBit::alloc(cs.namespace(|| "condition"), Some(should_we_select)) - .unwrap(), - ) - } else { - Boolean::constant(should_we_select) - }; - - // Conditionally negate - if rng.next_u32() % 2 != 0 { - b = b.not(); - should_we_select = !should_we_select; - } - - let q = p - .conditionally_select(cs.namespace(|| "select"), &b) - .unwrap(); - - assert!(cs.is_satisfied()); - - #[allow(clippy::branches_sharing_code)] - if should_we_select { - assert_eq!(q.u.get_value().unwrap(), u0); - assert_eq!(q.v.get_value().unwrap(), v0); - - cs.set("select/v'/num", bls12_381::Scalar::one()); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/v' computation"); - cs.set("select/u'/num", bls12_381::Scalar::zero()); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/u' computation"); - } else { - assert_eq!(q.u.get_value().unwrap(), bls12_381::Scalar::zero()); - assert_eq!(q.v.get_value().unwrap(), bls12_381::Scalar::one()); - - cs.set("select/v'/num", u0); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/v' computation"); - cs.set("select/u'/num", v0); - assert_eq!(cs.which_is_unsatisfied().unwrap(), "select/u' computation"); - } - } - } - - #[test] - fn test_edwards_addition() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, - 0xbc, 0xe5, - ]); - - for _ in 0..100 { - let p1 = jubjub::ExtendedPoint::random(&mut rng); - let p2 = jubjub::ExtendedPoint::random(&mut rng); - - let p3 = p1 + p2; - - let p1 = p1.to_affine(); - let p2 = p2.to_affine(); - let p3 = p3.to_affine(); - - let (u0, v0) = (p1.get_u(), p1.get_v()); - let (u1, v1) = (p2.get_u(), p2.get_v()); - let (u2, v2) = (p3.get_u(), p3.get_v()); - - let mut cs = TestConstraintSystem::new(); - - let num_u0 = AllocatedNum::alloc(cs.namespace(|| "u0"), || Ok(u0)).unwrap(); - let num_v0 = AllocatedNum::alloc(cs.namespace(|| "v0"), || Ok(v0)).unwrap(); - - let num_u1 = AllocatedNum::alloc(cs.namespace(|| "u1"), || Ok(u1)).unwrap(); - let num_v1 = AllocatedNum::alloc(cs.namespace(|| "v1"), || Ok(v1)).unwrap(); - - let p1 = EdwardsPoint { - u: num_u0, - v: num_v0, - }; - - let p2 = EdwardsPoint { - u: num_u1, - v: num_v1, - }; - - let p3 = p1.add(cs.namespace(|| "addition"), &p2).unwrap(); - - assert!(cs.is_satisfied()); - - assert!(p3.u.get_value().unwrap() == u2); - assert!(p3.v.get_value().unwrap() == v2); - - let uppercase_u = cs.get("addition/U/num"); - cs.set("addition/U/num", bls12_381::Scalar::random(&mut rng)); - assert_eq!(cs.which_is_unsatisfied(), Some("addition/U computation")); - cs.set("addition/U/num", uppercase_u); - assert!(cs.is_satisfied()); - - let u3 = cs.get("addition/u3/num"); - cs.set("addition/u3/num", bls12_381::Scalar::random(&mut rng)); - assert_eq!(cs.which_is_unsatisfied(), Some("addition/u3 computation")); - cs.set("addition/u3/num", u3); - assert!(cs.is_satisfied()); - - let v3 = cs.get("addition/v3/num"); - cs.set("addition/v3/num", bls12_381::Scalar::random(&mut rng)); - assert_eq!(cs.which_is_unsatisfied(), Some("addition/v3 computation")); - cs.set("addition/v3/num", v3); - assert!(cs.is_satisfied()); - } - } - - #[test] - fn test_edwards_doubling() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, - 0xbc, 0xe5, - ]); - - for _ in 0..100 { - let p1 = jubjub::ExtendedPoint::random(&mut rng); - let p2 = p1.double(); - - let p1 = p1.to_affine(); - let p2 = p2.to_affine(); - - let (u0, v0) = (p1.get_u(), p1.get_v()); - let (u1, v1) = (p2.get_u(), p2.get_v()); - - let mut cs = TestConstraintSystem::new(); - - let num_u0 = AllocatedNum::alloc(cs.namespace(|| "u0"), || Ok(u0)).unwrap(); - let num_v0 = AllocatedNum::alloc(cs.namespace(|| "v0"), || Ok(v0)).unwrap(); - - let p1 = EdwardsPoint { - u: num_u0, - v: num_v0, - }; - - let p2 = p1.double(cs.namespace(|| "doubling")).unwrap(); - - assert!(cs.is_satisfied()); - - assert!(p2.u.get_value().unwrap() == u1); - assert!(p2.v.get_value().unwrap() == v1); - } - } - - #[test] - fn test_montgomery_addition() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, - 0xbc, 0xe5, - ]); - - for _ in 0..100 { - let p1 = jubjub::ExtendedPoint::random(&mut rng); - let p2 = jubjub::ExtendedPoint::random(&mut rng); - let p3 = p1 + p2; - - let (x0, y0) = to_montgomery_coords(p1).unwrap(); - let (x1, y1) = to_montgomery_coords(p2).unwrap(); - let (x2, y2) = to_montgomery_coords(p3).unwrap(); - - let mut cs = TestConstraintSystem::new(); - - let num_x0 = AllocatedNum::alloc(cs.namespace(|| "x0"), || Ok(x0)).unwrap(); - let num_y0 = AllocatedNum::alloc(cs.namespace(|| "y0"), || Ok(y0)).unwrap(); - - let num_x1 = AllocatedNum::alloc(cs.namespace(|| "x1"), || Ok(x1)).unwrap(); - let num_y1 = AllocatedNum::alloc(cs.namespace(|| "y1"), || Ok(y1)).unwrap(); - - let p1 = MontgomeryPoint { - x: num_x0.into(), - y: num_y0.into(), - }; - - let p2 = MontgomeryPoint { - x: num_x1.into(), - y: num_y1.into(), - }; - - let p3 = p1.add(cs.namespace(|| "addition"), &p2).unwrap(); - - assert!(cs.is_satisfied()); - - assert!(p3.x.get_value().unwrap() == x2); - assert!(p3.y.get_value().unwrap() == y2); - - cs.set("addition/yprime/num", bls12_381::Scalar::random(&mut rng)); - assert_eq!(cs.which_is_unsatisfied(), Some("addition/evaluate yprime")); - cs.set("addition/yprime/num", y2); - assert!(cs.is_satisfied()); - - cs.set("addition/xprime/num", bls12_381::Scalar::random(&mut rng)); - assert_eq!(cs.which_is_unsatisfied(), Some("addition/evaluate xprime")); - cs.set("addition/xprime/num", x2); - assert!(cs.is_satisfied()); - - cs.set("addition/lambda/num", bls12_381::Scalar::random(&mut rng)); - assert_eq!(cs.which_is_unsatisfied(), Some("addition/evaluate lambda")); - } - } - - #[test] - fn test_assert_not_small_order() { - let check_small_order_from_p = |p: jubjub::ExtendedPoint, is_small_order| { - let mut cs = TestConstraintSystem::new(); - - let p = EdwardsPoint::witness(&mut cs, Some(p)).unwrap(); - assert!(cs.is_satisfied()); - assert!(p.assert_not_small_order(&mut cs).is_err() == is_small_order); - }; - - let check_small_order_from_u64s = |u, v| { - let (u, v) = (bls12_381::Scalar::from(u), bls12_381::Scalar::from(v)); - let p = jubjub::AffinePoint::from_raw_unchecked(u, v); - - check_small_order_from_p(p.into(), true); - }; - - // zero has low order - check_small_order_from_u64s(0, 1); - - // prime subgroup order - let prime_subgroup_order = jubjub::Fr::from_str_vartime( - "6554484396890773809930967563523245729705921265872317281365359162392183254199", - ) - .unwrap(); - let largest_small_subgroup_order = jubjub::Fr::from(8); - - let (zero_u, zero_v) = (bls12_381::Scalar::zero(), bls12_381::Scalar::one()); - - // generator for jubjub - let (u, v) = ( - bls12_381::Scalar::from_str_vartime( - "11076627216317271660298050606127911965867021807910416450833192264015104452986", - ) - .unwrap(), - bls12_381::Scalar::from_str_vartime( - "44412834903739585386157632289020980010620626017712148233229312325549216099227", - ) - .unwrap(), - ); - let g = jubjub::AffinePoint::from_raw_unchecked(u, v).into(); - check_small_order_from_p(g, false); - - // generator for the prime subgroup - let g_prime = g * largest_small_subgroup_order; - check_small_order_from_p(g_prime, false); - let prime_subgroup_order_minus_1 = prime_subgroup_order - jubjub::Fr::one(); - - let should_not_be_zero = g_prime * prime_subgroup_order_minus_1; - assert_ne!(zero_u, should_not_be_zero.to_affine().get_u()); - assert_ne!(zero_v, should_not_be_zero.to_affine().get_v()); - let should_be_zero = should_not_be_zero + g_prime; - assert_eq!(zero_u, should_be_zero.to_affine().get_u()); - assert_eq!(zero_v, should_be_zero.to_affine().get_v()); - - // generator for the small order subgroup - let g_small = g * prime_subgroup_order_minus_1; - let g_small = g_small + g; - check_small_order_from_p(g_small, true); - - // g_small does have order 8 - let largest_small_subgroup_order_minus_1 = largest_small_subgroup_order - jubjub::Fr::one(); - - let should_not_be_zero = g_small * largest_small_subgroup_order_minus_1; - assert_ne!(zero_u, should_not_be_zero.to_affine().get_u()); - assert_ne!(zero_v, should_not_be_zero.to_affine().get_v()); - - let should_be_zero = should_not_be_zero + g_small; - assert_eq!(zero_u, should_be_zero.to_affine().get_u()); - assert_eq!(zero_v, should_be_zero.to_affine().get_v()); - - // take all the points from the script - // assert should be different than multiplying by cofactor, which is the solution - // is user input verified? https://github.com/zcash/librustzcash/blob/f5d2afb4eabac29b1b1cc860d66e45a5b48b4f88/src/rustzcash.rs#L299 - } -} diff --git a/zcash_primitives/src/sapling/circuit/pedersen_hash.rs b/zcash_primitives/src/sapling/circuit/pedersen_hash.rs deleted file mode 100644 index eee666664..000000000 --- a/zcash_primitives/src/sapling/circuit/pedersen_hash.rs +++ /dev/null @@ -1,302 +0,0 @@ -//! Gadget for Zcash's Pedersen hash. - -use super::ecc::{EdwardsPoint, MontgomeryPoint}; -pub use crate::sapling::pedersen_hash::Personalization; -use bellman::gadgets::boolean::Boolean; -use bellman::gadgets::lookup::*; -use bellman::{ConstraintSystem, SynthesisError}; - -use super::constants::PEDERSEN_CIRCUIT_GENERATORS; - -fn get_constant_bools(person: &Personalization) -> Vec { - person - .get_bits() - .into_iter() - .map(Boolean::constant) - .collect() -} - -pub fn pedersen_hash( - mut cs: CS, - personalization: Personalization, - bits: &[Boolean], -) -> Result -where - CS: ConstraintSystem, -{ - let personalization = get_constant_bools(&personalization); - assert_eq!(personalization.len(), 6); - - let mut edwards_result = None; - let mut bits = personalization.iter().chain(bits.iter()).peekable(); - let mut segment_generators = PEDERSEN_CIRCUIT_GENERATORS.iter(); - let boolean_false = Boolean::constant(false); - - let mut segment_i = 0; - while bits.peek().is_some() { - let mut segment_result = None; - let mut segment_windows = &segment_generators.next().expect("enough segments")[..]; - - let mut window_i = 0; - while let Some(a) = bits.next() { - let b = bits.next().unwrap_or(&boolean_false); - let c = bits.next().unwrap_or(&boolean_false); - - let tmp = lookup3_xy_with_conditional_negation( - cs.namespace(|| format!("segment {}, window {}", segment_i, window_i)), - &[a.clone(), b.clone(), c.clone()], - &segment_windows[0], - )?; - - let tmp = MontgomeryPoint::interpret_unchecked(tmp.0, tmp.1); - - match segment_result { - None => { - segment_result = Some(tmp); - } - Some(ref mut segment_result) => { - *segment_result = tmp.add( - cs.namespace(|| { - format!("addition of segment {}, window {}", segment_i, window_i) - }), - segment_result, - )?; - } - } - - segment_windows = &segment_windows[1..]; - - if segment_windows.is_empty() { - break; - } - - window_i += 1; - } - - let segment_result = segment_result.expect( - "bits is not exhausted due to while condition; - thus there must be a segment window; - thus there must be a segment result", - ); - - // Convert this segment into twisted Edwards form. - let segment_result = segment_result.into_edwards( - cs.namespace(|| format!("conversion of segment {} into edwards", segment_i)), - )?; - - match edwards_result { - Some(ref mut edwards_result) => { - *edwards_result = segment_result.add( - cs.namespace(|| format!("addition of segment {} to accumulator", segment_i)), - edwards_result, - )?; - } - None => { - edwards_result = Some(segment_result); - } - } - - segment_i += 1; - } - - Ok(edwards_result.unwrap()) -} - -#[cfg(test)] -mod test { - use super::*; - use crate::sapling::pedersen_hash; - use bellman::gadgets::boolean::{AllocatedBit, Boolean}; - use bellman::gadgets::test::*; - use group::{ff::PrimeField, Curve}; - use rand_core::{RngCore, SeedableRng}; - use rand_xorshift::XorShiftRng; - - /// Predict the number of constraints of a Pedersen hash - fn ph_num_constraints(input_bits: usize) -> usize { - // Account for the 6 personalization bits. - let personalized_bits = 6 + input_bits; - // Constant booleans in the personalization and padding don't need lookup "precomp" constraints. - let precomputed_booleans = 2 + (personalized_bits % 3 == 1) as usize; - - // Count chunks and segments with ceiling division - let chunks = (personalized_bits + 3 - 1) / 3; - let segments = (chunks + 63 - 1) / 63; - let all_but_last_segments = segments - 1; - let last_chunks = chunks - all_but_last_segments * 63; - - // Constraints per operation - let lookup_chunk = 2; - let add_chunks = 3; // Montgomery addition - let convert_segment = 2; // Conversion to Edwards - let add_segments = 6; // Edwards addition - - (chunks) * lookup_chunk - precomputed_booleans - + segments * convert_segment - + all_but_last_segments * ((63 - 1) * add_chunks + add_segments) - + (last_chunks - 1) * add_chunks - } - - #[test] - fn test_pedersen_hash_constraints() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, - 0xbc, 0xe5, - ]); - - let leaves_len = 2 * 255; - let note_len = 64 + 256 + 256; - - for &n_bits in [ - 0, - 3 * 63 - 6, - 3 * 63 - 6 + 1, - 3 * 63 - 6 + 2, - leaves_len, - note_len, - ] - .iter() - { - let mut cs = TestConstraintSystem::new(); - - let input: Vec = (0..n_bits).map(|_| rng.next_u32() % 2 != 0).collect(); - - let input_bools: Vec = input - .iter() - .enumerate() - .map(|(i, b)| { - Boolean::from( - AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)) - .unwrap(), - ) - }) - .collect(); - - pedersen_hash( - cs.namespace(|| "pedersen hash"), - Personalization::NoteCommitment, - &input_bools, - ) - .unwrap(); - - assert!(cs.is_satisfied()); - - let bitness_constraints = n_bits; - let ph_constraints = ph_num_constraints(n_bits); - assert_eq!(cs.num_constraints(), bitness_constraints + ph_constraints); - // The actual usages - if n_bits == leaves_len { - assert_eq!(cs.num_constraints(), leaves_len + 867) - }; - if n_bits == note_len { - assert_eq!(cs.num_constraints(), note_len + 982) - }; - } - } - - #[test] - fn test_pedersen_hash() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, - 0xbc, 0xe5, - ]); - - for length in 0..751 { - for _ in 0..5 { - let input: Vec = (0..length).map(|_| rng.next_u32() % 2 != 0).collect(); - - let mut cs = TestConstraintSystem::new(); - - let input_bools: Vec = input - .iter() - .enumerate() - .map(|(i, b)| { - Boolean::from( - AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)) - .unwrap(), - ) - }) - .collect(); - - let res = pedersen_hash( - cs.namespace(|| "pedersen hash"), - Personalization::MerkleTree(1), - &input_bools, - ) - .unwrap(); - - assert!(cs.is_satisfied()); - - let expected = jubjub::ExtendedPoint::from(pedersen_hash::pedersen_hash( - Personalization::MerkleTree(1), - input.clone().into_iter(), - )) - .to_affine(); - - assert_eq!(res.get_u().get_value().unwrap(), expected.get_u()); - assert_eq!(res.get_v().get_value().unwrap(), expected.get_v()); - - // Test against the output of a different personalization - let unexpected = jubjub::ExtendedPoint::from(pedersen_hash::pedersen_hash( - Personalization::MerkleTree(0), - input.into_iter(), - )) - .to_affine(); - - assert!(res.get_u().get_value().unwrap() != unexpected.get_u()); - assert!(res.get_v().get_value().unwrap() != unexpected.get_v()); - } - } - } - - #[test] - fn test_pedersen_hash_external_test_vectors() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, - 0xbc, 0xe5, - ]); - - let expected_us = [ - "28161926966428986673895580777285905189725480206811328272001879986576840909576", - "39669831794597628158501766225645040955899576179071014703006420393381978263045", - ]; - let expected_vs = [ - "26869991781071974894722407757894142583682396277979904369818887810555917099932", - "2112827187110048608327330788910224944044097981650120385961435904443901436107", - ]; - for length in 300..302 { - let input: Vec = (0..length).map(|_| rng.next_u32() % 2 != 0).collect(); - - let mut cs = TestConstraintSystem::new(); - - let input_bools: Vec = input - .iter() - .enumerate() - .map(|(i, b)| { - Boolean::from( - AllocatedBit::alloc(cs.namespace(|| format!("input {}", i)), Some(*b)) - .unwrap(), - ) - }) - .collect(); - - let res = pedersen_hash( - cs.namespace(|| "pedersen hash"), - Personalization::MerkleTree(1), - &input_bools, - ) - .unwrap(); - - assert!(cs.is_satisfied()); - - assert_eq!( - res.get_u().get_value().unwrap(), - bls12_381::Scalar::from_str_vartime(expected_us[length - 300]).unwrap() - ); - assert_eq!( - res.get_v().get_value().unwrap(), - bls12_381::Scalar::from_str_vartime(expected_vs[length - 300]).unwrap() - ); - } - } -} diff --git a/zcash_primitives/src/sapling/constants.rs b/zcash_primitives/src/sapling/constants.rs deleted file mode 100644 index e9c4e4399..000000000 --- a/zcash_primitives/src/sapling/constants.rs +++ /dev/null @@ -1,436 +0,0 @@ -//! Various constants used by the Sapling protocol. - -use ff::PrimeField; -use group::Group; -use jubjub::SubgroupPoint; -use lazy_static::lazy_static; - -/// First 64 bytes of the BLAKE2s input during group hash. -/// This is chosen to be some random string that we couldn't have anticipated when we designed -/// the algorithm, for rigidity purposes. -/// We deliberately use an ASCII hex string of 32 bytes here. -pub const GH_FIRST_BLOCK: &[u8; 64] = - b"096b36a5804bfacef1691e173c366a47ff5ba84a44f26ddd7e8d9f79d5b42df0"; - -// BLAKE2s invocation personalizations -/// BLAKE2s Personalization for CRH^ivk = BLAKE2s(ak | nk) -pub const CRH_IVK_PERSONALIZATION: &[u8; 8] = b"Zcashivk"; - -/// BLAKE2s Personalization for PRF^nf = BLAKE2s(nk | rho) -pub const PRF_NF_PERSONALIZATION: &[u8; 8] = b"Zcash_nf"; - -// Group hash personalizations -/// BLAKE2s Personalization for Pedersen hash generators. -pub const PEDERSEN_HASH_GENERATORS_PERSONALIZATION: &[u8; 8] = b"Zcash_PH"; - -/// BLAKE2s Personalization for the group hash for key diversification -pub const KEY_DIVERSIFICATION_PERSONALIZATION: &[u8; 8] = b"Zcash_gd"; - -/// BLAKE2s Personalization for the spending key base point -pub const SPENDING_KEY_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_G_"; - -/// BLAKE2s Personalization for the proof generation key base point -pub const PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_H_"; - -/// BLAKE2s Personalization for the value commitment generator for the value -pub const VALUE_COMMITMENT_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_cv"; - -/// BLAKE2s Personalization for the nullifier position generator (for computing rho) -pub const NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION: &[u8; 8] = b"Zcash_J_"; - -/// The prover will demonstrate knowledge of discrete log with respect to this base when -/// they are constructing a proof, in order to authorize proof construction. -pub const PROOF_GENERATION_KEY_GENERATOR: SubgroupPoint = SubgroupPoint::from_raw_unchecked( - bls12_381::Scalar::from_raw([ - 0x3af2_dbef_b96e_2571, - 0xadf2_d038_f2fb_b820, - 0x7043_03f1_e890_6081, - 0x1457_a502_31cd_e2df, - ]), - bls12_381::Scalar::from_raw([ - 0x467a_f9f7_e05d_e8e7, - 0x50df_51ea_f5a1_49d2, - 0xdec9_0184_0f49_48cc, - 0x54b6_d107_18df_2a7a, - ]), -); - -/// The note commitment is randomized over this generator. -pub const NOTE_COMMITMENT_RANDOMNESS_GENERATOR: SubgroupPoint = SubgroupPoint::from_raw_unchecked( - bls12_381::Scalar::from_raw([ - 0xa514_3b34_a8e3_6462, - 0xf091_9d06_ffb1_ecda, - 0xa140_9aa1_f33b_ec2c, - 0x26eb_9f8a_9ec7_2a8c, - ]), - bls12_381::Scalar::from_raw([ - 0xd4fc_6365_796c_77ac, - 0x96b7_8bea_fa9c_c44c, - 0x949d_7747_6e26_2c95, - 0x114b_7501_ad10_4c57, - ]), -); - -/// The node commitment is randomized again by the position in order to supply the -/// nullifier computation with a unique input w.r.t. the note being spent, to prevent -/// Faerie gold attacks. -pub const NULLIFIER_POSITION_GENERATOR: SubgroupPoint = SubgroupPoint::from_raw_unchecked( - bls12_381::Scalar::from_raw([ - 0x2ce3_3921_888d_30db, - 0xe81c_ee09_a561_229e, - 0xdb56_b6db_8d80_75ed, - 0x2400_c2e2_e336_2644, - ]), - bls12_381::Scalar::from_raw([ - 0xa3f7_fa36_c72b_0065, - 0xe155_b8e8_ffff_2e42, - 0xfc9e_8a15_a096_ba8f, - 0x6136_9d54_40bf_84a5, - ]), -); - -/// The value commitment is used to check balance between inputs and outputs. The value is -/// placed over this generator. -pub const VALUE_COMMITMENT_VALUE_GENERATOR: SubgroupPoint = SubgroupPoint::from_raw_unchecked( - bls12_381::Scalar::from_raw([ - 0x3618_3b2c_b4d7_ef51, - 0x9472_c89a_c043_042d, - 0xd861_8ed1_d15f_ef4e, - 0x273f_910d_9ecc_1615, - ]), - bls12_381::Scalar::from_raw([ - 0xa77a_81f5_0667_c8d7, - 0xbc33_32d0_fa1c_cd18, - 0xd322_94fd_8977_4ad6, - 0x466a_7e3a_82f6_7ab1, - ]), -); - -/// The value commitment is randomized over this generator, for privacy. -pub const VALUE_COMMITMENT_RANDOMNESS_GENERATOR: SubgroupPoint = SubgroupPoint::from_raw_unchecked( - bls12_381::Scalar::from_raw([ - 0x3bce_3b77_9366_4337, - 0xd1d8_da41_af03_744e, - 0x7ff6_826a_d580_04b4, - 0x6800_f4fa_0f00_1cfc, - ]), - bls12_381::Scalar::from_raw([ - 0x3cae_fab9_380b_6a8b, - 0xad46_f1b0_473b_803b, - 0xe6fb_2a6e_1e22_ab50, - 0x6d81_d3a9_cb45_dedb, - ]), -); - -/// The spender proves discrete log with respect to this base at spend time. -pub const SPENDING_KEY_GENERATOR: SubgroupPoint = SubgroupPoint::from_raw_unchecked( - bls12_381::Scalar::from_raw([ - 0x47bf_4692_0a95_a753, - 0xd5b9_a7d3_ef8e_2827, - 0xd418_a7ff_2675_3b6a, - 0x0926_d4f3_2059_c712, - ]), - bls12_381::Scalar::from_raw([ - 0x3056_32ad_aaf2_b530, - 0x6d65_674d_cedb_ddbc, - 0x53bb_37d0_c21c_fd05, - 0x57a1_019e_6de9_b675, - ]), -); - -/// The generators (for each segment) used in all Pedersen commitments. -pub const PEDERSEN_HASH_GENERATORS: &[SubgroupPoint] = &[ - SubgroupPoint::from_raw_unchecked( - bls12_381::Scalar::from_raw([ - 0x194e_4292_6f66_1b51, - 0x2f0c_718f_6f0f_badd, - 0xb5ea_25de_7ec0_e378, - 0x73c0_16a4_2ded_9578, - ]), - bls12_381::Scalar::from_raw([ - 0x77bf_abd4_3224_3cca, - 0xf947_2e8b_c04e_4632, - 0x79c9_166b_837e_dc5e, - 0x289e_87a2_d352_1b57, - ]), - ), - SubgroupPoint::from_raw_unchecked( - bls12_381::Scalar::from_raw([ - 0xb981_9dc8_2d90_607e, - 0xa361_ee3f_d48f_df77, - 0x52a3_5a8c_1908_dd87, - 0x15a3_6d1f_0f39_0d88, - ]), - bls12_381::Scalar::from_raw([ - 0x7b0d_c53c_4ebf_1891, - 0x1f3a_beeb_98fa_d3e8, - 0xf789_1142_c001_d925, - 0x015d_8c7f_5b43_fe33, - ]), - ), - SubgroupPoint::from_raw_unchecked( - bls12_381::Scalar::from_raw([ - 0x76d6_f7c2_b67f_c475, - 0xbae8_e5c4_6641_ae5c, - 0xeb69_ae39_f5c8_4210, - 0x6643_21a5_8246_e2f6, - ]), - bls12_381::Scalar::from_raw([ - 0x80ed_502c_9793_d457, - 0x8bb2_2a7f_1784_b498, - 0xe000_a46c_8e8c_e853, - 0x362e_1500_d24e_ee9e, - ]), - ), - SubgroupPoint::from_raw_unchecked( - bls12_381::Scalar::from_raw([ - 0x4c76_7804_c1c4_a2cc, - 0x7d02_d50e_654b_87f2, - 0xedc5_f4a9_cff2_9fd5, - 0x323a_6548_ce9d_9876, - ]), - bls12_381::Scalar::from_raw([ - 0x8471_4bec_a335_70e9, - 0x5103_afa1_a11f_6a85, - 0x9107_0acb_d8d9_47b7, - 0x2f7e_e40c_4b56_cad8, - ]), - ), - SubgroupPoint::from_raw_unchecked( - bls12_381::Scalar::from_raw([ - 0x4680_9430_657f_82d1, - 0xefd5_9313_05f2_f0bf, - 0x89b6_4b4e_0336_2796, - 0x3bd2_6660_00b5_4796, - ]), - bls12_381::Scalar::from_raw([ - 0x9996_8299_c365_8aef, - 0xb3b9_d809_5859_d14c, - 0x3978_3238_1406_c9e5, - 0x494b_c521_03ab_9d0a, - ]), - ), - SubgroupPoint::from_raw_unchecked( - bls12_381::Scalar::from_raw([ - 0xcb3c_0232_58d3_2079, - 0x1d9e_5ca2_1135_ff6f, - 0xda04_9746_d76d_3ee5, - 0x6344_7b2b_a31b_b28a, - ]), - bls12_381::Scalar::from_raw([ - 0x4360_8211_9f8d_629a, - 0xa802_00d2_c66b_13a7, - 0x64cd_b107_0a13_6a28, - 0x64ec_4689_e8bf_b6e5, - ]), - ), -]; - -/// The maximum number of chunks per segment of the Pedersen hash. -pub const PEDERSEN_HASH_CHUNKS_PER_GENERATOR: usize = 63; - -/// The window size for exponentiation of Pedersen hash generators outside the circuit. -pub const PEDERSEN_HASH_EXP_WINDOW_SIZE: u32 = 8; - -lazy_static! { - /// The exp table for [`PEDERSEN_HASH_GENERATORS`]. - pub static ref PEDERSEN_HASH_EXP_TABLE: Vec>> = - generate_pedersen_hash_exp_table(); -} - -/// Creates the exp table for the Pedersen hash generators. -fn generate_pedersen_hash_exp_table() -> Vec>> { - let window = PEDERSEN_HASH_EXP_WINDOW_SIZE; - - PEDERSEN_HASH_GENERATORS - .iter() - .cloned() - .map(|mut g| { - let mut tables = vec![]; - - let mut num_bits = 0; - while num_bits <= jubjub::Fr::NUM_BITS { - let mut table = Vec::with_capacity(1 << window); - let mut base = SubgroupPoint::identity(); - - for _ in 0..(1 << window) { - table.push(base); - base += g; - } - - tables.push(table); - num_bits += window; - - for _ in 0..window { - g = g.double(); - } - } - - tables - }) - .collect() -} - -#[cfg(test)] -mod tests { - use jubjub::SubgroupPoint; - - use super::*; - use crate::sapling::group_hash::group_hash; - - fn find_group_hash(m: &[u8], personalization: &[u8; 8]) -> SubgroupPoint { - let mut tag = m.to_vec(); - let i = tag.len(); - tag.push(0u8); - - loop { - let gh = group_hash(&tag, personalization); - - // We don't want to overflow and start reusing generators - assert!(tag[i] != u8::max_value()); - tag[i] += 1; - - if let Some(gh) = gh { - break gh; - } - } - } - - #[test] - fn proof_generation_key_base_generator() { - assert_eq!( - find_group_hash(&[], PROOF_GENERATION_KEY_BASE_GENERATOR_PERSONALIZATION), - PROOF_GENERATION_KEY_GENERATOR, - ); - } - - #[test] - fn note_commitment_randomness_generator() { - assert_eq!( - find_group_hash(b"r", PEDERSEN_HASH_GENERATORS_PERSONALIZATION), - NOTE_COMMITMENT_RANDOMNESS_GENERATOR, - ); - } - - #[test] - fn nullifier_position_generator() { - assert_eq!( - find_group_hash(&[], NULLIFIER_POSITION_IN_TREE_GENERATOR_PERSONALIZATION), - NULLIFIER_POSITION_GENERATOR, - ); - } - - #[test] - fn value_commitment_value_generator() { - assert_eq!( - find_group_hash(b"v", VALUE_COMMITMENT_GENERATOR_PERSONALIZATION), - VALUE_COMMITMENT_VALUE_GENERATOR, - ); - } - - #[test] - fn value_commitment_randomness_generator() { - assert_eq!( - find_group_hash(b"r", VALUE_COMMITMENT_GENERATOR_PERSONALIZATION), - VALUE_COMMITMENT_RANDOMNESS_GENERATOR, - ); - } - - #[test] - fn spending_key_generator() { - assert_eq!( - find_group_hash(&[], SPENDING_KEY_GENERATOR_PERSONALIZATION), - SPENDING_KEY_GENERATOR, - ); - } - - #[test] - fn pedersen_hash_generators() { - for (m, actual) in PEDERSEN_HASH_GENERATORS.iter().enumerate() { - assert_eq!( - &find_group_hash( - &(m as u32).to_le_bytes(), - PEDERSEN_HASH_GENERATORS_PERSONALIZATION - ), - actual - ); - } - } - - #[test] - fn no_duplicate_fixed_base_generators() { - let fixed_base_generators = [ - PROOF_GENERATION_KEY_GENERATOR, - NOTE_COMMITMENT_RANDOMNESS_GENERATOR, - NULLIFIER_POSITION_GENERATOR, - VALUE_COMMITMENT_VALUE_GENERATOR, - VALUE_COMMITMENT_RANDOMNESS_GENERATOR, - SPENDING_KEY_GENERATOR, - ]; - - // Check for duplicates, far worse than spec inconsistencies! - for (i, p1) in fixed_base_generators.iter().enumerate() { - if p1.is_identity().into() { - panic!("Neutral element!"); - } - - for p2 in fixed_base_generators.iter().skip(i + 1) { - if p1 == p2 { - panic!("Duplicate generator!"); - } - } - } - } - - /// Check for simple relations between the generators, that make finding collisions easy; - /// far worse than spec inconsistencies! - fn check_consistency_of_pedersen_hash_generators( - pedersen_hash_generators: &[jubjub::SubgroupPoint], - ) { - for (i, p1) in pedersen_hash_generators.iter().enumerate() { - if p1.is_identity().into() { - panic!("Neutral element!"); - } - for p2 in pedersen_hash_generators.iter().skip(i + 1) { - if p1 == p2 { - panic!("Duplicate generator!"); - } - if *p1 == -p2 { - panic!("Inverse generator!"); - } - } - - // check for a generator being the sum of any other two - for (j, p2) in pedersen_hash_generators.iter().enumerate() { - if j == i { - continue; - } - for (k, p3) in pedersen_hash_generators.iter().enumerate() { - if k == j || k == i { - continue; - } - let sum = p2 + p3; - if sum == *p1 { - panic!("Linear relation between generators!"); - } - } - } - } - } - - #[test] - fn pedersen_hash_generators_consistency() { - check_consistency_of_pedersen_hash_generators(PEDERSEN_HASH_GENERATORS); - } - - #[test] - #[should_panic(expected = "Linear relation between generators!")] - fn test_jubjub_bls12_pedersen_hash_generators_consistency_check_linear_relation() { - let mut pedersen_hash_generators = PEDERSEN_HASH_GENERATORS.to_vec(); - - // Test for linear relation - pedersen_hash_generators.push(PEDERSEN_HASH_GENERATORS[0] + PEDERSEN_HASH_GENERATORS[1]); - - check_consistency_of_pedersen_hash_generators(&pedersen_hash_generators); - } -} diff --git a/zcash_primitives/src/sapling/group_hash.rs b/zcash_primitives/src/sapling/group_hash.rs deleted file mode 100644 index 30b0c5d0d..000000000 --- a/zcash_primitives/src/sapling/group_hash.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Implementation of [group hashing into Jubjub][grouphash]. -//! -//! [grouphash]: https://zips.z.cash/protocol/protocol.pdf#concretegrouphashjubjub - -use ff::PrimeField; -use group::{cofactor::CofactorGroup, Group, GroupEncoding}; - -use super::constants; -use blake2s_simd::Params; - -/// Produces a random point in the Jubjub curve. -/// The point is guaranteed to be prime order -/// and not the identity. -#[allow(clippy::assertions_on_constants)] -pub fn group_hash(tag: &[u8], personalization: &[u8]) -> Option { - assert_eq!(personalization.len(), 8); - - // Check to see that scalar field is 255 bits - assert!(bls12_381::Scalar::NUM_BITS == 255); - - let h = Params::new() - .hash_length(32) - .personal(personalization) - .to_state() - .update(constants::GH_FIRST_BLOCK) - .update(tag) - .finalize(); - - let p = jubjub::ExtendedPoint::from_bytes(h.as_array()); - if p.is_some().into() { - // ::clear_cofactor is implemented using - // ExtendedPoint::mul_by_cofactor in the jubjub crate. - let p = CofactorGroup::clear_cofactor(&p.unwrap()); - - if p.is_identity().into() { - None - } else { - Some(p) - } - } else { - None - } -} diff --git a/zcash_primitives/src/sapling/keys.rs b/zcash_primitives/src/sapling/keys.rs deleted file mode 100644 index b2d836084..000000000 --- a/zcash_primitives/src/sapling/keys.rs +++ /dev/null @@ -1,746 +0,0 @@ -//! Sapling key components. -//! -//! Implements [section 4.2.2] of the Zcash Protocol Specification. -//! -//! [section 4.2.2]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents - -use std::fmt; -use std::io::{self, Read, Write}; - -use super::{ - address::PaymentAddress, - constants::{self, PROOF_GENERATION_KEY_GENERATOR}, - note_encryption::KDF_SAPLING_PERSONALIZATION, - spec::{ - crh_ivk, diversify_hash, ka_sapling_agree, ka_sapling_agree_prepared, - ka_sapling_derive_public, ka_sapling_derive_public_subgroup_prepared, PreparedBase, - PreparedBaseSubgroup, PreparedScalar, - }, -}; - -use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams}; -use ff::{Field, PrimeField}; -use group::{Curve, Group, GroupEncoding}; -use redjubjub::SpendAuth; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; -use zcash_note_encryption::EphemeralKeyBytes; -use zcash_spec::PrfExpand; - -#[cfg(test)] -use rand_core::RngCore; - -/// Errors that can occur in the decoding of Sapling spending keys. -pub enum DecodingError { - /// The length of the byte slice provided for decoding was incorrect. - LengthInvalid { expected: usize, actual: usize }, - /// Could not decode the `ask` bytes to a jubjub field element. - InvalidAsk, - /// Could not decode the `nsk` bytes to a jubjub field element. - InvalidNsk, - /// An extended spending key had an unsupported child index: either a non-hardened - /// index, or a non-zero index at depth 0. - UnsupportedChildIndex, -} - -/// A spend authorizing key, used to create spend authorization signatures. -/// -/// $\mathsf{ask}$ as defined in [Zcash Protocol Spec § 4.2.2: Sapling Key Components][saplingkeycomponents]. -/// -/// [saplingkeycomponents]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents -#[derive(Clone, Debug)] -pub struct SpendAuthorizingKey(redjubjub::SigningKey); - -impl PartialEq for SpendAuthorizingKey { - fn eq(&self, other: &Self) -> bool { - <[u8; 32]>::from(self.0) - .ct_eq(&<[u8; 32]>::from(other.0)) - .into() - } -} - -impl Eq for SpendAuthorizingKey {} - -impl From<&SpendValidatingKey> for jubjub::ExtendedPoint { - fn from(spend_validating_key: &SpendValidatingKey) -> jubjub::ExtendedPoint { - jubjub::ExtendedPoint::from_bytes(&spend_validating_key.to_bytes()).unwrap() - } -} - -impl SpendAuthorizingKey { - /// Derives ask from sk. Internal use only, does not enforce all constraints. - fn derive_inner(sk: &[u8]) -> jubjub::Scalar { - jubjub::Scalar::from_bytes_wide(&PrfExpand::SAPLING_ASK.with(sk)) - } - - /// Constructs a `SpendAuthorizingKey` from a raw scalar. - pub(crate) fn from_scalar(ask: jubjub::Scalar) -> Option { - if ask.is_zero().into() { - None - } else { - Some(SpendAuthorizingKey(ask.to_bytes().try_into().unwrap())) - } - } - - /// Derives a `SpendAuthorizingKey` from a spending key. - fn from_spending_key(sk: &[u8]) -> Option { - Self::from_scalar(Self::derive_inner(sk)) - } - - /// Parses a `SpendAuthorizingKey` from its encoded form. - pub(crate) fn from_bytes(bytes: &[u8]) -> Option { - <[u8; 32]>::try_from(bytes) - .ok() - .and_then(|b| { - // RedJubjub.Private permits the full set of Jubjub scalars including - // zero. However, a SpendAuthorizingKey is further restricted within the - // Sapling key tree to be a non-zero scalar. - jubjub::Scalar::from_repr(b) - .and_then(|s| { - CtOption::new( - redjubjub::SigningKey::try_from(b) - .expect("RedJubjub permits the set of valid SpendAuthorizingKeys"), - !s.is_zero(), - ) - }) - .into() - }) - .map(SpendAuthorizingKey) - } - - /// Converts this spend authorizing key to its serialized form. - pub(crate) fn to_bytes(&self) -> [u8; 32] { - <[u8; 32]>::from(self.0) - } - - /// Converts this spend authorizing key to a raw scalar. - /// - /// Only used for ZIP 32 child derivation. - pub(crate) fn to_scalar(&self) -> jubjub::Scalar { - jubjub::Scalar::from_repr(self.0.into()).unwrap() - } - - /// Randomizes this spend authorizing key with the given `randomizer`. - /// - /// The resulting key can be used to actually sign a spend. - pub fn randomize(&self, randomizer: &jubjub::Scalar) -> redjubjub::SigningKey { - self.0.randomize(randomizer) - } -} - -/// A key used to validate spend authorization signatures. -/// -/// Defined in [Zcash Protocol Spec § 4.2.2: Sapling Key Components][saplingkeycomponents]. -/// -/// [saplingkeycomponents]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents -#[derive(Clone, Debug)] -pub struct SpendValidatingKey(redjubjub::VerificationKey); - -impl From<&SpendAuthorizingKey> for SpendValidatingKey { - fn from(ask: &SpendAuthorizingKey) -> Self { - SpendValidatingKey((&ask.0).into()) - } -} - -impl PartialEq for SpendValidatingKey { - fn eq(&self, other: &Self) -> bool { - <[u8; 32]>::from(self.0) - .ct_eq(&<[u8; 32]>::from(other.0)) - .into() - } -} - -impl Eq for SpendValidatingKey {} - -impl SpendValidatingKey { - /// For circuit tests only. - #[cfg(test)] - pub(crate) fn fake_random(mut rng: R) -> Self { - loop { - if let Some(k) = Self::from_bytes(&jubjub::SubgroupPoint::random(&mut rng).to_bytes()) { - break k; - } - } - } - - /// Only exposed for `zcashd` unit tests. - #[cfg(feature = "temporary-zcashd")] - pub fn temporary_zcash_from_bytes(bytes: &[u8]) -> Option { - Self::from_bytes(bytes) - } - - /// Parses a `SpendValidatingKey` from its encoded form. - pub(crate) fn from_bytes(bytes: &[u8]) -> Option { - <[u8; 32]>::try_from(bytes) - .ok() - .and_then(|b| { - // RedJubjub.Public permits the full set of Jubjub points including the - // identity and cofactors; this is the type used for `rk` in Spend - // descriptions. However, a SpendValidatingKey is further restricted - // within the Sapling key tree to be a non-identity element of the - // prime-order subgroup. - jubjub::SubgroupPoint::from_bytes(&b) - .and_then(|p| { - CtOption::new( - redjubjub::VerificationKey::try_from(b) - .expect("RedJubjub permits the set of valid SpendValidatingKeys"), - !p.is_identity(), - ) - }) - .into() - }) - .map(SpendValidatingKey) - } - - /// Converts this spend validating key to its serialized form, - /// `LEBS2OSP_256(repr_J(ak))`. - pub(crate) fn to_bytes(&self) -> [u8; 32] { - <[u8; 32]>::from(self.0) - } - - /// Randomizes this spend validating key with the given `randomizer`. - pub fn randomize(&self, randomizer: &jubjub::Scalar) -> redjubjub::VerificationKey { - self.0.randomize(randomizer) - } -} - -/// An outgoing viewing key -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct OutgoingViewingKey(pub [u8; 32]); - -/// A Sapling expanded spending key -#[derive(Clone)] -pub struct ExpandedSpendingKey { - pub ask: SpendAuthorizingKey, - pub nsk: jubjub::Fr, - pub ovk: OutgoingViewingKey, -} - -impl fmt::Debug for ExpandedSpendingKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ExpandedSpendingKey") - .finish_non_exhaustive() - } -} - -impl ExpandedSpendingKey { - /// Expands a spending key into its components. - /// - /// # Panics - /// - /// Panics if this spending key expands to `ask = 0`. This has a negligible - /// probability of occurring. - pub fn from_spending_key(sk: &[u8]) -> Self { - let ask = - SpendAuthorizingKey::from_spending_key(sk).expect("negligible chance of ask == 0"); - let nsk = jubjub::Fr::from_bytes_wide(&PrfExpand::SAPLING_NSK.with(sk)); - let mut ovk = OutgoingViewingKey([0u8; 32]); - ovk.0 - .copy_from_slice(&PrfExpand::SAPLING_OVK.with(sk)[..32]); - ExpandedSpendingKey { ask, nsk, ovk } - } - - pub fn proof_generation_key(&self) -> ProofGenerationKey { - ProofGenerationKey { - ak: (&self.ask).into(), - nsk: self.nsk, - } - } - - /// Decodes the expanded spending key from its serialized representation - /// as part of the encoding of the extended spending key as defined in - /// [ZIP 32](https://zips.z.cash/zip-0032) - pub fn from_bytes(b: &[u8]) -> Result { - if b.len() != 96 { - return Err(DecodingError::LengthInvalid { - expected: 96, - actual: b.len(), - }); - } - - let ask = SpendAuthorizingKey::from_bytes(&b[0..32]).ok_or(DecodingError::InvalidAsk)?; - let nsk = Option::from(jubjub::Fr::from_repr(b[32..64].try_into().unwrap())) - .ok_or(DecodingError::InvalidNsk)?; - let ovk = OutgoingViewingKey(b[64..96].try_into().unwrap()); - - Ok(ExpandedSpendingKey { ask, nsk, ovk }) - } - - pub fn read(mut reader: R) -> io::Result { - let mut repr = [0u8; 96]; - reader.read_exact(repr.as_mut())?; - Self::from_bytes(&repr).map_err(|e| match e { - DecodingError::InvalidAsk => { - io::Error::new(io::ErrorKind::InvalidData, "ask not in field") - } - DecodingError::InvalidNsk => { - io::Error::new(io::ErrorKind::InvalidData, "nsk not in field") - } - DecodingError::LengthInvalid { .. } | DecodingError::UnsupportedChildIndex => { - unreachable!() - } - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_all(&self.to_bytes()) - } - - /// Encodes the expanded spending key to the its seralized representation - /// as part of the encoding of the extended spending key as defined in - /// [ZIP 32](https://zips.z.cash/zip-0032) - pub fn to_bytes(&self) -> [u8; 96] { - let mut result = [0u8; 96]; - result[0..32].copy_from_slice(&self.ask.to_bytes()); - result[32..64].copy_from_slice(&self.nsk.to_repr()); - result[64..96].copy_from_slice(&self.ovk.0); - result - } -} - -#[derive(Clone)] -pub struct ProofGenerationKey { - pub ak: SpendValidatingKey, - pub nsk: jubjub::Fr, -} - -impl fmt::Debug for ProofGenerationKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ProofGenerationKey") - .field("ak", &self.ak) - .finish_non_exhaustive() - } -} - -impl ProofGenerationKey { - pub fn to_viewing_key(&self) -> ViewingKey { - ViewingKey { - ak: self.ak.clone(), - nk: NullifierDerivingKey(constants::PROOF_GENERATION_KEY_GENERATOR * self.nsk), - } - } -} - -/// A key used to derive the nullifier for a Sapling note. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct NullifierDerivingKey(pub jubjub::SubgroupPoint); - -#[derive(Debug, Clone)] -pub struct ViewingKey { - pub ak: SpendValidatingKey, - pub nk: NullifierDerivingKey, -} - -impl ViewingKey { - pub fn rk(&self, ar: jubjub::Fr) -> redjubjub::VerificationKey { - self.ak.randomize(&ar) - } - - pub fn ivk(&self) -> SaplingIvk { - SaplingIvk(crh_ivk(self.ak.to_bytes(), self.nk.0.to_bytes())) - } - - pub fn to_payment_address(&self, diversifier: Diversifier) -> Option { - self.ivk().to_payment_address(diversifier) - } -} - -/// A Sapling key that provides the capability to view incoming and outgoing transactions. -#[derive(Debug)] -pub struct FullViewingKey { - pub vk: ViewingKey, - pub ovk: OutgoingViewingKey, -} - -impl Clone for FullViewingKey { - fn clone(&self) -> Self { - FullViewingKey { - vk: ViewingKey { - ak: self.vk.ak.clone(), - nk: self.vk.nk, - }, - ovk: self.ovk, - } - } -} - -impl FullViewingKey { - pub fn from_expanded_spending_key(expsk: &ExpandedSpendingKey) -> Self { - FullViewingKey { - vk: ViewingKey { - ak: (&expsk.ask).into(), - nk: NullifierDerivingKey(PROOF_GENERATION_KEY_GENERATOR * expsk.nsk), - }, - ovk: expsk.ovk, - } - } - - pub fn read(mut reader: R) -> io::Result { - let ak = { - let mut buf = [0u8; 32]; - reader.read_exact(&mut buf)?; - SpendValidatingKey::from_bytes(&buf) - }; - let nk = { - let mut buf = [0u8; 32]; - reader.read_exact(&mut buf)?; - jubjub::SubgroupPoint::from_bytes(&buf) - }; - if ak.is_none() { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "ak not of prime order", - )); - } - if nk.is_none().into() { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "nk not in prime-order subgroup", - )); - } - let ak = ak.unwrap(); - let nk = NullifierDerivingKey(nk.unwrap()); - - let mut ovk = [0u8; 32]; - reader.read_exact(&mut ovk)?; - - Ok(FullViewingKey { - vk: ViewingKey { ak, nk }, - ovk: OutgoingViewingKey(ovk), - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_all(&self.vk.ak.to_bytes())?; - writer.write_all(&self.vk.nk.0.to_bytes())?; - writer.write_all(&self.ovk.0)?; - - Ok(()) - } - - pub fn to_bytes(&self) -> [u8; 96] { - let mut result = [0u8; 96]; - self.write(&mut result[..]) - .expect("should be able to serialize a FullViewingKey"); - result - } -} - -#[derive(Debug, Clone)] -pub struct SaplingIvk(pub jubjub::Fr); - -impl SaplingIvk { - pub fn to_payment_address(&self, diversifier: Diversifier) -> Option { - let prepared_ivk = PreparedIncomingViewingKey::new(self); - DiversifiedTransmissionKey::derive(&prepared_ivk, &diversifier) - .and_then(|pk_d| PaymentAddress::from_parts(diversifier, pk_d)) - } - - pub fn to_repr(&self) -> [u8; 32] { - self.0.to_repr() - } -} - -/// A Sapling incoming viewing key that has been precomputed for trial decryption. -#[derive(Clone, Debug)] -pub struct PreparedIncomingViewingKey(PreparedScalar); - -impl memuse::DynamicUsage for PreparedIncomingViewingKey { - fn dynamic_usage(&self) -> usize { - self.0.dynamic_usage() - } - - fn dynamic_usage_bounds(&self) -> (usize, Option) { - self.0.dynamic_usage_bounds() - } -} - -impl PreparedIncomingViewingKey { - /// Performs the necessary precomputations to use a `SaplingIvk` for note decryption. - pub fn new(ivk: &SaplingIvk) -> Self { - Self(PreparedScalar::new(&ivk.0)) - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct Diversifier(pub [u8; 11]); - -impl Diversifier { - pub fn g_d(&self) -> Option { - diversify_hash(&self.0) - } -} - -/// The diversified transmission key for a given payment address. -/// -/// Defined in [Zcash Protocol Spec § 4.2.2: Sapling Key Components][saplingkeycomponents]. -/// -/// Note that this type is allowed to be the identity in the protocol, but we reject this -/// in [`PaymentAddress::from_parts`]. -/// -/// [saplingkeycomponents]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] -pub struct DiversifiedTransmissionKey(jubjub::SubgroupPoint); - -impl DiversifiedTransmissionKey { - /// Defined in [Zcash Protocol Spec § 4.2.2: Sapling Key Components][saplingkeycomponents]. - /// - /// Returns `None` if `d` is an invalid diversifier. - /// - /// [saplingkeycomponents]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents - pub(crate) fn derive(ivk: &PreparedIncomingViewingKey, d: &Diversifier) -> Option { - d.g_d() - .map(PreparedBaseSubgroup::new) - .map(|g_d| ka_sapling_derive_public_subgroup_prepared(&ivk.0, &g_d)) - .map(DiversifiedTransmissionKey) - } - - /// $abst_J(bytes)$ - pub(crate) fn from_bytes(bytes: &[u8; 32]) -> CtOption { - jubjub::SubgroupPoint::from_bytes(bytes).map(DiversifiedTransmissionKey) - } - - /// $repr_J(self)$ - pub(crate) fn to_bytes(self) -> [u8; 32] { - self.0.to_bytes() - } - - /// Returns true if this is the identity. - pub(crate) fn is_identity(&self) -> bool { - self.0.is_identity().into() - } - - /// Exposes the inner Jubjub point. - /// - /// This API is exposed for `zcash_proof` usage, and will be removed when this type is - /// refactored into the `sapling-crypto` crate. - pub fn inner(&self) -> jubjub::SubgroupPoint { - self.0 - } -} - -impl ConditionallySelectable for DiversifiedTransmissionKey { - fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { - DiversifiedTransmissionKey(jubjub::SubgroupPoint::conditional_select( - &a.0, &b.0, choice, - )) - } -} - -/// An ephemeral secret key used to encrypt an output note on-chain. -/// -/// `esk` is "ephemeral" in the sense that each secret key is only used once. In -/// practice, `esk` is derived deterministically from the note that it is encrypting. -/// -/// $\mathsf{KA}^\mathsf{Sapling}.\mathsf{Private} := \mathbb{F}_{r_J}$ -/// -/// Defined in [section 5.4.5.3: Sapling Key Agreement][concretesaplingkeyagreement]. -/// -/// [concretesaplingkeyagreement]: https://zips.z.cash/protocol/protocol.pdf#concretesaplingkeyagreement -#[derive(Debug)] -pub struct EphemeralSecretKey(pub(crate) jubjub::Scalar); - -impl ConstantTimeEq for EphemeralSecretKey { - fn ct_eq(&self, other: &Self) -> subtle::Choice { - self.0.ct_eq(&other.0) - } -} - -impl EphemeralSecretKey { - pub(crate) fn from_bytes(bytes: &[u8; 32]) -> CtOption { - jubjub::Scalar::from_bytes(bytes).map(EphemeralSecretKey) - } - - pub(crate) fn derive_public(&self, g_d: jubjub::ExtendedPoint) -> EphemeralPublicKey { - EphemeralPublicKey(ka_sapling_derive_public(&self.0, &g_d)) - } - - pub(crate) fn agree(&self, pk_d: &DiversifiedTransmissionKey) -> SharedSecret { - SharedSecret(ka_sapling_agree(&self.0, &pk_d.0.into())) - } -} - -/// An ephemeral public key used to encrypt an output note on-chain. -/// -/// `epk` is "ephemeral" in the sense that each public key is only used once. In practice, -/// `epk` is derived deterministically from the note that it is encrypting. -/// -/// $\mathsf{KA}^\mathsf{Sapling}.\mathsf{Public} := \mathbb{J}$ -/// -/// Defined in [section 5.4.5.3: Sapling Key Agreement][concretesaplingkeyagreement]. -/// -/// [concretesaplingkeyagreement]: https://zips.z.cash/protocol/protocol.pdf#concretesaplingkeyagreement -#[derive(Debug)] -pub struct EphemeralPublicKey(jubjub::ExtendedPoint); - -impl EphemeralPublicKey { - pub(crate) fn from_affine(epk: jubjub::AffinePoint) -> Self { - EphemeralPublicKey(epk.into()) - } - - pub(crate) fn from_bytes(bytes: &[u8; 32]) -> CtOption { - jubjub::ExtendedPoint::from_bytes(bytes).map(EphemeralPublicKey) - } - - pub(crate) fn to_bytes(&self) -> EphemeralKeyBytes { - EphemeralKeyBytes(self.0.to_bytes()) - } -} - -/// A Sapling ephemeral public key that has been precomputed for trial decryption. -#[derive(Clone, Debug)] -pub struct PreparedEphemeralPublicKey(PreparedBase); - -impl PreparedEphemeralPublicKey { - pub(crate) fn new(epk: EphemeralPublicKey) -> Self { - PreparedEphemeralPublicKey(PreparedBase::new(epk.0)) - } - - pub(crate) fn agree(&self, ivk: &PreparedIncomingViewingKey) -> SharedSecret { - SharedSecret(ka_sapling_agree_prepared(&ivk.0, &self.0)) - } -} - -/// $\mathsf{KA}^\mathsf{Sapling}.\mathsf{SharedSecret} := \mathbb{J}^{(r)}$ -/// -/// Defined in [section 5.4.5.3: Sapling Key Agreement][concretesaplingkeyagreement]. -/// -/// [concretesaplingkeyagreement]: https://zips.z.cash/protocol/protocol.pdf#concretesaplingkeyagreement -#[derive(Debug)] -pub struct SharedSecret(jubjub::SubgroupPoint); - -impl SharedSecret { - /// For checking test vectors only. - #[cfg(test)] - pub(crate) fn to_bytes(&self) -> [u8; 32] { - self.0.to_bytes() - } - - /// Only for use in batched note encryption. - pub(crate) fn batch_to_affine( - shared_secrets: Vec>, - ) -> impl Iterator> { - // Filter out the positions for which ephemeral_key was not a valid encoding. - let secrets: Vec<_> = shared_secrets - .iter() - .filter_map(|s| s.as_ref().map(|s| jubjub::ExtendedPoint::from(s.0))) - .collect(); - - // Batch-normalize the shared secrets. - let mut secrets_affine = vec![jubjub::AffinePoint::identity(); secrets.len()]; - group::Curve::batch_normalize(&secrets, &mut secrets_affine); - - // Re-insert the invalid ephemeral_key positions. - let mut secrets_affine = secrets_affine.into_iter(); - shared_secrets - .into_iter() - .map(move |s| s.and_then(|_| secrets_affine.next())) - } - - /// Defined in [Zcash Protocol Spec § 5.4.5.4: Sapling Key Agreement][concretesaplingkdf]. - /// - /// [concretesaplingkdf]: https://zips.z.cash/protocol/protocol.pdf#concretesaplingkdf - pub(crate) fn kdf_sapling(self, ephemeral_key: &EphemeralKeyBytes) -> Blake2bHash { - Self::kdf_sapling_inner( - jubjub::ExtendedPoint::from(self.0).to_affine(), - ephemeral_key, - ) - } - - /// Only for direct use in batched note encryption. - pub(crate) fn kdf_sapling_inner( - secret: jubjub::AffinePoint, - ephemeral_key: &EphemeralKeyBytes, - ) -> Blake2bHash { - Blake2bParams::new() - .hash_length(32) - .personal(KDF_SAPLING_PERSONALIZATION) - .to_state() - .update(&secret.to_bytes()) - .update(ephemeral_key.as_ref()) - .finalize() - } -} - -#[cfg(any(test, feature = "test-dependencies"))] -pub mod testing { - use proptest::collection::vec; - use proptest::prelude::*; - - use super::{ExpandedSpendingKey, FullViewingKey, SaplingIvk}; - - prop_compose! { - pub fn arb_expanded_spending_key()(v in vec(any::(), 32..252)) -> ExpandedSpendingKey { - ExpandedSpendingKey::from_spending_key(&v) - } - } - - prop_compose! { - pub fn arb_full_viewing_key()(sk in arb_expanded_spending_key()) -> FullViewingKey { - FullViewingKey::from_expanded_spending_key(&sk) - } - } - - prop_compose! { - pub fn arb_incoming_viewing_key()(fvk in arb_full_viewing_key()) -> SaplingIvk { - fvk.vk.ivk() - } - } -} - -#[cfg(test)] -mod tests { - use group::{Group, GroupEncoding}; - - use super::{FullViewingKey, SpendAuthorizingKey, SpendValidatingKey}; - use crate::sapling::{constants::SPENDING_KEY_GENERATOR, test_vectors}; - - #[test] - fn ak_must_be_prime_order() { - let mut buf = [0; 96]; - let identity = jubjub::SubgroupPoint::identity(); - - // Set both ak and nk to the identity. - buf[0..32].copy_from_slice(&identity.to_bytes()); - buf[32..64].copy_from_slice(&identity.to_bytes()); - - // ak is not allowed to be the identity. - assert_eq!( - FullViewingKey::read(&buf[..]).unwrap_err().to_string(), - "ak not of prime order" - ); - - // Set ak to a basepoint. - let basepoint = SPENDING_KEY_GENERATOR; - buf[0..32].copy_from_slice(&basepoint.to_bytes()); - - // nk is allowed to be the identity. - assert!(FullViewingKey::read(&buf[..]).is_ok()); - } - - #[test] - fn spend_auth_sig_test_vectors() { - for tv in test_vectors::signatures::make_test_vectors() { - let sk = SpendAuthorizingKey::from_bytes(&tv.sk).unwrap(); - let vk = SpendValidatingKey::from_bytes(&tv.vk).unwrap(); - let rvk = redjubjub::VerificationKey::try_from(tv.rvk).unwrap(); - let sig = redjubjub::Signature::from(tv.sig); - let rsig = redjubjub::Signature::from(tv.rsig); - - let alpha = jubjub::Scalar::from_bytes(&tv.alpha).unwrap(); - - assert_eq!(<[u8; 32]>::from(sk.randomize(&alpha)), tv.rsk); - assert_eq!(vk.randomize(&alpha), rvk); - - // assert_eq!(vk.0.verify(&tv.m, &sig), Ok(())); - // assert_eq!(rvk.verify(&tv.m, &rsig), Ok(())); - assert_eq!( - vk.0.verify(&tv.m, &rsig), - Err(redjubjub::Error::InvalidSignature), - ); - assert_eq!( - rvk.verify(&tv.m, &sig), - Err(redjubjub::Error::InvalidSignature), - ); - } - } -} diff --git a/zcash_primitives/src/sapling/note.rs b/zcash_primitives/src/sapling/note.rs deleted file mode 100644 index 3d802b4cb..000000000 --- a/zcash_primitives/src/sapling/note.rs +++ /dev/null @@ -1,184 +0,0 @@ -use group::{ff::Field, GroupEncoding}; -use rand_core::{CryptoRng, RngCore}; -use zcash_spec::PrfExpand; - -use super::{ - keys::EphemeralSecretKey, value::NoteValue, Nullifier, NullifierDerivingKey, PaymentAddress, -}; - -mod commitment; -pub use self::commitment::{ExtractedNoteCommitment, NoteCommitment}; - -pub(super) mod nullifier; - -/// Enum for note randomness before and after [ZIP 212](https://zips.z.cash/zip-0212). -/// -/// Before ZIP 212, the note commitment trapdoor `rcm` must be a scalar value. -/// After ZIP 212, the note randomness `rseed` is a 32-byte sequence, used to derive -/// both the note commitment trapdoor `rcm` and the ephemeral private key `esk`. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Rseed { - BeforeZip212(jubjub::Fr), - AfterZip212([u8; 32]), -} - -impl Rseed { - /// Defined in [Zcash Protocol Spec § 4.7.2: Sending Notes (Sapling)][saplingsend]. - /// - /// [saplingsend]: https://zips.z.cash/protocol/protocol.pdf#saplingsend - pub(crate) fn rcm(&self) -> commitment::NoteCommitTrapdoor { - commitment::NoteCommitTrapdoor(match self { - Rseed::BeforeZip212(rcm) => *rcm, - Rseed::AfterZip212(rseed) => { - jubjub::Fr::from_bytes_wide(&PrfExpand::SAPLING_RCM.with(rseed)) - } - }) - } -} - -/// A discrete amount of funds received by an address. -#[derive(Clone, Debug)] -pub struct Note { - /// The recipient of the funds. - recipient: PaymentAddress, - /// The value of this note. - value: NoteValue, - /// The seed randomness for various note components. - rseed: Rseed, -} - -impl PartialEq for Note { - fn eq(&self, other: &Self) -> bool { - // Notes are canonically defined by their commitments. - self.cmu().eq(&other.cmu()) - } -} - -impl Eq for Note {} - -impl Note { - /// Creates a note from its component parts. - /// - /// # Caveats - /// - /// This low-level constructor enforces that the provided arguments produce an - /// internally valid `Note`. However, it allows notes to be constructed in a way that - /// violates required security checks for note decryption, as specified in - /// [Section 4.19] of the Zcash Protocol Specification. Users of this constructor - /// should only call it with note components that have been fully validated by - /// decrypting a received note according to [Section 4.19]. - /// - /// [Section 4.19]: https://zips.z.cash/protocol/protocol.pdf#saplingandorchardinband - pub fn from_parts(recipient: PaymentAddress, value: NoteValue, rseed: Rseed) -> Self { - Note { - recipient, - value, - rseed, - } - } - - /// Returns the recipient of this note. - pub fn recipient(&self) -> PaymentAddress { - self.recipient - } - - /// Returns the value of this note. - pub fn value(&self) -> NoteValue { - self.value - } - - /// Returns the rseed value of this note. - pub fn rseed(&self) -> &Rseed { - &self.rseed - } - - /// Computes the note commitment, returning the full point. - fn cm_full_point(&self) -> NoteCommitment { - NoteCommitment::derive( - self.recipient.g_d().to_bytes(), - self.recipient.pk_d().to_bytes(), - self.value, - self.rseed.rcm(), - ) - } - - /// Computes the nullifier given the nullifier deriving key and - /// note position - pub fn nf(&self, nk: &NullifierDerivingKey, position: u64) -> Nullifier { - Nullifier::derive(nk, self.cm_full_point(), position) - } - - /// Computes the note commitment - pub fn cmu(&self) -> ExtractedNoteCommitment { - self.cm_full_point().into() - } - - /// Defined in [Zcash Protocol Spec § 4.7.2: Sending Notes (Sapling)][saplingsend]. - /// - /// [saplingsend]: https://zips.z.cash/protocol/protocol.pdf#saplingsend - pub fn rcm(&self) -> jubjub::Fr { - self.rseed.rcm().0 - } - - /// Derives `esk` from the internal `Rseed` value, or generates a random value if this - /// note was created with a v1 (i.e. pre-ZIP 212) note plaintext. - pub fn generate_or_derive_esk( - &self, - rng: &mut R, - ) -> EphemeralSecretKey { - self.generate_or_derive_esk_internal(rng) - } - - pub(crate) fn generate_or_derive_esk_internal( - &self, - rng: &mut R, - ) -> EphemeralSecretKey { - match self.derive_esk() { - None => EphemeralSecretKey(jubjub::Fr::random(rng)), - Some(esk) => esk, - } - } - - /// Returns the derived `esk` if this note was created after ZIP 212 activated. - pub(crate) fn derive_esk(&self) -> Option { - match self.rseed { - Rseed::BeforeZip212(_) => None, - Rseed::AfterZip212(rseed) => Some(EphemeralSecretKey(jubjub::Fr::from_bytes_wide( - &PrfExpand::SAPLING_ESK.with(&rseed), - ))), - } - } -} - -#[cfg(any(test, feature = "test-dependencies"))] -pub(super) mod testing { - use proptest::{collection::vec, prelude::*}; - - use super::{ - super::{testing::arb_payment_address, value::NoteValue}, - ExtractedNoteCommitment, Note, Rseed, - }; - - prop_compose! { - pub fn arb_note(value: NoteValue)( - recipient in arb_payment_address(), - rseed in prop::array::uniform32(prop::num::u8::ANY).prop_map(Rseed::AfterZip212) - ) -> Note { - Note { - recipient, - value, - rseed - } - } - } - - prop_compose! { - pub(crate) fn arb_cmu()( - cmu in vec(any::(), 64) - .prop_map(|v| <[u8;64]>::try_from(v.as_slice()).unwrap()) - .prop_map(|v| bls12_381::Scalar::from_bytes_wide(&v)), - ) -> ExtractedNoteCommitment { - ExtractedNoteCommitment(cmu) - } - } -} diff --git a/zcash_primitives/src/sapling/note/commitment.rs b/zcash_primitives/src/sapling/note/commitment.rs deleted file mode 100644 index 403666461..000000000 --- a/zcash_primitives/src/sapling/note/commitment.rs +++ /dev/null @@ -1,110 +0,0 @@ -use core::iter; - -use bitvec::{array::BitArray, order::Lsb0}; -use group::ff::PrimeField; -use subtle::{ConstantTimeEq, CtOption}; - -use crate::sapling::{ - pedersen_hash::Personalization, - spec::{extract_p, windowed_pedersen_commit}, - value::NoteValue, -}; - -/// The trapdoor for a Sapling note commitment. -#[derive(Clone, Debug)] -pub(crate) struct NoteCommitTrapdoor(pub(super) jubjub::Fr); - -/// A commitment to a note. -#[derive(Clone, Debug)] -pub struct NoteCommitment(jubjub::SubgroupPoint); - -impl NoteCommitment { - pub(crate) fn inner(&self) -> jubjub::SubgroupPoint { - self.0 - } -} - -impl NoteCommitment { - /// Derives a Sapling note commitment. - #[cfg(feature = "temporary-zcashd")] - pub fn temporary_zcashd_derive( - g_d: [u8; 32], - pk_d: [u8; 32], - v: NoteValue, - rcm: jubjub::Fr, - ) -> Self { - Self::derive(g_d, pk_d, v, NoteCommitTrapdoor(rcm)) - } - - /// $NoteCommit^Sapling$. - /// - /// Defined in [Zcash Protocol Spec § 5.4.8.2: Windowed Pedersen commitments][concretewindowedcommit]. - /// - /// [concretewindowedcommit]: https://zips.z.cash/protocol/protocol.pdf#concretewindowedcommit - pub(super) fn derive( - g_d: [u8; 32], - pk_d: [u8; 32], - v: NoteValue, - rcm: NoteCommitTrapdoor, - ) -> Self { - NoteCommitment(windowed_pedersen_commit( - Personalization::NoteCommitment, - iter::empty() - .chain(v.to_le_bits().iter().by_vals()) - .chain(BitArray::<_, Lsb0>::new(g_d).iter().by_vals()) - .chain(BitArray::<_, Lsb0>::new(pk_d).iter().by_vals()), - rcm.0, - )) - } -} - -/// The u-coordinate of the commitment to a note. -#[derive(Copy, Clone, Debug)] -pub struct ExtractedNoteCommitment(pub(super) bls12_381::Scalar); - -impl ExtractedNoteCommitment { - /// Deserialize the extracted note commitment from a byte array. - /// - /// This method enforces the [consensus rule][cmucanon] that the byte representation - /// of cmu MUST be canonical. - /// - /// [cmucanon]: https://zips.z.cash/protocol/protocol.pdf#outputencodingandconsensus - pub fn from_bytes(bytes: &[u8; 32]) -> CtOption { - bls12_381::Scalar::from_repr(*bytes).map(ExtractedNoteCommitment) - } - - /// Serialize the value commitment to its canonical byte representation. - pub fn to_bytes(self) -> [u8; 32] { - self.0.to_repr() - } - - pub(crate) fn inner(&self) -> jubjub::Base { - self.0 - } -} - -impl From for ExtractedNoteCommitment { - fn from(cm: NoteCommitment) -> Self { - ExtractedNoteCommitment(extract_p(&cm.0)) - } -} - -impl From<&ExtractedNoteCommitment> for [u8; 32] { - fn from(cmu: &ExtractedNoteCommitment) -> Self { - cmu.to_bytes() - } -} - -impl ConstantTimeEq for ExtractedNoteCommitment { - fn ct_eq(&self, other: &Self) -> subtle::Choice { - self.0.ct_eq(&other.0) - } -} - -impl PartialEq for ExtractedNoteCommitment { - fn eq(&self, other: &Self) -> bool { - self.ct_eq(other).into() - } -} - -impl Eq for ExtractedNoteCommitment {} diff --git a/zcash_primitives/src/sapling/note/nullifier.rs b/zcash_primitives/src/sapling/note/nullifier.rs deleted file mode 100644 index 6fd212de4..000000000 --- a/zcash_primitives/src/sapling/note/nullifier.rs +++ /dev/null @@ -1,54 +0,0 @@ -use std::array::TryFromSliceError; -use std::fmt; - -use subtle::{Choice, ConstantTimeEq}; - -use super::NoteCommitment; -use crate::sapling::{ - keys::NullifierDerivingKey, - spec::{mixing_pedersen_hash, prf_nf}, -}; - -/// Typesafe wrapper for nullifier values. -#[derive(Copy, Clone, PartialEq, Eq)] -pub struct Nullifier(pub [u8; 32]); - -impl fmt::Debug for Nullifier { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Nullifier") - .field(&hex::encode(self.0)) - .finish() - } -} - -impl Nullifier { - pub fn from_slice(bytes: &[u8]) -> Result { - bytes.try_into().map(Nullifier) - } - - pub fn to_vec(&self) -> Vec { - self.0.to_vec() - } - - /// $DeriveNullifier$. - /// - /// Defined in [Zcash Protocol Spec § 4.16: Note Commitments and Nullifiers][commitmentsandnullifiers]. - /// - /// [commitmentsandnullifiers]: https://zips.z.cash/protocol/protocol.pdf#commitmentsandnullifiers - pub(super) fn derive(nk: &NullifierDerivingKey, cm: NoteCommitment, position: u64) -> Self { - let rho = mixing_pedersen_hash(cm.inner(), position); - Nullifier(prf_nf(&nk.0, &rho)) - } -} - -impl AsRef<[u8]> for Nullifier { - fn as_ref(&self) -> &[u8] { - &self.0 - } -} - -impl ConstantTimeEq for Nullifier { - fn ct_eq(&self, other: &Self) -> Choice { - self.0.ct_eq(&other.0) - } -} diff --git a/zcash_primitives/src/sapling/note_encryption.rs b/zcash_primitives/src/sapling/note_encryption.rs deleted file mode 100644 index 92d71664c..000000000 --- a/zcash_primitives/src/sapling/note_encryption.rs +++ /dev/null @@ -1,1519 +0,0 @@ -//! Implementation of in-band secret distribution for Zcash transactions. -//! -//! NB: the example code is only covering the post-Canopy case. - -use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams}; -use byteorder::{LittleEndian, WriteBytesExt}; -use ff::PrimeField; -use memuse::DynamicUsage; -use rand_core::RngCore; - -use zcash_note_encryption::{ - try_compact_note_decryption, try_note_decryption, try_output_recovery_with_ock, - try_output_recovery_with_ovk, BatchDomain, Domain, EphemeralKeyBytes, NoteEncryption, - NotePlaintextBytes, OutPlaintextBytes, OutgoingCipherKey, ShieldedOutput, COMPACT_NOTE_SIZE, - ENC_CIPHERTEXT_SIZE, NOTE_PLAINTEXT_SIZE, OUT_PLAINTEXT_SIZE, -}; - -use crate::sapling::{ - bundle::{GrothProofBytes, OutputDescription}, - keys::{ - DiversifiedTransmissionKey, EphemeralPublicKey, EphemeralSecretKey, OutgoingViewingKey, - SharedSecret, - }, - value::{NoteValue, ValueCommitment}, - Diversifier, Note, PaymentAddress, Rseed, -}; - -use super::note::ExtractedNoteCommitment; - -pub use crate::sapling::keys::{PreparedEphemeralPublicKey, PreparedIncomingViewingKey}; - -pub const KDF_SAPLING_PERSONALIZATION: &[u8; 16] = b"Zcash_SaplingKDF"; -pub const PRF_OCK_PERSONALIZATION: &[u8; 16] = b"Zcash_Derive_ock"; - -/// Sapling PRF^ock. -/// -/// Implemented per section 5.4.2 of the Zcash Protocol Specification. -pub fn prf_ock( - ovk: &OutgoingViewingKey, - cv: &ValueCommitment, - cmu_bytes: &[u8; 32], - ephemeral_key: &EphemeralKeyBytes, -) -> OutgoingCipherKey { - OutgoingCipherKey( - Blake2bParams::new() - .hash_length(32) - .personal(PRF_OCK_PERSONALIZATION) - .to_state() - .update(&ovk.0) - .update(&cv.to_bytes()) - .update(cmu_bytes) - .update(ephemeral_key.as_ref()) - .finalize() - .as_bytes() - .try_into() - .unwrap(), - ) -} - -/// The enforcement policy for ZIP 212 that should be applied when creating or decrypting -/// Sapling outputs. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum Zip212Enforcement { - Off, - GracePeriod, - On, -} - -/// `get_pk_d` must check that the diversifier contained within the note plaintext is a -/// valid Sapling diversifier. -fn sapling_parse_note_plaintext_without_memo( - domain: &SaplingDomain, - plaintext: &[u8], - get_pk_d: F, -) -> Option<(Note, PaymentAddress)> -where - F: FnOnce(&Diversifier) -> Option, -{ - assert!(plaintext.len() >= COMPACT_NOTE_SIZE); - - // Check note plaintext version - if !plaintext_version_is_valid(domain.zip212_enforcement, plaintext[0]) { - return None; - } - - // The unwraps below are guaranteed to succeed by the assertion above - let diversifier = Diversifier( - plaintext[1..12] - .try_into() - .expect("Note plaintext is checked to have length >= COMPACT_NOTE_SIZE."), - ); - let value = NoteValue::from_bytes( - plaintext[12..20] - .try_into() - .expect("Note plaintext is checked to have length >= COMPACT_NOTE_SIZE."), - ); - let r: [u8; 32] = plaintext[20..COMPACT_NOTE_SIZE] - .try_into() - .expect("Note plaintext is checked to have length >= COMPACT_NOTE_SIZE."); - - let rseed = if plaintext[0] == 0x01 { - let rcm = Option::from(jubjub::Fr::from_repr(r))?; - Rseed::BeforeZip212(rcm) - } else { - Rseed::AfterZip212(r) - }; - - let pk_d = get_pk_d(&diversifier)?; - - // `diversifier` was checked by `get_pk_d`. - let to = PaymentAddress::from_parts_unchecked(diversifier, pk_d)?; - let note = to.create_note(value, rseed); - Some((note, to)) -} - -pub struct SaplingDomain { - zip212_enforcement: Zip212Enforcement, -} - -memuse::impl_no_dynamic_usage!(SaplingDomain); - -impl SaplingDomain { - pub fn new(zip212_enforcement: Zip212Enforcement) -> Self { - Self { zip212_enforcement } - } -} - -impl Domain for SaplingDomain { - type EphemeralSecretKey = EphemeralSecretKey; - // It is acceptable for this to be a point rather than a byte array, because we - // enforce by consensus that points must not be small-order, and all points with - // non-canonical serialization are small-order. - type EphemeralPublicKey = EphemeralPublicKey; - type PreparedEphemeralPublicKey = PreparedEphemeralPublicKey; - type SharedSecret = SharedSecret; - type SymmetricKey = Blake2bHash; - type Note = Note; - type Recipient = PaymentAddress; - type DiversifiedTransmissionKey = DiversifiedTransmissionKey; - type IncomingViewingKey = PreparedIncomingViewingKey; - type OutgoingViewingKey = OutgoingViewingKey; - type ValueCommitment = ValueCommitment; - type ExtractedCommitment = ExtractedNoteCommitment; - type ExtractedCommitmentBytes = [u8; 32]; - type Memo = [u8; 512]; - - fn derive_esk(note: &Self::Note) -> Option { - note.derive_esk() - } - - fn get_pk_d(note: &Self::Note) -> Self::DiversifiedTransmissionKey { - *note.recipient().pk_d() - } - - fn prepare_epk(epk: Self::EphemeralPublicKey) -> Self::PreparedEphemeralPublicKey { - PreparedEphemeralPublicKey::new(epk) - } - - fn ka_derive_public( - note: &Self::Note, - esk: &Self::EphemeralSecretKey, - ) -> Self::EphemeralPublicKey { - esk.derive_public(note.recipient().g_d().into()) - } - - fn ka_agree_enc( - esk: &Self::EphemeralSecretKey, - pk_d: &Self::DiversifiedTransmissionKey, - ) -> Self::SharedSecret { - esk.agree(pk_d) - } - - fn ka_agree_dec( - ivk: &Self::IncomingViewingKey, - epk: &Self::PreparedEphemeralPublicKey, - ) -> Self::SharedSecret { - epk.agree(ivk) - } - - /// Sapling KDF for note encryption. - /// - /// Implements section 5.4.4.4 of the Zcash Protocol Specification. - fn kdf(dhsecret: SharedSecret, epk: &EphemeralKeyBytes) -> Blake2bHash { - dhsecret.kdf_sapling(epk) - } - - fn note_plaintext_bytes(note: &Self::Note, memo: &Self::Memo) -> NotePlaintextBytes { - // Note plaintext encoding is defined in section 5.5 of the Zcash Protocol - // Specification. - let mut input = [0; NOTE_PLAINTEXT_SIZE]; - input[0] = match note.rseed() { - Rseed::BeforeZip212(_) => 1, - Rseed::AfterZip212(_) => 2, - }; - input[1..12].copy_from_slice(¬e.recipient().diversifier().0); - (&mut input[12..20]) - .write_u64::(note.value().inner()) - .unwrap(); - - match note.rseed() { - Rseed::BeforeZip212(rcm) => { - input[20..COMPACT_NOTE_SIZE].copy_from_slice(rcm.to_repr().as_ref()); - } - Rseed::AfterZip212(rseed) => { - input[20..COMPACT_NOTE_SIZE].copy_from_slice(rseed); - } - } - - input[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE].copy_from_slice(&memo[..]); - - NotePlaintextBytes(input) - } - - fn derive_ock( - ovk: &Self::OutgoingViewingKey, - cv: &Self::ValueCommitment, - cmu_bytes: &Self::ExtractedCommitmentBytes, - epk: &EphemeralKeyBytes, - ) -> OutgoingCipherKey { - prf_ock(ovk, cv, cmu_bytes, epk) - } - - fn outgoing_plaintext_bytes( - note: &Self::Note, - esk: &Self::EphemeralSecretKey, - ) -> OutPlaintextBytes { - let mut input = [0u8; OUT_PLAINTEXT_SIZE]; - input[0..32].copy_from_slice(¬e.recipient().pk_d().to_bytes()); - input[32..OUT_PLAINTEXT_SIZE].copy_from_slice(esk.0.to_repr().as_ref()); - - OutPlaintextBytes(input) - } - - fn epk_bytes(epk: &Self::EphemeralPublicKey) -> EphemeralKeyBytes { - epk.to_bytes() - } - - fn epk(ephemeral_key: &EphemeralKeyBytes) -> Option { - // ZIP 216: We unconditionally reject non-canonical encodings, because these have - // always been rejected by consensus (due to small-order checks). - // https://zips.z.cash/zip-0216#specification - EphemeralPublicKey::from_bytes(&ephemeral_key.0).into() - } - - fn parse_note_plaintext_without_memo_ivk( - &self, - ivk: &Self::IncomingViewingKey, - plaintext: &[u8], - ) -> Option<(Self::Note, Self::Recipient)> { - sapling_parse_note_plaintext_without_memo(self, plaintext, |diversifier| { - DiversifiedTransmissionKey::derive(ivk, diversifier) - }) - } - - fn parse_note_plaintext_without_memo_ovk( - &self, - pk_d: &Self::DiversifiedTransmissionKey, - plaintext: &NotePlaintextBytes, - ) -> Option<(Self::Note, Self::Recipient)> { - sapling_parse_note_plaintext_without_memo(self, &plaintext.0, |diversifier| { - diversifier.g_d().map(|_| *pk_d) - }) - } - - fn cmstar(note: &Self::Note) -> Self::ExtractedCommitment { - note.cmu() - } - - fn extract_pk_d(op: &OutPlaintextBytes) -> Option { - DiversifiedTransmissionKey::from_bytes( - op.0[0..32].try_into().expect("slice is the correct length"), - ) - .into() - } - - fn extract_esk(op: &OutPlaintextBytes) -> Option { - EphemeralSecretKey::from_bytes( - op.0[32..OUT_PLAINTEXT_SIZE] - .try_into() - .expect("slice is the correct length"), - ) - .into() - } - - fn extract_memo(&self, plaintext: &NotePlaintextBytes) -> Self::Memo { - plaintext.0[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE] - .try_into() - .expect("correct length") - } -} - -impl BatchDomain for SaplingDomain { - fn batch_kdf<'a>( - items: impl Iterator, &'a EphemeralKeyBytes)>, - ) -> Vec> { - let (shared_secrets, ephemeral_keys): (Vec<_>, Vec<_>) = items.unzip(); - - SharedSecret::batch_to_affine(shared_secrets) - .zip(ephemeral_keys.into_iter()) - .map(|(secret, ephemeral_key)| { - secret.map(|dhsecret| SharedSecret::kdf_sapling_inner(dhsecret, ephemeral_key)) - }) - .collect() - } - - fn batch_epk( - ephemeral_keys: impl Iterator, - ) -> Vec<(Option, EphemeralKeyBytes)> { - let ephemeral_keys: Vec<_> = ephemeral_keys.collect(); - let epks = jubjub::AffinePoint::batch_from_bytes(ephemeral_keys.iter().map(|b| b.0)); - epks.into_iter() - .zip(ephemeral_keys.into_iter()) - .map(|(epk, ephemeral_key)| { - ( - Option::from(epk) - .map(EphemeralPublicKey::from_affine) - .map(Self::prepare_epk), - ephemeral_key, - ) - }) - .collect() - } -} - -#[derive(Clone)] -pub struct CompactOutputDescription { - pub ephemeral_key: EphemeralKeyBytes, - pub cmu: ExtractedNoteCommitment, - pub enc_ciphertext: [u8; COMPACT_NOTE_SIZE], -} - -memuse::impl_no_dynamic_usage!(CompactOutputDescription); - -impl ShieldedOutput for CompactOutputDescription { - fn ephemeral_key(&self) -> EphemeralKeyBytes { - self.ephemeral_key.clone() - } - - fn cmstar_bytes(&self) -> [u8; 32] { - self.cmu.to_bytes() - } - - fn enc_ciphertext(&self) -> &[u8; COMPACT_NOTE_SIZE] { - &self.enc_ciphertext - } -} - -/// Creates a new encryption context for the given note. -/// -/// Setting `ovk` to `None` represents the `ovk = ⊥` case, where the note cannot be -/// recovered by the sender. -/// -/// NB: the example code here only covers the post-Canopy case. -/// -/// # Examples -/// -/// ``` -/// use ff::Field; -/// use rand_core::OsRng; -/// use zcash_primitives::{ -/// consensus::{TEST_NETWORK, NetworkUpgrade, Parameters}, -/// sapling::{ -/// keys::OutgoingViewingKey, -/// note_encryption::{sapling_note_encryption, Zip212Enforcement}, -/// util::generate_random_rseed, -/// value::{NoteValue, ValueCommitTrapdoor, ValueCommitment}, -/// Diversifier, PaymentAddress, Rseed, SaplingIvk, -/// }, -/// }; -/// -/// let mut rng = OsRng; -/// -/// let ivk = SaplingIvk(jubjub::Scalar::random(&mut rng)); -/// let diversifier = Diversifier([0; 11]); -/// let to = ivk.to_payment_address(diversifier).unwrap(); -/// let ovk = Some(OutgoingViewingKey([0; 32])); -/// -/// let value = NoteValue::from_raw(1000); -/// let rcv = ValueCommitTrapdoor::random(&mut rng); -/// let cv = ValueCommitment::derive(value, rcv); -/// let height = TEST_NETWORK.activation_height(NetworkUpgrade::Canopy).unwrap(); -/// let rseed = generate_random_rseed( -/// Zip212Enforcement::GracePeriod, -/// &mut rng, -/// ); -/// let note = to.create_note(value, rseed); -/// let cmu = note.cmu(); -/// -/// let mut enc = sapling_note_encryption(ovk, note, [0x37; 512], &mut rng); -/// let encCiphertext = enc.encrypt_note_plaintext(); -/// let outCiphertext = enc.encrypt_outgoing_plaintext(&cv, &cmu, &mut rng); -/// ``` -pub fn sapling_note_encryption( - ovk: Option, - note: Note, - memo: [u8; 512], - rng: &mut R, -) -> NoteEncryption { - let esk = note.generate_or_derive_esk_internal(rng); - NoteEncryption::new_with_esk(esk, ovk, note, memo) -} - -#[allow(clippy::if_same_then_else)] -#[allow(clippy::needless_bool)] -pub fn plaintext_version_is_valid(zip212_enforcement: Zip212Enforcement, leadbyte: u8) -> bool { - match zip212_enforcement { - Zip212Enforcement::Off => leadbyte == 0x01, - Zip212Enforcement::GracePeriod => leadbyte == 0x01 || leadbyte == 0x02, - Zip212Enforcement::On => leadbyte == 0x02, - } -} - -pub fn try_sapling_note_decryption>( - ivk: &PreparedIncomingViewingKey, - output: &Output, - zip212_enforcement: Zip212Enforcement, -) -> Option<(Note, PaymentAddress, [u8; 512])> { - let domain = SaplingDomain::new(zip212_enforcement); - try_note_decryption(&domain, ivk, output) -} - -pub fn try_sapling_compact_note_decryption< - Output: ShieldedOutput, ->( - ivk: &PreparedIncomingViewingKey, - output: &Output, - zip212_enforcement: Zip212Enforcement, -) -> Option<(Note, PaymentAddress)> { - let domain = SaplingDomain::new(zip212_enforcement); - try_compact_note_decryption(&domain, ivk, output) -} - -/// Recovery of the full note plaintext by the sender. -/// -/// Attempts to decrypt and validate the given `enc_ciphertext` using the given `ock`. -/// If successful, the corresponding Sapling note and memo are returned, along with the -/// `PaymentAddress` to which the note was sent. -/// -/// Implements part of section 4.19.3 of the Zcash Protocol Specification. -/// For decryption using a Full Viewing Key see [`try_sapling_output_recovery`]. -pub fn try_sapling_output_recovery_with_ock( - ock: &OutgoingCipherKey, - output: &OutputDescription, - zip212_enforcement: Zip212Enforcement, -) -> Option<(Note, PaymentAddress, [u8; 512])> { - let domain = SaplingDomain::new(zip212_enforcement); - try_output_recovery_with_ock(&domain, ock, output, output.out_ciphertext()) -} - -/// Recovery of the full note plaintext by the sender. -/// -/// Attempts to decrypt and validate the given `enc_ciphertext` using the given `ovk`. -/// If successful, the corresponding Sapling note and memo are returned, along with the -/// `PaymentAddress` to which the note was sent. -/// -/// Implements section 4.19.3 of the Zcash Protocol Specification. -#[allow(clippy::too_many_arguments)] -pub fn try_sapling_output_recovery( - ovk: &OutgoingViewingKey, - output: &OutputDescription, - zip212_enforcement: Zip212Enforcement, -) -> Option<(Note, PaymentAddress, [u8; 512])> { - let domain = SaplingDomain::new(zip212_enforcement); - try_output_recovery_with_ovk(&domain, ovk, output, output.cv(), output.out_ciphertext()) -} - -#[cfg(test)] -mod tests { - use chacha20poly1305::{ - aead::{AeadInPlace, KeyInit}, - ChaCha20Poly1305, - }; - use ff::{Field, PrimeField}; - use group::Group; - use group::GroupEncoding; - use rand_core::OsRng; - use rand_core::{CryptoRng, RngCore}; - - use zcash_note_encryption::{ - batch, EphemeralKeyBytes, NoteEncryption, OutgoingCipherKey, ENC_CIPHERTEXT_SIZE, - NOTE_PLAINTEXT_SIZE, OUT_CIPHERTEXT_SIZE, OUT_PLAINTEXT_SIZE, - }; - - use super::{ - prf_ock, sapling_note_encryption, try_sapling_compact_note_decryption, - try_sapling_note_decryption, try_sapling_output_recovery, - try_sapling_output_recovery_with_ock, CompactOutputDescription, SaplingDomain, - Zip212Enforcement, - }; - - use crate::sapling::{ - bundle::{GrothProofBytes, OutputDescription}, - circuit::GROTH_PROOF_SIZE, - keys::{DiversifiedTransmissionKey, EphemeralSecretKey, OutgoingViewingKey}, - note::ExtractedNoteCommitment, - note_encryption::PreparedIncomingViewingKey, - util::generate_random_rseed, - value::{NoteValue, ValueCommitTrapdoor, ValueCommitment}, - Diversifier, PaymentAddress, Rseed, SaplingIvk, - }; - - fn random_enc_ciphertext( - zip212_enforcement: Zip212Enforcement, - mut rng: &mut R, - ) -> ( - OutgoingViewingKey, - OutgoingCipherKey, - PreparedIncomingViewingKey, - OutputDescription, - ) { - let ivk = SaplingIvk(jubjub::Fr::random(&mut rng)); - let prepared_ivk = PreparedIncomingViewingKey::new(&ivk); - - let (ovk, ock, output) = random_enc_ciphertext_with(&ivk, zip212_enforcement, rng); - - assert!(try_sapling_note_decryption(&prepared_ivk, &output, zip212_enforcement).is_some()); - assert!(try_sapling_compact_note_decryption( - &prepared_ivk, - &CompactOutputDescription::from(output.clone()), - zip212_enforcement, - ) - .is_some()); - - let ovk_output_recovery = try_sapling_output_recovery(&ovk, &output, zip212_enforcement); - - let ock_output_recovery = - try_sapling_output_recovery_with_ock(&ock, &output, zip212_enforcement); - assert!(ovk_output_recovery.is_some()); - assert!(ock_output_recovery.is_some()); - assert_eq!(ovk_output_recovery, ock_output_recovery); - - (ovk, ock, prepared_ivk, output) - } - - fn random_enc_ciphertext_with( - ivk: &SaplingIvk, - zip212_enforcement: Zip212Enforcement, - mut rng: &mut R, - ) -> ( - OutgoingViewingKey, - OutgoingCipherKey, - OutputDescription, - ) { - let diversifier = Diversifier([0; 11]); - let pa = ivk.to_payment_address(diversifier).unwrap(); - - // Construct the value commitment for the proof instance - let value = NoteValue::from_raw(100); - let rcv = ValueCommitTrapdoor::random(&mut rng); - let cv = ValueCommitment::derive(value, rcv); - - let rseed = generate_random_rseed(zip212_enforcement, &mut rng); - - let note = pa.create_note(value, rseed); - let cmu = note.cmu(); - - let ovk = OutgoingViewingKey([0; 32]); - let ne = sapling_note_encryption(Some(ovk), note, [0x37; 512], &mut rng); - let epk = ne.epk(); - let ock = prf_ock(&ovk, &cv, &cmu.to_bytes(), &epk.to_bytes()); - - let out_ciphertext = ne.encrypt_outgoing_plaintext(&cv, &cmu, &mut rng); - let output = OutputDescription::from_parts( - cv, - cmu, - epk.to_bytes(), - ne.encrypt_note_plaintext(), - out_ciphertext, - [0u8; GROTH_PROOF_SIZE], - ); - - (ovk, ock, output) - } - - fn reencrypt_out_ciphertext( - ovk: &OutgoingViewingKey, - cv: &ValueCommitment, - cmu: &ExtractedNoteCommitment, - ephemeral_key: &EphemeralKeyBytes, - out_ciphertext: &[u8; OUT_CIPHERTEXT_SIZE], - modify_plaintext: impl Fn(&mut [u8; OUT_PLAINTEXT_SIZE]), - ) -> [u8; OUT_CIPHERTEXT_SIZE] { - let ock = prf_ock(ovk, cv, &cmu.to_bytes(), ephemeral_key); - - let mut op = [0; OUT_PLAINTEXT_SIZE]; - op.copy_from_slice(&out_ciphertext[..OUT_PLAINTEXT_SIZE]); - - ChaCha20Poly1305::new(ock.as_ref().into()) - .decrypt_in_place_detached( - [0u8; 12][..].into(), - &[], - &mut op, - out_ciphertext[OUT_PLAINTEXT_SIZE..].into(), - ) - .unwrap(); - - modify_plaintext(&mut op); - - let tag = ChaCha20Poly1305::new(ock.as_ref().into()) - .encrypt_in_place_detached([0u8; 12][..].into(), &[], &mut op) - .unwrap(); - - let mut out_ciphertext = [0u8; OUT_CIPHERTEXT_SIZE]; - out_ciphertext[..OUT_PLAINTEXT_SIZE].copy_from_slice(&op); - out_ciphertext[OUT_PLAINTEXT_SIZE..].copy_from_slice(&tag); - out_ciphertext - } - - fn reencrypt_enc_ciphertext( - ovk: &OutgoingViewingKey, - cv: &ValueCommitment, - cmu: &ExtractedNoteCommitment, - ephemeral_key: &EphemeralKeyBytes, - enc_ciphertext: &[u8; ENC_CIPHERTEXT_SIZE], - out_ciphertext: &[u8; OUT_CIPHERTEXT_SIZE], - modify_plaintext: impl Fn(&mut [u8; NOTE_PLAINTEXT_SIZE]), - ) -> [u8; ENC_CIPHERTEXT_SIZE] { - let ock = prf_ock(ovk, cv, &cmu.to_bytes(), ephemeral_key); - - let mut op = [0; OUT_PLAINTEXT_SIZE]; - op.copy_from_slice(&out_ciphertext[..OUT_PLAINTEXT_SIZE]); - - ChaCha20Poly1305::new(ock.as_ref().into()) - .decrypt_in_place_detached( - [0u8; 12][..].into(), - &[], - &mut op, - out_ciphertext[OUT_PLAINTEXT_SIZE..].into(), - ) - .unwrap(); - - let pk_d = DiversifiedTransmissionKey::from_bytes(&op[0..32].try_into().unwrap()).unwrap(); - - let esk = jubjub::Fr::from_repr(op[32..OUT_PLAINTEXT_SIZE].try_into().unwrap()).unwrap(); - - let shared_secret = EphemeralSecretKey(esk).agree(&pk_d); - let key = shared_secret.kdf_sapling(ephemeral_key); - - let mut plaintext = [0; NOTE_PLAINTEXT_SIZE]; - plaintext.copy_from_slice(&enc_ciphertext[..NOTE_PLAINTEXT_SIZE]); - - ChaCha20Poly1305::new(key.as_bytes().into()) - .decrypt_in_place_detached( - [0u8; 12][..].into(), - &[], - &mut plaintext, - enc_ciphertext[NOTE_PLAINTEXT_SIZE..].into(), - ) - .unwrap(); - - modify_plaintext(&mut plaintext); - - let tag = ChaCha20Poly1305::new(key.as_ref().into()) - .encrypt_in_place_detached([0u8; 12][..].into(), &[], &mut plaintext) - .unwrap(); - - let mut enc_ciphertext = [0u8; ENC_CIPHERTEXT_SIZE]; - enc_ciphertext[..NOTE_PLAINTEXT_SIZE].copy_from_slice(&plaintext); - enc_ciphertext[NOTE_PLAINTEXT_SIZE..].copy_from_slice(&tag); - enc_ciphertext - } - - fn find_invalid_diversifier() -> Diversifier { - // Find an invalid diversifier - let mut d = Diversifier([0; 11]); - loop { - for k in 0..11 { - d.0[k] = d.0[k].wrapping_add(1); - if d.0[k] != 0 { - break; - } - } - if d.g_d().is_none() { - break; - } - } - d - } - - fn find_valid_diversifier() -> Diversifier { - // Find a different valid diversifier - let mut d = Diversifier([0; 11]); - loop { - for k in 0..11 { - d.0[k] = d.0[k].wrapping_add(1); - if d.0[k] != 0 { - break; - } - } - if d.g_d().is_some() { - break; - } - } - d - } - - #[test] - fn decryption_with_invalid_ivk() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (_, _, _, output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - - assert_eq!( - try_sapling_note_decryption( - &PreparedIncomingViewingKey::new(&SaplingIvk(jubjub::Fr::random(&mut rng))), - &output, - zip212_enforcement, - ), - None - ); - } - } - - #[test] - fn decryption_with_invalid_epk() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (_, _, ivk, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - - *output.ephemeral_key_mut() = jubjub::ExtendedPoint::random(&mut rng).to_bytes().into(); - - assert_eq!( - try_sapling_note_decryption(&ivk, &output, zip212_enforcement,), - None - ); - } - } - - #[test] - fn decryption_with_invalid_cmu() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (_, _, ivk, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - *output.cmu_mut() = - ExtractedNoteCommitment::from_bytes(&bls12_381::Scalar::random(&mut rng).to_repr()) - .unwrap(); - - assert_eq!( - try_sapling_note_decryption(&ivk, &output, zip212_enforcement,), - None - ); - } - } - - #[test] - fn decryption_with_invalid_tag() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (_, _, ivk, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - output.enc_ciphertext_mut()[ENC_CIPHERTEXT_SIZE - 1] ^= 0xff; - - assert_eq!( - try_sapling_note_decryption(&ivk, &output, zip212_enforcement,), - None - ); - } - } - - #[test] - fn decryption_with_invalid_version_byte() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - let leadbytes = [0x02, 0x03, 0x01]; - - for (zip212_enforcement, leadbyte) in zip212_states.into_iter().zip(leadbytes) { - let (ovk, _, ivk, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - - *output.enc_ciphertext_mut() = reencrypt_enc_ciphertext( - &ovk, - output.cv(), - output.cmu(), - output.ephemeral_key(), - output.enc_ciphertext(), - output.out_ciphertext(), - |pt| pt[0] = leadbyte, - ); - assert_eq!( - try_sapling_note_decryption(&ivk, &output, zip212_enforcement), - None - ); - } - } - - #[test] - fn decryption_with_invalid_diversifier() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (ovk, _, ivk, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - - *output.enc_ciphertext_mut() = reencrypt_enc_ciphertext( - &ovk, - output.cv(), - output.cmu(), - output.ephemeral_key(), - output.enc_ciphertext(), - output.out_ciphertext(), - |pt| pt[1..12].copy_from_slice(&find_invalid_diversifier().0), - ); - assert_eq!( - try_sapling_note_decryption(&ivk, &output, zip212_enforcement), - None - ); - } - } - - #[test] - fn decryption_with_incorrect_diversifier() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (ovk, _, ivk, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - - *output.enc_ciphertext_mut() = reencrypt_enc_ciphertext( - &ovk, - output.cv(), - output.cmu(), - output.ephemeral_key(), - output.enc_ciphertext(), - output.out_ciphertext(), - |pt| pt[1..12].copy_from_slice(&find_valid_diversifier().0), - ); - - assert_eq!( - try_sapling_note_decryption(&ivk, &output, zip212_enforcement), - None - ); - } - } - - #[test] - fn compact_decryption_with_invalid_ivk() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (_, _, _, output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - - assert_eq!( - try_sapling_compact_note_decryption( - &PreparedIncomingViewingKey::new(&SaplingIvk(jubjub::Fr::random(&mut rng))), - &CompactOutputDescription::from(output), - zip212_enforcement, - ), - None - ); - } - } - - #[test] - fn compact_decryption_with_invalid_epk() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (_, _, ivk, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - *output.ephemeral_key_mut() = jubjub::ExtendedPoint::random(&mut rng).to_bytes().into(); - - assert_eq!( - try_sapling_compact_note_decryption( - &ivk, - &CompactOutputDescription::from(output), - zip212_enforcement, - ), - None - ); - } - } - - #[test] - fn compact_decryption_with_invalid_cmu() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (_, _, ivk, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - *output.cmu_mut() = - ExtractedNoteCommitment::from_bytes(&bls12_381::Scalar::random(&mut rng).to_repr()) - .unwrap(); - - assert_eq!( - try_sapling_compact_note_decryption( - &ivk, - &CompactOutputDescription::from(output), - zip212_enforcement, - ), - None - ); - } - } - - #[test] - fn compact_decryption_with_invalid_version_byte() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - let leadbytes = [0x02, 0x03, 0x01]; - - for (zip212_enforcement, leadbyte) in zip212_states.into_iter().zip(leadbytes) { - let (ovk, _, ivk, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - - *output.enc_ciphertext_mut() = reencrypt_enc_ciphertext( - &ovk, - output.cv(), - output.cmu(), - output.ephemeral_key(), - output.enc_ciphertext(), - output.out_ciphertext(), - |pt| pt[0] = leadbyte, - ); - assert_eq!( - try_sapling_compact_note_decryption( - &ivk, - &CompactOutputDescription::from(output), - zip212_enforcement, - ), - None - ); - } - } - - #[test] - fn compact_decryption_with_invalid_diversifier() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (ovk, _, ivk, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - - *output.enc_ciphertext_mut() = reencrypt_enc_ciphertext( - &ovk, - output.cv(), - output.cmu(), - output.ephemeral_key(), - output.enc_ciphertext(), - output.out_ciphertext(), - |pt| pt[1..12].copy_from_slice(&find_invalid_diversifier().0), - ); - assert_eq!( - try_sapling_compact_note_decryption( - &ivk, - &CompactOutputDescription::from(output), - zip212_enforcement, - ), - None - ); - } - } - - #[test] - fn compact_decryption_with_incorrect_diversifier() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (ovk, _, ivk, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - - *output.enc_ciphertext_mut() = reencrypt_enc_ciphertext( - &ovk, - output.cv(), - output.cmu(), - output.ephemeral_key(), - output.enc_ciphertext(), - output.out_ciphertext(), - |pt| pt[1..12].copy_from_slice(&find_valid_diversifier().0), - ); - assert_eq!( - try_sapling_compact_note_decryption( - &ivk, - &CompactOutputDescription::from(output), - zip212_enforcement, - ), - None - ); - } - } - - #[test] - fn recovery_with_invalid_ovk() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (mut ovk, _, _, output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - - ovk.0[0] ^= 0xff; - assert_eq!( - try_sapling_output_recovery(&ovk, &output, zip212_enforcement), - None - ); - } - } - - #[test] - fn recovery_with_invalid_ock() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (_, _, _, output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - - assert_eq!( - try_sapling_output_recovery_with_ock( - &OutgoingCipherKey([0u8; 32]), - &output, - zip212_enforcement, - ), - None - ); - } - } - - #[test] - fn recovery_with_invalid_cv() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (ovk, _, _, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - *output.cv_mut() = ValueCommitment::derive( - NoteValue::from_raw(7), - ValueCommitTrapdoor::random(&mut rng), - ); - - assert_eq!( - try_sapling_output_recovery(&ovk, &output, zip212_enforcement,), - None - ); - } - } - - #[test] - fn recovery_with_invalid_cmu() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (ovk, ock, _, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - *output.cmu_mut() = - ExtractedNoteCommitment::from_bytes(&bls12_381::Scalar::random(&mut rng).to_repr()) - .unwrap(); - - assert_eq!( - try_sapling_output_recovery(&ovk, &output, zip212_enforcement), - None - ); - - assert_eq!( - try_sapling_output_recovery_with_ock(&ock, &output, zip212_enforcement), - None - ); - } - } - - #[test] - fn recovery_with_invalid_epk() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (ovk, ock, _, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - *output.ephemeral_key_mut() = jubjub::ExtendedPoint::random(&mut rng).to_bytes().into(); - - assert_eq!( - try_sapling_output_recovery(&ovk, &output, zip212_enforcement), - None - ); - - assert_eq!( - try_sapling_output_recovery_with_ock(&ock, &output, zip212_enforcement), - None - ); - } - } - - #[test] - fn recovery_with_invalid_enc_tag() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (ovk, ock, _, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - - output.enc_ciphertext_mut()[ENC_CIPHERTEXT_SIZE - 1] ^= 0xff; - assert_eq!( - try_sapling_output_recovery(&ovk, &output, zip212_enforcement), - None - ); - assert_eq!( - try_sapling_output_recovery_with_ock(&ock, &output, zip212_enforcement), - None - ); - } - } - - #[test] - fn recovery_with_invalid_out_tag() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (ovk, ock, _, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - - output.out_ciphertext_mut()[OUT_CIPHERTEXT_SIZE - 1] ^= 0xff; - assert_eq!( - try_sapling_output_recovery(&ovk, &output, zip212_enforcement), - None - ); - assert_eq!( - try_sapling_output_recovery_with_ock(&ock, &output, zip212_enforcement), - None - ); - } - } - - #[test] - fn recovery_with_invalid_version_byte() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - let leadbytes = [0x02, 0x03, 0x01]; - - for (zip212_enforcement, leadbyte) in zip212_states.into_iter().zip(leadbytes) { - let (ovk, ock, _, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - - *output.enc_ciphertext_mut() = reencrypt_enc_ciphertext( - &ovk, - output.cv(), - output.cmu(), - output.ephemeral_key(), - output.enc_ciphertext(), - output.out_ciphertext(), - |pt| pt[0] = leadbyte, - ); - assert_eq!( - try_sapling_output_recovery(&ovk, &output, zip212_enforcement), - None - ); - assert_eq!( - try_sapling_output_recovery_with_ock(&ock, &output, zip212_enforcement), - None - ); - } - } - - #[test] - fn recovery_with_invalid_diversifier() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (ovk, ock, _, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - - *output.enc_ciphertext_mut() = reencrypt_enc_ciphertext( - &ovk, - output.cv(), - output.cmu(), - output.ephemeral_key(), - output.enc_ciphertext(), - output.out_ciphertext(), - |pt| pt[1..12].copy_from_slice(&find_invalid_diversifier().0), - ); - assert_eq!( - try_sapling_output_recovery(&ovk, &output, zip212_enforcement), - None - ); - assert_eq!( - try_sapling_output_recovery_with_ock(&ock, &output, zip212_enforcement), - None - ); - } - } - - #[test] - fn recovery_with_incorrect_diversifier() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (ovk, ock, _, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - - *output.enc_ciphertext_mut() = reencrypt_enc_ciphertext( - &ovk, - output.cv(), - output.cmu(), - output.ephemeral_key(), - output.enc_ciphertext(), - output.out_ciphertext(), - |pt| pt[1..12].copy_from_slice(&find_valid_diversifier().0), - ); - assert_eq!( - try_sapling_output_recovery(&ovk, &output, zip212_enforcement), - None - ); - assert_eq!( - try_sapling_output_recovery_with_ock(&ock, &output, zip212_enforcement), - None - ); - } - } - - #[test] - fn recovery_with_invalid_pk_d() { - let mut rng = OsRng; - let zip212_states = [ - Zip212Enforcement::Off, - Zip212Enforcement::GracePeriod, - Zip212Enforcement::On, - ]; - - for zip212_enforcement in zip212_states { - let (ovk, ock, _, mut output) = random_enc_ciphertext(zip212_enforcement, &mut rng); - - *output.out_ciphertext_mut() = reencrypt_out_ciphertext( - &ovk, - output.cv(), - output.cmu(), - output.ephemeral_key(), - output.out_ciphertext(), - |pt| pt[0..32].copy_from_slice(&jubjub::ExtendedPoint::random(rng).to_bytes()), - ); - assert_eq!( - try_sapling_output_recovery(&ovk, &output, zip212_enforcement), - None - ); - assert_eq!( - try_sapling_output_recovery_with_ock(&ock, &output, zip212_enforcement), - None - ); - } - } - - #[test] - fn test_vectors() { - let test_vectors = crate::test_vectors::note_encryption::make_test_vectors(); - - macro_rules! read_cmu { - ($field:expr) => {{ - ExtractedNoteCommitment::from_bytes($field[..].try_into().unwrap()).unwrap() - }}; - } - - macro_rules! read_jubjub_scalar { - ($field:expr) => {{ - jubjub::Fr::from_repr($field[..].try_into().unwrap()).unwrap() - }}; - } - - macro_rules! read_pk_d { - ($field:expr) => { - DiversifiedTransmissionKey::from_bytes(&$field).unwrap() - }; - } - - macro_rules! read_cv { - ($field:expr) => { - ValueCommitment::from_bytes_not_small_order(&$field).unwrap() - }; - } - - let zip212_enforcement = Zip212Enforcement::Off; - - for tv in test_vectors { - // - // Load the test vector components - // - - let ivk = PreparedIncomingViewingKey::new(&SaplingIvk(read_jubjub_scalar!(tv.ivk))); - let pk_d = read_pk_d!(tv.default_pk_d); - let rcm = read_jubjub_scalar!(tv.rcm); - let cv = read_cv!(tv.cv); - let cmu = read_cmu!(tv.cmu); - let esk = EphemeralSecretKey(read_jubjub_scalar!(tv.esk)); - let ephemeral_key = EphemeralKeyBytes(tv.epk); - - // - // Test the individual components - // - - let shared_secret = esk.agree(&pk_d); - assert_eq!(shared_secret.to_bytes(), tv.shared_secret); - - let k_enc = shared_secret.kdf_sapling(&ephemeral_key); - assert_eq!(k_enc.as_bytes(), tv.k_enc); - - let ovk = OutgoingViewingKey(tv.ovk); - let ock = prf_ock(&ovk, &cv, &cmu.to_bytes(), &ephemeral_key); - assert_eq!(ock.as_ref(), tv.ock); - - let to = PaymentAddress::from_parts(Diversifier(tv.default_d), pk_d).unwrap(); - let note = to.create_note(NoteValue::from_raw(tv.v), Rseed::BeforeZip212(rcm)); - assert_eq!(note.cmu(), cmu); - - let output = OutputDescription::from_parts( - cv.clone(), - cmu, - ephemeral_key, - tv.c_enc, - tv.c_out, - [0u8; GROTH_PROOF_SIZE], - ); - - // - // Test decryption - // (Tested first because it only requires immutable references.) - // - - match try_sapling_note_decryption(&ivk, &output, zip212_enforcement) { - Some((decrypted_note, decrypted_to, decrypted_memo)) => { - assert_eq!(decrypted_note, note); - assert_eq!(decrypted_to, to); - assert_eq!(&decrypted_memo[..], &tv.memo[..]); - } - None => panic!("Note decryption failed"), - } - - match try_sapling_compact_note_decryption( - &ivk, - &CompactOutputDescription::from(output.clone()), - zip212_enforcement, - ) { - Some((decrypted_note, decrypted_to)) => { - assert_eq!(decrypted_note, note); - assert_eq!(decrypted_to, to); - } - None => panic!("Compact note decryption failed"), - } - - match try_sapling_output_recovery(&ovk, &output, zip212_enforcement) { - Some((decrypted_note, decrypted_to, decrypted_memo)) => { - assert_eq!(decrypted_note, note); - assert_eq!(decrypted_to, to); - assert_eq!(&decrypted_memo[..], &tv.memo[..]); - } - None => panic!("Output recovery failed"), - } - - match &batch::try_note_decryption( - &[ivk.clone()], - &[(SaplingDomain::new(zip212_enforcement), output.clone())], - )[..] - { - [Some(((decrypted_note, decrypted_to, decrypted_memo), i))] => { - assert_eq!(decrypted_note, ¬e); - assert_eq!(decrypted_to, &to); - assert_eq!(&decrypted_memo[..], &tv.memo[..]); - assert_eq!(*i, 0); - } - _ => panic!("Note decryption failed"), - } - - match &batch::try_compact_note_decryption( - &[ivk.clone()], - &[( - SaplingDomain::new(zip212_enforcement), - CompactOutputDescription::from(output.clone()), - )], - )[..] - { - [Some(((decrypted_note, decrypted_to), i))] => { - assert_eq!(decrypted_note, ¬e); - assert_eq!(decrypted_to, &to); - assert_eq!(*i, 0); - } - _ => panic!("Note decryption failed"), - } - - // - // Test encryption - // - - let ne = NoteEncryption::::new_with_esk(esk, Some(ovk), note, tv.memo); - - assert_eq!(ne.encrypt_note_plaintext().as_ref(), &tv.c_enc[..]); - assert_eq!( - &ne.encrypt_outgoing_plaintext(&cv, &cmu, &mut OsRng)[..], - &tv.c_out[..] - ); - } - } - - #[test] - fn batching() { - let mut rng = OsRng; - let zip212_enforcement = Zip212Enforcement::On; - - // Test batch trial-decryption with multiple IVKs and outputs. - let invalid_ivk = PreparedIncomingViewingKey::new(&SaplingIvk(jubjub::Fr::random(rng))); - let valid_ivk = SaplingIvk(jubjub::Fr::random(rng)); - let outputs: Vec<_> = (0..10) - .map(|_| { - ( - SaplingDomain::new(zip212_enforcement), - random_enc_ciphertext_with(&valid_ivk, zip212_enforcement, &mut rng).2, - ) - }) - .collect(); - let valid_ivk = PreparedIncomingViewingKey::new(&valid_ivk); - - // Check that batched trial decryptions with invalid_ivk fails. - let res = batch::try_note_decryption(&[invalid_ivk.clone()], &outputs); - assert_eq!(res.len(), 10); - assert_eq!(&res[..], &vec![None; 10][..]); - - // Check that batched trial decryptions with valid_ivk succeeds. - let res = batch::try_note_decryption(&[invalid_ivk, valid_ivk.clone()], &outputs); - assert_eq!(res.len(), 10); - for (result, (_, output)) in res.iter().zip(outputs.iter()) { - // Confirm the successful batched trial decryptions gave the same result. - // In all cases, the index of the valid ivk is returned. - assert!(result.is_some()); - assert_eq!( - result, - &try_sapling_note_decryption(&valid_ivk, output, zip212_enforcement) - .map(|r| (r, 1)) - ); - } - } -} diff --git a/zcash_primitives/src/sapling/pedersen_hash.rs b/zcash_primitives/src/sapling/pedersen_hash.rs deleted file mode 100644 index 20cc40a5c..000000000 --- a/zcash_primitives/src/sapling/pedersen_hash.rs +++ /dev/null @@ -1,160 +0,0 @@ -//! Implementation of the Pedersen hash function used in Sapling. - -#[cfg(test)] -pub(crate) mod test_vectors; - -use byteorder::{ByteOrder, LittleEndian}; -use ff::PrimeField; -use group::Group; -use std::ops::{AddAssign, Neg}; - -use super::constants::{ - PEDERSEN_HASH_CHUNKS_PER_GENERATOR, PEDERSEN_HASH_EXP_TABLE, PEDERSEN_HASH_EXP_WINDOW_SIZE, -}; - -#[derive(Copy, Clone)] -pub enum Personalization { - NoteCommitment, - MerkleTree(usize), -} - -impl Personalization { - pub fn get_bits(&self) -> Vec { - match *self { - Personalization::NoteCommitment => vec![true, true, true, true, true, true], - Personalization::MerkleTree(num) => { - assert!(num < 63); - - (0..6).map(|i| (num >> i) & 1 == 1).collect() - } - } - } -} - -pub fn pedersen_hash(personalization: Personalization, bits: I) -> jubjub::SubgroupPoint -where - I: IntoIterator, -{ - let mut bits = personalization - .get_bits() - .into_iter() - .chain(bits.into_iter()); - - let mut result = jubjub::SubgroupPoint::identity(); - let mut generators = PEDERSEN_HASH_EXP_TABLE.iter(); - - loop { - let mut acc = jubjub::Fr::zero(); - let mut cur = jubjub::Fr::one(); - let mut chunks_remaining = PEDERSEN_HASH_CHUNKS_PER_GENERATOR; - let mut encountered_bits = false; - - // Grab three bits from the input - while let Some(a) = bits.next() { - encountered_bits = true; - - let b = bits.next().unwrap_or(false); - let c = bits.next().unwrap_or(false); - - // Start computing this portion of the scalar - let mut tmp = cur; - if a { - tmp.add_assign(&cur); - } - cur = cur.double(); // 2^1 * cur - if b { - tmp.add_assign(&cur); - } - - // conditionally negate - if c { - tmp = tmp.neg(); - } - - acc.add_assign(&tmp); - - chunks_remaining -= 1; - - if chunks_remaining == 0 { - break; - } else { - cur = cur.double().double().double(); // 2^4 * cur - } - } - - if !encountered_bits { - break; - } - - let mut table: &[Vec] = - generators.next().expect("we don't have enough generators"); - let window = PEDERSEN_HASH_EXP_WINDOW_SIZE as usize; - let window_mask = (1u64 << window) - 1; - - let acc = acc.to_repr(); - let num_limbs: usize = acc.as_ref().len() / 8; - let mut limbs = vec![0u64; num_limbs + 1]; - LittleEndian::read_u64_into(acc.as_ref(), &mut limbs[..num_limbs]); - - let mut tmp = jubjub::SubgroupPoint::identity(); - - let mut pos = 0; - while pos < jubjub::Fr::NUM_BITS as usize { - let u64_idx = pos / 64; - let bit_idx = pos % 64; - let i = (if bit_idx + window < 64 { - // This window's bits are contained in a single u64. - limbs[u64_idx] >> bit_idx - } else { - // Combine the current u64's bits with the bits from the next u64. - (limbs[u64_idx] >> bit_idx) | (limbs[u64_idx + 1] << (64 - bit_idx)) - } & window_mask) as usize; - - tmp += table[0][i]; - - pos += window; - table = &table[1..]; - } - - result += tmp; - } - - result -} - -#[cfg(test)] -pub mod test { - use group::Curve; - - use super::*; - - pub struct TestVector<'a> { - pub personalization: Personalization, - pub input_bits: Vec, - pub hash_u: &'a str, - pub hash_v: &'a str, - } - - #[test] - fn test_pedersen_hash_points() { - let test_vectors = test_vectors::get_vectors(); - - assert!(!test_vectors.is_empty()); - - for v in test_vectors.iter() { - let input_bools: Vec = v.input_bits.iter().map(|&i| i == 1).collect(); - - // The 6 bits prefix is handled separately - assert_eq!(v.personalization.get_bits(), &input_bools[..6]); - - let p = jubjub::ExtendedPoint::from(pedersen_hash( - v.personalization, - input_bools.into_iter().skip(6), - )) - .to_affine(); - - assert_eq!(p.get_u().to_string(), v.hash_u); - assert_eq!(p.get_v().to_string(), v.hash_v); - } - } -} diff --git a/zcash_primitives/src/sapling/pedersen_hash/test_vectors.rs b/zcash_primitives/src/sapling/pedersen_hash/test_vectors.rs deleted file mode 100644 index 4d051afca..000000000 --- a/zcash_primitives/src/sapling/pedersen_hash/test_vectors.rs +++ /dev/null @@ -1,715 +0,0 @@ -//! Test vectors from https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_pedersen.py - -use super::{test::TestVector, Personalization}; - -pub fn get_vectors<'a>() -> Vec> { - vec![ - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![1, 1, 1, 1, 1, 1], - hash_u: "0x06b1187c11ca4fb4383b2e0d0dbbde3ad3617338b5029187ec65a5eaed5e4d0b", - hash_v: "0x3ce70f536652f0dea496393a1e55c4e08b9d55508e16d11e5db40d4810cbc982", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![1, 1, 1, 1, 1, 1, 0], - hash_u: "0x2fc3bc454c337f71d4f04f86304262fcbfc9ecd808716b92fc42cbe6827f7f1a", - hash_v: "0x46d0d25bf1a654eedc6a9b1e5af398925113959feac31b7a2c036ff9b9ec0638", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![1, 1, 1, 1, 1, 1, 1], - hash_u: "0x4f8ce0e0a9e674b3ab9606a7d7aefba386e81583d81918127814cde41d209d97", - hash_v: "0x312b5ab93b14c9b9af334fe1fe3c50fffb53fbd074fa40ca600febde7c97e346", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![1, 1, 1, 1, 1, 1, 1, 0, 0], - hash_u: "0x4f8ce0e0a9e674b3ab9606a7d7aefba386e81583d81918127814cde41d209d97", - hash_v: "0x312b5ab93b14c9b9af334fe1fe3c50fffb53fbd074fa40ca600febde7c97e346", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![ - 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, - 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, - 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, - 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, - 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, - ], - hash_u: "0x599ab788360ae8c6d5bb7618aec37056d6227408d857fdc394078a3d7afdfe0f", - hash_v: "0x4320c373da670e28d168f4ffd72b43208e8c815f40841682c57a3ee1d005a527", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![ - 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, - 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, - 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, - 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, - 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, - 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, - ], - hash_u: "0x2da510317620f5dfdce1f31db6019f947eedcf02ff2972cff597a5c3ad21f5dd", - hash_v: "0x198789969c0c33e6c359b9da4a51771f4d50863f36beef90436944fe568399f2", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![ - 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, - 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, - 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, - 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, - 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, - ], - hash_u: "0x601247c7e640992d193dfb51df6ed93446687a7f2bcd0e4a598e6feb1ef20c40", - hash_v: "0x371931733b73e7b95c2cad55a6cebd15c83619f697c64283e54e5ef61442a743", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![ - 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, - 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, - 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, - 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, - 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, - 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, - 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, - 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, - 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, - 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, - 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, - 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, - 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, - 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, - 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, - 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, - 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, - 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, - 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, - 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, - 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, - 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, - 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, - 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, - 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, - ], - hash_u: "0x314192ecb1f2d8806a8108704c875a25d9fb7e444f9f373919adedebe8f2ae27", - hash_v: "0x6b12b32f1372ad574799dee9eb591d961b704bf611f55fcc71f7e82cd3330b74", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![ - 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, - 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, - 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, - 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, - 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, - 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, - 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, - 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, - 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, - 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, - 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, - 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, - 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, - 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, - 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, - 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, - 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, - 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, - 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, - 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, - 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, - 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, - 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, - 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, - 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, - 0, - ], - hash_u: "0x0666c2bce7f362a2b807d212e9a577f116891a932affd7addec39fbf372c494e", - hash_v: "0x6758bccfaf2e47c07756b96edea23aa8d10c33b38220bd1c411af612eeec18ab", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![ - 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, - 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, - 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, - 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, - 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, - 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, - 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, - 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, - 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, - 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, - 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, - 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, - 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, - 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, - 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, - 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, - 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, - 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, - 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, - 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, - 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, - 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, - 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, - 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, - 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, - 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, - 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, - ], - hash_u: "0x130afe02b99375484efb0998f5331d2178e1d00e803049bb0769099420624f5f", - hash_v: "0x5e2fc6970554ffe358652aa7968ac4fcf3de0c830e6ea492e01a38fafb68cd71", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![ - 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, - 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, - 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, - 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, - 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, - 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, - 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, - 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, - 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, - 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, - 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, - 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, - 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, - 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, - 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, - 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, - 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, - 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, - 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, - 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, - 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, - 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, - 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, - 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, - 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, - 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, - 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, - 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, - 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, - 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, - 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, - 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, - ], - hash_u: "0x67914ebd539961b70f468fa23d4cb42133693a8ac57cd35a1e6369fe34fbedf7", - hash_v: "0x44770870c0f0cfe59a10df95d6c21e6f1514a2f464b66377599438c126052d9f", - }, - TestVector { - personalization: Personalization::MerkleTree(0), - input_bits: vec![0, 0, 0, 0, 0, 0], - hash_u: "0x62454a957289b3930d10f3def0d512cfe0ef3de06421321221af3558de9d481d", - hash_v: "0x0279f0aebfb66e53ff69fba16b6608dbf4319b944432f45c6e69a3dbd1f7b330", - }, - TestVector { - personalization: Personalization::MerkleTree(0), - input_bits: vec![0, 0, 0, 0, 0, 0, 0], - hash_u: "0x283c7880f35179e201161402d9c4556b255917dbbf0142ae60519787d36d4dea", - hash_v: "0x648224408b4b83297cd0feb4cdc4eeb224237734931145432793bcd414228dc4", - }, - TestVector { - personalization: Personalization::MerkleTree(0), - input_bits: vec![0, 0, 0, 0, 0, 0, 1], - hash_u: "0x1f1086b287636a20063c9614db2de66bb7d49242e88060956a5e5845057f6f5d", - hash_v: "0x6b1b395421dde74d53341caa9e01f39d7a3138efb9b57fc0381f98f4868df622", - }, - TestVector { - personalization: Personalization::MerkleTree(0), - input_bits: vec![0, 0, 0, 0, 0, 0, 1, 0, 0], - hash_u: "0x1f1086b287636a20063c9614db2de66bb7d49242e88060956a5e5845057f6f5d", - hash_v: "0x6b1b395421dde74d53341caa9e01f39d7a3138efb9b57fc0381f98f4868df622", - }, - TestVector { - personalization: Personalization::MerkleTree(0), - input_bits: vec![ - 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, - 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, - 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, - 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, - 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, - 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, - 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, - ], - hash_u: "0x20d2b1b0551efe511755d564f8da4f5bf285fd6051331fa5f129ad95b318f6cd", - hash_v: "0x2834d96950de67ae80e85545f8333c6e14b5cf5be7325dac768f401e6edd9544", - }, - TestVector { - personalization: Personalization::MerkleTree(0), - input_bits: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, - 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, - 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, - 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, - 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, - 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, - ], - hash_u: "0x01f4850a0f40e07186fee1f0a276f52fb12cffe05c18eb2aa18170330a93c555", - hash_v: "0x19b0807358e7c8cba9168815ec54c4cd76997c34c592607d172151c48d5377cb", - }, - TestVector { - personalization: Personalization::MerkleTree(0), - input_bits: vec![ - 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, - 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, - 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, - 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, - 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, - 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, - ], - hash_u: "0x26dd81a3ffa37452c6a932d41eb4f2e0fedd531e9af8c2a7935b91dff653879d", - hash_v: "0x2fc7aebb729ef5cabf0fb3f883bc2eb2603093850b0ec19c1a3c08b653e7f27f", - }, - TestVector { - personalization: Personalization::MerkleTree(0), - input_bits: vec![ - 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, - 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, - 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, - 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, - 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, - 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, - 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, - 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, - 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, - 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, - 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, - 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, - 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, - 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, - 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, - 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, - 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, - 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, - 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, - 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, - 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, - 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, - 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, - 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, - ], - hash_u: "0x1111740552773b00aa6a2334575aa94102cfbd084290a430c90eb56d6db65b85", - hash_v: "0x6560c44b11683c20030626f89456f78a53ae8a89f565956a98ffc554b48fbb1a", - }, - TestVector { - personalization: Personalization::MerkleTree(0), - input_bits: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, - 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, - 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, - 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, - 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, - 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, - 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, - 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, - 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, - 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, - 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, - 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, - 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, - 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, - 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, - 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, - 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, - 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, - 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, - 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, - 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, - 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, - 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, - 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, - 0, - ], - hash_u: "0x429349ea9b5f8163bcda3014b3e15554df5173353fd73f315a49360c97265f68", - hash_v: "0x188774bb6de41eba669be5d368942783f937acf2f418385fc5c78479b0a405ee", - }, - TestVector { - personalization: Personalization::MerkleTree(0), - input_bits: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, - 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, - 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, - 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, - 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, - 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, - 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, - 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, - 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, - 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, - 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, - 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, - 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, - 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, - 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, - 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, - 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, - 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, - 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, - 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, - 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, - 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, - 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, - 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, - 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, - 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, - 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, - 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, - 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, - 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, - ], - hash_u: "0x00e827f3ed136f3c91c61c97ab9b7cca0ea53c20e47abb5e226ede297bdd5f37", - hash_v: "0x315cc00a54972df6a19f650d3fab5f2ad0fb07397bacb6944568618f2aa76bf6", - }, - TestVector { - personalization: Personalization::MerkleTree(0), - input_bits: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, - 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, - 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, - 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, - 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, - 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, - 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, - 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, - 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, - 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, - 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, - 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, - 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, - 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, - 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, - 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, - 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, - 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, - 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, - 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, - 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, - 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, - 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, - 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, - 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, - 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, - 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, - 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, - 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, - ], - hash_u: "0x3ee50557c4aa9158c4bb9d5961208e6c62f55c73ad7c7695a0eba0bcb6d83d05", - hash_v: "0x1b1a2be6e47688828aeadf2d37db298eac0c2736c2722b227871fdeeee29de33", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![0, 1, 0, 0, 0, 1], - hash_u: "0x61f8e2cb8e945631677b450d5e5669bc6b5f2ec69b321ac550dbe74525d7ac9a", - hash_v: "0x4e11951ab9c9400ee38a18bd98cdb9453f1f67141ee9d9bf0c1c157d4fb34f9a", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![0, 1, 0, 0, 0, 1, 0], - hash_u: "0x27fa1e296c37dde8448483ce5485c2604d1d830e53812246299773a02ecd519c", - hash_v: "0x08e499113675202cb42b4b681a31430814edebd72c5bb3bc3bfedf91fb0605df", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![0, 1, 0, 0, 0, 1, 1], - hash_u: "0x52112dd7a4293d049bb011683244a0f957e6ba95e1d1cf2fb6654d449a6d3fbc", - hash_v: "0x2ae14ecd81bb5b4489d2d64b5d2eb92a684087b28dd9a4950ecdb78c014e178c", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![0, 1, 0, 0, 0, 1, 1, 0, 0], - hash_u: "0x52112dd7a4293d049bb011683244a0f957e6ba95e1d1cf2fb6654d449a6d3fbc", - hash_v: "0x2ae14ecd81bb5b4489d2d64b5d2eb92a684087b28dd9a4950ecdb78c014e178c", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![ - 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, - 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, - 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, - 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, - 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, - 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, - ], - hash_u: "0x544a0b44c35dca64ee806d1af70b7c44134e5d86efed413947657ffd71adf9b2", - hash_v: "0x5ddc5dbf12abbbc5561defd3782a32f450b3c398f52ff4629677e59e86e3ab31", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![ - 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, - 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, - 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, - 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, - 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, - ], - hash_u: "0x6cb6490ccb0ca9ccd657146f58a7b800bc4fb2556ee37861227ee8fda724acfb", - hash_v: "0x05c6fe100926f5cc441e54e72f024b6b12c907f2ec5680335057896411984c9f", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![ - 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, - 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, - 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, - 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, - 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, - 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, - ], - hash_u: "0x40901e2175cb7f06a00c676d54d90e59fd448f11cbbc5eb517f9fea74b795ce2", - hash_v: "0x42d512891f91087310c9bc630c8d0ecc014596f884fd6df55dada8195ed726de", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![ - 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, - 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, - 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, - 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, - 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, - 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, - 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, - 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, - 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, - 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, - 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, - 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, - 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, - 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, - 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, - 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, - 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, - 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, - 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, - 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, - 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, - 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, - 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, - 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, - ], - hash_u: "0x66a433542419f1a086ed0663b0e8df2ece9a04065f147896976baba1a916b6dc", - hash_v: "0x203bd3672522e1d3c86fa6b9f3b58f20199a4216adfd40982add13a856f6f3de", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![ - 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, - 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, - 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, - 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, - 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, - 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, - 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, - 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, - 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, - 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, - 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, - 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, - 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, - 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, - 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, - 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, - 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, - 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, - 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, - 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, - 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, - 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, - 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, - 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, - 1, - ], - hash_u: "0x119db3b38086c1a3c6c6f53c529ee62d9311d69c2d8aeeafa6e172e650d3afda", - hash_v: "0x72287540be7d2b0f58f5c73eaa53c55bea6b79dd79873b4e47cc11787bb9a15d", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![ - 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, - 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, - 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, - 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, - 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, - 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, - 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, - 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, - 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, - 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, - 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, - 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, - 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, - 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, - 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, - 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, - 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, - 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, - 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, - 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, - 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, - 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, - 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, - 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, - 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, - 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, - 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, - 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, - 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, - 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, - ], - hash_u: "0x446efdcf89b70ba2b03427a0893008181d0fc4e76b84b1a500d7ee523c8e3666", - hash_v: "0x125ee0048efb0372b92c3c15d51a7c5c77a712054cc4fdd0774563da46ec7289", - }, - TestVector { - personalization: Personalization::MerkleTree(34), - input_bits: vec![ - 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, - 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, - 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, - 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, - 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, - 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, - 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, - 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, - 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, - 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, - 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, - 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, - 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, - 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, - 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, - 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, - 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, - 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, - 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, - 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, - 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, - 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, - 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, - 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, - 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, - 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, - 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, - 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, - 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, - 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, - ], - hash_u: "0x72723bf0573bcb4b72d4184cfeb707d9556b7f705f56a4652707a36f2edf10f7", - hash_v: "0x3a7f0999a6a1393bd49fc82302e7352e01176fbebb0192bf5e6ef39eb8c585ad", - }, - TestVector { - personalization: Personalization::MerkleTree(27), - input_bits: vec![ - 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, - 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, - 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, - 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, - 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, - 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, - 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, - ], - hash_u: "0x414f6ba05f6b92da1f9051950769e1083d05615def32b016ae424309828a11f4", - hash_v: "0x471d2109656afcb96d0609b371b132b97efcf72c6051064dd19fdc004799bfa9", - }, - TestVector { - personalization: Personalization::MerkleTree(36), - input_bits: vec![ - 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, - 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, - 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, - 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, - 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, - 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, - 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, - ], - hash_u: "0x62d6fe1e373225a5695f3115aed8265c59e2d6275ceef6bbc53fde3fc6594024", - hash_v: "0x407275be7d5a4c48204c8d83f5b211d09a2f285d4f0f87a928d4de9a6338e1d1", - }, - TestVector { - personalization: Personalization::MerkleTree(0), - input_bits: vec![ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], - hash_u: "0x1116a934f26b57a2c9daa6f25ac9b1a8f9dacddba30f65433ac021bf39a6bfdd", - hash_v: "0x407275be7d5a4c48204c8d83f5b211d09a2f285d4f0f87a928d4de9a6338e1d1", - }, - TestVector { - personalization: Personalization::NoteCommitment, - input_bits: vec![ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - ], - hash_u: "0x329e3bb2ca31ea6e13a986730237f6fd16b842a510cbabe851bdbcf57d75ee0d", - hash_v: "0x471d2109656afcb96d0609b371b132b97efcf72c6051064dd19fdc004799bfa9", - }, - ] -} diff --git a/zcash_primitives/src/sapling/prover.rs b/zcash_primitives/src/sapling/prover.rs deleted file mode 100644 index 511ffa8f1..000000000 --- a/zcash_primitives/src/sapling/prover.rs +++ /dev/null @@ -1,279 +0,0 @@ -//! Abstractions over the proving system and parameters. - -use bellman::groth16::{create_random_proof, Proof}; -use bls12_381::Bls12; -use rand_core::RngCore; - -use crate::sapling::{ - self, - bundle::GrothProofBytes, - circuit::GROTH_PROOF_SIZE, - value::{NoteValue, ValueCommitTrapdoor}, - MerklePath, -}; - -use super::{ - circuit::{Output, OutputParameters, Spend, SpendParameters, ValueCommitmentOpening}, - Diversifier, Note, PaymentAddress, ProofGenerationKey, Rseed, -}; - -/// Interface for creating Sapling Spend proofs. -pub trait SpendProver { - /// The proof type created by this prover. - type Proof; - - /// Prepares an instance of the Sapling Spend circuit for the given inputs. - /// - /// Returns `None` if `diversifier` is not a valid Sapling diversifier. - #[allow(clippy::too_many_arguments)] - fn prepare_circuit( - proof_generation_key: ProofGenerationKey, - diversifier: Diversifier, - rseed: Rseed, - value: NoteValue, - alpha: jubjub::Fr, - rcv: ValueCommitTrapdoor, - anchor: bls12_381::Scalar, - merkle_path: MerklePath, - ) -> Option; - - /// Create the proof for a Sapling [`SpendDescription`]. - /// - /// [`SpendDescription`]: crate::transaction::components::SpendDescription - fn create_proof( - &self, - circuit: sapling::circuit::Spend, - rng: &mut R, - ) -> Self::Proof; - - /// Encodes the given Sapling [`SpendDescription`] proof, erasing its type. - /// - /// [`SpendDescription`]: crate::transaction::components::SpendDescription - fn encode_proof(proof: Self::Proof) -> GrothProofBytes; -} - -/// Interface for creating Sapling Output proofs. -pub trait OutputProver { - /// The proof type created by this prover. - type Proof; - - /// Prepares an instance of the Sapling Output circuit for the given inputs. - /// - /// Returns `None` if `diversifier` is not a valid Sapling diversifier. - fn prepare_circuit( - esk: jubjub::Fr, - payment_address: PaymentAddress, - rcm: jubjub::Fr, - value: NoteValue, - rcv: ValueCommitTrapdoor, - ) -> sapling::circuit::Output; - - /// Create the proof for a Sapling [`OutputDescription`]. - /// - /// [`OutputDescription`]: crate::transaction::components::OutputDescription - fn create_proof( - &self, - circuit: sapling::circuit::Output, - rng: &mut R, - ) -> Self::Proof; - - /// Encodes the given Sapling [`OutputDescription`] proof, erasing its type. - /// - /// [`OutputDescription`]: crate::transaction::components::OutputDescription - fn encode_proof(proof: Self::Proof) -> GrothProofBytes; -} - -impl SpendProver for SpendParameters { - type Proof = Proof; - - fn prepare_circuit( - proof_generation_key: ProofGenerationKey, - diversifier: Diversifier, - rseed: Rseed, - value: NoteValue, - alpha: jubjub::Fr, - rcv: ValueCommitTrapdoor, - anchor: bls12_381::Scalar, - merkle_path: MerklePath, - ) -> Option { - // Construct the value commitment - let value_commitment_opening = ValueCommitmentOpening { - value, - randomness: rcv.inner(), - }; - - // Construct the viewing key - let viewing_key = proof_generation_key.to_viewing_key(); - - // Construct the payment address with the viewing key / diversifier - let payment_address = viewing_key.to_payment_address(diversifier)?; - - let note = Note::from_parts(payment_address, value, rseed); - - // We now have the full witness for our circuit - let pos: u64 = merkle_path.position().into(); - Some(Spend { - value_commitment_opening: Some(value_commitment_opening), - proof_generation_key: Some(proof_generation_key), - payment_address: Some(payment_address), - commitment_randomness: Some(note.rcm()), - ar: Some(alpha), - auth_path: merkle_path - .path_elems() - .iter() - .enumerate() - .map(|(i, node)| Some(((*node).into(), pos >> i & 0x1 == 1))) - .collect(), - anchor: Some(anchor), - }) - } - - fn create_proof(&self, circuit: Spend, rng: &mut R) -> Self::Proof { - create_random_proof(circuit, &self.0, rng).expect("proving should not fail") - } - - fn encode_proof(proof: Self::Proof) -> GrothProofBytes { - let mut zkproof = [0u8; GROTH_PROOF_SIZE]; - proof - .write(&mut zkproof[..]) - .expect("should be able to serialize a proof"); - zkproof - } -} - -impl OutputProver for OutputParameters { - type Proof = Proof; - - fn prepare_circuit( - esk: jubjub::Fr, - payment_address: PaymentAddress, - rcm: jubjub::Fr, - value: NoteValue, - rcv: ValueCommitTrapdoor, - ) -> Output { - // Construct the value commitment for the proof instance - let value_commitment_opening = ValueCommitmentOpening { - value, - randomness: rcv.inner(), - }; - - // We now have a full witness for the output proof. - Output { - value_commitment_opening: Some(value_commitment_opening), - payment_address: Some(payment_address), - commitment_randomness: Some(rcm), - esk: Some(esk), - } - } - - fn create_proof(&self, circuit: Output, rng: &mut R) -> Self::Proof { - create_random_proof(circuit, &self.0, rng).expect("proving should not fail") - } - - fn encode_proof(proof: Self::Proof) -> GrothProofBytes { - let mut zkproof = [0u8; GROTH_PROOF_SIZE]; - proof - .write(&mut zkproof[..]) - .expect("should be able to serialize a proof"); - zkproof - } -} - -#[cfg(any(test, feature = "test-dependencies"))] -pub mod mock { - use ff::Field; - - use super::{OutputProver, SpendProver}; - use crate::{ - sapling::{ - self, - bundle::GrothProofBytes, - circuit::ValueCommitmentOpening, - value::{NoteValue, ValueCommitTrapdoor}, - Diversifier, PaymentAddress, ProofGenerationKey, Rseed, - }, - transaction::components::GROTH_PROOF_SIZE, - }; - - pub struct MockSpendProver; - - impl SpendProver for MockSpendProver { - type Proof = GrothProofBytes; - - fn prepare_circuit( - proof_generation_key: ProofGenerationKey, - diversifier: Diversifier, - _rseed: Rseed, - value: NoteValue, - alpha: jubjub::Fr, - rcv: ValueCommitTrapdoor, - anchor: bls12_381::Scalar, - _merkle_path: sapling::MerklePath, - ) -> Option { - let payment_address = proof_generation_key - .to_viewing_key() - .ivk() - .to_payment_address(diversifier); - Some(sapling::circuit::Spend { - value_commitment_opening: Some(ValueCommitmentOpening { - value, - randomness: rcv.inner(), - }), - proof_generation_key: Some(proof_generation_key), - payment_address, - commitment_randomness: Some(jubjub::Scalar::ZERO), - ar: Some(alpha), - auth_path: vec![], - anchor: Some(anchor), - }) - } - - fn create_proof( - &self, - _circuit: sapling::circuit::Spend, - _rng: &mut R, - ) -> Self::Proof { - [0u8; GROTH_PROOF_SIZE] - } - - fn encode_proof(proof: Self::Proof) -> GrothProofBytes { - proof - } - } - - pub struct MockOutputProver; - - impl OutputProver for MockOutputProver { - type Proof = GrothProofBytes; - - fn prepare_circuit( - esk: jubjub::Fr, - payment_address: PaymentAddress, - rcm: jubjub::Fr, - value: NoteValue, - rcv: ValueCommitTrapdoor, - ) -> sapling::circuit::Output { - sapling::circuit::Output { - value_commitment_opening: Some(ValueCommitmentOpening { - value, - randomness: rcv.inner(), - }), - payment_address: Some(payment_address), - commitment_randomness: Some(rcm), - esk: Some(esk), - } - } - - fn create_proof( - &self, - _circuit: sapling::circuit::Output, - _rng: &mut R, - ) -> Self::Proof { - [0u8; GROTH_PROOF_SIZE] - } - - fn encode_proof(proof: Self::Proof) -> GrothProofBytes { - proof - } - } -} diff --git a/zcash_primitives/src/sapling/spec.rs b/zcash_primitives/src/sapling/spec.rs deleted file mode 100644 index eabf17a3d..000000000 --- a/zcash_primitives/src/sapling/spec.rs +++ /dev/null @@ -1,165 +0,0 @@ -//! Helper functions defined in the Zcash Protocol Specification. - -use blake2s_simd::Params as Blake2sParams; -use group::{cofactor::CofactorGroup, ff::PrimeField, Curve, GroupEncoding, WnafBase, WnafScalar}; - -use super::{ - constants::{ - CRH_IVK_PERSONALIZATION, KEY_DIVERSIFICATION_PERSONALIZATION, - NOTE_COMMITMENT_RANDOMNESS_GENERATOR, NULLIFIER_POSITION_GENERATOR, PRF_NF_PERSONALIZATION, - }, - group_hash::group_hash, - pedersen_hash::{pedersen_hash, Personalization}, -}; - -const PREPARED_WINDOW_SIZE: usize = 4; -pub(crate) type PreparedBase = WnafBase; -pub(crate) type PreparedBaseSubgroup = WnafBase; -pub(crate) type PreparedScalar = WnafScalar; - -/// $CRH^\mathsf{ivk}(ak, nk)$ -/// -/// Defined in [Zcash Protocol Spec § 5.4.1.5: CRH^ivk Hash Function][concretecrhivk]. -/// -/// [concretecrhivk]: https://zips.z.cash/protocol/protocol.pdf#concretecrhivk -pub(crate) fn crh_ivk(ak: [u8; 32], nk: [u8; 32]) -> jubjub::Scalar { - let mut h: [u8; 32] = Blake2sParams::new() - .hash_length(32) - .personal(CRH_IVK_PERSONALIZATION) - .to_state() - .update(&ak) - .update(&nk) - .finalize() - .as_bytes() - .try_into() - .expect("output length is correct"); - - // Drop the most significant five bits, so it can be interpreted as a scalar. - h[31] &= 0b0000_0111; - - jubjub::Fr::from_repr(h).unwrap() -} - -/// Defined in [Zcash Protocol Spec § 5.4.1.6: DiversifyHash^Sapling and DiversifyHash^Orchard Hash Functions][concretediversifyhash]. -/// -/// [concretediversifyhash]: https://zips.z.cash/protocol/protocol.pdf#concretediversifyhash -pub(crate) fn diversify_hash(d: &[u8; 11]) -> Option { - group_hash(d, KEY_DIVERSIFICATION_PERSONALIZATION) -} - -/// $MixingPedersenHash$. -/// -/// Defined in [Zcash Protocol Spec § 5.4.1.8: Mixing Pedersen Hash Function][concretemixinghash]. -/// -/// [concretemixinghash]: https://zips.z.cash/protocol/protocol.pdf#concretemixinghash -pub(crate) fn mixing_pedersen_hash( - cm: jubjub::SubgroupPoint, - position: u64, -) -> jubjub::SubgroupPoint { - cm + (NULLIFIER_POSITION_GENERATOR * jubjub::Fr::from(position)) -} - -/// $PRF^\mathsf{nfSapling}_{nk}(\rho)$ -/// -/// Defined in [Zcash Protocol Spec § 5.4.2: Pseudo Random Functions][concreteprfs]. -/// -/// [concreteprfs]: https://zips.z.cash/protocol/protocol.pdf#concreteprfs -pub(crate) fn prf_nf(nk: &jubjub::SubgroupPoint, rho: &jubjub::SubgroupPoint) -> [u8; 32] { - Blake2sParams::new() - .hash_length(32) - .personal(PRF_NF_PERSONALIZATION) - .to_state() - .update(&nk.to_bytes()) - .update(&rho.to_bytes()) - .finalize() - .as_bytes() - .try_into() - .expect("output length is correct") -} - -/// Defined in [Zcash Protocol Spec § 5.4.5.3: Sapling Key Agreement][concretesaplingkeyagreement]. -/// -/// [concretesaplingkeyagreement]: https://zips.z.cash/protocol/protocol.pdf#concretesaplingkeyagreement -pub(crate) fn ka_sapling_derive_public( - sk: &jubjub::Scalar, - b: &jubjub::ExtendedPoint, -) -> jubjub::ExtendedPoint { - ka_sapling_derive_public_prepared(&PreparedScalar::new(sk), &PreparedBase::new(*b)) -} - -/// Defined in [Zcash Protocol Spec § 5.4.5.3: Sapling Key Agreement][concretesaplingkeyagreement]. -/// -/// [concretesaplingkeyagreement]: https://zips.z.cash/protocol/protocol.pdf#concretesaplingkeyagreement -pub(crate) fn ka_sapling_derive_public_prepared( - sk: &PreparedScalar, - b: &PreparedBase, -) -> jubjub::ExtendedPoint { - // [sk] b - b * sk -} - -/// This is defined implicitly by [Zcash Protocol Spec § 4.2.2: Sapling Key Components][saplingkeycomponents] -/// which uses $KA^\mathsf{Sapling}.\mathsf{DerivePublic}$ to produce a diversified -/// transmission key with type $KA^\mathsf{Sapling}.\mathsf{PublicPrimeSubgroup}$. -/// -/// [saplingkeycomponents]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents -pub(crate) fn ka_sapling_derive_public_subgroup_prepared( - sk: &PreparedScalar, - b: &PreparedBaseSubgroup, -) -> jubjub::SubgroupPoint { - // [sk] b - b * sk -} - -/// Defined in [Zcash Protocol Spec § 5.4.5.3: Sapling Key Agreement][concretesaplingkeyagreement]. -/// -/// [concretesaplingkeyagreement]: https://zips.z.cash/protocol/protocol.pdf#concretesaplingkeyagreement -pub(crate) fn ka_sapling_agree( - sk: &jubjub::Scalar, - b: &jubjub::ExtendedPoint, -) -> jubjub::SubgroupPoint { - ka_sapling_agree_prepared(&PreparedScalar::new(sk), &PreparedBase::new(*b)) -} - -/// Defined in [Zcash Protocol Spec § 5.4.5.3: Sapling Key Agreement][concretesaplingkeyagreement]. -/// -/// [concretesaplingkeyagreement]: https://zips.z.cash/protocol/protocol.pdf#concretesaplingkeyagreement -pub(crate) fn ka_sapling_agree_prepared( - sk: &PreparedScalar, - b: &PreparedBase, -) -> jubjub::SubgroupPoint { - // [8 sk] b - // ::clear_cofactor is implemented using - // ExtendedPoint::mul_by_cofactor in the jubjub crate. - - (b * sk).clear_cofactor() -} - -/// $WindowedPedersenCommit_r(s)$ -/// -/// Defined in [Zcash Protocol Spec § 5.4.8.2: Windowed Pedersen commitments][concretewindowedcommit]. -/// -/// [concretewindowedcommit]: https://zips.z.cash/protocol/protocol.pdf#concretewindowedcommit -pub(crate) fn windowed_pedersen_commit( - personalization: Personalization, - s: I, - r: jubjub::Scalar, -) -> jubjub::SubgroupPoint -where - I: IntoIterator, -{ - pedersen_hash(personalization, s) + (NOTE_COMMITMENT_RANDOMNESS_GENERATOR * r) -} - -/// Coordinate extractor for Jubjub. -/// -/// Defined in [Zcash Protocol Spec § 5.4.9.4: Coordinate Extractor for Jubjub][concreteextractorjubjub]. -/// -/// [concreteextractorjubjub]: https://zips.z.cash/protocol/protocol.pdf#concreteextractorjubjub -pub(crate) fn extract_p(point: &jubjub::SubgroupPoint) -> bls12_381::Scalar { - // The commitment is in the prime order subgroup, so mapping the - // commitment to the u-coordinate is an injective encoding. - Into::<&jubjub::ExtendedPoint>::into(point) - .to_affine() - .get_u() -} diff --git a/zcash_primitives/src/sapling/test_vectors.rs b/zcash_primitives/src/sapling/test_vectors.rs deleted file mode 100644 index 8232fe04e..000000000 --- a/zcash_primitives/src/sapling/test_vectors.rs +++ /dev/null @@ -1 +0,0 @@ -pub(crate) mod signatures; diff --git a/zcash_primitives/src/sapling/test_vectors/signatures.rs b/zcash_primitives/src/sapling/test_vectors/signatures.rs deleted file mode 100644 index 7ce341cff..000000000 --- a/zcash_primitives/src/sapling/test_vectors/signatures.rs +++ /dev/null @@ -1,476 +0,0 @@ -pub(crate) struct TestVector { - pub(crate) sk: [u8; 32], - pub(crate) vk: [u8; 32], - pub(crate) alpha: [u8; 32], - pub(crate) rsk: [u8; 32], - pub(crate) rvk: [u8; 32], - pub(crate) m: [u8; 32], - pub(crate) sig: [u8; 64], - pub(crate) rsig: [u8; 64], -} - -pub(crate) fn make_test_vectors() -> Vec { - // From https://github.com/zcash/zcash-test-vectors/blob/master/zcash_test_vectors/sapling/redjubjub.py - vec![ - TestVector { - sk: [ - 0x18, 0xe2, 0x8d, 0xea, 0x5c, 0x11, 0x81, 0x7a, 0xee, 0xb2, 0x1a, 0x19, 0x98, 0x1d, - 0x28, 0x36, 0x8e, 0xc4, 0x38, 0xaf, 0xc2, 0x5a, 0x8d, 0xb9, 0x4e, 0xbe, 0x08, 0xd7, - 0xa0, 0x28, 0x8e, 0x09, - ], - vk: [ - 0x9b, 0x01, 0x53, 0xb0, 0x3d, 0x32, 0x0f, 0xe2, 0x3e, 0x28, 0x34, 0xd5, 0xd6, 0x1d, - 0xbb, 0x1f, 0x51, 0x9b, 0x3f, 0x41, 0xf8, 0xf9, 0x46, 0x15, 0x2b, 0xf0, 0xc3, 0xf2, - 0x47, 0xd1, 0x18, 0x07, - ], - alpha: [ - 0xff, 0xd1, 0xa1, 0x27, 0x32, 0x52, 0xb1, 0x87, 0xf4, 0xed, 0x32, 0x6d, 0xfc, 0x98, - 0x85, 0x3e, 0x29, 0x17, 0xc2, 0xb3, 0x63, 0x79, 0xb1, 0x75, 0xda, 0x63, 0xb9, 0xef, - 0x6d, 0xda, 0x6c, 0x08, - ], - rsk: [ - 0x60, 0x87, 0x38, 0x3b, 0x30, 0x55, 0x9b, 0x31, 0x60, 0x90, 0x85, 0xb9, 0x00, 0x96, - 0x45, 0xce, 0xb6, 0xa0, 0xc6, 0x61, 0x25, 0x99, 0xd7, 0x28, 0x80, 0x72, 0x8e, 0x61, - 0x24, 0x4e, 0x7d, 0x03, - ], - rvk: [ - 0xc1, 0xba, 0xbc, 0xb6, 0xea, 0xe2, 0xb9, 0x94, 0xee, 0x6d, 0x65, 0xc1, 0x0b, 0x9d, - 0xad, 0x59, 0x40, 0xdc, 0x73, 0x5b, 0x07, 0x50, 0x4d, 0xae, 0xd1, 0xe4, 0x6b, 0x07, - 0x09, 0xb4, 0x51, 0x36, - ], - m: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - sig: [ - 0xdc, 0xa3, 0xbb, 0x2c, 0xb8, 0xf0, 0x48, 0xcc, 0xab, 0x10, 0xae, 0xd7, 0x75, 0x46, - 0xc1, 0xdb, 0xb1, 0x0c, 0xc4, 0xfb, 0x15, 0xab, 0x02, 0xac, 0xae, 0xf9, 0x44, 0xdd, - 0xab, 0x8b, 0x67, 0x22, 0x54, 0x5f, 0xda, 0x4c, 0x62, 0x04, 0x6d, 0x69, 0xd9, 0x8f, - 0x92, 0x2f, 0x4e, 0x8c, 0x21, 0x0b, 0xc4, 0x7b, 0x4f, 0xdd, 0xe0, 0xa1, 0x94, 0x71, - 0x79, 0x80, 0x4c, 0x1a, 0xce, 0x56, 0x90, 0x05, - ], - rsig: [ - 0x70, 0xc2, 0x84, 0x50, 0x4e, 0x90, 0xf0, 0x00, 0x8e, 0x8e, 0xd2, 0x20, 0x8f, 0x49, - 0x69, 0x72, 0x7a, 0x41, 0x5e, 0xc3, 0x10, 0x2c, 0x29, 0x9e, 0x39, 0x8b, 0x6c, 0x16, - 0x57, 0x2b, 0xd9, 0x64, 0x3e, 0xe1, 0x01, 0x17, 0x66, 0x68, 0x1e, 0x40, 0x6e, 0xe6, - 0xbe, 0xe3, 0xd0, 0x3e, 0xe8, 0xf2, 0x71, 0x76, 0xe3, 0x2f, 0xba, 0xbd, 0xde, 0xd2, - 0x0b, 0x0d, 0x17, 0x86, 0xa4, 0xee, 0x18, 0x01, - ], - }, - TestVector { - sk: [ - 0x05, 0x96, 0x54, 0xf9, 0x61, 0x27, 0x3d, 0xaf, 0xda, 0x3b, 0x26, 0x77, 0xb3, 0x5c, - 0x18, 0xaf, 0x6b, 0x11, 0xad, 0xfb, 0x9e, 0xe9, 0x0b, 0x48, 0x93, 0x5e, 0x55, 0x7c, - 0x8d, 0x5d, 0x9c, 0x04, - ], - vk: [ - 0xfa, 0xf6, 0xc3, 0xb7, 0x37, 0xe8, 0xe6, 0x11, 0xaa, 0xfe, 0xa5, 0x2f, 0x03, 0xbb, - 0x27, 0x86, 0xe1, 0x83, 0x53, 0xeb, 0xe0, 0xd3, 0x13, 0x9e, 0x3c, 0x54, 0x49, 0x87, - 0x80, 0xc8, 0xc1, 0x99, - ], - alpha: [ - 0xc3, 0x0b, 0x96, 0x20, 0x8d, 0xa8, 0x00, 0xe1, 0x0a, 0xf0, 0x25, 0x42, 0xce, 0x69, - 0x4b, 0x7e, 0xd7, 0x6a, 0x28, 0x29, 0x9f, 0x85, 0x99, 0x8e, 0x5d, 0x61, 0x08, 0x12, - 0x68, 0x1b, 0xf0, 0x03, - ], - rsk: [ - 0xc8, 0xa1, 0xea, 0x19, 0xef, 0xcf, 0x3d, 0x90, 0xe5, 0x2b, 0x4c, 0xb9, 0x81, 0xc6, - 0x63, 0x2d, 0x43, 0x7c, 0xd5, 0x24, 0x3e, 0x6f, 0xa5, 0xd6, 0xf0, 0xbf, 0x5d, 0x8e, - 0xf5, 0x78, 0x8c, 0x08, - ], - rvk: [ - 0xd5, 0x24, 0xdc, 0xe7, 0x73, 0x40, 0x69, 0x75, 0x8a, 0x91, 0xf0, 0x07, 0xa8, 0x69, - 0x50, 0x5d, 0xfc, 0x4a, 0xba, 0x17, 0x20, 0x59, 0x4d, 0x4d, 0x74, 0xf0, 0x07, 0x70, - 0x0e, 0x62, 0xee, 0x00, - ], - m: [ - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, - ], - sig: [ - 0xb5, 0xa1, 0xf3, 0x2d, 0x3d, 0x50, 0xfc, 0x73, 0x8b, 0x5c, 0x3b, 0x4e, 0x99, 0x60, - 0x72, 0x9c, 0xe4, 0x31, 0x6b, 0xa7, 0x72, 0x1a, 0x12, 0x68, 0x66, 0x04, 0xfe, 0xba, - 0x6b, 0xd7, 0x48, 0x45, 0x00, 0x70, 0xcb, 0x92, 0x24, 0x06, 0xfd, 0xfc, 0x5d, 0x60, - 0xde, 0xa9, 0xbe, 0x3a, 0x52, 0x6a, 0x16, 0xcf, 0xeb, 0x87, 0x77, 0x79, 0xfb, 0x78, - 0x2d, 0x5d, 0x41, 0x39, 0x5b, 0x45, 0x5f, 0x04, - ], - rsig: [ - 0x5a, 0x5a, 0x20, 0xd2, 0x00, 0xef, 0xdd, 0xd4, 0x98, 0xdf, 0xae, 0x2a, 0x9e, 0xf8, - 0xcf, 0x01, 0x28, 0x1a, 0x89, 0x19, 0x01, 0x8a, 0x82, 0x4c, 0xc7, 0xa4, 0x98, 0x3b, - 0x9a, 0x0d, 0x4a, 0x06, 0xff, 0x17, 0x20, 0x79, 0xe0, 0x13, 0xd4, 0x2a, 0x2a, 0x3a, - 0x88, 0xa6, 0x52, 0x0c, 0x86, 0xfc, 0xe3, 0xb9, 0x8e, 0x1e, 0xfa, 0xa3, 0x25, 0x83, - 0x2a, 0x6a, 0x56, 0x58, 0xd8, 0xdd, 0x7c, 0x0a, - ], - }, - TestVector { - sk: [ - 0xad, 0xe7, 0xab, 0xb5, 0x51, 0xc7, 0x9d, 0x0f, 0x0e, 0x42, 0xef, 0x7f, 0x12, 0x06, - 0xb8, 0x77, 0x12, 0xa8, 0x4a, 0x61, 0xde, 0xa3, 0xf3, 0x7b, 0x42, 0x49, 0x6d, 0x7e, - 0xfd, 0x12, 0x52, 0x0c, - ], - vk: [ - 0x36, 0x9e, 0xa7, 0x51, 0x76, 0x2f, 0x83, 0x9d, 0x25, 0x70, 0x1a, 0x5e, 0xeb, 0x55, - 0x1e, 0xc4, 0xf0, 0x6c, 0x12, 0x90, 0xb3, 0xb9, 0xc3, 0xa7, 0x24, 0x40, 0x2d, 0xec, - 0x02, 0x73, 0x92, 0x21, - ], - alpha: [ - 0x81, 0x92, 0x25, 0x29, 0xa6, 0x3e, 0xe7, 0x43, 0xfc, 0x4f, 0xbb, 0xac, 0x45, 0xc4, - 0x98, 0x83, 0x16, 0xbc, 0x9b, 0x6e, 0x42, 0x8b, 0x01, 0xa8, 0xd3, 0x1f, 0xc1, 0xc2, - 0xa6, 0xca, 0x62, 0x05, - ], - rsk: [ - 0x77, 0x4d, 0xda, 0x07, 0x99, 0xf7, 0xed, 0x82, 0x87, 0x81, 0xe2, 0x5f, 0xc4, 0xa9, - 0xe8, 0x54, 0x28, 0x29, 0xb2, 0xce, 0x1f, 0xf4, 0x8d, 0x1d, 0x6d, 0xb9, 0xfa, 0xdb, - 0xb9, 0x28, 0x37, 0x03, - ], - rvk: [ - 0x0d, 0x92, 0xad, 0x6d, 0x46, 0xed, 0xac, 0xd0, 0x23, 0xd4, 0xd2, 0xef, 0x70, 0x3a, - 0x6c, 0xa0, 0xa7, 0x92, 0xcf, 0xc4, 0xb7, 0xda, 0x11, 0xc2, 0x35, 0x3b, 0xc8, 0x45, - 0xa2, 0x7a, 0x97, 0x4d, - ], - m: [ - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, - ], - sig: [ - 0x1f, 0x3e, 0x8a, 0x94, 0x31, 0x0c, 0x20, 0x71, 0xa7, 0x0f, 0x9d, 0xf5, 0xe7, 0x9a, - 0xa9, 0xe8, 0x48, 0x5d, 0xec, 0xcb, 0x17, 0x8b, 0xdf, 0xf9, 0x80, 0x5f, 0xcb, 0xe6, - 0xf7, 0xd5, 0x51, 0xee, 0xe3, 0xc3, 0x54, 0x2c, 0xa7, 0x5c, 0x9d, 0x8d, 0x4a, 0xdc, - 0x54, 0xd7, 0x2c, 0x3d, 0xbe, 0x28, 0x62, 0x6d, 0x20, 0x78, 0x5b, 0xb7, 0xf5, 0x88, - 0xc1, 0xa5, 0x82, 0xb8, 0x93, 0xdb, 0xb6, 0x01, - ], - rsig: [ - 0xd1, 0x36, 0x21, 0x4c, 0x5d, 0x52, 0x8e, 0xa3, 0xd4, 0xcb, 0x7b, 0x63, 0x1a, 0x6b, - 0xb0, 0x36, 0x06, 0x49, 0x73, 0xa1, 0x08, 0xb7, 0x33, 0xa5, 0xe3, 0xa4, 0x52, 0xab, - 0x52, 0xa6, 0x59, 0xe5, 0x67, 0xcb, 0x55, 0xd2, 0x64, 0x4e, 0x74, 0xb6, 0xe8, 0x42, - 0x6f, 0x2a, 0x7d, 0xd2, 0xa0, 0x4d, 0x2d, 0xda, 0x49, 0x35, 0xcc, 0x38, 0x20, 0xb7, - 0x7a, 0x9c, 0x1a, 0xb6, 0x19, 0x86, 0x3c, 0x05, - ], - }, - TestVector { - sk: [ - 0xc9, 0xd2, 0xae, 0x1f, 0x6d, 0x32, 0xa6, 0x75, 0xd0, 0x9e, 0xb0, 0x82, 0x3f, 0x46, - 0x7f, 0xa9, 0x21, 0xb3, 0x28, 0x4a, 0xcb, 0x35, 0xfa, 0xbd, 0xfc, 0x99, 0x4d, 0xe5, - 0x49, 0xb8, 0x59, 0x0d, - ], - vk: [ - 0x2d, 0x2f, 0x31, 0x6e, 0x5c, 0x36, 0x9a, 0xe4, 0xdd, 0x2c, 0x82, 0x5f, 0x3d, 0x86, - 0x46, 0x00, 0x58, 0x40, 0x71, 0x84, 0x60, 0x3b, 0x21, 0x2c, 0xf3, 0x45, 0x9f, 0x36, - 0xc8, 0x69, 0x7f, 0xd8, - ], - alpha: [ - 0xeb, 0xbc, 0x89, 0x03, 0x11, 0x07, 0xc4, 0x4f, 0x47, 0x88, 0x9e, 0xd4, 0xd4, 0x37, - 0x5a, 0x41, 0x14, 0xcf, 0x8a, 0x75, 0xdd, 0x33, 0xb9, 0x62, 0xf2, 0xd7, 0x59, 0xd3, - 0xf4, 0xc6, 0xdf, 0x06, - ], - rsk: [ - 0xfd, 0x62, 0x41, 0x4c, 0x1f, 0x2b, 0xd3, 0xf4, 0x94, 0x16, 0x87, 0x8a, 0x80, 0x5d, - 0x71, 0x44, 0x35, 0x47, 0x7f, 0xbe, 0xa7, 0x2e, 0x4c, 0x1a, 0x46, 0xc2, 0x73, 0x53, - 0x54, 0xca, 0xbb, 0x05, - ], - rvk: [ - 0xf0, 0x43, 0x0e, 0x95, 0x3b, 0xe6, 0x0b, 0xf4, 0x38, 0xdb, 0xdc, 0xc2, 0x30, 0x3f, - 0x0e, 0x32, 0xa6, 0xf7, 0xce, 0x2f, 0xbe, 0xdf, 0xb1, 0x3a, 0xc5, 0x18, 0xf7, 0x5a, - 0x3f, 0xd1, 0x0e, 0xb5, - ], - m: [ - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, - ], - sig: [ - 0x12, 0xc7, 0x8d, 0xdd, 0x20, 0xd3, 0x0a, 0x61, 0xf8, 0x93, 0x0c, 0x6f, 0xe0, 0x85, - 0x0f, 0xd1, 0x12, 0xbb, 0x7b, 0xe8, 0x8b, 0x12, 0x38, 0xea, 0x33, 0xd6, 0xbe, 0xf8, - 0x81, 0xc1, 0x02, 0xd1, 0x04, 0xaa, 0x36, 0x54, 0x4a, 0x78, 0x47, 0x1c, 0x9e, 0x28, - 0x42, 0xe6, 0xfd, 0x42, 0x55, 0x83, 0x46, 0xcf, 0xf4, 0x31, 0x27, 0x03, 0x26, 0x66, - 0xeb, 0x11, 0x6f, 0x44, 0x2a, 0x28, 0x48, 0x0c, - ], - rsig: [ - 0x01, 0xba, 0xaa, 0x26, 0x27, 0x4c, 0x14, 0x9a, 0xcf, 0x12, 0xe1, 0xcc, 0xf5, 0x50, - 0x7d, 0x56, 0x79, 0x04, 0x82, 0xf0, 0x67, 0xe5, 0xc9, 0x2b, 0x32, 0x19, 0xad, 0x6b, - 0xf9, 0x11, 0x18, 0xcc, 0x3f, 0xce, 0x8d, 0x2a, 0x23, 0x19, 0x8a, 0x3b, 0x29, 0x0a, - 0x7b, 0xf6, 0x8c, 0x2a, 0xc0, 0x7b, 0x5d, 0x90, 0x62, 0xb9, 0xf8, 0x68, 0x66, 0x2b, - 0xb2, 0x52, 0x49, 0x12, 0xd4, 0x85, 0x6e, 0x0c, - ], - }, - TestVector { - sk: [ - 0x33, 0xbc, 0xd2, 0x86, 0x45, 0x41, 0xb8, 0xbb, 0x7f, 0xdc, 0x77, 0xa1, 0x9d, 0x97, - 0x0f, 0x92, 0x4e, 0xae, 0xec, 0xf4, 0x10, 0x3c, 0x38, 0xc8, 0xd2, 0xb0, 0x66, 0x81, - 0x42, 0xf2, 0x7d, 0x09, - ], - vk: [ - 0x74, 0x17, 0x94, 0xe6, 0x2c, 0xf9, 0x32, 0x0c, 0x58, 0xba, 0xc5, 0x94, 0xa2, 0xb9, - 0x0e, 0x34, 0x0a, 0x6d, 0x8a, 0x68, 0x05, 0x6f, 0x6e, 0xd5, 0xc7, 0x86, 0x8c, 0x5f, - 0xf3, 0xe4, 0xd6, 0x16, - ], - alpha: [ - 0x7c, 0xe7, 0x25, 0xa5, 0xfe, 0xf6, 0x1b, 0xd4, 0xa1, 0xe9, 0xc7, 0x73, 0x28, 0xe8, - 0x21, 0x0e, 0xb7, 0x29, 0x2d, 0x95, 0x4c, 0x64, 0xe9, 0x9e, 0x8b, 0xed, 0xd0, 0x7a, - 0xb3, 0xab, 0x0e, 0x0d, - ], - rsk: [ - 0xf8, 0x76, 0x01, 0x55, 0xe5, 0x29, 0x3d, 0xbf, 0x9e, 0xb5, 0x77, 0x48, 0x32, 0x5f, - 0xc9, 0xf9, 0x04, 0x9d, 0xe5, 0x88, 0x5c, 0x65, 0xba, 0x60, 0xb5, 0xee, 0x03, 0x97, - 0x0b, 0xe9, 0x0e, 0x08, - ], - rvk: [ - 0x66, 0x62, 0xba, 0x09, 0x95, 0x0a, 0xcc, 0xd2, 0xce, 0xa3, 0xc7, 0xa8, 0x12, 0x90, - 0xcd, 0x59, 0x78, 0xa6, 0x2b, 0x5a, 0xc5, 0xbb, 0xc4, 0x8d, 0x9f, 0x58, 0x19, 0xcd, - 0xc9, 0x64, 0x6f, 0x0a, - ], - m: [ - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, - ], - sig: [ - 0x77, 0x4a, 0xc4, 0x67, 0x3f, 0x09, 0xf3, 0xac, 0x57, 0x89, 0xb2, 0x86, 0xb5, 0xee, - 0xcb, 0xed, 0xb2, 0x57, 0x23, 0x4e, 0x8c, 0xdf, 0xd9, 0x3f, 0x02, 0x89, 0x09, 0x78, - 0xa6, 0xbb, 0xa6, 0x11, 0x69, 0xed, 0x48, 0xf9, 0xe1, 0xc9, 0xfd, 0x13, 0x19, 0xbd, - 0x33, 0x0d, 0x2c, 0xf5, 0xb4, 0x91, 0x01, 0x0d, 0x69, 0xb0, 0x43, 0xf4, 0x64, 0x8b, - 0xff, 0x55, 0x41, 0x62, 0xc6, 0xa6, 0xdc, 0x09, - ], - rsig: [ - 0x7c, 0x6c, 0x49, 0x8d, 0xe0, 0x01, 0x78, 0x61, 0x09, 0xb3, 0x03, 0xa4, 0xc5, 0xdc, - 0xb7, 0xfd, 0x07, 0x57, 0x50, 0xa0, 0xb9, 0xdf, 0x5e, 0x1e, 0x2a, 0x8e, 0x75, 0x47, - 0xb7, 0xed, 0x70, 0xcc, 0x0b, 0x56, 0xa5, 0xbf, 0xa9, 0x65, 0x78, 0x43, 0xef, 0xd8, - 0x9c, 0x66, 0xa8, 0x4f, 0x41, 0xd2, 0xb1, 0xb5, 0x07, 0x51, 0x19, 0x6b, 0x1e, 0x8c, - 0x0c, 0x44, 0x98, 0x60, 0x06, 0x96, 0xa4, 0x04, - ], - }, - TestVector { - sk: [ - 0xca, 0x35, 0x06, 0xd6, 0xaf, 0x77, 0x67, 0xb5, 0x79, 0x0e, 0xf0, 0xc5, 0x19, 0x0f, - 0xb3, 0xf3, 0x87, 0x7c, 0x4a, 0xab, 0x40, 0xe0, 0xdd, 0x65, 0x1a, 0xbb, 0xda, 0xcb, - 0x54, 0x4e, 0xd0, 0x05, - ], - vk: [ - 0xba, 0xb6, 0xcf, 0xb5, 0xc8, 0xea, 0x34, 0x91, 0x25, 0x1b, 0x46, 0xd5, 0x2a, 0xca, - 0x25, 0xd9, 0xe9, 0xaf, 0x69, 0xfa, 0xa9, 0xb4, 0xe4, 0x0b, 0x03, 0xad, 0x00, 0x86, - 0xde, 0x59, 0xb5, 0x1f, - ], - alpha: [ - 0xbe, 0xa3, 0x87, 0x20, 0x3f, 0x43, 0x76, 0x0a, 0xd3, 0x7d, 0x61, 0xde, 0x0e, 0xb5, - 0x9f, 0xca, 0x6c, 0xab, 0x75, 0x60, 0xdf, 0x64, 0xfa, 0xbb, 0x95, 0x11, 0x57, 0x9f, - 0x6f, 0x68, 0x26, 0x06, - ], - rsk: [ - 0x88, 0xd9, 0x8d, 0xf6, 0xee, 0xba, 0xdd, 0xbf, 0x4c, 0x8c, 0x51, 0xa4, 0x28, 0xc4, - 0x52, 0xbe, 0xf4, 0x27, 0xc0, 0x0b, 0x20, 0x45, 0xd8, 0x21, 0xb0, 0xcc, 0x31, 0x6b, - 0xc4, 0xb6, 0xf6, 0x0b, - ], - rvk: [ - 0x11, 0x26, 0x7d, 0x14, 0xd5, 0xe0, 0xb2, 0xbb, 0x3c, 0xe0, 0x99, 0xe8, 0xef, 0x84, - 0x49, 0x47, 0x1c, 0xbc, 0xfc, 0x69, 0x39, 0xa4, 0xb3, 0x48, 0xde, 0xa2, 0xc1, 0x73, - 0x56, 0xa1, 0xe8, 0xdd, - ], - m: [ - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, - 0x05, 0x05, 0x05, 0x05, - ], - sig: [ - 0x9a, 0x25, 0x42, 0x9f, 0x3e, 0xfd, 0x9b, 0x2f, 0x7d, 0xe2, 0x9e, 0x45, 0x12, 0x8d, - 0xd7, 0xb7, 0x60, 0xf0, 0x50, 0x8c, 0xd9, 0x58, 0x21, 0x82, 0xab, 0xaf, 0x53, 0xdd, - 0x76, 0xc0, 0x34, 0x2c, 0xe4, 0x1b, 0x4a, 0xcf, 0x8e, 0x0a, 0x48, 0x24, 0xe4, 0x11, - 0x08, 0xc2, 0x02, 0x65, 0x73, 0x11, 0x4b, 0x60, 0xbe, 0xec, 0xb1, 0x74, 0x01, 0x2a, - 0x2b, 0xdb, 0xee, 0xcb, 0xaa, 0x00, 0xb5, 0x06, - ], - rsig: [ - 0xcf, 0xf5, 0x83, 0x57, 0x13, 0xbe, 0x07, 0xfb, 0xe1, 0x25, 0xbb, 0xf2, 0x7a, 0x63, - 0x6a, 0xdd, 0x13, 0x1c, 0x90, 0x81, 0x71, 0x6c, 0x52, 0xfd, 0xa8, 0x75, 0x42, 0x6d, - 0x03, 0x98, 0x2c, 0xd2, 0x7e, 0xbd, 0x14, 0xb4, 0x22, 0x7b, 0x83, 0x96, 0x15, 0xfd, - 0x03, 0x71, 0xbf, 0xdb, 0x8a, 0x30, 0xab, 0xdd, 0xff, 0x74, 0xd7, 0x95, 0xf3, 0xe2, - 0x7d, 0x1d, 0x47, 0xc6, 0x29, 0x46, 0x9b, 0x08, - ], - }, - TestVector { - sk: [ - 0xbc, 0x27, 0x83, 0x8d, 0xe2, 0xa6, 0x14, 0xcf, 0xba, 0x6c, 0x3e, 0x92, 0x2a, 0x8f, - 0x84, 0x24, 0xd9, 0x85, 0x6f, 0x68, 0x16, 0xf3, 0xbc, 0x61, 0x02, 0x31, 0x3b, 0x7f, - 0xaf, 0x5c, 0x3a, 0x0c, - ], - vk: [ - 0xd7, 0x9b, 0xe9, 0xff, 0x22, 0x9a, 0x2e, 0x35, 0xf5, 0xbc, 0xa4, 0x48, 0xe5, 0xeb, - 0x4a, 0x8a, 0xa9, 0x7f, 0xb4, 0x18, 0x02, 0x91, 0x25, 0xcf, 0xba, 0xa7, 0x8a, 0x91, - 0xa3, 0x82, 0xb0, 0x94, - ], - alpha: [ - 0x21, 0xa7, 0x15, 0x0e, 0x19, 0x4f, 0xed, 0xfe, 0xf9, 0x0c, 0x5d, 0x10, 0xe4, 0x20, - 0x85, 0x8b, 0xca, 0x40, 0x04, 0x04, 0x0e, 0xb6, 0x81, 0xd1, 0x4e, 0x75, 0xc4, 0x47, - 0x13, 0x51, 0xcb, 0x02, - ], - rsk: [ - 0x26, 0xa2, 0xa1, 0xc4, 0x9c, 0xe7, 0x6a, 0xfd, 0x31, 0x69, 0xd3, 0xd5, 0x7a, 0x8f, - 0xa1, 0x09, 0xa3, 0x8b, 0x3f, 0x6b, 0x23, 0x6e, 0xd7, 0x2c, 0xa8, 0xf6, 0xcb, 0x61, - 0xd8, 0xf8, 0x87, 0x00, - ], - rvk: [ - 0x54, 0xbf, 0x1b, 0xe7, 0x2e, 0x6d, 0x41, 0x20, 0x8b, 0x8a, 0xec, 0x11, 0x61, 0xd3, - 0xba, 0x59, 0x51, 0x9f, 0xb9, 0x3d, 0xa0, 0x1a, 0x55, 0xe6, 0x78, 0xe2, 0x75, 0x20, - 0x06, 0x60, 0x36, 0xc9, - ], - m: [ - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, - 0x06, 0x06, 0x06, 0x06, - ], - sig: [ - 0xbb, 0xe0, 0x23, 0x59, 0x87, 0xc6, 0xe0, 0xec, 0x68, 0x6d, 0xdb, 0x8a, 0x65, 0x72, - 0x66, 0xad, 0x60, 0x5f, 0x7b, 0x75, 0x95, 0x5b, 0xb0, 0xe8, 0x02, 0xf8, 0x81, 0x64, - 0xa0, 0xff, 0xe1, 0x0c, 0x3b, 0x73, 0x85, 0x04, 0xab, 0xb3, 0xd1, 0x05, 0x62, 0xb9, - 0x27, 0xb3, 0xd2, 0x9f, 0xe9, 0xb0, 0xd3, 0x56, 0x28, 0x6a, 0xea, 0xe5, 0xa2, 0xac, - 0x9e, 0x43, 0x5f, 0x20, 0x79, 0x1a, 0xf8, 0x00, - ], - rsig: [ - 0x6d, 0xe3, 0x2b, 0x54, 0x15, 0xd7, 0x7a, 0x90, 0x5f, 0x09, 0x03, 0x90, 0x2a, 0x11, - 0x7e, 0xda, 0x79, 0x3c, 0x70, 0x8e, 0x23, 0xa5, 0x42, 0x45, 0xba, 0x8a, 0x8d, 0x1f, - 0xe0, 0x26, 0x75, 0x23, 0x23, 0x15, 0x65, 0xe0, 0x57, 0x09, 0xae, 0xd9, 0x6c, 0x22, - 0x1f, 0xb1, 0xf3, 0xd0, 0x42, 0x04, 0x35, 0x03, 0xff, 0x33, 0x85, 0x85, 0xa9, 0xbb, - 0x98, 0x9c, 0x9d, 0xd4, 0x30, 0xd6, 0xd6, 0x0b, - ], - }, - TestVector { - sk: [ - 0xb2, 0x08, 0x59, 0xb8, 0x8e, 0xe3, 0x33, 0x8a, 0x64, 0x95, 0x4f, 0x8a, 0x9e, 0x8e, - 0x9b, 0xf3, 0xe7, 0x11, 0x5a, 0xcf, 0x7c, 0x6e, 0x7f, 0x01, 0x43, 0x2c, 0x5f, 0x76, - 0x96, 0xd2, 0xd0, 0x05, - ], - vk: [ - 0xa8, 0x1f, 0xe6, 0x84, 0x6d, 0xbe, 0x0a, 0x75, 0xc0, 0xf4, 0x9b, 0x21, 0x32, 0x32, - 0xbe, 0xad, 0xd1, 0xf9, 0xa5, 0x64, 0x67, 0x3d, 0x25, 0xb9, 0x1e, 0xe0, 0xf1, 0x7c, - 0xe9, 0xca, 0xa3, 0x63, - ], - alpha: [ - 0x44, 0xd9, 0x08, 0xe1, 0xc1, 0x5e, 0x6b, 0xd9, 0x38, 0x0a, 0x8b, 0x23, 0x5a, 0xce, - 0x02, 0xfa, 0xc1, 0xc0, 0x87, 0x94, 0x45, 0x4b, 0xcd, 0xb4, 0xa6, 0xf4, 0x8c, 0xea, - 0x78, 0xa7, 0x4a, 0x04, - ], - rsk: [ - 0xf6, 0xe1, 0x61, 0x99, 0x50, 0x42, 0x9f, 0x63, 0x9d, 0x9f, 0xda, 0xad, 0xf8, 0x5c, - 0x9e, 0xed, 0xa9, 0xd2, 0xe1, 0x63, 0xc2, 0xb9, 0x4c, 0xb6, 0xe9, 0x20, 0xec, 0x60, - 0x0f, 0x7a, 0x1b, 0x0a, - ], - rvk: [ - 0x0b, 0x68, 0xd5, 0x0f, 0x91, 0x3c, 0xd1, 0xb7, 0x8b, 0x59, 0x92, 0x1e, 0x16, 0x56, - 0xd5, 0x76, 0xb0, 0xeb, 0x17, 0x1e, 0xd3, 0x87, 0x0d, 0x39, 0xfe, 0xc6, 0x94, 0x41, - 0xb3, 0x4b, 0x25, 0x38, - ], - m: [ - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, - 0x07, 0x07, 0x07, 0x07, - ], - sig: [ - 0x44, 0x6d, 0x67, 0x7c, 0x4c, 0xfe, 0xfd, 0x02, 0x4b, 0x0a, 0xeb, 0x37, 0xa5, 0x98, - 0xcc, 0x2e, 0xb3, 0xd2, 0x9b, 0x02, 0x94, 0xfe, 0x5b, 0xb6, 0x97, 0x8e, 0x8b, 0x43, - 0xd3, 0x2b, 0x2e, 0x4f, 0x09, 0x56, 0xac, 0xd1, 0x3e, 0x7e, 0x3a, 0x63, 0xa1, 0x8f, - 0xca, 0x32, 0xd6, 0xab, 0x94, 0xb9, 0x4e, 0xd0, 0x33, 0xe9, 0xa1, 0x0f, 0xc5, 0x69, - 0x28, 0xbc, 0x8a, 0x0f, 0x4f, 0x8e, 0x95, 0x00, - ], - rsig: [ - 0x8d, 0xe0, 0x41, 0xe7, 0x09, 0xdb, 0x62, 0x4a, 0xe2, 0xbe, 0x16, 0x48, 0xb6, 0x62, - 0x23, 0x9c, 0xde, 0xdf, 0x85, 0xec, 0xd3, 0x82, 0x26, 0x8b, 0x0e, 0x35, 0x54, 0xbf, - 0xa0, 0xf2, 0x08, 0x1c, 0xd6, 0x41, 0xbc, 0xa0, 0x40, 0x78, 0xaa, 0x89, 0xf7, 0xdd, - 0x25, 0x40, 0x58, 0x7c, 0xed, 0x6b, 0x45, 0x89, 0x16, 0xb1, 0x3e, 0x4b, 0x6a, 0x36, - 0x30, 0xda, 0x69, 0x76, 0x46, 0xdb, 0xbf, 0x09, - ], - }, - TestVector { - sk: [ - 0x32, 0x16, 0xae, 0x47, 0xe9, 0xf5, 0x3e, 0x8a, 0x52, 0x79, 0x6f, 0x24, 0xb6, 0x24, - 0x60, 0x77, 0x6b, 0xd5, 0xf2, 0x05, 0xa7, 0x8e, 0x15, 0x95, 0xbc, 0x8e, 0xfe, 0xdc, - 0x51, 0x9d, 0x36, 0x0b, - ], - vk: [ - 0xdf, 0x74, 0xbf, 0x04, 0x79, 0x61, 0xcc, 0x5c, 0xda, 0xc8, 0x28, 0x90, 0xc7, 0x6e, - 0xc6, 0x75, 0xbd, 0x4e, 0x89, 0xea, 0xd2, 0x80, 0xc9, 0x52, 0xd7, 0xc3, 0x3e, 0xea, - 0xf2, 0xb5, 0xa6, 0x6b, - ], - alpha: [ - 0xc9, 0x61, 0xf2, 0xdd, 0x93, 0x68, 0x2a, 0xdb, 0x93, 0xf5, 0xc0, 0x5a, 0x73, 0xfd, - 0xbc, 0x6d, 0x43, 0xc7, 0x0e, 0x1b, 0x15, 0xe8, 0xd5, 0x3e, 0x3f, 0x17, 0xa8, 0x24, - 0x94, 0xe3, 0xf2, 0x09, - ], - rsk: [ - 0x44, 0x4b, 0xa9, 0x4e, 0x1e, 0x50, 0xd2, 0x94, 0x63, 0x5e, 0x68, 0xb2, 0x95, 0x01, - 0xb5, 0x3e, 0xae, 0x61, 0xcd, 0x1f, 0xbb, 0x3b, 0x84, 0xcd, 0x52, 0xf6, 0x72, 0x9c, - 0xfb, 0xcb, 0xab, 0x06, - ], - rvk: [ - 0x0a, 0xfb, 0xe4, 0x06, 0xa8, 0x91, 0xc3, 0xb8, 0xc3, 0x10, 0xc2, 0x15, 0xbc, 0x68, - 0xa9, 0x13, 0xde, 0x7c, 0xda, 0x06, 0xaf, 0x29, 0x42, 0x00, 0x56, 0x46, 0x8d, 0x0c, - 0x08, 0x85, 0x5b, 0x28, - ], - m: [ - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, - 0x08, 0x08, 0x08, 0x08, - ], - sig: [ - 0x99, 0x35, 0x80, 0xef, 0x93, 0x34, 0x9a, 0x1c, 0x9e, 0xe9, 0x60, 0xca, 0x3e, 0x7c, - 0xd0, 0x4c, 0x13, 0xb4, 0xa0, 0xec, 0x4f, 0xd1, 0x80, 0x53, 0xa1, 0x9c, 0xff, 0x77, - 0x63, 0x62, 0x09, 0x65, 0xfb, 0xee, 0x96, 0xc1, 0x64, 0x72, 0x30, 0xe3, 0x73, 0xcb, - 0x82, 0xb8, 0x1d, 0x00, 0x03, 0x92, 0x23, 0xd3, 0x0b, 0x39, 0x3e, 0xd1, 0x72, 0xc9, - 0xb3, 0xc5, 0x63, 0xc6, 0x11, 0x79, 0x22, 0x05, - ], - rsig: [ - 0xcc, 0x7a, 0xae, 0x1c, 0xed, 0xad, 0x2d, 0x7f, 0x6c, 0xe0, 0x4c, 0x19, 0xc5, 0xa5, - 0xb6, 0xb7, 0xa6, 0xa0, 0x82, 0x78, 0x5c, 0x54, 0x0c, 0x14, 0xf6, 0x30, 0x9b, 0x06, - 0x4d, 0x1f, 0xfa, 0x68, 0x17, 0x29, 0x53, 0xfb, 0xa0, 0xc2, 0xfc, 0xfb, 0x87, 0x5c, - 0xa7, 0xf7, 0xea, 0x98, 0xef, 0x55, 0xa0, 0x40, 0x2f, 0xd5, 0x29, 0xcf, 0xcd, 0xdf, - 0x99, 0x6c, 0xa2, 0xb8, 0xca, 0x89, 0x90, 0x0a, - ], - }, - TestVector { - sk: [ - 0x85, 0x83, 0x6f, 0x98, 0x32, 0xb2, 0x8d, 0xe7, 0xc6, 0x36, 0x13, 0xe2, 0xa6, 0xed, - 0x36, 0xfb, 0x1a, 0xb4, 0x4f, 0xb0, 0xc1, 0x3f, 0xa8, 0x79, 0x8c, 0xd9, 0xcd, 0x30, - 0x30, 0xd4, 0x55, 0x03, - ], - vk: [ - 0xbf, 0xd5, 0xbc, 0x00, 0xc7, 0xc0, 0x22, 0xaa, 0x89, 0x01, 0xae, 0x08, 0x3c, 0x12, - 0xd5, 0x4b, 0x82, 0xf0, 0xdd, 0xff, 0x8e, 0xd6, 0xdb, 0x9a, 0x12, 0xd5, 0x9a, 0x5e, - 0xf6, 0xa5, 0xa2, 0xe0, - ], - alpha: [ - 0xa2, 0xe8, 0xb9, 0xe1, 0x6d, 0x6f, 0xf3, 0xca, 0x6c, 0x53, 0xd4, 0xe8, 0x8a, 0xbb, - 0xb9, 0x9b, 0xe7, 0xaf, 0x7e, 0x36, 0x59, 0x63, 0x1f, 0x1e, 0xae, 0x1e, 0xff, 0x23, - 0x87, 0x4d, 0x8e, 0x0c, - ], - rsk: [ - 0x70, 0x3f, 0x32, 0xa3, 0x41, 0x13, 0xea, 0xe1, 0xb0, 0x79, 0x1f, 0xfe, 0x9d, 0x88, - 0x88, 0xf0, 0x01, 0x29, 0x9a, 0xe5, 0x19, 0x68, 0x60, 0x91, 0x91, 0x48, 0x99, 0xef, - 0xcc, 0x6c, 0x66, 0x01, - ], - rvk: [ - 0xeb, 0x92, 0x97, 0x03, 0x6c, 0xf5, 0x17, 0xe1, 0x5e, 0x9e, 0xfe, 0x39, 0x75, 0x32, - 0x8d, 0xb4, 0x8e, 0xe7, 0xc2, 0x69, 0x4e, 0x94, 0x6d, 0xb2, 0x5f, 0x52, 0x87, 0x88, - 0xf6, 0xa1, 0xdb, 0x14, - ], - m: [ - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, - 0x09, 0x09, 0x09, 0x09, - ], - sig: [ - 0xce, 0x90, 0xdd, 0xf4, 0xaf, 0x21, 0xaa, 0xc4, 0xd9, 0x41, 0x93, 0xea, 0x16, 0xff, - 0x35, 0xcd, 0x93, 0x79, 0x20, 0x4e, 0x7d, 0x8f, 0xf4, 0xc0, 0xf5, 0x41, 0x17, 0xab, - 0xb1, 0x6b, 0x7c, 0x85, 0xa0, 0xb1, 0x97, 0xcf, 0x13, 0xab, 0x14, 0xd7, 0xc3, 0xba, - 0x68, 0x01, 0x0a, 0xb8, 0x05, 0x12, 0x25, 0x91, 0x3b, 0xdb, 0xc3, 0x9a, 0x51, 0xf6, - 0x03, 0x7a, 0xfc, 0x6c, 0xee, 0xcb, 0x0b, 0x06, - ], - rsig: [ - 0xa8, 0x47, 0x74, 0x2e, 0x94, 0x01, 0xcf, 0x22, 0x39, 0x21, 0x3d, 0xc8, 0x81, 0x3e, - 0x97, 0x72, 0xe9, 0x7a, 0xf8, 0xd6, 0x7a, 0xdf, 0xfe, 0xab, 0xc8, 0xe6, 0x7f, 0x5d, - 0x2d, 0x90, 0xd0, 0xb4, 0x1b, 0xc2, 0x5b, 0x05, 0xf9, 0x4a, 0xce, 0x16, 0x8a, 0xec, - 0xc6, 0x58, 0x3e, 0x18, 0xf7, 0x63, 0x74, 0x92, 0xf3, 0x7a, 0x9c, 0xa3, 0x00, 0x20, - 0x2b, 0xc0, 0x65, 0xab, 0xd3, 0x80, 0xec, 0x00, - ], - }, - ] -} diff --git a/zcash_primitives/src/sapling/tree.rs b/zcash_primitives/src/sapling/tree.rs deleted file mode 100644 index b3b9f87ff..000000000 --- a/zcash_primitives/src/sapling/tree.rs +++ /dev/null @@ -1,142 +0,0 @@ -use bitvec::{order::Lsb0, view::AsBits}; -use group::{ff::PrimeField, Curve}; -use incrementalmerkletree::{Hashable, Level}; -use lazy_static::lazy_static; -use subtle::CtOption; - -use std::fmt; - -use super::{ - note::ExtractedNoteCommitment, - pedersen_hash::{pedersen_hash, Personalization}, -}; - -pub const NOTE_COMMITMENT_TREE_DEPTH: u8 = 32; -pub type CommitmentTree = - incrementalmerkletree::frontier::CommitmentTree; -pub type IncrementalWitness = - incrementalmerkletree::witness::IncrementalWitness; -pub type MerklePath = incrementalmerkletree::MerklePath; - -lazy_static! { - static ref UNCOMMITTED_SAPLING: bls12_381::Scalar = bls12_381::Scalar::one(); - static ref EMPTY_ROOTS: Vec = { - let mut v = vec![Node::empty_leaf()]; - for d in 0..NOTE_COMMITMENT_TREE_DEPTH { - let next = Node::combine(d.into(), &v[usize::from(d)], &v[usize::from(d)]); - v.push(next); - } - v - }; -} - -/// Compute a parent node in the Sapling commitment tree given its two children. -pub fn merkle_hash(depth: usize, lhs: &[u8; 32], rhs: &[u8; 32]) -> [u8; 32] { - merkle_hash_field(depth, lhs, rhs).to_repr() -} - -fn merkle_hash_field(depth: usize, lhs: &[u8; 32], rhs: &[u8; 32]) -> jubjub::Base { - let lhs = { - let mut tmp = [false; 256]; - for (a, b) in tmp.iter_mut().zip(lhs.as_bits::()) { - *a = *b; - } - tmp - }; - - let rhs = { - let mut tmp = [false; 256]; - for (a, b) in tmp.iter_mut().zip(rhs.as_bits::()) { - *a = *b; - } - tmp - }; - - jubjub::ExtendedPoint::from(pedersen_hash( - Personalization::MerkleTree(depth), - lhs.iter() - .copied() - .take(bls12_381::Scalar::NUM_BITS as usize) - .chain( - rhs.iter() - .copied() - .take(bls12_381::Scalar::NUM_BITS as usize), - ), - )) - .to_affine() - .get_u() -} - -/// A node within the Sapling commitment tree. -#[derive(Clone, Copy, PartialEq, Eq)] -pub struct Node(jubjub::Base); - -impl fmt::Debug for Node { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Node") - .field("repr", &hex::encode(self.0.to_bytes())) - .finish() - } -} - -impl Node { - /// Creates a tree leaf from the given Sapling note commitment. - pub fn from_cmu(value: &ExtractedNoteCommitment) -> Self { - Node(value.inner()) - } - - /// Constructs a new note commitment tree node from a [`bls12_381::Scalar`] - pub fn from_scalar(cmu: bls12_381::Scalar) -> Self { - Self(cmu) - } - - /// Parses a tree leaf from the bytes of a Sapling note commitment. - /// - /// Returns `None` if the provided bytes represent a non-canonical encoding. - pub fn from_bytes(bytes: [u8; 32]) -> CtOption { - jubjub::Base::from_repr(bytes).map(Self) - } - - /// Returns the canonical byte representation of this node. - pub fn to_bytes(&self) -> [u8; 32] { - self.0.to_repr() - } -} - -impl Hashable for Node { - fn empty_leaf() -> Self { - Node(*UNCOMMITTED_SAPLING) - } - - fn combine(level: Level, lhs: &Self, rhs: &Self) -> Self { - Node(merkle_hash_field( - level.into(), - &lhs.0.to_bytes(), - &rhs.0.to_bytes(), - )) - } - - fn empty_root(level: Level) -> Self { - EMPTY_ROOTS[::from(level)] - } -} - -impl From for bls12_381::Scalar { - fn from(node: Node) -> Self { - node.0 - } -} - -#[cfg(any(test, feature = "test-dependencies"))] -pub(super) mod testing { - use proptest::prelude::*; - - use super::Node; - use crate::sapling::note::testing::arb_cmu; - - prop_compose! { - pub fn arb_node()(cmu in arb_cmu()) -> Node { - Node::from_cmu(&cmu) - } - } -} diff --git a/zcash_primitives/src/sapling/util.rs b/zcash_primitives/src/sapling/util.rs deleted file mode 100644 index 2175e2a3a..000000000 --- a/zcash_primitives/src/sapling/util.rs +++ /dev/null @@ -1,34 +0,0 @@ -use blake2b_simd::Params; -use ff::Field; -use rand_core::{CryptoRng, RngCore}; - -use super::{note_encryption::Zip212Enforcement, Rseed}; - -pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> jubjub::Fr { - let mut hasher = Params::new().hash_length(64).personal(persona).to_state(); - hasher.update(a); - hasher.update(b); - let ret = hasher.finalize(); - jubjub::Fr::from_bytes_wide(ret.as_array()) -} - -pub fn generate_random_rseed( - zip212_enforcement: Zip212Enforcement, - rng: &mut R, -) -> Rseed { - generate_random_rseed_internal(zip212_enforcement, rng) -} - -pub(crate) fn generate_random_rseed_internal( - zip212_enforcement: Zip212Enforcement, - rng: &mut R, -) -> Rseed { - match zip212_enforcement { - Zip212Enforcement::Off => Rseed::BeforeZip212(jubjub::Fr::random(rng)), - Zip212Enforcement::GracePeriod | Zip212Enforcement::On => { - let mut buffer = [0u8; 32]; - rng.fill_bytes(&mut buffer); - Rseed::AfterZip212(buffer) - } - } -} diff --git a/zcash_primitives/src/sapling/value.rs b/zcash_primitives/src/sapling/value.rs deleted file mode 100644 index 16bab4aa5..000000000 --- a/zcash_primitives/src/sapling/value.rs +++ /dev/null @@ -1,264 +0,0 @@ -//! Monetary values within the Sapling shielded pool. -//! -//! Values are represented in three places within the Sapling protocol: -//! - [`NoteValue`], the value of an individual note. It is an unsigned 64-bit integer -//! (with maximum value [`MAX_NOTE_VALUE`]), and is serialized in a note plaintext. -//! - [`ValueSum`], the sum of note values within a Sapling [`Bundle`]. It is represented -//! as an `i128` and places an upper bound on the maximum number of notes within a -//! single [`Bundle`]. -//! - `valueBalanceSapling`, which is a signed 63-bit integer. This is represented -//! by a user-defined type parameter on [`Bundle`], returned by -//! [`Bundle::value_balance`] and [`SaplingBuilder::value_balance`]. -//! -//! If your specific instantiation of the Sapling protocol requires a smaller bound on -//! valid note values (for example, Zcash's `MAX_MONEY` fits into a 51-bit integer), you -//! should enforce this in two ways: -//! -//! - Define your `valueBalanceSapling` type to enforce your valid value range. This can -//! be checked in its `TryFrom` implementation. -//! - Define your own "amount" type for note values, and convert it to `NoteValue` prior -//! to calling [`SaplingBuilder::add_output`]. -//! -//! Inside the circuit, note values are constrained to be unsigned 64-bit integers. -//! -//! # Caution! -//! -//! An `i64` is _not_ a signed 64-bit integer! The [Rust documentation] calls `i64` the -//! 64-bit signed integer type, which is true in the sense that its encoding in memory -//! takes up 64 bits. Numerically, however, `i64` is a signed 63-bit integer. -//! -//! Fortunately, users of this crate should never need to construct [`ValueSum`] directly; -//! you should only need to interact with [`NoteValue`] (which can be safely constructed -//! from a `u64`) and `valueBalanceSapling` (which can be represented as an `i64`). -//! -//! [`Bundle`]: crate::sapling::Bundle -//! [`Bundle::value_balance`]: crate::sapling::Bundle::value_balance -//! [`SaplingBuilder::value_balance`]: crate::sapling::builder::SaplingBuilder::value_balance -//! [`SaplingBuilder::add_output`]: crate::sapling::builder::SaplingBuilder::add_output -//! [Rust documentation]: https://doc.rust-lang.org/stable/std/primitive.i64.html - -use bitvec::{array::BitArray, order::Lsb0}; -use ff::{Field, PrimeField}; -use group::GroupEncoding; -use rand::RngCore; -use subtle::CtOption; - -use super::constants::{VALUE_COMMITMENT_RANDOMNESS_GENERATOR, VALUE_COMMITMENT_VALUE_GENERATOR}; - -mod sums; -pub use sums::{CommitmentSum, OverflowError, TrapdoorSum, ValueSum}; - -/// Maximum note value. -pub const MAX_NOTE_VALUE: u64 = u64::MAX; - -/// The non-negative value of an individual Sapling note. -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] -pub struct NoteValue(u64); - -impl NoteValue { - /// Returns the raw underlying value. - pub fn inner(&self) -> u64 { - self.0 - } - - /// Creates a note value from its raw numeric value. - /// - /// This only enforces that the value is an unsigned 64-bit integer. Callers should - /// enforce any additional constraints on the value's valid range themselves. - pub fn from_raw(value: u64) -> Self { - NoteValue(value) - } - - pub(crate) fn from_bytes(bytes: [u8; 8]) -> Self { - NoteValue(u64::from_le_bytes(bytes)) - } - - pub(crate) fn to_le_bits(self) -> BitArray<[u8; 8], Lsb0> { - BitArray::<_, Lsb0>::new(self.0.to_le_bytes()) - } -} - -/// The blinding factor for a [`ValueCommitment`]. -#[derive(Clone, Debug)] -pub struct ValueCommitTrapdoor(jubjub::Scalar); - -impl ValueCommitTrapdoor { - /// Generates a new value commitment trapdoor. - /// - /// This is public for access by `zcash_proofs`. - pub fn random(rng: impl RngCore) -> Self { - ValueCommitTrapdoor(jubjub::Scalar::random(rng)) - } - - /// Constructs `ValueCommitTrapdoor` from the byte representation of a scalar. - /// - /// Returns a `None` [`CtOption`] if `bytes` is not a canonical representation of a - /// Jubjub scalar. - /// - /// This is a low-level API, requiring a detailed understanding of the - /// [use of value commitment trapdoors][saplingbalance] in the Zcash protocol - /// to use correctly and securely. It is intended to be used in combination - /// with [`ValueCommitment::derive`]. - /// - /// [saplingbalance]: https://zips.z.cash/protocol/protocol.pdf#saplingbalance - pub fn from_bytes(bytes: [u8; 32]) -> CtOption { - jubjub::Scalar::from_repr(bytes).map(ValueCommitTrapdoor) - } - - /// Returns the inner Jubjub scalar representing this trapdoor. - /// - /// This is public for access by `zcash_proofs`. - pub fn inner(&self) -> jubjub::Scalar { - self.0 - } -} - -/// A commitment to a [`ValueSum`]. -/// -/// # Consensus rules -/// -/// The Zcash Protocol Spec requires Sapling Spend Descriptions and Output Descriptions to -/// not contain a small order `ValueCommitment`. However, the `ValueCommitment` type as -/// specified (and implemented here) may contain a small order point. In practice, it will -/// not occur: -/// - [`ValueCommitment::derive`] will only produce a small order point if both the given -/// [`NoteValue`] and [`ValueCommitTrapdoor`] are zero. However, the only constructor -/// available for `ValueCommitTrapdoor` is [`ValueCommitTrapdoor::random`], which will -/// produce zero with negligible probability (assuming a non-broken PRNG). -/// - [`ValueCommitment::from_bytes_not_small_order`] enforces this by definition, and is -/// the only constructor that can be used with data received over the network. -#[derive(Clone, Debug)] -pub struct ValueCommitment(jubjub::ExtendedPoint); - -impl ValueCommitment { - /// Derives a `ValueCommitment` by $\mathsf{ValueCommit^{Sapling}}$. - /// - /// Defined in [Zcash Protocol Spec § 5.4.8.3: Homomorphic Pedersen commitments (Sapling and Orchard)][concretehomomorphiccommit]. - /// - /// [concretehomomorphiccommit]: https://zips.z.cash/protocol/protocol.pdf#concretehomomorphiccommit - pub fn derive(value: NoteValue, rcv: ValueCommitTrapdoor) -> Self { - let cv = (VALUE_COMMITMENT_VALUE_GENERATOR * jubjub::Scalar::from(value.0)) - + (VALUE_COMMITMENT_RANDOMNESS_GENERATOR * rcv.0); - - ValueCommitment(cv.into()) - } - - /// Returns the inner Jubjub point representing this value commitment. - /// - /// This is public for access by `zcash_proofs`. - pub fn as_inner(&self) -> &jubjub::ExtendedPoint { - &self.0 - } - - /// Deserializes a value commitment from its byte representation. - /// - /// Returns `None` if `bytes` is an invalid representation of a Jubjub point, or the - /// resulting point is of small order. - /// - /// This method can be used to enforce the "not small order" consensus rules defined - /// in [Zcash Protocol Spec § 4.4: Spend Descriptions][spenddesc] and - /// [§ 4.5: Output Descriptions][outputdesc]. - /// - /// [spenddesc]: https://zips.z.cash/protocol/protocol.pdf#spenddesc - /// [outputdesc]: https://zips.z.cash/protocol/protocol.pdf#outputdesc - pub fn from_bytes_not_small_order(bytes: &[u8; 32]) -> CtOption { - jubjub::ExtendedPoint::from_bytes(bytes) - .and_then(|cv| CtOption::new(ValueCommitment(cv), !cv.is_small_order())) - } - - /// Serializes this value commitment to its canonical byte representation. - pub fn to_bytes(&self) -> [u8; 32] { - self.0.to_bytes() - } -} - -/// Generators for property testing. -#[cfg(any(test, feature = "test-dependencies"))] -#[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] -pub mod testing { - use proptest::prelude::*; - - use super::{NoteValue, ValueCommitTrapdoor, MAX_NOTE_VALUE}; - - prop_compose! { - /// Generate an arbitrary value in the range of valid nonnegative amounts. - pub fn arb_note_value()(value in 0u64..MAX_NOTE_VALUE) -> NoteValue { - NoteValue(value) - } - } - - prop_compose! { - /// Generate an arbitrary value in the range of valid positive amounts less than a - /// specified value. - pub fn arb_note_value_bounded(max: u64)(value in 0u64..max) -> NoteValue { - NoteValue(value) - } - } - - prop_compose! { - /// Generate an arbitrary value in the range of valid positive amounts less than a - /// specified value. - pub fn arb_positive_note_value(max: u64)(value in 1u64..max) -> NoteValue { - NoteValue(value) - } - } - - prop_compose! { - /// Generate an arbitrary Jubjub scalar. - fn arb_scalar()(bytes in prop::array::uniform32(0u8..)) -> jubjub::Scalar { - // Instead of rejecting out-of-range bytes, let's reduce them. - let mut buf = [0; 64]; - buf[..32].copy_from_slice(&bytes); - jubjub::Scalar::from_bytes_wide(&buf) - } - } - - prop_compose! { - /// Generate an arbitrary ValueCommitTrapdoor - pub fn arb_trapdoor()(rcv in arb_scalar()) -> ValueCommitTrapdoor { - ValueCommitTrapdoor(rcv) - } - } -} - -#[cfg(test)] -mod tests { - use proptest::prelude::*; - - use super::{ - testing::{arb_note_value_bounded, arb_trapdoor}, - CommitmentSum, OverflowError, TrapdoorSum, ValueCommitment, ValueSum, - }; - - proptest! { - #[test] - fn bsk_consistent_with_bvk( - values in (1usize..10).prop_flat_map(|n_values| prop::collection::vec( - (arb_note_value_bounded((i64::MAX as u64) / (n_values as u64)), arb_trapdoor()), - n_values, - )) - ) { - let value_balance: i64 = values - .iter() - .map(|(value, _)| value) - .sum::>() - .expect("we generate values that won't overflow") - .try_into() - .unwrap(); - - let bsk = values - .iter() - .map(|(_, rcv)| rcv) - .sum::() - .into_bsk(); - - let bvk = values - .into_iter() - .map(|(value, rcv)| ValueCommitment::derive(value, rcv)) - .sum::() - .into_bvk(value_balance); - - assert_eq!(redjubjub::VerificationKey::from(&bsk), bvk); - } - } -} diff --git a/zcash_primitives/src/sapling/value/sums.rs b/zcash_primitives/src/sapling/value/sums.rs deleted file mode 100644 index 69bfc9237..000000000 --- a/zcash_primitives/src/sapling/value/sums.rs +++ /dev/null @@ -1,241 +0,0 @@ -use core::fmt::{self, Debug}; -use core::iter::Sum; -use core::ops::{Add, AddAssign, Sub, SubAssign}; - -use group::GroupEncoding; -use redjubjub::Binding; - -use super::{NoteValue, ValueCommitTrapdoor, ValueCommitment}; -use crate::sapling::constants::VALUE_COMMITMENT_VALUE_GENERATOR; - -/// A value operation overflowed. -#[derive(Debug)] -pub struct OverflowError; - -impl fmt::Display for OverflowError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Sapling value operation overflowed") - } -} - -impl std::error::Error for OverflowError {} - -/// A sum of Sapling note values. -/// -/// [Zcash Protocol Spec § 4.13: Balance and Binding Signature (Sapling)][saplingbalance] -/// constrains the range of this type to between `[-(r_J - 1)/2..(r_J - 1)/2]` in the -/// abstract protocol, and `[−38913406623490299131842..104805176454780817500623]` in the -/// concrete Zcash protocol. We represent it as an `i128`, which has a range large enough -/// to handle Zcash transactions while small enough to ensure the abstract protocol bounds -/// are not breached. -/// -/// [saplingbalance]: https://zips.z.cash/protocol/protocol.pdf#saplingbalance -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] -pub struct ValueSum(i128); - -impl ValueSum { - /// Initializes a sum of `NoteValue`s to zero. - pub fn zero() -> Self { - ValueSum(0) - } -} - -impl Add for ValueSum { - type Output = Option; - - #[allow(clippy::suspicious_arithmetic_impl)] - fn add(self, rhs: NoteValue) -> Self::Output { - self.0.checked_add(rhs.0.into()).map(ValueSum) - } -} - -impl Sub for ValueSum { - type Output = Option; - - #[allow(clippy::suspicious_arithmetic_impl)] - fn sub(self, rhs: NoteValue) -> Self::Output { - self.0.checked_sub(rhs.0.into()).map(ValueSum) - } -} - -impl<'a> Sum<&'a NoteValue> for Result { - fn sum>(iter: I) -> Self { - iter.fold(Ok(ValueSum(0)), |acc, v| (acc? + *v).ok_or(OverflowError)) - } -} - -impl Sum for Result { - fn sum>(iter: I) -> Self { - iter.fold(Ok(ValueSum(0)), |acc, v| (acc? + v).ok_or(OverflowError)) - } -} - -impl TryFrom for i64 { - type Error = OverflowError; - - fn try_from(v: ValueSum) -> Result { - i64::try_from(v.0).map_err(|_| OverflowError) - } -} - -/// A sum of Sapling value commitment blinding factors. -#[derive(Clone, Copy, Debug)] -pub struct TrapdoorSum(jubjub::Scalar); - -impl TrapdoorSum { - /// Initializes a sum of `ValueCommitTrapdoor`s to zero. - pub fn zero() -> Self { - TrapdoorSum(jubjub::Scalar::zero()) - } - - /// Transform this trapdoor sum into the corresponding RedJubjub private key. - /// - /// This is public for access by `zcash_proofs`. - pub fn into_bsk(self) -> redjubjub::SigningKey { - redjubjub::SigningKey::try_from(self.0.to_bytes()) - .expect("valid scalars are valid signing keys") - } -} - -impl Add<&ValueCommitTrapdoor> for ValueCommitTrapdoor { - type Output = TrapdoorSum; - - fn add(self, rhs: &Self) -> Self::Output { - TrapdoorSum(self.0 + rhs.0) - } -} - -impl Add<&ValueCommitTrapdoor> for TrapdoorSum { - type Output = TrapdoorSum; - - fn add(self, rhs: &ValueCommitTrapdoor) -> Self::Output { - TrapdoorSum(self.0 + rhs.0) - } -} - -impl AddAssign<&ValueCommitTrapdoor> for TrapdoorSum { - fn add_assign(&mut self, rhs: &ValueCommitTrapdoor) { - self.0 += rhs.0; - } -} - -impl Sub<&ValueCommitTrapdoor> for ValueCommitTrapdoor { - type Output = TrapdoorSum; - - fn sub(self, rhs: &Self) -> Self::Output { - TrapdoorSum(self.0 - rhs.0) - } -} - -impl Sub for TrapdoorSum { - type Output = TrapdoorSum; - - fn sub(self, rhs: Self) -> Self::Output { - TrapdoorSum(self.0 - rhs.0) - } -} - -impl SubAssign<&ValueCommitTrapdoor> for TrapdoorSum { - fn sub_assign(&mut self, rhs: &ValueCommitTrapdoor) { - self.0 -= rhs.0; - } -} - -impl<'a> Sum<&'a ValueCommitTrapdoor> for TrapdoorSum { - fn sum>(iter: I) -> Self { - iter.fold(TrapdoorSum::zero(), |acc, cv| acc + cv) - } -} - -/// A sum of Sapling value commitments. -#[derive(Clone, Copy, Debug)] -pub struct CommitmentSum(jubjub::ExtendedPoint); - -impl CommitmentSum { - /// Initializes a sum of `ValueCommitment`s to zero. - pub fn zero() -> Self { - CommitmentSum(jubjub::ExtendedPoint::identity()) - } - - /// Transform this value commitment sum into the corresponding RedJubjub public key. - /// - /// This is public for access by `zcash_proofs`. - pub fn into_bvk>(self, value_balance: V) -> redjubjub::VerificationKey { - let value: i64 = value_balance.into(); - - // Compute the absolute value. - let abs_value = match value.checked_abs() { - Some(v) => u64::try_from(v).expect("v is non-negative"), - None => 1u64 << 63, - }; - - // Construct the field representation of the signed value. - let value_balance = if value.is_negative() { - -jubjub::Scalar::from(abs_value) - } else { - jubjub::Scalar::from(abs_value) - }; - - // Subtract `value_balance` from the sum to get the final bvk. - let bvk = self.0 - VALUE_COMMITMENT_VALUE_GENERATOR * value_balance; - - redjubjub::VerificationKey::try_from(bvk.to_bytes()) - .expect("valid points are valid verification keys") - } -} - -impl Add<&ValueCommitment> for ValueCommitment { - type Output = CommitmentSum; - - fn add(self, rhs: &Self) -> Self::Output { - CommitmentSum(self.0 + rhs.0) - } -} - -impl Add<&ValueCommitment> for CommitmentSum { - type Output = CommitmentSum; - - fn add(self, rhs: &ValueCommitment) -> Self::Output { - CommitmentSum(self.0 + rhs.0) - } -} - -impl AddAssign<&ValueCommitment> for CommitmentSum { - fn add_assign(&mut self, rhs: &ValueCommitment) { - self.0 += rhs.0; - } -} - -impl Sub<&ValueCommitment> for ValueCommitment { - type Output = CommitmentSum; - - fn sub(self, rhs: &Self) -> Self::Output { - CommitmentSum(self.0 - rhs.0) - } -} - -impl SubAssign<&ValueCommitment> for CommitmentSum { - fn sub_assign(&mut self, rhs: &ValueCommitment) { - self.0 -= rhs.0; - } -} - -impl Sub for CommitmentSum { - type Output = CommitmentSum; - - fn sub(self, rhs: Self) -> Self::Output { - CommitmentSum(self.0 - rhs.0) - } -} - -impl Sum for CommitmentSum { - fn sum>(iter: I) -> Self { - iter.fold(CommitmentSum::zero(), |acc, cv| acc + &cv) - } -} - -impl<'a> Sum<&'a ValueCommitment> for CommitmentSum { - fn sum>(iter: I) -> Self { - iter.fold(CommitmentSum::zero(), |acc, cv| acc + cv) - } -} diff --git a/zcash_primitives/src/sapling/verifier.rs b/zcash_primitives/src/sapling/verifier.rs deleted file mode 100644 index e03f07d7f..000000000 --- a/zcash_primitives/src/sapling/verifier.rs +++ /dev/null @@ -1,149 +0,0 @@ -use bellman::{gadgets::multipack, groth16::Proof}; -use bls12_381::Bls12; -use group::{ff::PrimeField, Curve}; -use redjubjub::{Binding, SpendAuth}; - -use crate::sapling::{ - note::ExtractedNoteCommitment, - value::{CommitmentSum, ValueCommitment}, -}; - -mod single; -pub use single::SaplingVerificationContext; - -mod batch; -pub use batch::BatchValidator; - -/// A context object for verifying the Sapling components of a Zcash transaction. -struct SaplingVerificationContextInner { - // (sum of the Spend value commitments) - (sum of the Output value commitments) - cv_sum: CommitmentSum, -} - -impl SaplingVerificationContextInner { - /// Construct a new context to be used with a single transaction. - fn new() -> Self { - SaplingVerificationContextInner { - cv_sum: CommitmentSum::zero(), - } - } - - /// Perform consensus checks on a Sapling SpendDescription, while - /// accumulating its value commitment inside the context for later use. - #[allow(clippy::too_many_arguments)] - fn check_spend( - &mut self, - cv: &ValueCommitment, - anchor: bls12_381::Scalar, - nullifier: &[u8; 32], - rk: &redjubjub::VerificationKey, - zkproof: Proof, - verifier_ctx: &mut C, - spend_auth_sig_verifier: impl FnOnce(&mut C, &redjubjub::VerificationKey) -> bool, - proof_verifier: impl FnOnce(&mut C, Proof, [bls12_381::Scalar; 7]) -> bool, - ) -> bool { - // The "cv is not small order" happens when a SpendDescription is deserialized. - // This happens when transactions or blocks are received over the network, or when - // mined blocks are introduced via the `submitblock` RPC method on full nodes. - let rk_affine = jubjub::AffinePoint::from_bytes((*rk).into()).unwrap(); - if rk_affine.is_small_order().into() { - return false; - } - - // Accumulate the value commitment in the context - self.cv_sum += cv; - - // Grab the nullifier as a sequence of bytes - let nullifier = &nullifier[..]; - - // Verify the spend_auth_sig - if !spend_auth_sig_verifier(verifier_ctx, rk) { - return false; - } - - // Construct public input for circuit - let mut public_input = [bls12_381::Scalar::zero(); 7]; - { - let affine = rk_affine; - let (u, v) = (affine.get_u(), affine.get_v()); - public_input[0] = u; - public_input[1] = v; - } - { - let affine = cv.as_inner().to_affine(); - let (u, v) = (affine.get_u(), affine.get_v()); - public_input[2] = u; - public_input[3] = v; - } - public_input[4] = anchor; - - // Add the nullifier through multiscalar packing - { - let nullifier = multipack::bytes_to_bits_le(nullifier); - let nullifier = multipack::compute_multipacking(&nullifier); - - assert_eq!(nullifier.len(), 2); - - public_input[5] = nullifier[0]; - public_input[6] = nullifier[1]; - } - - // Verify the proof - proof_verifier(verifier_ctx, zkproof, public_input) - } - - /// Perform consensus checks on a Sapling OutputDescription, while - /// accumulating its value commitment inside the context for later use. - fn check_output( - &mut self, - cv: &ValueCommitment, - cmu: ExtractedNoteCommitment, - epk: jubjub::ExtendedPoint, - zkproof: Proof, - proof_verifier: impl FnOnce(Proof, [bls12_381::Scalar; 5]) -> bool, - ) -> bool { - // The "cv is not small order" happens when an OutputDescription is deserialized. - // This happens when transactions or blocks are received over the network, or when - // mined blocks are introduced via the `submitblock` RPC method on full nodes. - if epk.is_small_order().into() { - return false; - } - - // Accumulate the value commitment in the context - self.cv_sum -= cv; - - // Construct public input for circuit - let mut public_input = [bls12_381::Scalar::zero(); 5]; - { - let affine = cv.as_inner().to_affine(); - let (u, v) = (affine.get_u(), affine.get_v()); - public_input[0] = u; - public_input[1] = v; - } - { - let affine = epk.to_affine(); - let (u, v) = (affine.get_u(), affine.get_v()); - public_input[2] = u; - public_input[3] = v; - } - public_input[4] = bls12_381::Scalar::from_repr(cmu.to_bytes()).unwrap(); - - // Verify the proof - proof_verifier(zkproof, public_input) - } - - /// Perform consensus checks on the valueBalance and bindingSig parts of a - /// Sapling transaction. All SpendDescriptions and OutputDescriptions must - /// have been checked before calling this function. - fn final_check>( - &self, - value_balance: V, - binding_sig_verifier: impl FnOnce(redjubjub::VerificationKey) -> bool, - ) -> bool { - // Compute the final bvk. - let bvk = self.cv_sum.into_bvk(value_balance); - - // Verify the binding_sig - binding_sig_verifier(bvk) - } -} diff --git a/zcash_primitives/src/sapling/verifier/batch.rs b/zcash_primitives/src/sapling/verifier/batch.rs deleted file mode 100644 index 950be192b..000000000 --- a/zcash_primitives/src/sapling/verifier/batch.rs +++ /dev/null @@ -1,166 +0,0 @@ -use bellman::groth16; -use bls12_381::Bls12; -use group::GroupEncoding; -use rand_core::{CryptoRng, RngCore}; - -use super::SaplingVerificationContextInner; -use crate::sapling::{ - bundle::{Authorized, Bundle}, - circuit::{OutputVerifyingKey, SpendVerifyingKey}, -}; - -/// Batch validation context for Sapling. -/// -/// This batch-validates Spend and Output proofs, and RedJubjub signatures. -/// -/// Signatures are verified assuming ZIP 216 is active. -pub struct BatchValidator { - bundles_added: bool, - spend_proofs: groth16::batch::Verifier, - output_proofs: groth16::batch::Verifier, - signatures: redjubjub::batch::Verifier, -} - -impl Default for BatchValidator { - fn default() -> Self { - Self::new() - } -} - -impl BatchValidator { - /// Constructs a new batch validation context. - pub fn new() -> Self { - BatchValidator { - bundles_added: false, - spend_proofs: groth16::batch::Verifier::new(), - output_proofs: groth16::batch::Verifier::new(), - signatures: redjubjub::batch::Verifier::new(), - } - } - - /// Checks the bundle against Sapling-specific consensus rules, and adds its proof and - /// signatures to the validator. - /// - /// Returns `false` if the bundle doesn't satisfy all of the consensus rules. This - /// `BatchValidator` can continue to be used regardless, but some or all of the proofs - /// and signatures from this bundle may have already been added to the batch even if - /// it fails other consensus rules. - pub fn check_bundle>( - &mut self, - bundle: Bundle, - sighash: [u8; 32], - ) -> bool { - self.bundles_added = true; - - let mut ctx = SaplingVerificationContextInner::new(); - - for spend in bundle.shielded_spends() { - // Deserialize the proof - let zkproof = match groth16::Proof::read(&spend.zkproof()[..]) { - Ok(p) => p, - Err(_) => return false, - }; - - // Check the Spend consensus rules, and batch its proof and spend - // authorization signature. - let consensus_rules_passed = ctx.check_spend( - spend.cv(), - *spend.anchor(), - &spend.nullifier().0, - spend.rk(), - zkproof, - self, - |this, rk| { - this.signatures - .queue(((*rk).into(), *spend.spend_auth_sig(), &sighash)); - true - }, - |this, proof, public_inputs| { - this.spend_proofs.queue((proof, public_inputs.to_vec())); - true - }, - ); - if !consensus_rules_passed { - return false; - } - } - - for output in bundle.shielded_outputs() { - // Deserialize the ephemeral key - let epk = match jubjub::ExtendedPoint::from_bytes(&output.ephemeral_key().0).into() { - Some(p) => p, - None => return false, - }; - - // Deserialize the proof - let zkproof = match groth16::Proof::read(&output.zkproof()[..]) { - Ok(p) => p, - Err(_) => return false, - }; - - // Check the Output consensus rules, and batch its proof. - let consensus_rules_passed = ctx.check_output( - output.cv(), - *output.cmu(), - epk, - zkproof, - |proof, public_inputs| { - self.output_proofs.queue((proof, public_inputs.to_vec())); - true - }, - ); - if !consensus_rules_passed { - return false; - } - } - - // Check the whole-bundle consensus rules, and batch the binding signature. - ctx.final_check(*bundle.value_balance(), |bvk| { - self.signatures - .queue((bvk.into(), bundle.authorization().binding_sig, &sighash)); - true - }) - } - - /// Batch-validates the accumulated bundles. - /// - /// Returns `true` if every proof and signature in every bundle added to the batch - /// validator is valid, or `false` if one or more are invalid. No attempt is made to - /// figure out which of the accumulated bundles might be invalid; if that information - /// is desired, construct separate [`BatchValidator`]s for sub-batches of the bundles. - pub fn validate( - self, - spend_vk: &SpendVerifyingKey, - output_vk: &OutputVerifyingKey, - mut rng: R, - ) -> bool { - if !self.bundles_added { - // An empty batch is always valid, but is not free to run; skip it. - return true; - } - - if let Err(e) = self.signatures.verify(&mut rng) { - tracing::debug!("Signature batch validation failed: {}", e); - return false; - } - - #[cfg(feature = "multicore")] - let verify_proofs = |batch: groth16::batch::Verifier, vk| batch.verify_multicore(vk); - - #[cfg(not(feature = "multicore"))] - let mut verify_proofs = - |batch: groth16::batch::Verifier, vk| batch.verify(&mut rng, vk); - - if verify_proofs(self.spend_proofs, &spend_vk.0).is_err() { - tracing::debug!("Spend proof batch validation failed"); - return false; - } - - if verify_proofs(self.output_proofs, &output_vk.0).is_err() { - tracing::debug!("Output proof batch validation failed"); - return false; - } - - true - } -} diff --git a/zcash_primitives/src/sapling/verifier/single.rs b/zcash_primitives/src/sapling/verifier/single.rs deleted file mode 100644 index 79af455b1..000000000 --- a/zcash_primitives/src/sapling/verifier/single.rs +++ /dev/null @@ -1,83 +0,0 @@ -use bellman::groth16::{verify_proof, Proof}; -use bls12_381::Bls12; -use redjubjub::{Binding, SpendAuth}; - -use super::SaplingVerificationContextInner; -use crate::sapling::{ - circuit::{PreparedOutputVerifyingKey, PreparedSpendVerifyingKey}, - note::ExtractedNoteCommitment, - value::ValueCommitment, -}; - -/// A context object for verifying the Sapling components of a single Zcash transaction. -pub struct SaplingVerificationContext { - inner: SaplingVerificationContextInner, -} - -impl SaplingVerificationContext { - /// Construct a new context to be used with a single transaction. - #[allow(clippy::new_without_default)] - pub fn new() -> Self { - SaplingVerificationContext { - inner: SaplingVerificationContextInner::new(), - } - } - - /// Perform consensus checks on a Sapling SpendDescription, while - /// accumulating its value commitment inside the context for later use. - #[allow(clippy::too_many_arguments)] - pub fn check_spend( - &mut self, - cv: &ValueCommitment, - anchor: bls12_381::Scalar, - nullifier: &[u8; 32], - rk: redjubjub::VerificationKey, - sighash_value: &[u8; 32], - spend_auth_sig: redjubjub::Signature, - zkproof: Proof, - verifying_key: &PreparedSpendVerifyingKey, - ) -> bool { - self.inner.check_spend( - cv, - anchor, - nullifier, - &rk, - zkproof, - &mut (), - |_, rk| rk.verify(sighash_value, &spend_auth_sig).is_ok(), - |_, proof, public_inputs| { - verify_proof(&verifying_key.0, &proof, &public_inputs[..]).is_ok() - }, - ) - } - - /// Perform consensus checks on a Sapling OutputDescription, while - /// accumulating its value commitment inside the context for later use. - pub fn check_output( - &mut self, - cv: &ValueCommitment, - cmu: ExtractedNoteCommitment, - epk: jubjub::ExtendedPoint, - zkproof: Proof, - verifying_key: &PreparedOutputVerifyingKey, - ) -> bool { - self.inner - .check_output(cv, cmu, epk, zkproof, |proof, public_inputs| { - verify_proof(&verifying_key.0, &proof, &public_inputs[..]).is_ok() - }) - } - - /// Perform consensus checks on the valueBalance and bindingSig parts of a - /// Sapling transaction. All SpendDescriptions and OutputDescriptions must - /// have been checked before calling this function. - pub fn final_check>( - &self, - value_balance: V, - sighash_value: &[u8; 32], - binding_sig: redjubjub::Signature, - ) -> bool { - self.inner.final_check(value_balance, |bvk| { - bvk.verify(sighash_value, &binding_sig).is_ok() - }) - } -} diff --git a/zcash_primitives/src/sapling/zip32.rs b/zcash_primitives/src/sapling/zip32.rs deleted file mode 100644 index 950e429fc..000000000 --- a/zcash_primitives/src/sapling/zip32.rs +++ /dev/null @@ -1,1735 +0,0 @@ -//! Sapling key derivation according to ZIP 32 and ZIP 316 -//! -//! Implements [section 4.2.2] of the Zcash Protocol Specification. -//! -//! [section 4.2.2]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents - -use aes::Aes256; -use blake2b_simd::Params as Blake2bParams; -use byteorder::{ByteOrder, LittleEndian, ReadBytesExt, WriteBytesExt}; -use fpe::ff1::{BinaryNumeralString, FF1}; -use zcash_spec::PrfExpand; - -use std::io::{self, Read, Write}; -use std::ops::AddAssign; - -use super::{Diversifier, NullifierDerivingKey, PaymentAddress, ViewingKey}; -use crate::{ - sapling::{ - constants::PROOF_GENERATION_KEY_GENERATOR, - keys::{ - DecodingError, ExpandedSpendingKey, FullViewingKey, OutgoingViewingKey, - SpendAuthorizingKey, - }, - SaplingIvk, - }, - zip32::{ChainCode, ChildIndex, DiversifierIndex, Scope}, -}; - -pub const ZIP32_SAPLING_MASTER_PERSONALIZATION: &[u8; 16] = b"ZcashIP32Sapling"; -pub const ZIP32_SAPLING_FVFP_PERSONALIZATION: &[u8; 16] = b"ZcashSaplingFVFP"; -pub const ZIP32_SAPLING_INT_PERSONALIZATION: &[u8; 16] = b"Zcash_SaplingInt"; - -/// Attempt to produce a payment address given the specified diversifier -/// index, and return None if the specified index does not produce a valid -/// diversifier. -pub fn sapling_address( - fvk: &FullViewingKey, - dk: &DiversifierKey, - j: DiversifierIndex, -) -> Option { - dk.diversifier(j) - .and_then(|d_j| fvk.vk.to_payment_address(d_j)) -} - -/// Search the diversifier space starting at diversifier index `j` for -/// one which will produce a valid diversifier, and return the payment address -/// constructed using that diversifier along with the index at which the -/// valid diversifier was found. -pub fn sapling_find_address( - fvk: &FullViewingKey, - dk: &DiversifierKey, - j: DiversifierIndex, -) -> Option<(DiversifierIndex, PaymentAddress)> { - let (j, d_j) = dk.find_diversifier(j)?; - fvk.vk.to_payment_address(d_j).map(|addr| (j, addr)) -} - -/// Returns the payment address corresponding to the smallest valid diversifier -/// index, along with that index. -pub fn sapling_default_address( - fvk: &FullViewingKey, - dk: &DiversifierKey, -) -> (DiversifierIndex, PaymentAddress) { - // This unwrap is safe, if you have to search the 2^88 space of - // diversifiers it'll never return anyway. - sapling_find_address(fvk, dk, DiversifierIndex::new()).unwrap() -} - -/// Convenience function for child OVK derivation -fn derive_child_ovk(parent: &OutgoingViewingKey, i_l: &[u8]) -> OutgoingViewingKey { - let mut ovk = [0u8; 32]; - ovk.copy_from_slice(&PrfExpand::SAPLING_ZIP32_CHILD_OVK.with(i_l, &parent.0)[..32]); - OutgoingViewingKey(ovk) -} - -/// Returns the internal full viewing key and diversifier key -/// for the provided external FVK = (ak, nk, ovk) and dk encoded -/// in a [Unified FVK]. -/// -/// [Unified FVK]: https://zips.z.cash/zip-0316#encoding-of-unified-full-incoming-viewing-keys -pub fn sapling_derive_internal_fvk( - fvk: &FullViewingKey, - dk: &DiversifierKey, -) -> (FullViewingKey, DiversifierKey) { - let i = { - let mut h = Blake2bParams::new() - .hash_length(32) - .personal(ZIP32_SAPLING_INT_PERSONALIZATION) - .to_state(); - h.update(&fvk.to_bytes()); - h.update(&dk.0); - h.finalize() - }; - let i_nsk = - jubjub::Fr::from_bytes_wide(&PrfExpand::SAPLING_ZIP32_INTERNAL_NSK.with(i.as_bytes())); - let r = PrfExpand::SAPLING_ZIP32_INTERNAL_DK_OVK.with(i.as_bytes()); - // PROOF_GENERATION_KEY_GENERATOR = \mathcal{H}^Sapling - let nk_internal = NullifierDerivingKey(PROOF_GENERATION_KEY_GENERATOR * i_nsk + fvk.vk.nk.0); - let dk_internal = DiversifierKey(r[..32].try_into().unwrap()); - let ovk_internal = OutgoingViewingKey(r[32..].try_into().unwrap()); - - ( - FullViewingKey { - vk: ViewingKey { - ak: fvk.vk.ak.clone(), - nk: nk_internal, - }, - ovk: ovk_internal, - }, - dk_internal, - ) -} - -/// A Sapling full viewing key fingerprint -struct FvkFingerprint([u8; 32]); - -impl From<&FullViewingKey> for FvkFingerprint { - fn from(fvk: &FullViewingKey) -> Self { - let mut h = Blake2bParams::new() - .hash_length(32) - .personal(ZIP32_SAPLING_FVFP_PERSONALIZATION) - .to_state(); - h.update(&fvk.to_bytes()); - let mut fvfp = [0u8; 32]; - fvfp.copy_from_slice(h.finalize().as_bytes()); - FvkFingerprint(fvfp) - } -} - -impl FvkFingerprint { - fn tag(&self) -> FvkTag { - let mut tag = [0u8; 4]; - tag.copy_from_slice(&self.0[..4]); - FvkTag(tag) - } -} - -/// A Sapling full viewing key tag -#[derive(Clone, Copy, Debug, PartialEq)] -struct FvkTag([u8; 4]); - -impl FvkTag { - fn master() -> Self { - FvkTag([0u8; 4]) - } - - fn as_bytes(&self) -> &[u8; 4] { - &self.0 - } -} - -/// A key used to derive diversifiers for a particular child key -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct DiversifierKey([u8; 32]); - -impl DiversifierKey { - pub fn master(sk_m: &[u8]) -> Self { - let mut dk_m = [0u8; 32]; - dk_m.copy_from_slice(&PrfExpand::SAPLING_ZIP32_MASTER_DK.with(sk_m)[..32]); - DiversifierKey(dk_m) - } - - /// Constructs the diversifier key from its constituent bytes. - pub fn from_bytes(key: [u8; 32]) -> Self { - DiversifierKey(key) - } - - /// Returns the byte representation of the diversifier key. - pub fn as_bytes(&self) -> &[u8; 32] { - &self.0 - } - - fn derive_child(&self, i_l: &[u8]) -> Self { - let mut dk = [0u8; 32]; - dk.copy_from_slice(&PrfExpand::SAPLING_ZIP32_CHILD_DK.with(i_l, &self.0)[..32]); - DiversifierKey(dk) - } - - fn try_diversifier_internal(ff: &FF1, j: DiversifierIndex) -> Option { - // Generate d_j - let enc = ff - .encrypt(&[], &BinaryNumeralString::from_bytes_le(j.as_bytes())) - .unwrap(); - let mut d_j = [0; 11]; - d_j.copy_from_slice(&enc.to_bytes_le()); - let diversifier = Diversifier(d_j); - - // validate that the generated diversifier maps to a jubjub subgroup point. - diversifier.g_d().map(|_| diversifier) - } - - /// Attempts to produce a diversifier at the given index. Returns None - /// if the index does not produce a valid diversifier. - pub fn diversifier(&self, j: DiversifierIndex) -> Option { - let ff = FF1::::new(&self.0, 2).unwrap(); - Self::try_diversifier_internal(&ff, j) - } - - /// Returns the diversifier index to which this key maps the given diversifier. - /// - /// This method cannot be used to verify whether the diversifier was originally - /// generated with this diversifier key, because all valid diversifiers can be - /// produced by all diversifier keys. - pub fn diversifier_index(&self, d: &Diversifier) -> DiversifierIndex { - let ff = FF1::::new(&self.0, 2).unwrap(); - let dec = ff - .decrypt(&[], &BinaryNumeralString::from_bytes_le(&d.0[..])) - .unwrap(); - DiversifierIndex::from(<[u8; 11]>::try_from(&dec.to_bytes_le()[..]).unwrap()) - } - - /// Returns the first index starting from j that generates a valid - /// diversifier, along with the corresponding diversifier. Returns - /// `None` if the diversifier space contains no valid diversifiers - /// at or above the specified diversifier index. - pub fn find_diversifier( - &self, - mut j: DiversifierIndex, - ) -> Option<(DiversifierIndex, Diversifier)> { - let ff = FF1::::new(&self.0, 2).unwrap(); - loop { - match Self::try_diversifier_internal(&ff, j) { - Some(d_j) => return Some((j, d_j)), - None => { - if j.increment().is_err() { - return None; - } - } - } - } - } -} - -/// The derivation index associated with a key. -/// -/// Master keys are never derived via the ZIP 32 child derivation process, but they have -/// an index in their encoding. This type allows the encoding to be represented, while -/// also enabling the derivation methods to only accept [`ChildIndex`]. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -enum KeyIndex { - Master, - Child(ChildIndex), -} - -impl KeyIndex { - fn new(depth: u8, i: u32) -> Option { - match (depth == 0, i) { - (true, 0) => Some(KeyIndex::Master), - (false, _) => ChildIndex::from_index(i).map(KeyIndex::Child), - _ => None, - } - } - - fn index(&self) -> u32 { - match self { - KeyIndex::Master => 0, - KeyIndex::Child(i) => i.index(), - } - } -} - -/// A Sapling extended spending key -#[derive(Clone)] -pub struct ExtendedSpendingKey { - depth: u8, - parent_fvk_tag: FvkTag, - child_index: KeyIndex, - chain_code: ChainCode, - pub expsk: ExpandedSpendingKey, - dk: DiversifierKey, -} - -impl std::cmp::PartialEq for ExtendedSpendingKey { - fn eq(&self, rhs: &ExtendedSpendingKey) -> bool { - self.depth == rhs.depth - && self.parent_fvk_tag == rhs.parent_fvk_tag - && self.child_index == rhs.child_index - && self.chain_code == rhs.chain_code - && self.expsk.ask == rhs.expsk.ask - && self.expsk.nsk == rhs.expsk.nsk - && self.expsk.ovk == rhs.expsk.ovk - && self.dk == rhs.dk - } -} - -impl std::fmt::Debug for ExtendedSpendingKey { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - write!( - f, - "ExtendedSpendingKey(d = {}, tag_p = {:?}, i = {:?})", - self.depth, self.parent_fvk_tag, self.child_index - ) - } -} - -impl ExtendedSpendingKey { - pub fn master(seed: &[u8]) -> Self { - let i = Blake2bParams::new() - .hash_length(64) - .personal(ZIP32_SAPLING_MASTER_PERSONALIZATION) - .hash(seed); - - let sk_m = &i.as_bytes()[..32]; - let mut c_m = [0u8; 32]; - c_m.copy_from_slice(&i.as_bytes()[32..]); - - ExtendedSpendingKey { - depth: 0, - parent_fvk_tag: FvkTag::master(), - child_index: KeyIndex::Master, - chain_code: ChainCode::new(c_m), - expsk: ExpandedSpendingKey::from_spending_key(sk_m), - dk: DiversifierKey::master(sk_m), - } - } - - /// Decodes the extended spending key from its serialized representation as defined in - /// [ZIP 32](https://zips.z.cash/zip-0032) - pub fn from_bytes(b: &[u8]) -> Result { - if b.len() != 169 { - return Err(DecodingError::LengthInvalid { - expected: 169, - actual: b.len(), - }); - } - - let depth = b[0]; - - let mut parent_fvk_tag = FvkTag([0; 4]); - parent_fvk_tag.0[..].copy_from_slice(&b[1..5]); - - let mut ci_bytes = [0u8; 4]; - ci_bytes[..].copy_from_slice(&b[5..9]); - let child_index = KeyIndex::new(depth, u32::from_le_bytes(ci_bytes)) - .ok_or(DecodingError::UnsupportedChildIndex)?; - - let mut c = [0u8; 32]; - c[..].copy_from_slice(&b[9..41]); - - let expsk = ExpandedSpendingKey::from_bytes(&b[41..137])?; - - let mut dk = DiversifierKey([0u8; 32]); - dk.0[..].copy_from_slice(&b[137..169]); - - Ok(ExtendedSpendingKey { - depth, - parent_fvk_tag, - child_index, - chain_code: ChainCode::new(c), - expsk, - dk, - }) - } - - /// Reads and decodes the encoded form of the extended spending key as defined in - /// [ZIP 32](https://zips.z.cash/zip-0032) from the provided reader. - pub fn read(mut reader: R) -> io::Result { - let depth = reader.read_u8()?; - let mut tag = [0; 4]; - reader.read_exact(&mut tag)?; - let child_index = reader.read_u32::().and_then(|i| { - KeyIndex::new(depth, i).ok_or_else(|| { - io::Error::new( - io::ErrorKind::Unsupported, - "Unsupported child index in encoding", - ) - }) - })?; - let mut c = [0; 32]; - reader.read_exact(&mut c)?; - let expsk = ExpandedSpendingKey::read(&mut reader)?; - let mut dk = [0; 32]; - reader.read_exact(&mut dk)?; - - Ok(ExtendedSpendingKey { - depth, - parent_fvk_tag: FvkTag(tag), - child_index, - chain_code: ChainCode::new(c), - expsk, - dk: DiversifierKey(dk), - }) - } - - /// Encodes the extended spending key to the its seralized representation as defined in - /// [ZIP 32](https://zips.z.cash/zip-0032) - pub fn to_bytes(&self) -> [u8; 169] { - let mut result = [0u8; 169]; - result[0] = self.depth; - result[1..5].copy_from_slice(&self.parent_fvk_tag.as_bytes()[..]); - result[5..9].copy_from_slice(&self.child_index.index().to_le_bytes()[..]); - result[9..41].copy_from_slice(&self.chain_code.as_bytes()[..]); - result[41..137].copy_from_slice(&self.expsk.to_bytes()[..]); - result[137..169].copy_from_slice(&self.dk.as_bytes()[..]); - result - } - - /// Writes the encoded form of the extended spending key as defined in - /// [ZIP 32](https://zips.z.cash/zip-0032) to the provided writer. - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_all(&self.to_bytes()) - } - - /// Returns the child key corresponding to the path derived from the master key - pub fn from_path(master: &ExtendedSpendingKey, path: &[ChildIndex]) -> Self { - let mut xsk = master.clone(); - for &i in path.iter() { - xsk = xsk.derive_child(i); - } - xsk - } - - /// Derives the child key at the given (hardened) index. - /// - /// # Panics - /// - /// Panics if the child key has `ask = 0`. This has a negligible probability of - /// occurring. - #[must_use] - pub fn derive_child(&self, i: ChildIndex) -> Self { - let fvk = FullViewingKey::from_expanded_spending_key(&self.expsk); - let tmp = { - let mut le_i = [0; 4]; - LittleEndian::write_u32(&mut le_i, i.index()); - PrfExpand::SAPLING_ZIP32_CHILD_HARDENED.with( - self.chain_code.as_bytes(), - &self.expsk.to_bytes(), - &self.dk.0, - &le_i, - ) - }; - let i_l = &tmp[..32]; - let mut c_i = [0u8; 32]; - c_i.copy_from_slice(&tmp[32..]); - - ExtendedSpendingKey { - depth: self.depth + 1, - parent_fvk_tag: FvkFingerprint::from(&fvk).tag(), - child_index: KeyIndex::Child(i), - chain_code: ChainCode::new(c_i), - expsk: { - let mut ask = - jubjub::Fr::from_bytes_wide(&PrfExpand::SAPLING_ZIP32_CHILD_I_ASK.with(i_l)); - let mut nsk = - jubjub::Fr::from_bytes_wide(&PrfExpand::SAPLING_ZIP32_CHILD_I_NSK.with(i_l)); - ask.add_assign(self.expsk.ask.to_scalar()); - nsk.add_assign(&self.expsk.nsk); - let ovk = derive_child_ovk(&self.expsk.ovk, i_l); - ExpandedSpendingKey { - ask: SpendAuthorizingKey::from_scalar(ask) - .expect("negligible chance of ask == 0"), - nsk, - ovk, - } - }, - dk: self.dk.derive_child(i_l), - } - } - - /// Returns the address with the lowest valid diversifier index, along with - /// the diversifier index that generated that address. - pub fn default_address(&self) -> (DiversifierIndex, PaymentAddress) { - self.to_diversifiable_full_viewing_key().default_address() - } - - /// Derives an internal spending key given an external spending key. - /// - /// Specified in [ZIP 32](https://zips.z.cash/zip-0032#deriving-a-sapling-internal-spending-key). - #[must_use] - pub fn derive_internal(&self) -> Self { - let i = { - let fvk = FullViewingKey::from_expanded_spending_key(&self.expsk); - let mut h = Blake2bParams::new() - .hash_length(32) - .personal(ZIP32_SAPLING_INT_PERSONALIZATION) - .to_state(); - h.update(&fvk.to_bytes()); - h.update(&self.dk.0); - h.finalize() - }; - let i_nsk = - jubjub::Fr::from_bytes_wide(&PrfExpand::SAPLING_ZIP32_INTERNAL_NSK.with(i.as_bytes())); - let r = PrfExpand::SAPLING_ZIP32_INTERNAL_DK_OVK.with(i.as_bytes()); - let nsk_internal = i_nsk + self.expsk.nsk; - let dk_internal = DiversifierKey(r[..32].try_into().unwrap()); - let ovk_internal = OutgoingViewingKey(r[32..].try_into().unwrap()); - - ExtendedSpendingKey { - depth: self.depth, - parent_fvk_tag: self.parent_fvk_tag, - child_index: self.child_index, - chain_code: self.chain_code, - expsk: ExpandedSpendingKey { - ask: self.expsk.ask.clone(), - nsk: nsk_internal, - ovk: ovk_internal, - }, - dk: dk_internal, - } - } - - #[deprecated(note = "Use `to_diversifiable_full_viewing_key` instead.")] - pub fn to_extended_full_viewing_key(&self) -> ExtendedFullViewingKey { - ExtendedFullViewingKey { - depth: self.depth, - parent_fvk_tag: self.parent_fvk_tag, - child_index: self.child_index, - chain_code: self.chain_code, - fvk: FullViewingKey::from_expanded_spending_key(&self.expsk), - dk: self.dk, - } - } - - pub fn to_diversifiable_full_viewing_key(&self) -> DiversifiableFullViewingKey { - DiversifiableFullViewingKey { - fvk: FullViewingKey::from_expanded_spending_key(&self.expsk), - dk: self.dk, - } - } -} - -// A Sapling extended full viewing key -#[derive(Clone)] -pub struct ExtendedFullViewingKey { - depth: u8, - parent_fvk_tag: FvkTag, - child_index: KeyIndex, - chain_code: ChainCode, - pub fvk: FullViewingKey, - pub(crate) dk: DiversifierKey, -} - -impl std::cmp::PartialEq for ExtendedFullViewingKey { - fn eq(&self, rhs: &ExtendedFullViewingKey) -> bool { - self.depth == rhs.depth - && self.parent_fvk_tag == rhs.parent_fvk_tag - && self.child_index == rhs.child_index - && self.chain_code == rhs.chain_code - && self.fvk.vk.ak == rhs.fvk.vk.ak - && self.fvk.vk.nk == rhs.fvk.vk.nk - && self.fvk.ovk == rhs.fvk.ovk - && self.dk == rhs.dk - } -} - -impl std::fmt::Debug for ExtendedFullViewingKey { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - write!( - f, - "ExtendedFullViewingKey(d = {}, tag_p = {:?}, i = {:?})", - self.depth, self.parent_fvk_tag, self.child_index - ) - } -} - -impl ExtendedFullViewingKey { - pub fn read(mut reader: R) -> io::Result { - let depth = reader.read_u8()?; - let mut tag = [0; 4]; - reader.read_exact(&mut tag)?; - let child_index = reader.read_u32::().and_then(|i| { - KeyIndex::new(depth, i).ok_or_else(|| { - io::Error::new( - io::ErrorKind::Unsupported, - "Unsupported child index in encoding", - ) - }) - })?; - let mut c = [0; 32]; - reader.read_exact(&mut c)?; - let fvk = FullViewingKey::read(&mut reader)?; - let mut dk = [0; 32]; - reader.read_exact(&mut dk)?; - - Ok(ExtendedFullViewingKey { - depth, - parent_fvk_tag: FvkTag(tag), - child_index, - chain_code: ChainCode::new(c), - fvk, - dk: DiversifierKey(dk), - }) - } - - pub fn write(&self, mut writer: W) -> io::Result<()> { - writer.write_u8(self.depth)?; - writer.write_all(&self.parent_fvk_tag.0)?; - writer.write_u32::(self.child_index.index())?; - writer.write_all(self.chain_code.as_bytes())?; - writer.write_all(&self.fvk.to_bytes())?; - writer.write_all(&self.dk.0)?; - - Ok(()) - } - - /// Attempt to produce a payment address given the specified diversifier - /// index, and return None if the specified index does not produce a valid - /// diversifier. - pub fn address(&self, j: DiversifierIndex) -> Option { - sapling_address(&self.fvk, &self.dk, j) - } - - /// Search the diversifier space starting at diversifier index `j` for - /// one which will produce a valid diversifier, and return the payment address - /// constructed using that diversifier along with the index at which the - /// valid diversifier was found. - pub fn find_address(&self, j: DiversifierIndex) -> Option<(DiversifierIndex, PaymentAddress)> { - sapling_find_address(&self.fvk, &self.dk, j) - } - - /// Returns the payment address corresponding to the smallest valid diversifier - /// index, along with that index. - pub fn default_address(&self) -> (DiversifierIndex, PaymentAddress) { - sapling_default_address(&self.fvk, &self.dk) - } - - /// Derives an internal full viewing key used for internal operations such - /// as change and auto-shielding. The internal FVK has the same spend authority - /// (the private key corresponding to ak) as the original, but viewing authority - /// only for internal transfers. - /// - /// Specified in [ZIP 32](https://zips.z.cash/zip-0032#deriving-a-sapling-internal-full-viewing-key). - #[must_use] - pub fn derive_internal(&self) -> Self { - let (fvk_internal, dk_internal) = sapling_derive_internal_fvk(&self.fvk, &self.dk); - - ExtendedFullViewingKey { - depth: self.depth, - parent_fvk_tag: self.parent_fvk_tag, - child_index: self.child_index, - chain_code: self.chain_code, - fvk: fvk_internal, - dk: dk_internal, - } - } - - pub fn to_diversifiable_full_viewing_key(&self) -> DiversifiableFullViewingKey { - DiversifiableFullViewingKey { - fvk: self.fvk.clone(), - dk: self.dk, - } - } -} - -/// A Sapling key that provides the capability to view incoming and outgoing transactions. -/// -/// This key is useful anywhere you need to maintain accurate balance, but do not want the -/// ability to spend funds (such as a view-only wallet). -/// -/// It comprises the subset of the ZIP 32 extended full viewing key that is used for the -/// Sapling item in a [ZIP 316 Unified Full Viewing Key][zip-0316-ufvk]. -/// -/// [zip-0316-ufvk]: https://zips.z.cash/zip-0316#encoding-of-unified-full-incoming-viewing-keys -#[derive(Clone, Debug)] -pub struct DiversifiableFullViewingKey { - fvk: FullViewingKey, - dk: DiversifierKey, -} - -impl From for DiversifiableFullViewingKey { - fn from(extfvk: ExtendedFullViewingKey) -> Self { - DiversifiableFullViewingKey { - fvk: extfvk.fvk, - dk: extfvk.dk, - } - } -} - -impl From<&ExtendedFullViewingKey> for DiversifiableFullViewingKey { - fn from(extfvk: &ExtendedFullViewingKey) -> Self { - extfvk.to_diversifiable_full_viewing_key() - } -} - -impl DiversifiableFullViewingKey { - /// Parses a `DiversifiableFullViewingKey` from its raw byte encoding. - /// - /// Returns `None` if the bytes do not contain a valid encoding of a diversifiable - /// Sapling full viewing key. - pub fn from_bytes(bytes: &[u8; 128]) -> Option { - FullViewingKey::read(&bytes[..96]).ok().map(|fvk| Self { - fvk, - dk: DiversifierKey::from_bytes(bytes[96..].try_into().unwrap()), - }) - } - - /// Returns the raw encoding of this `DiversifiableFullViewingKey`. - pub fn to_bytes(&self) -> [u8; 128] { - let mut bytes = [0; 128]; - self.fvk - .write(&mut bytes[..96]) - .expect("slice should be the correct length"); - bytes[96..].copy_from_slice(&self.dk.as_bytes()[..]); - bytes - } - - /// Derives the internal `DiversifiableFullViewingKey` corresponding to `self` (which - /// is assumed here to be an external DFVK). - fn derive_internal(&self) -> Self { - let (fvk, dk) = sapling_derive_internal_fvk(&self.fvk, &self.dk); - Self { fvk, dk } - } - - /// Exposes the external [`FullViewingKey`] component of this diversifiable full viewing key. - pub fn fvk(&self) -> &FullViewingKey { - &self.fvk - } - - /// Derives a nullifier-deriving key for the provided scope. - /// - /// This API is provided so that nullifiers for change notes can be correctly computed. - pub fn to_nk(&self, scope: Scope) -> NullifierDerivingKey { - match scope { - Scope::External => self.fvk.vk.nk, - Scope::Internal => self.derive_internal().fvk.vk.nk, - } - } - - /// Derives an incoming viewing key corresponding to this full viewing key. - pub fn to_ivk(&self, scope: Scope) -> SaplingIvk { - match scope { - Scope::External => self.fvk.vk.ivk(), - Scope::Internal => self.derive_internal().fvk.vk.ivk(), - } - } - - /// Derives an outgoing viewing key corresponding to this full viewing key. - pub fn to_ovk(&self, scope: Scope) -> OutgoingViewingKey { - match scope { - Scope::External => self.fvk.ovk, - Scope::Internal => self.derive_internal().fvk.ovk, - } - } - - /// Attempts to produce a valid payment address for the given diversifier index. - /// - /// Returns `None` if the diversifier index does not produce a valid diversifier for - /// this `DiversifiableFullViewingKey`. - pub fn address(&self, j: DiversifierIndex) -> Option { - sapling_address(&self.fvk, &self.dk, j) - } - - /// Finds the next valid payment address starting from the given diversifier index. - /// - /// This searches the diversifier space starting at `j` and incrementing, to find an - /// index which will produce a valid diversifier (a 50% probability for each index). - /// - /// Returns the index at which the valid diversifier was found along with the payment - /// address constructed using that diversifier, or `None` if the maximum index was - /// reached and no valid diversifier was found. - pub fn find_address(&self, j: DiversifierIndex) -> Option<(DiversifierIndex, PaymentAddress)> { - sapling_find_address(&self.fvk, &self.dk, j) - } - - /// Returns the payment address corresponding to the smallest valid diversifier index, - /// along with that index. - pub fn default_address(&self) -> (DiversifierIndex, PaymentAddress) { - sapling_default_address(&self.fvk, &self.dk) - } - - /// Returns the payment address corresponding to the specified diversifier, if any. - /// - /// In general, it is preferable to use `find_address` instead, but this method is - /// useful in some cases for matching keys to existing payment addresses. - pub fn diversified_address(&self, diversifier: Diversifier) -> Option { - self.fvk.vk.to_payment_address(diversifier) - } - - /// Returns the internal address corresponding to the smallest valid diversifier index, - /// along with that index. - /// - /// This address **MUST NOT** be encoded and exposed to end users. User interfaces - /// should instead mark these notes as "change notes" or "internal wallet operations". - pub fn change_address(&self) -> (DiversifierIndex, PaymentAddress) { - let internal_dfvk = self.derive_internal(); - sapling_default_address(&internal_dfvk.fvk, &internal_dfvk.dk) - } - - /// Returns the change address corresponding to the specified diversifier, if any. - /// - /// In general, it is preferable to use `change_address` instead, but this method is - /// useful in some cases for matching keys to existing payment addresses. - pub fn diversified_change_address(&self, diversifier: Diversifier) -> Option { - self.derive_internal() - .fvk - .vk - .to_payment_address(diversifier) - } - - /// Attempts to decrypt the given address's diversifier with this full viewing key. - /// - /// This method extracts the diversifier from the given address and decrypts it as a - /// diversifier index, then verifies that this diversifier index produces the same - /// address. Decryption is attempted using both the internal and external parts of the - /// full viewing key. - /// - /// Returns the decrypted diversifier index and its scope, or `None` if the address - /// was not generated from this key. - pub fn decrypt_diversifier(&self, addr: &PaymentAddress) -> Option<(DiversifierIndex, Scope)> { - let j_external = self.dk.diversifier_index(addr.diversifier()); - if self.address(j_external).as_ref() == Some(addr) { - return Some((j_external, Scope::External)); - } - - let j_internal = self - .derive_internal() - .dk - .diversifier_index(addr.diversifier()); - if self.address(j_internal).as_ref() == Some(addr) { - return Some((j_internal, Scope::Internal)); - } - - None - } -} - -#[cfg(test)] -mod tests { - use super::*; - - use super::{DiversifiableFullViewingKey, ExtendedSpendingKey}; - use ff::PrimeField; - use group::GroupEncoding; - - #[test] - #[allow(deprecated)] - fn derive_hardened_child() { - let seed = [0; 32]; - let xsk_m = ExtendedSpendingKey::master(&seed); - - let i_5h = ChildIndex::hardened(5); - let _ = xsk_m.derive_child(i_5h); - } - - #[test] - fn path() { - let seed = [0; 32]; - let xsk_m = ExtendedSpendingKey::master(&seed); - - let xsk_5h = xsk_m.derive_child(ChildIndex::hardened(5)); - assert_eq!( - ExtendedSpendingKey::from_path(&xsk_m, &[ChildIndex::hardened(5)]), - xsk_5h - ); - - let xsk_5h_7 = xsk_5h.derive_child(ChildIndex::hardened(7)); - assert_eq!( - ExtendedSpendingKey::from_path( - &xsk_m, - &[ChildIndex::hardened(5), ChildIndex::hardened(7)] - ), - xsk_5h_7 - ); - } - - #[test] - fn diversifier() { - let dk = DiversifierKey([0; 32]); - let j_0 = DiversifierIndex::new(); - let j_1 = DiversifierIndex::from([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - let j_2 = DiversifierIndex::from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - let j_3 = DiversifierIndex::from([3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - // Computed using this Rust implementation - let d_0 = [220, 231, 126, 188, 236, 10, 38, 175, 214, 153, 140]; - let d_3 = [60, 253, 170, 8, 171, 147, 220, 31, 3, 144, 34]; - - // j = 0 - let d_j = dk.diversifier(j_0).unwrap(); - assert_eq!(d_j.0, d_0); - assert_eq!(dk.diversifier_index(&Diversifier(d_0)), j_0); - - // j = 1 - assert_eq!(dk.diversifier(j_1), None); - - // j = 2 - assert_eq!(dk.diversifier(j_2), None); - - // j = 3 - let d_j = dk.diversifier(j_3).unwrap(); - assert_eq!(d_j.0, d_3); - assert_eq!(dk.diversifier_index(&Diversifier(d_3)), j_3); - } - - #[test] - fn diversifier_index_from() { - let di32: u32 = 0xa0b0c0d0; - assert_eq!( - DiversifierIndex::from(di32), - DiversifierIndex::from([0xd0, 0xc0, 0xb0, 0xa0, 0, 0, 0, 0, 0, 0, 0]) - ); - let di64: u64 = 0x0102030405060708; - assert_eq!( - DiversifierIndex::from(di64), - DiversifierIndex::from([8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0]) - ); - } - - #[test] - fn find_diversifier() { - let dk = DiversifierKey([0; 32]); - let j_0 = DiversifierIndex::new(); - let j_1 = DiversifierIndex::from([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - let j_2 = DiversifierIndex::from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - let j_3 = DiversifierIndex::from([3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - // Computed using this Rust implementation - let d_0 = [220, 231, 126, 188, 236, 10, 38, 175, 214, 153, 140]; - let d_3 = [60, 253, 170, 8, 171, 147, 220, 31, 3, 144, 34]; - - // j = 0 - let (j, d_j) = dk.find_diversifier(j_0).unwrap(); - assert_eq!(j, j_0); - assert_eq!(d_j.0, d_0); - - // j = 1 - let (j, d_j) = dk.find_diversifier(j_1).unwrap(); - assert_eq!(j, j_3); - assert_eq!(d_j.0, d_3); - - // j = 2 - let (j, d_j) = dk.find_diversifier(j_2).unwrap(); - assert_eq!(j, j_3); - assert_eq!(d_j.0, d_3); - - // j = 3 - let (j, d_j) = dk.find_diversifier(j_3).unwrap(); - assert_eq!(j, j_3); - assert_eq!(d_j.0, d_3); - } - - #[test] - fn dfvk_round_trip() { - let dfvk = { - let extsk = ExtendedSpendingKey::master(&[]); - #[allow(deprecated)] - let extfvk = extsk.to_extended_full_viewing_key(); - DiversifiableFullViewingKey::from(extfvk) - }; - - // Check value -> bytes -> parsed round trip. - let dfvk_bytes = dfvk.to_bytes(); - let dfvk_parsed = DiversifiableFullViewingKey::from_bytes(&dfvk_bytes).unwrap(); - assert_eq!(dfvk_parsed.fvk.vk.ak, dfvk.fvk.vk.ak); - assert_eq!(dfvk_parsed.fvk.vk.nk, dfvk.fvk.vk.nk); - assert_eq!(dfvk_parsed.fvk.ovk, dfvk.fvk.ovk); - assert_eq!(dfvk_parsed.dk, dfvk.dk); - - // Check bytes -> parsed -> bytes round trip. - assert_eq!(dfvk_parsed.to_bytes(), dfvk_bytes); - } - - #[test] - fn address() { - let seed = [0; 32]; - let xsk_m = ExtendedSpendingKey::master(&seed); - let xfvk_m = xsk_m.to_diversifiable_full_viewing_key(); - let j_0 = DiversifierIndex::new(); - let addr_m = xfvk_m.address(j_0).unwrap(); - assert_eq!( - addr_m.diversifier().0, - // Computed using this Rust implementation - [59, 246, 250, 31, 131, 191, 69, 99, 200, 167, 19] - ); - - let j_1 = DiversifierIndex::from([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(xfvk_m.address(j_1), None); - } - - #[test] - fn default_address() { - let seed = [0; 32]; - let xsk_m = ExtendedSpendingKey::master(&seed); - let (j_m, addr_m) = xsk_m.default_address(); - assert_eq!(j_m.as_bytes(), &[0; 11]); - assert_eq!( - addr_m.diversifier().0, - // Computed using this Rust implementation - [59, 246, 250, 31, 131, 191, 69, 99, 200, 167, 19] - ); - } - - #[test] - #[allow(deprecated)] - fn read_write() { - let seed = [0; 32]; - let xsk = ExtendedSpendingKey::master(&seed); - let fvk = xsk.to_extended_full_viewing_key(); - - let mut ser = vec![]; - xsk.write(&mut ser).unwrap(); - let xsk2 = ExtendedSpendingKey::read(&ser[..]).unwrap(); - assert_eq!(xsk2, xsk); - - let mut ser = vec![]; - fvk.write(&mut ser).unwrap(); - let fvk2 = ExtendedFullViewingKey::read(&ser[..]).unwrap(); - assert_eq!(fvk2, fvk); - } - - #[test] - #[allow(deprecated)] - fn test_vectors() { - struct TestVector { - ask: Option<[u8; 32]>, - nsk: Option<[u8; 32]>, - ovk: [u8; 32], - dk: [u8; 32], - c: [u8; 32], - ak: [u8; 32], - nk: [u8; 32], - ivk: [u8; 32], - xsk: Option<[u8; 169]>, - xfvk: [u8; 169], - fp: [u8; 32], - d0: Option<[u8; 11]>, - d1: Option<[u8; 11]>, - d2: Option<[u8; 11]>, - dmax: Option<[u8; 11]>, - internal_nsk: Option<[u8; 32]>, - internal_ovk: [u8; 32], - internal_dk: [u8; 32], - internal_nk: [u8; 32], - internal_ivk: [u8; 32], - internal_xsk: Option<[u8; 169]>, - internal_xfvk: [u8; 169], - internal_fp: [u8; 32], - } - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_zip32.py - let test_vectors = vec![ - TestVector { - ask: Some([ - 0xb6, 0xc0, 0x0c, 0x93, 0xd3, 0x60, 0x32, 0xb9, 0xa2, 0x68, 0xe9, 0x9e, 0x86, - 0xa8, 0x60, 0x77, 0x65, 0x60, 0xbf, 0x0e, 0x83, 0xc1, 0xa1, 0x0b, 0x51, 0xf6, - 0x07, 0xc9, 0x54, 0x74, 0x25, 0x06, - ]), - nsk: Some([ - 0x82, 0x04, 0xed, 0xe8, 0x3b, 0x2f, 0x1f, 0xbd, 0x84, 0xf9, 0xb4, 0x5d, 0x7f, - 0x99, 0x6e, 0x2e, 0xbd, 0x0a, 0x03, 0x0a, 0xd2, 0x43, 0xb4, 0x8e, 0xd3, 0x9f, - 0x74, 0x8a, 0x88, 0x21, 0xea, 0x06, - ]), - ovk: [ - 0x39, 0x58, 0x84, 0x89, 0x03, 0x23, 0xb9, 0xd4, 0x93, 0x3c, 0x02, 0x1d, 0xb8, - 0x9b, 0xcf, 0x76, 0x7d, 0xf2, 0x19, 0x77, 0xb2, 0xff, 0x06, 0x83, 0x84, 0x83, - 0x21, 0xa4, 0xdf, 0x4a, 0xfb, 0x21, - ], - dk: [ - 0x77, 0xc1, 0x7c, 0xb7, 0x5b, 0x77, 0x96, 0xaf, 0xb3, 0x9f, 0x0f, 0x3e, 0x91, - 0xc9, 0x24, 0x60, 0x7d, 0xa5, 0x6f, 0xa9, 0xa2, 0x0e, 0x28, 0x35, 0x09, 0xbc, - 0x8a, 0x3e, 0xf9, 0x96, 0xa1, 0x72, - ], - c: [ - 0xd0, 0x94, 0x7c, 0x4b, 0x03, 0xbf, 0x72, 0xa3, 0x7a, 0xb4, 0x4f, 0x72, 0x27, - 0x6d, 0x1c, 0xf3, 0xfd, 0xcd, 0x7e, 0xbf, 0x3e, 0x73, 0x34, 0x8b, 0x7e, 0x55, - 0x0d, 0x75, 0x20, 0x18, 0x66, 0x8e, - ], - ak: [ - 0x93, 0x44, 0x2e, 0x5f, 0xef, 0xfb, 0xff, 0x16, 0xe7, 0x21, 0x72, 0x02, 0xdc, - 0x73, 0x06, 0x72, 0x9f, 0xff, 0xfe, 0x85, 0xaf, 0x56, 0x83, 0xbc, 0xe2, 0x64, - 0x2e, 0x3e, 0xeb, 0x5d, 0x38, 0x71, - ], - nk: [ - 0xdc, 0xe8, 0xe7, 0xed, 0xec, 0xe0, 0x4b, 0x89, 0x50, 0x41, 0x7f, 0x85, 0xba, - 0x57, 0x69, 0x1b, 0x78, 0x3c, 0x45, 0xb1, 0xa2, 0x74, 0x22, 0xdb, 0x16, 0x93, - 0xdc, 0xeb, 0x67, 0xb1, 0x01, 0x06, - ], - ivk: [ - 0x48, 0x47, 0xa1, 0x30, 0xe7, 0x99, 0xd3, 0xdb, 0xea, 0x36, 0xa1, 0xc1, 0x64, - 0x67, 0xd6, 0x21, 0xfb, 0x2d, 0x80, 0xe3, 0x0b, 0x3b, 0x1d, 0x1a, 0x42, 0x68, - 0x93, 0x41, 0x5d, 0xad, 0x66, 0x01, - ], - xsk: Some([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x94, 0x7c, 0x4b, - 0x03, 0xbf, 0x72, 0xa3, 0x7a, 0xb4, 0x4f, 0x72, 0x27, 0x6d, 0x1c, 0xf3, 0xfd, - 0xcd, 0x7e, 0xbf, 0x3e, 0x73, 0x34, 0x8b, 0x7e, 0x55, 0x0d, 0x75, 0x20, 0x18, - 0x66, 0x8e, 0xb6, 0xc0, 0x0c, 0x93, 0xd3, 0x60, 0x32, 0xb9, 0xa2, 0x68, 0xe9, - 0x9e, 0x86, 0xa8, 0x60, 0x77, 0x65, 0x60, 0xbf, 0x0e, 0x83, 0xc1, 0xa1, 0x0b, - 0x51, 0xf6, 0x07, 0xc9, 0x54, 0x74, 0x25, 0x06, 0x82, 0x04, 0xed, 0xe8, 0x3b, - 0x2f, 0x1f, 0xbd, 0x84, 0xf9, 0xb4, 0x5d, 0x7f, 0x99, 0x6e, 0x2e, 0xbd, 0x0a, - 0x03, 0x0a, 0xd2, 0x43, 0xb4, 0x8e, 0xd3, 0x9f, 0x74, 0x8a, 0x88, 0x21, 0xea, - 0x06, 0x39, 0x58, 0x84, 0x89, 0x03, 0x23, 0xb9, 0xd4, 0x93, 0x3c, 0x02, 0x1d, - 0xb8, 0x9b, 0xcf, 0x76, 0x7d, 0xf2, 0x19, 0x77, 0xb2, 0xff, 0x06, 0x83, 0x84, - 0x83, 0x21, 0xa4, 0xdf, 0x4a, 0xfb, 0x21, 0x77, 0xc1, 0x7c, 0xb7, 0x5b, 0x77, - 0x96, 0xaf, 0xb3, 0x9f, 0x0f, 0x3e, 0x91, 0xc9, 0x24, 0x60, 0x7d, 0xa5, 0x6f, - 0xa9, 0xa2, 0x0e, 0x28, 0x35, 0x09, 0xbc, 0x8a, 0x3e, 0xf9, 0x96, 0xa1, 0x72, - ]), - xfvk: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x94, 0x7c, 0x4b, - 0x03, 0xbf, 0x72, 0xa3, 0x7a, 0xb4, 0x4f, 0x72, 0x27, 0x6d, 0x1c, 0xf3, 0xfd, - 0xcd, 0x7e, 0xbf, 0x3e, 0x73, 0x34, 0x8b, 0x7e, 0x55, 0x0d, 0x75, 0x20, 0x18, - 0x66, 0x8e, 0x93, 0x44, 0x2e, 0x5f, 0xef, 0xfb, 0xff, 0x16, 0xe7, 0x21, 0x72, - 0x02, 0xdc, 0x73, 0x06, 0x72, 0x9f, 0xff, 0xfe, 0x85, 0xaf, 0x56, 0x83, 0xbc, - 0xe2, 0x64, 0x2e, 0x3e, 0xeb, 0x5d, 0x38, 0x71, 0xdc, 0xe8, 0xe7, 0xed, 0xec, - 0xe0, 0x4b, 0x89, 0x50, 0x41, 0x7f, 0x85, 0xba, 0x57, 0x69, 0x1b, 0x78, 0x3c, - 0x45, 0xb1, 0xa2, 0x74, 0x22, 0xdb, 0x16, 0x93, 0xdc, 0xeb, 0x67, 0xb1, 0x01, - 0x06, 0x39, 0x58, 0x84, 0x89, 0x03, 0x23, 0xb9, 0xd4, 0x93, 0x3c, 0x02, 0x1d, - 0xb8, 0x9b, 0xcf, 0x76, 0x7d, 0xf2, 0x19, 0x77, 0xb2, 0xff, 0x06, 0x83, 0x84, - 0x83, 0x21, 0xa4, 0xdf, 0x4a, 0xfb, 0x21, 0x77, 0xc1, 0x7c, 0xb7, 0x5b, 0x77, - 0x96, 0xaf, 0xb3, 0x9f, 0x0f, 0x3e, 0x91, 0xc9, 0x24, 0x60, 0x7d, 0xa5, 0x6f, - 0xa9, 0xa2, 0x0e, 0x28, 0x35, 0x09, 0xbc, 0x8a, 0x3e, 0xf9, 0x96, 0xa1, 0x72, - ], - fp: [ - 0x14, 0xc2, 0x71, 0x3a, 0xdc, 0xe9, 0x3a, 0x83, 0x0e, 0xa8, 0x3a, 0x05, 0x19, - 0x08, 0xb7, 0x44, 0x77, 0x83, 0xf5, 0xd1, 0x06, 0xc0, 0x98, 0x5e, 0x02, 0x55, - 0x0e, 0x42, 0x6f, 0x27, 0x59, 0x7c, - ], - d0: Some([ - 0xd8, 0x62, 0x1b, 0x98, 0x1c, 0xf3, 0x00, 0xe9, 0xd4, 0xcc, 0x89, - ]), - d1: Some([ - 0x48, 0xea, 0x17, 0xa1, 0x99, 0xc8, 0x4b, 0xd1, 0xba, 0xa5, 0xd4, - ]), - d2: None, - dmax: None, - internal_nsk: Some([ - 0x51, 0x12, 0x33, 0x63, 0x6b, 0x95, 0xfd, 0x0a, 0xfb, 0x6b, 0xf8, 0x19, 0x3a, - 0x7d, 0x8f, 0x49, 0xef, 0xd7, 0x36, 0xa9, 0x88, 0x77, 0x5c, 0x54, 0xf9, 0x56, - 0x68, 0x76, 0x46, 0xea, 0xab, 0x07, - ]), - internal_ovk: [ - 0x9d, 0xc4, 0x77, 0xfe, 0x1e, 0x7d, 0x28, 0x29, 0x13, 0xf6, 0x51, 0x65, 0x4d, - 0x39, 0x85, 0xf0, 0x9d, 0x53, 0xc2, 0xd3, 0xb5, 0x76, 0x3d, 0x7a, 0x72, 0x3b, - 0xcb, 0xd6, 0xee, 0x05, 0x3d, 0x5a, - ], - internal_dk: [ - 0x40, 0xdd, 0xc5, 0x6e, 0x69, 0x75, 0x13, 0x8c, 0x08, 0x39, 0xe5, 0x80, 0xb5, - 0x4d, 0x6d, 0x99, 0x9d, 0xc6, 0x16, 0x84, 0x3c, 0xfe, 0x04, 0x1e, 0x8f, 0x38, - 0x8b, 0x12, 0x4e, 0xf7, 0xb5, 0xed, - ], - internal_nk: [ - 0xa3, 0x83, 0x1a, 0x5c, 0x69, 0x33, 0xf8, 0xec, 0x6a, 0xa5, 0xce, 0x31, 0x6c, - 0x50, 0x8b, 0x79, 0x91, 0xcd, 0x94, 0xd3, 0xbd, 0xb7, 0x00, 0xa1, 0xc4, 0x27, - 0xa6, 0xae, 0x15, 0xe7, 0x2f, 0xb5, - ], - internal_ivk: [ - 0x79, 0x05, 0x77, 0x32, 0x1c, 0x51, 0x18, 0x04, 0x63, 0x6e, 0xe6, 0xba, 0xa4, - 0xee, 0xa7, 0x79, 0xb4, 0xa4, 0x6a, 0x5a, 0x12, 0xf8, 0x5d, 0x36, 0x50, 0x74, - 0xa0, 0x9d, 0x05, 0x4f, 0x34, 0x01, - ], - internal_xsk: Some([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x94, 0x7c, 0x4b, - 0x03, 0xbf, 0x72, 0xa3, 0x7a, 0xb4, 0x4f, 0x72, 0x27, 0x6d, 0x1c, 0xf3, 0xfd, - 0xcd, 0x7e, 0xbf, 0x3e, 0x73, 0x34, 0x8b, 0x7e, 0x55, 0x0d, 0x75, 0x20, 0x18, - 0x66, 0x8e, 0xb6, 0xc0, 0x0c, 0x93, 0xd3, 0x60, 0x32, 0xb9, 0xa2, 0x68, 0xe9, - 0x9e, 0x86, 0xa8, 0x60, 0x77, 0x65, 0x60, 0xbf, 0x0e, 0x83, 0xc1, 0xa1, 0x0b, - 0x51, 0xf6, 0x07, 0xc9, 0x54, 0x74, 0x25, 0x06, 0x51, 0x12, 0x33, 0x63, 0x6b, - 0x95, 0xfd, 0x0a, 0xfb, 0x6b, 0xf8, 0x19, 0x3a, 0x7d, 0x8f, 0x49, 0xef, 0xd7, - 0x36, 0xa9, 0x88, 0x77, 0x5c, 0x54, 0xf9, 0x56, 0x68, 0x76, 0x46, 0xea, 0xab, - 0x07, 0x9d, 0xc4, 0x77, 0xfe, 0x1e, 0x7d, 0x28, 0x29, 0x13, 0xf6, 0x51, 0x65, - 0x4d, 0x39, 0x85, 0xf0, 0x9d, 0x53, 0xc2, 0xd3, 0xb5, 0x76, 0x3d, 0x7a, 0x72, - 0x3b, 0xcb, 0xd6, 0xee, 0x05, 0x3d, 0x5a, 0x40, 0xdd, 0xc5, 0x6e, 0x69, 0x75, - 0x13, 0x8c, 0x08, 0x39, 0xe5, 0x80, 0xb5, 0x4d, 0x6d, 0x99, 0x9d, 0xc6, 0x16, - 0x84, 0x3c, 0xfe, 0x04, 0x1e, 0x8f, 0x38, 0x8b, 0x12, 0x4e, 0xf7, 0xb5, 0xed, - ]), - internal_xfvk: [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x94, 0x7c, 0x4b, - 0x03, 0xbf, 0x72, 0xa3, 0x7a, 0xb4, 0x4f, 0x72, 0x27, 0x6d, 0x1c, 0xf3, 0xfd, - 0xcd, 0x7e, 0xbf, 0x3e, 0x73, 0x34, 0x8b, 0x7e, 0x55, 0x0d, 0x75, 0x20, 0x18, - 0x66, 0x8e, 0x93, 0x44, 0x2e, 0x5f, 0xef, 0xfb, 0xff, 0x16, 0xe7, 0x21, 0x72, - 0x02, 0xdc, 0x73, 0x06, 0x72, 0x9f, 0xff, 0xfe, 0x85, 0xaf, 0x56, 0x83, 0xbc, - 0xe2, 0x64, 0x2e, 0x3e, 0xeb, 0x5d, 0x38, 0x71, 0xa3, 0x83, 0x1a, 0x5c, 0x69, - 0x33, 0xf8, 0xec, 0x6a, 0xa5, 0xce, 0x31, 0x6c, 0x50, 0x8b, 0x79, 0x91, 0xcd, - 0x94, 0xd3, 0xbd, 0xb7, 0x00, 0xa1, 0xc4, 0x27, 0xa6, 0xae, 0x15, 0xe7, 0x2f, - 0xb5, 0x9d, 0xc4, 0x77, 0xfe, 0x1e, 0x7d, 0x28, 0x29, 0x13, 0xf6, 0x51, 0x65, - 0x4d, 0x39, 0x85, 0xf0, 0x9d, 0x53, 0xc2, 0xd3, 0xb5, 0x76, 0x3d, 0x7a, 0x72, - 0x3b, 0xcb, 0xd6, 0xee, 0x05, 0x3d, 0x5a, 0x40, 0xdd, 0xc5, 0x6e, 0x69, 0x75, - 0x13, 0x8c, 0x08, 0x39, 0xe5, 0x80, 0xb5, 0x4d, 0x6d, 0x99, 0x9d, 0xc6, 0x16, - 0x84, 0x3c, 0xfe, 0x04, 0x1e, 0x8f, 0x38, 0x8b, 0x12, 0x4e, 0xf7, 0xb5, 0xed, - ], - internal_fp: [ - 0x82, 0x64, 0xed, 0xec, 0x63, 0xb1, 0x55, 0x00, 0x1d, 0x84, 0x96, 0x68, 0x5c, - 0xc7, 0xc2, 0x1e, 0xa9, 0x57, 0xc6, 0xf5, 0x91, 0x09, 0x0a, 0x1c, 0x20, 0xe5, - 0x2a, 0x41, 0x89, 0xb8, 0xbb, 0x96, - ], - }, - TestVector { - ask: Some([ - 0xd5, 0xf7, 0xe9, 0x2e, 0xfb, 0x7a, 0xbe, 0x04, 0xdc, 0x8c, 0x14, 0x8b, 0x0b, - 0x3b, 0x0f, 0xc2, 0x3e, 0x04, 0x29, 0xf0, 0x02, 0x08, 0xff, 0x93, 0xb6, 0x8d, - 0x21, 0xa6, 0xe1, 0x31, 0xbd, 0x04, - ]), - nsk: Some([ - 0x37, 0x2a, 0x7c, 0x68, 0x22, 0xcb, 0xe6, 0x03, 0xf3, 0x46, 0x5c, 0x4b, 0x9b, - 0x65, 0x58, 0xf3, 0xa3, 0x51, 0x2d, 0xec, 0xd4, 0x34, 0x01, 0x2e, 0x67, 0xbf, - 0xfc, 0xf6, 0x57, 0xe5, 0x75, 0x0a, - ]), - ovk: [ - 0x25, 0x30, 0x76, 0x19, 0x33, 0x34, 0x8c, 0x1f, 0xcf, 0x14, 0x35, 0x54, 0x33, - 0xa8, 0xd2, 0x91, 0x16, 0x7f, 0xbb, 0x37, 0xb2, 0xce, 0x37, 0xca, 0x97, 0x16, - 0x0a, 0x47, 0xec, 0x33, 0x1c, 0x69, - ], - dk: [ - 0xf2, 0x88, 0x40, 0x0f, 0xd6, 0x5f, 0x9a, 0xdf, 0xe3, 0xa7, 0xc3, 0x72, 0x0a, - 0xce, 0xee, 0x0d, 0xae, 0x05, 0x0d, 0x0a, 0x81, 0x9d, 0x61, 0x9f, 0x92, 0xe9, - 0xe2, 0xcb, 0x44, 0x34, 0xd5, 0x26, - ], - c: [ - 0x6f, 0xcc, 0xaa, 0x45, 0xa8, 0x20, 0x6b, 0x06, 0x3e, 0xbb, 0x68, 0xc6, 0x10, - 0xe0, 0x59, 0x27, 0xaa, 0x94, 0xd6, 0x1b, 0xe9, 0x3e, 0xc2, 0x5e, 0xb4, 0xf8, - 0x2e, 0xfd, 0x68, 0xca, 0xae, 0xdb, - ], - ak: [ - 0xcf, 0xca, 0x79, 0xd3, 0x37, 0xbc, 0x68, 0x98, 0x13, 0xe4, 0x09, 0xa5, 0x4e, - 0x3e, 0x72, 0xad, 0x8e, 0x2f, 0x70, 0x3a, 0xe6, 0xf8, 0x22, 0x3c, 0x9b, 0xec, - 0xbd, 0xe9, 0xa8, 0xa3, 0x5f, 0x53, - ], - nk: [ - 0x51, 0x3d, 0xe6, 0x40, 0x85, 0xd3, 0x5a, 0x3a, 0xdf, 0x23, 0xd8, 0x9d, 0x5a, - 0x21, 0xcd, 0xee, 0x4d, 0xb4, 0xc6, 0x25, 0xbd, 0x6a, 0x3c, 0x3c, 0x62, 0x4b, - 0xef, 0x43, 0x44, 0x14, 0x1d, 0xeb, - ], - ivk: [ - 0xf6, 0xe7, 0x5c, 0xd9, 0x80, 0xc3, 0x0e, 0xab, 0xc6, 0x1f, 0x49, 0xac, 0x68, - 0xf4, 0x88, 0x57, 0x3a, 0xb3, 0xe6, 0xaf, 0xe1, 0x53, 0x76, 0x37, 0x5d, 0x34, - 0xe4, 0x06, 0x70, 0x2f, 0xfd, 0x02, - ], - xsk: Some([ - 0x01, 0x14, 0xc2, 0x71, 0x3a, 0x01, 0x00, 0x00, 0x80, 0x6f, 0xcc, 0xaa, 0x45, - 0xa8, 0x20, 0x6b, 0x06, 0x3e, 0xbb, 0x68, 0xc6, 0x10, 0xe0, 0x59, 0x27, 0xaa, - 0x94, 0xd6, 0x1b, 0xe9, 0x3e, 0xc2, 0x5e, 0xb4, 0xf8, 0x2e, 0xfd, 0x68, 0xca, - 0xae, 0xdb, 0xd5, 0xf7, 0xe9, 0x2e, 0xfb, 0x7a, 0xbe, 0x04, 0xdc, 0x8c, 0x14, - 0x8b, 0x0b, 0x3b, 0x0f, 0xc2, 0x3e, 0x04, 0x29, 0xf0, 0x02, 0x08, 0xff, 0x93, - 0xb6, 0x8d, 0x21, 0xa6, 0xe1, 0x31, 0xbd, 0x04, 0x37, 0x2a, 0x7c, 0x68, 0x22, - 0xcb, 0xe6, 0x03, 0xf3, 0x46, 0x5c, 0x4b, 0x9b, 0x65, 0x58, 0xf3, 0xa3, 0x51, - 0x2d, 0xec, 0xd4, 0x34, 0x01, 0x2e, 0x67, 0xbf, 0xfc, 0xf6, 0x57, 0xe5, 0x75, - 0x0a, 0x25, 0x30, 0x76, 0x19, 0x33, 0x34, 0x8c, 0x1f, 0xcf, 0x14, 0x35, 0x54, - 0x33, 0xa8, 0xd2, 0x91, 0x16, 0x7f, 0xbb, 0x37, 0xb2, 0xce, 0x37, 0xca, 0x97, - 0x16, 0x0a, 0x47, 0xec, 0x33, 0x1c, 0x69, 0xf2, 0x88, 0x40, 0x0f, 0xd6, 0x5f, - 0x9a, 0xdf, 0xe3, 0xa7, 0xc3, 0x72, 0x0a, 0xce, 0xee, 0x0d, 0xae, 0x05, 0x0d, - 0x0a, 0x81, 0x9d, 0x61, 0x9f, 0x92, 0xe9, 0xe2, 0xcb, 0x44, 0x34, 0xd5, 0x26, - ]), - xfvk: [ - 0x01, 0x14, 0xc2, 0x71, 0x3a, 0x01, 0x00, 0x00, 0x80, 0x6f, 0xcc, 0xaa, 0x45, - 0xa8, 0x20, 0x6b, 0x06, 0x3e, 0xbb, 0x68, 0xc6, 0x10, 0xe0, 0x59, 0x27, 0xaa, - 0x94, 0xd6, 0x1b, 0xe9, 0x3e, 0xc2, 0x5e, 0xb4, 0xf8, 0x2e, 0xfd, 0x68, 0xca, - 0xae, 0xdb, 0xcf, 0xca, 0x79, 0xd3, 0x37, 0xbc, 0x68, 0x98, 0x13, 0xe4, 0x09, - 0xa5, 0x4e, 0x3e, 0x72, 0xad, 0x8e, 0x2f, 0x70, 0x3a, 0xe6, 0xf8, 0x22, 0x3c, - 0x9b, 0xec, 0xbd, 0xe9, 0xa8, 0xa3, 0x5f, 0x53, 0x51, 0x3d, 0xe6, 0x40, 0x85, - 0xd3, 0x5a, 0x3a, 0xdf, 0x23, 0xd8, 0x9d, 0x5a, 0x21, 0xcd, 0xee, 0x4d, 0xb4, - 0xc6, 0x25, 0xbd, 0x6a, 0x3c, 0x3c, 0x62, 0x4b, 0xef, 0x43, 0x44, 0x14, 0x1d, - 0xeb, 0x25, 0x30, 0x76, 0x19, 0x33, 0x34, 0x8c, 0x1f, 0xcf, 0x14, 0x35, 0x54, - 0x33, 0xa8, 0xd2, 0x91, 0x16, 0x7f, 0xbb, 0x37, 0xb2, 0xce, 0x37, 0xca, 0x97, - 0x16, 0x0a, 0x47, 0xec, 0x33, 0x1c, 0x69, 0xf2, 0x88, 0x40, 0x0f, 0xd6, 0x5f, - 0x9a, 0xdf, 0xe3, 0xa7, 0xc3, 0x72, 0x0a, 0xce, 0xee, 0x0d, 0xae, 0x05, 0x0d, - 0x0a, 0x81, 0x9d, 0x61, 0x9f, 0x92, 0xe9, 0xe2, 0xcb, 0x44, 0x34, 0xd5, 0x26, - ], - fp: [ - 0x76, 0x84, 0x23, 0xcb, 0x88, 0xd2, 0x2d, 0xee, 0x91, 0xb5, 0xb7, 0x66, 0x1e, - 0x72, 0xed, 0x00, 0x95, 0x57, 0xeb, 0xa1, 0x44, 0xc7, 0x8d, 0x1a, 0xa7, 0x1a, - 0x3e, 0x88, 0xb6, 0x91, 0x06, 0x96, - ], - d0: None, - d1: Some([ - 0xbc, 0xc3, 0x23, 0xe8, 0xda, 0x39, 0xb4, 0x96, 0xc0, 0x50, 0x51, - ]), - d2: None, - dmax: Some([ - 0x25, 0x14, 0x32, 0x0d, 0x33, 0x9c, 0x66, 0x6a, 0x25, 0x4c, 0x06, - ]), - internal_nsk: Some([ - 0x5d, 0x47, 0x0f, 0x97, 0x79, 0xcc, 0x25, 0x7f, 0x21, 0x28, 0x8f, 0x50, 0x5a, - 0x4e, 0x65, 0xb3, 0x8e, 0xb8, 0x53, 0xf1, 0xa2, 0x45, 0x63, 0xb9, 0xf6, 0x74, - 0x17, 0x26, 0xf4, 0xd3, 0x01, 0x03, - ]), - internal_ovk: [ - 0x78, 0x64, 0xe8, 0xc7, 0x9c, 0xea, 0xab, 0x97, 0xe6, 0xae, 0x5b, 0xca, 0x10, - 0xf7, 0xd5, 0x1d, 0xf4, 0x20, 0x9a, 0xd0, 0xd4, 0x6e, 0x80, 0xac, 0x18, 0x0d, - 0x50, 0xd3, 0xff, 0x09, 0xa6, 0x70, - ], - internal_dk: [ - 0x54, 0xf1, 0x1e, 0x3f, 0xa3, 0x0d, 0x34, 0xd6, 0xa7, 0x4d, 0xef, 0x1e, 0x6d, - 0x5d, 0xaf, 0x58, 0xcf, 0xc7, 0xd7, 0x8b, 0x27, 0xcb, 0x07, 0x15, 0xc1, 0xaf, - 0xfa, 0x29, 0xae, 0x39, 0x92, 0xfa, - ], - internal_nk: [ - 0x31, 0x42, 0x48, 0x75, 0xd6, 0xa5, 0xed, 0x75, 0xde, 0x20, 0x0b, 0xb5, 0xc1, - 0xd8, 0x1a, 0xec, 0x4d, 0xff, 0x16, 0x50, 0xb7, 0x8b, 0xb0, 0xca, 0xde, 0x3c, - 0x8c, 0x7a, 0xb0, 0x3d, 0xf1, 0x11, - ], - internal_ivk: [ - 0xe5, 0x42, 0x6b, 0x5b, 0x80, 0xb1, 0x18, 0x67, 0x97, 0x01, 0x65, 0x80, 0xc1, - 0xf4, 0x1c, 0x34, 0x19, 0x68, 0x3a, 0xac, 0x77, 0xcf, 0x8d, 0xe0, 0x2f, 0x2f, - 0x98, 0x07, 0xd1, 0x50, 0xb4, 0x02, - ], - internal_xsk: Some([ - 0x01, 0x14, 0xc2, 0x71, 0x3a, 0x01, 0x00, 0x00, 0x80, 0x6f, 0xcc, 0xaa, 0x45, - 0xa8, 0x20, 0x6b, 0x06, 0x3e, 0xbb, 0x68, 0xc6, 0x10, 0xe0, 0x59, 0x27, 0xaa, - 0x94, 0xd6, 0x1b, 0xe9, 0x3e, 0xc2, 0x5e, 0xb4, 0xf8, 0x2e, 0xfd, 0x68, 0xca, - 0xae, 0xdb, 0xd5, 0xf7, 0xe9, 0x2e, 0xfb, 0x7a, 0xbe, 0x04, 0xdc, 0x8c, 0x14, - 0x8b, 0x0b, 0x3b, 0x0f, 0xc2, 0x3e, 0x04, 0x29, 0xf0, 0x02, 0x08, 0xff, 0x93, - 0xb6, 0x8d, 0x21, 0xa6, 0xe1, 0x31, 0xbd, 0x04, 0x5d, 0x47, 0x0f, 0x97, 0x79, - 0xcc, 0x25, 0x7f, 0x21, 0x28, 0x8f, 0x50, 0x5a, 0x4e, 0x65, 0xb3, 0x8e, 0xb8, - 0x53, 0xf1, 0xa2, 0x45, 0x63, 0xb9, 0xf6, 0x74, 0x17, 0x26, 0xf4, 0xd3, 0x01, - 0x03, 0x78, 0x64, 0xe8, 0xc7, 0x9c, 0xea, 0xab, 0x97, 0xe6, 0xae, 0x5b, 0xca, - 0x10, 0xf7, 0xd5, 0x1d, 0xf4, 0x20, 0x9a, 0xd0, 0xd4, 0x6e, 0x80, 0xac, 0x18, - 0x0d, 0x50, 0xd3, 0xff, 0x09, 0xa6, 0x70, 0x54, 0xf1, 0x1e, 0x3f, 0xa3, 0x0d, - 0x34, 0xd6, 0xa7, 0x4d, 0xef, 0x1e, 0x6d, 0x5d, 0xaf, 0x58, 0xcf, 0xc7, 0xd7, - 0x8b, 0x27, 0xcb, 0x07, 0x15, 0xc1, 0xaf, 0xfa, 0x29, 0xae, 0x39, 0x92, 0xfa, - ]), - internal_xfvk: [ - 0x01, 0x14, 0xc2, 0x71, 0x3a, 0x01, 0x00, 0x00, 0x80, 0x6f, 0xcc, 0xaa, 0x45, - 0xa8, 0x20, 0x6b, 0x06, 0x3e, 0xbb, 0x68, 0xc6, 0x10, 0xe0, 0x59, 0x27, 0xaa, - 0x94, 0xd6, 0x1b, 0xe9, 0x3e, 0xc2, 0x5e, 0xb4, 0xf8, 0x2e, 0xfd, 0x68, 0xca, - 0xae, 0xdb, 0xcf, 0xca, 0x79, 0xd3, 0x37, 0xbc, 0x68, 0x98, 0x13, 0xe4, 0x09, - 0xa5, 0x4e, 0x3e, 0x72, 0xad, 0x8e, 0x2f, 0x70, 0x3a, 0xe6, 0xf8, 0x22, 0x3c, - 0x9b, 0xec, 0xbd, 0xe9, 0xa8, 0xa3, 0x5f, 0x53, 0x31, 0x42, 0x48, 0x75, 0xd6, - 0xa5, 0xed, 0x75, 0xde, 0x20, 0x0b, 0xb5, 0xc1, 0xd8, 0x1a, 0xec, 0x4d, 0xff, - 0x16, 0x50, 0xb7, 0x8b, 0xb0, 0xca, 0xde, 0x3c, 0x8c, 0x7a, 0xb0, 0x3d, 0xf1, - 0x11, 0x78, 0x64, 0xe8, 0xc7, 0x9c, 0xea, 0xab, 0x97, 0xe6, 0xae, 0x5b, 0xca, - 0x10, 0xf7, 0xd5, 0x1d, 0xf4, 0x20, 0x9a, 0xd0, 0xd4, 0x6e, 0x80, 0xac, 0x18, - 0x0d, 0x50, 0xd3, 0xff, 0x09, 0xa6, 0x70, 0x54, 0xf1, 0x1e, 0x3f, 0xa3, 0x0d, - 0x34, 0xd6, 0xa7, 0x4d, 0xef, 0x1e, 0x6d, 0x5d, 0xaf, 0x58, 0xcf, 0xc7, 0xd7, - 0x8b, 0x27, 0xcb, 0x07, 0x15, 0xc1, 0xaf, 0xfa, 0x29, 0xae, 0x39, 0x92, 0xfa, - ], - internal_fp: [ - 0x12, 0x87, 0xc3, 0x79, 0x02, 0x35, 0x69, 0x16, 0x4e, 0xb5, 0x23, 0xff, 0xdd, - 0x72, 0x03, 0x1c, 0x35, 0xe1, 0x85, 0x9f, 0x3e, 0xf8, 0xd4, 0x83, 0x0a, 0x29, - 0x91, 0xba, 0x7e, 0x15, 0xde, 0x2d, - ], - }, - TestVector { - ask: Some([ - 0x7f, 0xf3, 0x5d, 0xb6, 0x9e, 0x13, 0xc3, 0x6f, 0x59, 0xad, 0x9c, 0x08, 0xd3, - 0x2d, 0x52, 0x27, 0x37, 0x8d, 0xa0, 0xcf, 0xf9, 0x71, 0xfd, 0x42, 0x4b, 0xae, - 0xf9, 0xa6, 0x33, 0x2f, 0x51, 0x06, - ]), - nsk: Some([ - 0x77, 0x9c, 0x6e, 0xe4, 0xa0, 0x39, 0x44, 0xeb, 0xa2, 0x8b, 0xc9, 0xbd, 0xc1, - 0x32, 0x9a, 0x39, 0x14, 0x07, 0xf4, 0x8c, 0x41, 0x0d, 0x5a, 0xe0, 0xa3, 0x64, - 0xf5, 0x99, 0x59, 0xbf, 0xde, 0x00, - ]), - ovk: [ - 0xd9, 0xfc, 0x71, 0x01, 0xbf, 0x90, 0x7f, 0x41, 0x88, 0x6a, 0x73, 0x30, 0xa5, - 0xd6, 0xa7, 0xbd, 0x23, 0x53, 0x5e, 0x30, 0x5e, 0xb7, 0x67, 0x9b, 0xc2, 0x3d, - 0x76, 0x05, 0x93, 0x61, 0x85, 0xac, - ], - dk: [ - 0xe4, 0x69, 0x9e, 0x9a, 0x86, 0xe0, 0x31, 0xc5, 0x4b, 0x21, 0xcd, 0xd0, 0x96, - 0x0a, 0xc1, 0x8d, 0xdd, 0x61, 0xec, 0x9f, 0x7a, 0xe9, 0x8d, 0x55, 0x82, 0xa6, - 0xfa, 0xf6, 0x5f, 0x32, 0x48, 0xd1, - ], - c: [ - 0x44, 0x79, 0x08, 0x6c, 0x75, 0xd0, 0x80, 0x79, 0x60, 0x20, 0xf5, 0x00, 0xc1, - 0xe3, 0x0a, 0x54, 0xcf, 0xe2, 0x9d, 0xda, 0x36, 0xf2, 0x14, 0x4f, 0xb3, 0x3a, - 0x50, 0x80, 0x6f, 0xbe, 0xf7, 0xda, - ], - ak: [ - 0x9a, 0x85, 0x3f, 0x95, 0x44, 0x71, 0x37, 0x97, 0xe0, 0x85, 0x17, 0x64, 0xda, - 0x39, 0x2e, 0x68, 0x53, 0x4b, 0x1d, 0x94, 0x8d, 0xae, 0x47, 0x42, 0xee, 0x76, - 0x5c, 0x72, 0x75, 0x72, 0xab, 0x4e, - ], - nk: [ - 0xf1, 0x66, 0xa2, 0x8a, 0x4f, 0x88, 0xce, 0xc1, 0x21, 0x41, 0xa8, 0x2d, 0x21, - 0x20, 0xbd, 0x6d, 0x8c, 0xaf, 0x87, 0x9c, 0x9a, 0x1b, 0x3a, 0xd2, 0x11, 0x85, - 0x01, 0x36, 0x4f, 0x5d, 0x4f, 0xbe, - ], - ivk: [ - 0x33, 0xbd, 0x46, 0x01, 0x5a, 0x2c, 0xad, 0x17, 0xd6, 0xe0, 0x15, 0xeb, 0x88, - 0x86, 0x1b, 0x0c, 0x91, 0x77, 0x96, 0x24, 0x65, 0x70, 0x52, 0x1c, 0x9e, 0x1a, - 0xe4, 0xb1, 0xc8, 0x31, 0x1d, 0x06, - ], - xsk: Some([ - 0x02, 0x76, 0x84, 0x23, 0xcb, 0x02, 0x00, 0x00, 0x80, 0x44, 0x79, 0x08, 0x6c, - 0x75, 0xd0, 0x80, 0x79, 0x60, 0x20, 0xf5, 0x00, 0xc1, 0xe3, 0x0a, 0x54, 0xcf, - 0xe2, 0x9d, 0xda, 0x36, 0xf2, 0x14, 0x4f, 0xb3, 0x3a, 0x50, 0x80, 0x6f, 0xbe, - 0xf7, 0xda, 0x7f, 0xf3, 0x5d, 0xb6, 0x9e, 0x13, 0xc3, 0x6f, 0x59, 0xad, 0x9c, - 0x08, 0xd3, 0x2d, 0x52, 0x27, 0x37, 0x8d, 0xa0, 0xcf, 0xf9, 0x71, 0xfd, 0x42, - 0x4b, 0xae, 0xf9, 0xa6, 0x33, 0x2f, 0x51, 0x06, 0x77, 0x9c, 0x6e, 0xe4, 0xa0, - 0x39, 0x44, 0xeb, 0xa2, 0x8b, 0xc9, 0xbd, 0xc1, 0x32, 0x9a, 0x39, 0x14, 0x07, - 0xf4, 0x8c, 0x41, 0x0d, 0x5a, 0xe0, 0xa3, 0x64, 0xf5, 0x99, 0x59, 0xbf, 0xde, - 0x00, 0xd9, 0xfc, 0x71, 0x01, 0xbf, 0x90, 0x7f, 0x41, 0x88, 0x6a, 0x73, 0x30, - 0xa5, 0xd6, 0xa7, 0xbd, 0x23, 0x53, 0x5e, 0x30, 0x5e, 0xb7, 0x67, 0x9b, 0xc2, - 0x3d, 0x76, 0x05, 0x93, 0x61, 0x85, 0xac, 0xe4, 0x69, 0x9e, 0x9a, 0x86, 0xe0, - 0x31, 0xc5, 0x4b, 0x21, 0xcd, 0xd0, 0x96, 0x0a, 0xc1, 0x8d, 0xdd, 0x61, 0xec, - 0x9f, 0x7a, 0xe9, 0x8d, 0x55, 0x82, 0xa6, 0xfa, 0xf6, 0x5f, 0x32, 0x48, 0xd1, - ]), - xfvk: [ - 0x02, 0x76, 0x84, 0x23, 0xcb, 0x02, 0x00, 0x00, 0x80, 0x44, 0x79, 0x08, 0x6c, - 0x75, 0xd0, 0x80, 0x79, 0x60, 0x20, 0xf5, 0x00, 0xc1, 0xe3, 0x0a, 0x54, 0xcf, - 0xe2, 0x9d, 0xda, 0x36, 0xf2, 0x14, 0x4f, 0xb3, 0x3a, 0x50, 0x80, 0x6f, 0xbe, - 0xf7, 0xda, 0x9a, 0x85, 0x3f, 0x95, 0x44, 0x71, 0x37, 0x97, 0xe0, 0x85, 0x17, - 0x64, 0xda, 0x39, 0x2e, 0x68, 0x53, 0x4b, 0x1d, 0x94, 0x8d, 0xae, 0x47, 0x42, - 0xee, 0x76, 0x5c, 0x72, 0x75, 0x72, 0xab, 0x4e, 0xf1, 0x66, 0xa2, 0x8a, 0x4f, - 0x88, 0xce, 0xc1, 0x21, 0x41, 0xa8, 0x2d, 0x21, 0x20, 0xbd, 0x6d, 0x8c, 0xaf, - 0x87, 0x9c, 0x9a, 0x1b, 0x3a, 0xd2, 0x11, 0x85, 0x01, 0x36, 0x4f, 0x5d, 0x4f, - 0xbe, 0xd9, 0xfc, 0x71, 0x01, 0xbf, 0x90, 0x7f, 0x41, 0x88, 0x6a, 0x73, 0x30, - 0xa5, 0xd6, 0xa7, 0xbd, 0x23, 0x53, 0x5e, 0x30, 0x5e, 0xb7, 0x67, 0x9b, 0xc2, - 0x3d, 0x76, 0x05, 0x93, 0x61, 0x85, 0xac, 0xe4, 0x69, 0x9e, 0x9a, 0x86, 0xe0, - 0x31, 0xc5, 0x4b, 0x21, 0xcd, 0xd0, 0x96, 0x0a, 0xc1, 0x8d, 0xdd, 0x61, 0xec, - 0x9f, 0x7a, 0xe9, 0x8d, 0x55, 0x82, 0xa6, 0xfa, 0xf6, 0x5f, 0x32, 0x48, 0xd1, - ], - fp: [ - 0x0b, 0xdc, 0x2d, 0x2b, 0x6e, 0xb1, 0xf9, 0x27, 0xcb, 0xab, 0xdb, 0xb9, 0xd4, - 0x3d, 0xb8, 0xde, 0x85, 0x7b, 0xb7, 0x16, 0xdf, 0x86, 0xce, 0xcf, 0x08, 0x1e, - 0x1a, 0x2b, 0x74, 0xfc, 0xad, 0x55, - ], - d0: None, - d1: None, - d2: None, - dmax: None, - internal_nsk: Some([ - 0x7b, 0x17, 0x17, 0x65, 0x27, 0xf9, 0x17, 0x99, 0x0f, 0x9f, 0x51, 0x79, 0xcb, - 0x23, 0xc1, 0x6e, 0xc0, 0xa9, 0x26, 0xed, 0xc4, 0x1a, 0xb2, 0xba, 0x42, 0x13, - 0x7b, 0xef, 0x5c, 0x20, 0x9f, 0x09, - ]), - internal_ovk: [ - 0xc6, 0x12, 0xcb, 0xc9, 0x77, 0x30, 0x7e, 0x53, 0x52, 0xa1, 0x58, 0x8b, 0xd7, - 0x0f, 0x41, 0xaf, 0x11, 0xe7, 0x3b, 0x7b, 0xc6, 0xbc, 0xbc, 0x73, 0x2a, 0xa3, - 0x06, 0xc2, 0x1c, 0xd0, 0x0f, 0x3a, - ], - internal_dk: [ - 0x35, 0xef, 0x4d, 0x26, 0x59, 0x51, 0xdc, 0xaa, 0xec, 0x26, 0xef, 0x8f, 0xbd, - 0xf8, 0x4c, 0x92, 0xb7, 0x90, 0x04, 0x9d, 0x09, 0x93, 0x77, 0x2e, 0xfb, 0x43, - 0x97, 0xf0, 0x49, 0x30, 0xf1, 0x67, - ], - internal_nk: [ - 0x8d, 0x05, 0x55, 0xe8, 0xe0, 0x20, 0xc9, 0xd3, 0x60, 0x68, 0x5d, 0x24, 0x2f, - 0x2b, 0xa9, 0xf7, 0x74, 0x61, 0x3f, 0xa0, 0x94, 0x01, 0xf1, 0x25, 0xbc, 0xa9, - 0x29, 0xec, 0xa4, 0x86, 0xa3, 0xd1, - ], - internal_ivk: [ - 0x7f, 0x7c, 0xee, 0xfa, 0x65, 0x42, 0x8e, 0x8b, 0x70, 0x76, 0x19, 0x1a, 0x23, - 0x93, 0x95, 0x7b, 0x9c, 0x09, 0x50, 0x61, 0xd8, 0xcc, 0xe1, 0x28, 0x3d, 0xd1, - 0x5c, 0x2b, 0x5e, 0x8f, 0xc3, 0x05, - ], - internal_xsk: Some([ - 0x02, 0x76, 0x84, 0x23, 0xcb, 0x02, 0x00, 0x00, 0x80, 0x44, 0x79, 0x08, 0x6c, - 0x75, 0xd0, 0x80, 0x79, 0x60, 0x20, 0xf5, 0x00, 0xc1, 0xe3, 0x0a, 0x54, 0xcf, - 0xe2, 0x9d, 0xda, 0x36, 0xf2, 0x14, 0x4f, 0xb3, 0x3a, 0x50, 0x80, 0x6f, 0xbe, - 0xf7, 0xda, 0x7f, 0xf3, 0x5d, 0xb6, 0x9e, 0x13, 0xc3, 0x6f, 0x59, 0xad, 0x9c, - 0x08, 0xd3, 0x2d, 0x52, 0x27, 0x37, 0x8d, 0xa0, 0xcf, 0xf9, 0x71, 0xfd, 0x42, - 0x4b, 0xae, 0xf9, 0xa6, 0x33, 0x2f, 0x51, 0x06, 0x7b, 0x17, 0x17, 0x65, 0x27, - 0xf9, 0x17, 0x99, 0x0f, 0x9f, 0x51, 0x79, 0xcb, 0x23, 0xc1, 0x6e, 0xc0, 0xa9, - 0x26, 0xed, 0xc4, 0x1a, 0xb2, 0xba, 0x42, 0x13, 0x7b, 0xef, 0x5c, 0x20, 0x9f, - 0x09, 0xc6, 0x12, 0xcb, 0xc9, 0x77, 0x30, 0x7e, 0x53, 0x52, 0xa1, 0x58, 0x8b, - 0xd7, 0x0f, 0x41, 0xaf, 0x11, 0xe7, 0x3b, 0x7b, 0xc6, 0xbc, 0xbc, 0x73, 0x2a, - 0xa3, 0x06, 0xc2, 0x1c, 0xd0, 0x0f, 0x3a, 0x35, 0xef, 0x4d, 0x26, 0x59, 0x51, - 0xdc, 0xaa, 0xec, 0x26, 0xef, 0x8f, 0xbd, 0xf8, 0x4c, 0x92, 0xb7, 0x90, 0x04, - 0x9d, 0x09, 0x93, 0x77, 0x2e, 0xfb, 0x43, 0x97, 0xf0, 0x49, 0x30, 0xf1, 0x67, - ]), - internal_xfvk: [ - 0x02, 0x76, 0x84, 0x23, 0xcb, 0x02, 0x00, 0x00, 0x80, 0x44, 0x79, 0x08, 0x6c, - 0x75, 0xd0, 0x80, 0x79, 0x60, 0x20, 0xf5, 0x00, 0xc1, 0xe3, 0x0a, 0x54, 0xcf, - 0xe2, 0x9d, 0xda, 0x36, 0xf2, 0x14, 0x4f, 0xb3, 0x3a, 0x50, 0x80, 0x6f, 0xbe, - 0xf7, 0xda, 0x9a, 0x85, 0x3f, 0x95, 0x44, 0x71, 0x37, 0x97, 0xe0, 0x85, 0x17, - 0x64, 0xda, 0x39, 0x2e, 0x68, 0x53, 0x4b, 0x1d, 0x94, 0x8d, 0xae, 0x47, 0x42, - 0xee, 0x76, 0x5c, 0x72, 0x75, 0x72, 0xab, 0x4e, 0x8d, 0x05, 0x55, 0xe8, 0xe0, - 0x20, 0xc9, 0xd3, 0x60, 0x68, 0x5d, 0x24, 0x2f, 0x2b, 0xa9, 0xf7, 0x74, 0x61, - 0x3f, 0xa0, 0x94, 0x01, 0xf1, 0x25, 0xbc, 0xa9, 0x29, 0xec, 0xa4, 0x86, 0xa3, - 0xd1, 0xc6, 0x12, 0xcb, 0xc9, 0x77, 0x30, 0x7e, 0x53, 0x52, 0xa1, 0x58, 0x8b, - 0xd7, 0x0f, 0x41, 0xaf, 0x11, 0xe7, 0x3b, 0x7b, 0xc6, 0xbc, 0xbc, 0x73, 0x2a, - 0xa3, 0x06, 0xc2, 0x1c, 0xd0, 0x0f, 0x3a, 0x35, 0xef, 0x4d, 0x26, 0x59, 0x51, - 0xdc, 0xaa, 0xec, 0x26, 0xef, 0x8f, 0xbd, 0xf8, 0x4c, 0x92, 0xb7, 0x90, 0x04, - 0x9d, 0x09, 0x93, 0x77, 0x2e, 0xfb, 0x43, 0x97, 0xf0, 0x49, 0x30, 0xf1, 0x67, - ], - internal_fp: [ - 0xe0, 0xba, 0xa5, 0xdb, 0xb8, 0x06, 0xc7, 0x21, 0x33, 0x3c, 0x63, 0x08, 0x34, - 0x5f, 0xc5, 0x1c, 0x2d, 0xc1, 0xe0, 0x09, 0xda, 0x04, 0x47, 0x78, 0xa3, 0xc3, - 0x29, 0x4d, 0x68, 0x17, 0xa3, 0xc4, - ], - }, - TestVector { - ask: Some([ - 0x45, 0x93, 0xd2, 0x4d, 0x21, 0xe3, 0x59, 0x37, 0xf1, 0x52, 0xcf, 0x90, 0x46, - 0x1c, 0x33, 0x2f, 0x69, 0x50, 0x3c, 0x10, 0x45, 0x81, 0xd6, 0x83, 0xe0, 0xac, - 0x29, 0xf8, 0x4d, 0xec, 0xaf, 0x07, - ]), - nsk: Some([ - 0x1a, 0xc8, 0x7e, 0xc2, 0x12, 0x3f, 0x50, 0x57, 0xe3, 0xc0, 0xf8, 0x58, 0xe8, - 0x0d, 0xfa, 0x0e, 0xe4, 0x55, 0x3d, 0xed, 0x27, 0xb7, 0xb5, 0xab, 0xfb, 0xb6, - 0xfa, 0x6e, 0xff, 0xa7, 0xbb, 0x0b, - ]), - ovk: [ - 0x1e, 0x36, 0xea, 0x0c, 0xf2, 0xbe, 0x2e, 0x9d, 0x6c, 0xe3, 0x80, 0xa8, 0xaf, - 0x18, 0xe7, 0x5d, 0xa9, 0x22, 0x55, 0x51, 0xfb, 0xef, 0x8b, 0x98, 0x31, 0x1b, - 0x5c, 0x9c, 0x1b, 0x4b, 0x9e, 0xe3, - ], - dk: [ - 0x57, 0xfc, 0x6c, 0x59, 0xa4, 0xf3, 0xad, 0x5a, 0x6f, 0x60, 0x9d, 0xb6, 0x71, - 0xd2, 0x8c, 0xbf, 0x70, 0x3f, 0x0d, 0x14, 0xdc, 0x36, 0x3a, 0xaa, 0xed, 0x70, - 0x72, 0x9c, 0x10, 0x7b, 0xbb, 0x6a, - ], - c: [ - 0x33, 0xdc, 0x01, 0x2d, 0x76, 0x90, 0xce, 0xd2, 0xcd, 0x2b, 0xcb, 0x2c, 0xc3, - 0xe4, 0x63, 0xe2, 0x8d, 0x8c, 0x29, 0xef, 0x3b, 0x01, 0xbe, 0x59, 0xb2, 0xbd, - 0xfc, 0x38, 0x5b, 0xbd, 0xc7, 0x4b, - ], - ak: [ - 0x9c, 0x6d, 0x85, 0x9a, 0x75, 0x2c, 0x30, 0x5d, 0x62, 0x63, 0xde, 0x95, 0xf2, - 0xfc, 0xf7, 0x34, 0xb1, 0x26, 0xdf, 0x24, 0x56, 0xc7, 0xd3, 0x1b, 0xc6, 0x01, - 0xc8, 0xdd, 0xec, 0x40, 0x91, 0x12, - ], - nk: [ - 0xd3, 0xee, 0x41, 0xf8, 0x4b, 0x5a, 0x95, 0x08, 0xb6, 0x1d, 0x29, 0xb2, 0xfb, - 0x45, 0x63, 0x6d, 0x19, 0xaa, 0x10, 0xd7, 0x82, 0xcd, 0x97, 0x8c, 0xfe, 0x67, - 0x15, 0x49, 0x2f, 0xcd, 0x22, 0x4e, - ], - ivk: [ - 0xd1, 0x38, 0xe1, 0x37, 0xc6, 0x67, 0x1d, 0xe7, 0x82, 0xfb, 0x01, 0xba, 0x91, - 0x1d, 0x98, 0x64, 0xbe, 0xbc, 0x44, 0x36, 0xcc, 0xb3, 0x88, 0xb4, 0xc1, 0xce, - 0x02, 0x56, 0xa8, 0xdb, 0x74, 0x01, - ], - xsk: Some([ - 0x03, 0x0b, 0xdc, 0x2d, 0x2b, 0x03, 0x00, 0x00, 0x80, 0x33, 0xdc, 0x01, 0x2d, - 0x76, 0x90, 0xce, 0xd2, 0xcd, 0x2b, 0xcb, 0x2c, 0xc3, 0xe4, 0x63, 0xe2, 0x8d, - 0x8c, 0x29, 0xef, 0x3b, 0x01, 0xbe, 0x59, 0xb2, 0xbd, 0xfc, 0x38, 0x5b, 0xbd, - 0xc7, 0x4b, 0x45, 0x93, 0xd2, 0x4d, 0x21, 0xe3, 0x59, 0x37, 0xf1, 0x52, 0xcf, - 0x90, 0x46, 0x1c, 0x33, 0x2f, 0x69, 0x50, 0x3c, 0x10, 0x45, 0x81, 0xd6, 0x83, - 0xe0, 0xac, 0x29, 0xf8, 0x4d, 0xec, 0xaf, 0x07, 0x1a, 0xc8, 0x7e, 0xc2, 0x12, - 0x3f, 0x50, 0x57, 0xe3, 0xc0, 0xf8, 0x58, 0xe8, 0x0d, 0xfa, 0x0e, 0xe4, 0x55, - 0x3d, 0xed, 0x27, 0xb7, 0xb5, 0xab, 0xfb, 0xb6, 0xfa, 0x6e, 0xff, 0xa7, 0xbb, - 0x0b, 0x1e, 0x36, 0xea, 0x0c, 0xf2, 0xbe, 0x2e, 0x9d, 0x6c, 0xe3, 0x80, 0xa8, - 0xaf, 0x18, 0xe7, 0x5d, 0xa9, 0x22, 0x55, 0x51, 0xfb, 0xef, 0x8b, 0x98, 0x31, - 0x1b, 0x5c, 0x9c, 0x1b, 0x4b, 0x9e, 0xe3, 0x57, 0xfc, 0x6c, 0x59, 0xa4, 0xf3, - 0xad, 0x5a, 0x6f, 0x60, 0x9d, 0xb6, 0x71, 0xd2, 0x8c, 0xbf, 0x70, 0x3f, 0x0d, - 0x14, 0xdc, 0x36, 0x3a, 0xaa, 0xed, 0x70, 0x72, 0x9c, 0x10, 0x7b, 0xbb, 0x6a, - ]), - xfvk: [ - 0x03, 0x0b, 0xdc, 0x2d, 0x2b, 0x03, 0x00, 0x00, 0x80, 0x33, 0xdc, 0x01, 0x2d, - 0x76, 0x90, 0xce, 0xd2, 0xcd, 0x2b, 0xcb, 0x2c, 0xc3, 0xe4, 0x63, 0xe2, 0x8d, - 0x8c, 0x29, 0xef, 0x3b, 0x01, 0xbe, 0x59, 0xb2, 0xbd, 0xfc, 0x38, 0x5b, 0xbd, - 0xc7, 0x4b, 0x9c, 0x6d, 0x85, 0x9a, 0x75, 0x2c, 0x30, 0x5d, 0x62, 0x63, 0xde, - 0x95, 0xf2, 0xfc, 0xf7, 0x34, 0xb1, 0x26, 0xdf, 0x24, 0x56, 0xc7, 0xd3, 0x1b, - 0xc6, 0x01, 0xc8, 0xdd, 0xec, 0x40, 0x91, 0x12, 0xd3, 0xee, 0x41, 0xf8, 0x4b, - 0x5a, 0x95, 0x08, 0xb6, 0x1d, 0x29, 0xb2, 0xfb, 0x45, 0x63, 0x6d, 0x19, 0xaa, - 0x10, 0xd7, 0x82, 0xcd, 0x97, 0x8c, 0xfe, 0x67, 0x15, 0x49, 0x2f, 0xcd, 0x22, - 0x4e, 0x1e, 0x36, 0xea, 0x0c, 0xf2, 0xbe, 0x2e, 0x9d, 0x6c, 0xe3, 0x80, 0xa8, - 0xaf, 0x18, 0xe7, 0x5d, 0xa9, 0x22, 0x55, 0x51, 0xfb, 0xef, 0x8b, 0x98, 0x31, - 0x1b, 0x5c, 0x9c, 0x1b, 0x4b, 0x9e, 0xe3, 0x57, 0xfc, 0x6c, 0x59, 0xa4, 0xf3, - 0xad, 0x5a, 0x6f, 0x60, 0x9d, 0xb6, 0x71, 0xd2, 0x8c, 0xbf, 0x70, 0x3f, 0x0d, - 0x14, 0xdc, 0x36, 0x3a, 0xaa, 0xed, 0x70, 0x72, 0x9c, 0x10, 0x7b, 0xbb, 0x6a, - ], - fp: [ - 0xdf, 0x0a, 0x89, 0xbd, 0x88, 0x35, 0x39, 0xc0, 0x7b, 0x89, 0xe0, 0x4c, 0x92, - 0x76, 0x4e, 0xc2, 0xd1, 0x59, 0x69, 0x0f, 0x5a, 0xd5, 0xdd, 0x3d, 0x0a, 0xd8, - 0xac, 0x29, 0x69, 0xde, 0x22, 0xc8, - ], - d0: None, - d1: None, - d2: None, - dmax: Some([ - 0xb8, 0x31, 0xc2, 0x96, 0x5a, 0x86, 0x0a, 0xd7, 0x60, 0xec, 0x2a, - ]), - internal_nsk: Some([ - 0x9c, 0x39, 0x3c, 0x5b, 0xd7, 0x66, 0x4d, 0x63, 0xef, 0xa1, 0xba, 0xea, 0x99, - 0xfc, 0x6d, 0xc4, 0x74, 0xfe, 0xa7, 0x53, 0xce, 0x84, 0xc8, 0x81, 0xd9, 0xef, - 0x28, 0x77, 0x86, 0x75, 0xb1, 0x05, - ]), - internal_ovk: [ - 0x69, 0xaa, 0xb0, 0x2e, 0xa6, 0x43, 0x57, 0x9d, 0x4d, 0x85, 0x2a, 0xf8, 0xb4, - 0x32, 0xb8, 0x8d, 0x1c, 0xa0, 0x00, 0x44, 0x4a, 0xb0, 0x73, 0x7a, 0x41, 0x15, - 0xe0, 0x63, 0xf1, 0x48, 0xd2, 0x72, - ], - internal_dk: [ - 0x88, 0x26, 0xa9, 0x3c, 0x65, 0xc6, 0x6e, 0x75, 0x54, 0x32, 0x74, 0xe6, 0x72, - 0xad, 0xf5, 0x59, 0xf7, 0xd7, 0x26, 0x5e, 0x99, 0xcc, 0x11, 0xda, 0x4a, 0x14, - 0x20, 0xa3, 0x7b, 0x92, 0xf7, 0xab, - ], - internal_nk: [ - 0x59, 0xba, 0xa9, 0x0f, 0x83, 0x4a, 0x66, 0x1b, 0xf2, 0xbe, 0x42, 0x46, 0xa4, - 0x3d, 0x18, 0x9c, 0x7d, 0x0e, 0x17, 0xa8, 0x24, 0x7b, 0x4f, 0xd9, 0xd2, 0xe1, - 0x53, 0xa5, 0x97, 0x3d, 0xc8, 0xec, - ], - internal_ivk: [ - 0x8a, 0x86, 0xfb, 0x27, 0x81, 0xfe, 0x6f, 0x24, 0xd9, 0x60, 0xdd, 0xdb, 0x2f, - 0x78, 0x13, 0xc0, 0x31, 0xfe, 0xc5, 0x5d, 0x26, 0xcc, 0xde, 0xe1, 0xf7, 0x18, - 0x2a, 0x3e, 0xc6, 0x83, 0xcf, 0x04, - ], - internal_xsk: Some([ - 0x03, 0x0b, 0xdc, 0x2d, 0x2b, 0x03, 0x00, 0x00, 0x80, 0x33, 0xdc, 0x01, 0x2d, - 0x76, 0x90, 0xce, 0xd2, 0xcd, 0x2b, 0xcb, 0x2c, 0xc3, 0xe4, 0x63, 0xe2, 0x8d, - 0x8c, 0x29, 0xef, 0x3b, 0x01, 0xbe, 0x59, 0xb2, 0xbd, 0xfc, 0x38, 0x5b, 0xbd, - 0xc7, 0x4b, 0x45, 0x93, 0xd2, 0x4d, 0x21, 0xe3, 0x59, 0x37, 0xf1, 0x52, 0xcf, - 0x90, 0x46, 0x1c, 0x33, 0x2f, 0x69, 0x50, 0x3c, 0x10, 0x45, 0x81, 0xd6, 0x83, - 0xe0, 0xac, 0x29, 0xf8, 0x4d, 0xec, 0xaf, 0x07, 0x9c, 0x39, 0x3c, 0x5b, 0xd7, - 0x66, 0x4d, 0x63, 0xef, 0xa1, 0xba, 0xea, 0x99, 0xfc, 0x6d, 0xc4, 0x74, 0xfe, - 0xa7, 0x53, 0xce, 0x84, 0xc8, 0x81, 0xd9, 0xef, 0x28, 0x77, 0x86, 0x75, 0xb1, - 0x05, 0x69, 0xaa, 0xb0, 0x2e, 0xa6, 0x43, 0x57, 0x9d, 0x4d, 0x85, 0x2a, 0xf8, - 0xb4, 0x32, 0xb8, 0x8d, 0x1c, 0xa0, 0x00, 0x44, 0x4a, 0xb0, 0x73, 0x7a, 0x41, - 0x15, 0xe0, 0x63, 0xf1, 0x48, 0xd2, 0x72, 0x88, 0x26, 0xa9, 0x3c, 0x65, 0xc6, - 0x6e, 0x75, 0x54, 0x32, 0x74, 0xe6, 0x72, 0xad, 0xf5, 0x59, 0xf7, 0xd7, 0x26, - 0x5e, 0x99, 0xcc, 0x11, 0xda, 0x4a, 0x14, 0x20, 0xa3, 0x7b, 0x92, 0xf7, 0xab, - ]), - internal_xfvk: [ - 0x03, 0x0b, 0xdc, 0x2d, 0x2b, 0x03, 0x00, 0x00, 0x80, 0x33, 0xdc, 0x01, 0x2d, - 0x76, 0x90, 0xce, 0xd2, 0xcd, 0x2b, 0xcb, 0x2c, 0xc3, 0xe4, 0x63, 0xe2, 0x8d, - 0x8c, 0x29, 0xef, 0x3b, 0x01, 0xbe, 0x59, 0xb2, 0xbd, 0xfc, 0x38, 0x5b, 0xbd, - 0xc7, 0x4b, 0x9c, 0x6d, 0x85, 0x9a, 0x75, 0x2c, 0x30, 0x5d, 0x62, 0x63, 0xde, - 0x95, 0xf2, 0xfc, 0xf7, 0x34, 0xb1, 0x26, 0xdf, 0x24, 0x56, 0xc7, 0xd3, 0x1b, - 0xc6, 0x01, 0xc8, 0xdd, 0xec, 0x40, 0x91, 0x12, 0x59, 0xba, 0xa9, 0x0f, 0x83, - 0x4a, 0x66, 0x1b, 0xf2, 0xbe, 0x42, 0x46, 0xa4, 0x3d, 0x18, 0x9c, 0x7d, 0x0e, - 0x17, 0xa8, 0x24, 0x7b, 0x4f, 0xd9, 0xd2, 0xe1, 0x53, 0xa5, 0x97, 0x3d, 0xc8, - 0xec, 0x69, 0xaa, 0xb0, 0x2e, 0xa6, 0x43, 0x57, 0x9d, 0x4d, 0x85, 0x2a, 0xf8, - 0xb4, 0x32, 0xb8, 0x8d, 0x1c, 0xa0, 0x00, 0x44, 0x4a, 0xb0, 0x73, 0x7a, 0x41, - 0x15, 0xe0, 0x63, 0xf1, 0x48, 0xd2, 0x72, 0x88, 0x26, 0xa9, 0x3c, 0x65, 0xc6, - 0x6e, 0x75, 0x54, 0x32, 0x74, 0xe6, 0x72, 0xad, 0xf5, 0x59, 0xf7, 0xd7, 0x26, - 0x5e, 0x99, 0xcc, 0x11, 0xda, 0x4a, 0x14, 0x20, 0xa3, 0x7b, 0x92, 0xf7, 0xab, - ], - internal_fp: [ - 0x3f, 0x63, 0x16, 0x1d, 0x5b, 0x43, 0x72, 0x04, 0xf7, 0x01, 0x2a, 0x3a, 0x1d, - 0x36, 0x58, 0x1d, 0xab, 0x39, 0x7a, 0x84, 0x3b, 0x2c, 0x58, 0x98, 0x11, 0xed, - 0xcc, 0x5b, 0x50, 0x1c, 0xd4, 0xeb, - ], - }, - ]; - - 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, - ]; - - let i1h = ChildIndex::hardened(1); - let i2h = ChildIndex::hardened(2); - let i3h = ChildIndex::hardened(3); - - let m = ExtendedSpendingKey::master(&seed); - let m_1h = m.derive_child(i1h); - let m_1h_2h = ExtendedSpendingKey::from_path(&m, &[i1h, i2h]); - let m_1h_2h_3h = m_1h_2h.derive_child(i3h); - - let xfvks = [ - m.to_extended_full_viewing_key(), - m_1h.to_extended_full_viewing_key(), - m_1h_2h.to_extended_full_viewing_key(), - m_1h_2h_3h.to_extended_full_viewing_key(), - ]; - assert_eq!(test_vectors.len(), xfvks.len()); - - let xsks = [m, m_1h, m_1h_2h, m_1h_2h_3h]; - - for (xsk, tv) in xsks.iter().zip(test_vectors.iter()) { - assert_eq!(xsk.expsk.ask.to_bytes(), tv.ask.unwrap()); - assert_eq!(xsk.expsk.nsk.to_repr().as_ref(), tv.nsk.unwrap()); - - assert_eq!(xsk.expsk.ovk.0, tv.ovk); - assert_eq!(xsk.dk.0, tv.dk); - assert_eq!(xsk.chain_code.as_bytes(), &tv.c); - - let mut ser = vec![]; - xsk.write(&mut ser).unwrap(); - assert_eq!(&ser[..], &tv.xsk.unwrap()[..]); - - let internal_xsk = xsk.derive_internal(); - assert_eq!(internal_xsk.expsk.ask.to_bytes(), tv.ask.unwrap()); - assert_eq!( - internal_xsk.expsk.nsk.to_repr().as_ref(), - tv.internal_nsk.unwrap() - ); - - assert_eq!(internal_xsk.expsk.ovk.0, tv.internal_ovk); - assert_eq!(internal_xsk.dk.0, tv.internal_dk); - assert_eq!(internal_xsk.chain_code.as_bytes(), &tv.c); - - let mut ser = vec![]; - internal_xsk.write(&mut ser).unwrap(); - assert_eq!(&ser[..], &tv.internal_xsk.unwrap()[..]); - } - - for (xfvk, tv) in xfvks.iter().zip(test_vectors.iter()) { - assert_eq!(xfvk.fvk.vk.ak.to_bytes(), tv.ak); - assert_eq!(xfvk.fvk.vk.nk.0.to_bytes(), tv.nk); - - assert_eq!(xfvk.fvk.ovk.0, tv.ovk); - assert_eq!(xfvk.dk.0, tv.dk); - assert_eq!(xfvk.chain_code.as_bytes(), &tv.c); - - assert_eq!(xfvk.fvk.vk.ivk().to_repr().as_ref(), tv.ivk); - - let mut ser = vec![]; - xfvk.write(&mut ser).unwrap(); - assert_eq!(&ser[..], &tv.xfvk[..]); - assert_eq!(FvkFingerprint::from(&xfvk.fvk).0, tv.fp); - - // d0 - let mut di = DiversifierIndex::new(); - match xfvk.dk.find_diversifier(di).unwrap() { - (l, d) if l == di => assert_eq!(d.0, tv.d0.unwrap()), - (_, _) => assert!(tv.d0.is_none()), - } - - // d1 - di.increment().unwrap(); - match xfvk.dk.find_diversifier(di).unwrap() { - (l, d) if l == di => assert_eq!(d.0, tv.d1.unwrap()), - (_, _) => assert!(tv.d1.is_none()), - } - - // d2 - di.increment().unwrap(); - match xfvk.dk.find_diversifier(di).unwrap() { - (l, d) if l == di => assert_eq!(d.0, tv.d2.unwrap()), - (_, _) => assert!(tv.d2.is_none()), - } - - // dmax - let dmax = DiversifierIndex::from([0xff; 11]); - match xfvk.dk.find_diversifier(dmax) { - Some((l, d)) if l == dmax => assert_eq!(d.0, tv.dmax.unwrap()), - Some((_, _)) => panic!(), - None => assert!(tv.dmax.is_none()), - } - - let internal_xfvk = xfvk.derive_internal(); - assert_eq!(internal_xfvk.fvk.vk.ak.to_bytes(), tv.ak); - assert_eq!(internal_xfvk.fvk.vk.nk.0.to_bytes(), tv.internal_nk); - - assert_eq!(internal_xfvk.fvk.ovk.0, tv.internal_ovk); - assert_eq!(internal_xfvk.dk.0, tv.internal_dk); - assert_eq!(internal_xfvk.chain_code.as_bytes(), &tv.c); - - assert_eq!( - internal_xfvk.fvk.vk.ivk().to_repr().as_ref(), - tv.internal_ivk - ); - - let mut ser = vec![]; - internal_xfvk.write(&mut ser).unwrap(); - assert_eq!(&ser[..], &tv.internal_xfvk[..]); - assert_eq!(FvkFingerprint::from(&internal_xfvk.fvk).0, tv.internal_fp); - } - } -} - -#[cfg(any(test, feature = "test-dependencies"))] -pub mod testing { - use proptest::collection::vec; - use proptest::prelude::{any, prop_compose}; - - use super::ExtendedSpendingKey; - - prop_compose! { - pub fn arb_extended_spending_key()(v in vec(any::(), 32..252)) -> ExtendedSpendingKey { - ExtendedSpendingKey::master(&v) - } - } -} diff --git a/zcash_primitives/src/test_vectors.rs b/zcash_primitives/src/test_vectors.rs deleted file mode 100644 index 403fbc962..000000000 --- a/zcash_primitives/src/test_vectors.rs +++ /dev/null @@ -1 +0,0 @@ -pub(crate) mod note_encryption; diff --git a/zcash_primitives/src/test_vectors/note_encryption.rs b/zcash_primitives/src/test_vectors/note_encryption.rs deleted file mode 100644 index 09209f29a..000000000 --- a/zcash_primitives/src/test_vectors/note_encryption.rs +++ /dev/null @@ -1,2046 +0,0 @@ -pub(crate) struct TestVector { - pub ovk: [u8; 32], - pub ivk: [u8; 32], - pub default_d: [u8; 11], - pub default_pk_d: [u8; 32], - pub v: u64, - pub rcm: [u8; 32], - pub memo: [u8; 512], - pub cv: [u8; 32], - pub cmu: [u8; 32], - pub esk: [u8; 32], - pub epk: [u8; 32], - pub shared_secret: [u8; 32], - pub k_enc: [u8; 32], - pub _p_enc: [u8; 564], - pub c_enc: [u8; 580], - pub ock: [u8; 32], - pub _op: [u8; 64], - pub c_out: [u8; 80], -} - -pub(crate) fn make_test_vectors() -> Vec { - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/sapling_note_encryption.py - vec![ - TestVector { - ovk: [ - 0x98, 0xd1, 0x69, 0x13, 0xd9, 0x9b, 0x04, 0x17, 0x7c, 0xab, 0xa4, 0x4f, 0x6e, 0x4d, - 0x22, 0x4e, 0x03, 0xb5, 0xac, 0x03, 0x1d, 0x7c, 0xe4, 0x5e, 0x86, 0x51, 0x38, 0xe1, - 0xb9, 0x96, 0xd6, 0x3b, - ], - ivk: [ - 0xb7, 0x0b, 0x7c, 0xd0, 0xed, 0x03, 0xcb, 0xdf, 0xd7, 0xad, 0xa9, 0x50, 0x2e, 0xe2, - 0x45, 0xb1, 0x3e, 0x56, 0x9d, 0x54, 0xa5, 0x71, 0x9d, 0x2d, 0xaa, 0x0f, 0x5f, 0x14, - 0x51, 0x47, 0x92, 0x04, - ], - default_d: [ - 0xf1, 0x9d, 0x9b, 0x79, 0x7e, 0x39, 0xf3, 0x37, 0x44, 0x58, 0x39, - ], - default_pk_d: [ - 0xdb, 0x4c, 0xd2, 0xb0, 0xaa, 0xc4, 0xf7, 0xeb, 0x8c, 0xa1, 0x31, 0xf1, 0x65, 0x67, - 0xc4, 0x45, 0xa9, 0x55, 0x51, 0x26, 0xd3, 0xc2, 0x9f, 0x14, 0xe3, 0xd7, 0x76, 0xe8, - 0x41, 0xae, 0x74, 0x15, - ], - v: 100000000, - rcm: [ - 0x39, 0x17, 0x6d, 0xac, 0x39, 0xac, 0xe4, 0x98, 0x0e, 0xcc, 0x8d, 0x77, 0x8e, 0x89, - 0x86, 0x02, 0x55, 0xec, 0x36, 0x15, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - memo: [ - 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - cv: [ - 0xa9, 0xcb, 0x0d, 0x13, 0x72, 0x32, 0xff, 0x84, 0x48, 0xd0, 0xf0, 0x78, 0xb6, 0x81, - 0x4c, 0x66, 0xcb, 0x33, 0x1b, 0x0f, 0x2d, 0x3d, 0x8a, 0x08, 0x5b, 0xed, 0xba, 0x81, - 0x5f, 0x00, 0xa8, 0xdb, - ], - cmu: [ - 0x63, 0x55, 0x72, 0xf5, 0x72, 0xa8, 0xa1, 0xa0, 0xb7, 0xac, 0xbc, 0x0a, 0xfc, 0x6d, - 0x66, 0xf1, 0x4a, 0x02, 0xef, 0xac, 0xde, 0x7b, 0xdf, 0x03, 0x44, 0x3e, 0xd4, 0xc3, - 0xe5, 0x51, 0xd4, 0x70, - ], - esk: [ - 0x81, 0xc7, 0xb2, 0x17, 0x1f, 0xf4, 0x41, 0x52, 0x50, 0xca, 0xc0, 0x1f, 0x59, 0x82, - 0xfd, 0x8f, 0x49, 0x61, 0x9d, 0x61, 0xad, 0x78, 0xf6, 0x83, 0x0b, 0x3c, 0x60, 0x61, - 0x45, 0x96, 0x2a, 0x0e, - ], - epk: [ - 0xde, 0xd6, 0x8f, 0x05, 0xc6, 0x58, 0xfc, 0xae, 0x5a, 0xe2, 0x18, 0x64, 0x6f, 0xf8, - 0x44, 0x40, 0x6f, 0x84, 0x42, 0x67, 0x84, 0x04, 0x0d, 0x0b, 0xef, 0x2b, 0x09, 0xcb, - 0x38, 0x48, 0xc4, 0xdc, - ], - shared_secret: [ - 0x67, 0xf9, 0x61, 0x34, 0x04, 0xd9, 0xe9, 0x27, 0x1f, 0x16, 0x74, 0x01, 0x1b, 0x03, - 0x9b, 0x3d, 0x43, 0x81, 0xa4, 0xd7, 0x0c, 0x58, 0x6c, 0x8a, 0x13, 0x42, 0x28, 0x3f, - 0xd5, 0xfc, 0x3a, 0xde, - ], - k_enc: [ - 0xe5, 0xbf, 0x8a, 0xb2, 0xf9, 0x41, 0xe9, 0xb9, 0xd2, 0xc7, 0x4a, 0xce, 0x2d, 0xf6, - 0xb3, 0x3c, 0x3c, 0x32, 0x29, 0xfa, 0x0b, 0x91, 0x26, 0xf9, 0xdd, 0xdb, 0x43, 0x29, - 0x66, 0x10, 0x00, 0x69, - ], - _p_enc: [ - 0x01, 0xf1, 0x9d, 0x9b, 0x79, 0x7e, 0x39, 0xf3, 0x37, 0x44, 0x58, 0x39, 0x00, 0xe1, - 0xf5, 0x05, 0x00, 0x00, 0x00, 0x00, 0x39, 0x17, 0x6d, 0xac, 0x39, 0xac, 0xe4, 0x98, - 0x0e, 0xcc, 0x8d, 0x77, 0x8e, 0x89, 0x86, 0x02, 0x55, 0xec, 0x36, 0x15, 0x06, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - c_enc: [ - 0x8d, 0x6b, 0x27, 0xe7, 0xef, 0xf5, 0x9b, 0xfb, 0xa0, 0x1d, 0x65, 0x88, 0xba, 0xdd, - 0x36, 0x6c, 0xe5, 0x9b, 0x4d, 0x5b, 0x0e, 0xf9, 0x3b, 0xeb, 0xcb, 0xf2, 0x11, 0x41, - 0x7c, 0x56, 0xae, 0x70, 0x0a, 0xe1, 0x82, 0x44, 0xba, 0xc2, 0xfb, 0x64, 0x37, 0xdb, - 0x01, 0xf8, 0x3d, 0xc1, 0x49, 0xe2, 0x78, 0x6e, 0xc4, 0xec, 0x32, 0xc1, 0x1b, 0x05, - 0x4a, 0x4c, 0x0e, 0x2b, 0xdb, 0xe3, 0x43, 0x78, 0x8b, 0xb9, 0xc3, 0x3f, 0xf4, 0x2f, - 0xae, 0x99, 0x32, 0x32, 0x13, 0xe0, 0x96, 0x3e, 0x6f, 0x97, 0x6d, 0x6f, 0xff, 0xb8, - 0xc9, 0xfc, 0xf5, 0x21, 0x95, 0x74, 0xc7, 0xa9, 0x4c, 0x0e, 0x72, 0xf6, 0x09, 0x3a, - 0xed, 0xaf, 0xe3, 0x80, 0x62, 0x1b, 0x3b, 0xa8, 0x15, 0xd2, 0xb9, 0x72, 0x40, 0xf6, - 0x77, 0xd3, 0x90, 0xf5, 0xfc, 0x5d, 0x45, 0xee, 0xff, 0x16, 0x68, 0x8e, 0x40, 0xb9, - 0xee, 0xe8, 0xee, 0x1d, 0x39, 0x3b, 0x00, 0x97, 0x50, 0xcb, 0x73, 0xdf, 0x7a, 0x47, - 0xfd, 0x07, 0xa2, 0x81, 0x41, 0xdb, 0x49, 0xbd, 0x9c, 0xca, 0xb1, 0xf1, 0x8d, 0x0b, - 0x6a, 0x55, 0xed, 0x10, 0x1c, 0xa1, 0x6f, 0x73, 0x45, 0xbc, 0xb0, 0xbe, 0xaf, 0x7c, - 0xd7, 0x9a, 0x3d, 0x2b, 0xf2, 0x88, 0xf1, 0xd8, 0x8e, 0xbb, 0x1e, 0x4b, 0x74, 0x21, - 0x99, 0xd3, 0x30, 0xc3, 0x0a, 0x9f, 0xee, 0x1b, 0x44, 0xc6, 0x86, 0xa1, 0xff, 0x5c, - 0xc3, 0x3d, 0x46, 0x27, 0xf8, 0x3d, 0x61, 0xce, 0x34, 0xd6, 0xf1, 0x34, 0x4e, 0x2b, - 0x11, 0xa5, 0xf7, 0x17, 0x24, 0x42, 0x29, 0x60, 0x75, 0x91, 0x90, 0x05, 0x43, 0x4a, - 0x57, 0x4e, 0xd4, 0xe4, 0xc9, 0x8e, 0x23, 0x8e, 0xdd, 0x53, 0x67, 0xe8, 0xf5, 0x75, - 0x24, 0xb6, 0x38, 0xdd, 0x2d, 0x58, 0x30, 0xe8, 0x3f, 0x7f, 0x32, 0x08, 0x0d, 0x2d, - 0x51, 0xa0, 0x8a, 0xe8, 0x4e, 0x37, 0x42, 0x9c, 0x84, 0x38, 0xfa, 0xae, 0x15, 0x40, - 0x86, 0x7b, 0x12, 0xac, 0x2c, 0xf6, 0xa7, 0x7d, 0xa7, 0x80, 0xd9, 0x2c, 0xfa, 0x50, - 0x0c, 0x19, 0x5a, 0x07, 0x1c, 0xe8, 0xae, 0x3f, 0x10, 0x2c, 0xe0, 0x95, 0x01, 0xec, - 0xda, 0xc0, 0x8a, 0x79, 0x52, 0xa0, 0x8d, 0x53, 0xf3, 0x62, 0xd3, 0x7b, 0x64, 0x94, - 0x8c, 0x99, 0x15, 0xcb, 0xfc, 0x9f, 0x2d, 0x3c, 0x4e, 0x82, 0x22, 0xd3, 0x9a, 0x34, - 0x84, 0x21, 0x44, 0x7f, 0xab, 0xe4, 0xd5, 0xf0, 0x87, 0x80, 0x9a, 0x79, 0xe8, 0x49, - 0xb2, 0x8d, 0xff, 0xbc, 0x97, 0xfb, 0xbf, 0x64, 0x7f, 0xf3, 0x4f, 0x79, 0xff, 0x64, - 0xe7, 0x37, 0xeb, 0xf0, 0x3d, 0x8a, 0xdd, 0x44, 0xc1, 0x54, 0x32, 0x5f, 0x2b, 0xff, - 0x14, 0xc6, 0xe9, 0xe9, 0x0b, 0x0f, 0x98, 0x89, 0xf3, 0x25, 0xa9, 0x26, 0xa3, 0x68, - 0x56, 0x41, 0xa7, 0xa2, 0x19, 0xec, 0xe6, 0xfb, 0x2b, 0x4d, 0xee, 0xbf, 0x31, 0x09, - 0xd7, 0xee, 0x0f, 0x03, 0x9d, 0xac, 0x42, 0x74, 0x44, 0x99, 0x34, 0x85, 0x84, 0x84, - 0x44, 0xcc, 0xaf, 0xda, 0x5e, 0xa3, 0x28, 0x74, 0x06, 0x66, 0xdd, 0x75, 0xc3, 0x23, - 0xce, 0x7b, 0x92, 0x0e, 0xe0, 0xf3, 0xdc, 0x3a, 0xbc, 0xe6, 0xbd, 0x09, 0xc1, 0x3c, - 0x95, 0x7c, 0x5e, 0xa8, 0x95, 0x28, 0x27, 0x11, 0x6b, 0xb5, 0xbd, 0x0e, 0x5c, 0x27, - 0xf8, 0x20, 0xf2, 0xcf, 0x72, 0xa5, 0x10, 0x5d, 0x95, 0x55, 0xbe, 0x1e, 0x1e, 0x5e, - 0x68, 0xff, 0xfb, 0x71, 0x33, 0xdc, 0x39, 0x00, 0x19, 0x4e, 0x3b, 0x73, 0x1c, 0x7d, - 0x39, 0x11, 0x70, 0xad, 0x6d, 0x4a, 0xf1, 0x3a, 0x78, 0xa0, 0x6c, 0x25, 0xcf, 0xbb, - 0x0d, 0x09, 0x91, 0xd5, 0xa8, 0x83, 0xcf, 0xf5, 0x1c, 0xb6, 0xf5, 0x91, 0xc7, 0x92, - 0xd9, 0x9d, 0xcc, 0x55, 0x9c, 0xde, 0x9b, 0x7b, 0x39, 0xc4, 0xf5, 0x4a, 0x6b, 0xfb, - 0x29, 0xf1, 0xf8, 0x5e, 0x13, 0x5d, 0x17, 0x33, 0xb4, 0x9d, 0x5d, 0xd6, 0x70, 0x18, - 0xe6, 0x2e, 0x8c, 0x1a, 0xb0, 0xc1, 0x9a, 0x25, 0x41, 0x87, 0x26, 0xcc, 0xf2, 0xf5, - 0xe8, 0x8b, 0x97, 0x69, 0x21, 0x12, 0x92, 0x4b, 0xda, 0x2f, 0xde, 0x73, 0x48, 0xba, - 0xd7, 0x29, 0x52, 0x41, 0x72, 0x9d, 0xb4, 0xf3, 0x87, 0x11, 0xc7, 0xea, 0x98, 0xc5, - 0xd4, 0x19, 0x7c, 0x66, 0xfd, 0x23, - ], - ock: [ - 0x6c, 0xe6, 0x1e, 0xad, 0x78, 0x49, 0x20, 0x42, 0x93, 0x34, 0x9e, 0x83, 0x2e, 0x95, - 0xca, 0x3a, 0xc6, 0x42, 0x2e, 0xc4, 0xfe, 0x21, 0xe5, 0xd1, 0x53, 0x86, 0x55, 0x8e, - 0x4d, 0x37, 0x79, 0x6d, - ], - _op: [ - 0xdb, 0x4c, 0xd2, 0xb0, 0xaa, 0xc4, 0xf7, 0xeb, 0x8c, 0xa1, 0x31, 0xf1, 0x65, 0x67, - 0xc4, 0x45, 0xa9, 0x55, 0x51, 0x26, 0xd3, 0xc2, 0x9f, 0x14, 0xe3, 0xd7, 0x76, 0xe8, - 0x41, 0xae, 0x74, 0x15, 0x81, 0xc7, 0xb2, 0x17, 0x1f, 0xf4, 0x41, 0x52, 0x50, 0xca, - 0xc0, 0x1f, 0x59, 0x82, 0xfd, 0x8f, 0x49, 0x61, 0x9d, 0x61, 0xad, 0x78, 0xf6, 0x83, - 0x0b, 0x3c, 0x60, 0x61, 0x45, 0x96, 0x2a, 0x0e, - ], - c_out: [ - 0x0e, 0xb2, 0xb0, 0x1b, 0xe8, 0x88, 0x0f, 0xc0, 0x46, 0x98, 0x42, 0x27, 0x14, 0x18, - 0xb5, 0x2b, 0xad, 0x40, 0x19, 0x89, 0x2c, 0xde, 0x53, 0xee, 0xca, 0xcd, 0xb2, 0xe4, - 0x5f, 0x5f, 0x33, 0x75, 0x85, 0xf7, 0xf6, 0x17, 0x5d, 0x88, 0x8f, 0x6e, 0x2c, 0x4e, - 0xd1, 0x35, 0x71, 0xcd, 0x96, 0xfd, 0x17, 0x7a, 0x01, 0xab, 0x10, 0x19, 0x08, 0xd7, - 0xca, 0x4a, 0x6d, 0x81, 0xd9, 0x16, 0x62, 0x2f, 0x5f, 0xf0, 0x77, 0xb1, 0x3f, 0x34, - 0x55, 0x90, 0xe2, 0x27, 0xc1, 0x0e, 0x08, 0x95, 0xe2, 0x04, - ], - }, - TestVector { - ovk: [ - 0x3b, 0x94, 0x62, 0x10, 0xce, 0x6d, 0x1b, 0x16, 0x92, 0xd7, 0x39, 0x2a, 0xc8, 0x4a, - 0x8b, 0xc8, 0xf0, 0x3b, 0x72, 0x72, 0x3c, 0x7d, 0x36, 0x72, 0x1b, 0x80, 0x9a, 0x79, - 0xc9, 0xd6, 0xe4, 0x5b, - ], - ivk: [ - 0xc5, 0x18, 0x38, 0x44, 0x66, 0xb2, 0x69, 0x88, 0xb5, 0x10, 0x90, 0x67, 0x41, 0x8d, - 0x19, 0x2d, 0x9d, 0x6b, 0xd0, 0xd9, 0x23, 0x22, 0x05, 0xd7, 0x74, 0x18, 0xc2, 0x40, - 0xfc, 0x68, 0xa4, 0x06, - ], - default_d: [ - 0xae, 0xf1, 0x80, 0xf6, 0xe3, 0x4e, 0x35, 0x4b, 0x88, 0x8f, 0x81, - ], - default_pk_d: [ - 0xa6, 0xb1, 0x3e, 0xa3, 0x36, 0xdd, 0xb7, 0xa6, 0x7b, 0xb0, 0x9a, 0x0e, 0x68, 0xe9, - 0xd3, 0xcf, 0xb3, 0x92, 0x10, 0x83, 0x1e, 0xa3, 0xa2, 0x96, 0xba, 0x09, 0xa9, 0x22, - 0x06, 0x0f, 0xd3, 0x8b, - ], - v: 200000000, - rcm: [ - 0x47, 0x8b, 0xa0, 0xee, 0x6e, 0x1a, 0x75, 0xb6, 0x00, 0x03, 0x6f, 0x26, 0xf1, 0x8b, - 0x70, 0x15, 0xab, 0x55, 0x6b, 0xed, 0xdf, 0x8b, 0x96, 0x02, 0x38, 0x86, 0x9f, 0x89, - 0xdd, 0x80, 0x4e, 0x06, - ], - memo: [ - 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - cv: [ - 0xfc, 0x54, 0x31, 0x9a, 0x39, 0xbe, 0x49, 0xc0, 0x48, 0x0c, 0x4d, 0xf3, 0x3b, 0x8f, - 0x77, 0xca, 0x67, 0x3a, 0x42, 0xbf, 0xde, 0xdf, 0xb8, 0x0e, 0xe4, 0x6b, 0x8f, 0x70, - 0xfc, 0x0d, 0xcd, 0x3d, - ], - cmu: [ - 0x0c, 0x87, 0x41, 0x75, 0x77, 0x48, 0x0b, 0x69, 0x77, 0xba, 0x92, 0xc5, 0x54, 0x25, - 0xd6, 0x2b, 0x03, 0xb1, 0xe5, 0xf3, 0xc3, 0x82, 0x9c, 0xac, 0x49, 0xbf, 0xe5, 0x15, - 0xae, 0x72, 0x29, 0x45, - ], - esk: [ - 0xad, 0x4a, 0xd6, 0x24, 0x77, 0xc2, 0xc8, 0x83, 0xc8, 0xba, 0xbf, 0xed, 0x5d, 0x38, - 0x5b, 0x51, 0xab, 0xdc, 0xc6, 0x98, 0xe9, 0x36, 0xe7, 0x8d, 0xc2, 0x26, 0x71, 0x72, - 0x91, 0x55, 0x62, 0x0b, - ], - epk: [ - 0xf0, 0x6c, 0xba, 0xf8, 0xcb, 0x5c, 0x84, 0x82, 0x38, 0x47, 0xa1, 0x20, 0x10, 0x4c, - 0x85, 0xad, 0x70, 0x72, 0x28, 0xad, 0xba, 0x87, 0x6c, 0x6d, 0x83, 0x7e, 0xfd, 0x41, - 0x4e, 0x1c, 0x1d, 0xb4, - ], - shared_secret: [ - 0xb9, 0x8a, 0x2c, 0x3b, 0xf0, 0xdc, 0x56, 0xb2, 0xbf, 0x65, 0xf5, 0xbd, 0x15, 0x25, - 0x05, 0x5e, 0xed, 0x22, 0xac, 0x0d, 0xcc, 0x2c, 0x11, 0xe3, 0x00, 0xc4, 0x67, 0x80, - 0x2b, 0x85, 0x88, 0x97, - ], - k_enc: [ - 0xb2, 0xef, 0x45, 0xb0, 0xf7, 0x25, 0x36, 0xa6, 0xc0, 0x22, 0xdd, 0xce, 0xe6, 0x2e, - 0xa7, 0x02, 0x7a, 0x49, 0x36, 0x2a, 0xa2, 0xdd, 0x3b, 0x54, 0x36, 0xd8, 0x89, 0x75, - 0xe0, 0x2a, 0xd0, 0xca, - ], - _p_enc: [ - 0x01, 0xae, 0xf1, 0x80, 0xf6, 0xe3, 0x4e, 0x35, 0x4b, 0x88, 0x8f, 0x81, 0x00, 0xc2, - 0xeb, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x47, 0x8b, 0xa0, 0xee, 0x6e, 0x1a, 0x75, 0xb6, - 0x00, 0x03, 0x6f, 0x26, 0xf1, 0x8b, 0x70, 0x15, 0xab, 0x55, 0x6b, 0xed, 0xdf, 0x8b, - 0x96, 0x02, 0x38, 0x86, 0x9f, 0x89, 0xdd, 0x80, 0x4e, 0x06, 0xf6, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - c_enc: [ - 0x8a, 0x3f, 0x60, 0x25, 0x2f, 0x4d, 0xf9, 0x96, 0x39, 0x2e, 0x55, 0xaf, 0xee, 0x07, - 0x22, 0xf1, 0x24, 0xb1, 0xa1, 0x34, 0xe8, 0xa1, 0xfb, 0x1e, 0xaa, 0x88, 0x88, 0x9e, - 0x6a, 0xd4, 0x89, 0xcf, 0x1b, 0xa9, 0x12, 0x55, 0xee, 0x56, 0xfa, 0x1a, 0x09, 0xdb, - 0x71, 0x56, 0xc3, 0x55, 0x1a, 0xed, 0x29, 0x69, 0xa6, 0xff, 0x37, 0xf2, 0xa7, 0x7a, - 0x60, 0xb3, 0xea, 0x43, 0x75, 0xfa, 0xff, 0x04, 0x9e, 0x85, 0xc2, 0x72, 0x21, 0xcc, - 0x2b, 0xa9, 0x89, 0xbd, 0x18, 0xff, 0x96, 0x98, 0x00, 0x0a, 0xf1, 0xa7, 0x64, 0x3f, - 0x87, 0x85, 0xd6, 0x5e, 0xbb, 0x04, 0xc8, 0x5b, 0x24, 0x75, 0xdf, 0x62, 0x5b, 0x47, - 0xe3, 0xe9, 0xc7, 0xac, 0xa8, 0x4c, 0x13, 0x17, 0x23, 0x77, 0x6b, 0xd8, 0xc2, 0x9f, - 0x9d, 0x1f, 0x5f, 0xd2, 0x57, 0xe5, 0x8f, 0x72, 0xb6, 0x04, 0xf9, 0xb5, 0x7b, 0x1c, - 0x2d, 0x05, 0x31, 0xeb, 0xbb, 0x19, 0xcf, 0xc2, 0x73, 0x68, 0x89, 0x0d, 0x25, 0x6e, - 0x9a, 0xba, 0x30, 0x8d, 0xb9, 0xd8, 0x85, 0x6f, 0x49, 0xd4, 0x66, 0x3a, 0xfe, 0x55, - 0x50, 0x72, 0xed, 0x64, 0xc8, 0x19, 0x8e, 0x6a, 0xd1, 0x5c, 0x0c, 0x43, 0xbb, 0x16, - 0x85, 0x49, 0xa5, 0xbe, 0x38, 0xc5, 0xb4, 0x6d, 0xc1, 0x2f, 0x0c, 0x2a, 0x96, 0x1f, - 0xf3, 0xcf, 0xe3, 0x2a, 0x1c, 0x3e, 0xfe, 0x80, 0xb1, 0x5e, 0x37, 0xe4, 0xce, 0xbe, - 0x2a, 0x7a, 0xbe, 0x03, 0xeb, 0x17, 0xf4, 0xbb, 0xad, 0x22, 0x31, 0xcb, 0x52, 0x55, - 0xe2, 0x9c, 0xd0, 0x3c, 0xb9, 0x61, 0x33, 0x2c, 0xf5, 0xe5, 0x5e, 0x60, 0x53, 0xcd, - 0x40, 0x65, 0xc3, 0x78, 0x56, 0x06, 0xb2, 0x18, 0x5f, 0x18, 0xc4, 0xa3, 0xa2, 0x26, - 0x23, 0xd2, 0x59, 0xcd, 0x20, 0xdb, 0xe1, 0x54, 0xc4, 0xaf, 0x6b, 0x2b, 0xdc, 0xf3, - 0xb9, 0xc0, 0xff, 0x13, 0xce, 0x27, 0xe3, 0x95, 0x05, 0xa9, 0xf1, 0xb8, 0x2f, 0x6f, - 0xce, 0xea, 0xc0, 0x95, 0x38, 0x47, 0x17, 0xe8, 0x97, 0x0e, 0xe0, 0x29, 0xde, 0x96, - 0x4e, 0x80, 0x4a, 0xbd, 0x32, 0xd4, 0xda, 0x93, 0xbb, 0x8d, 0xc2, 0xb6, 0xbd, 0x60, - 0x44, 0xd8, 0xdf, 0xd7, 0x9d, 0xf7, 0x20, 0x7e, 0xa0, 0x3b, 0xdf, 0x03, 0x6f, 0xa6, - 0x26, 0x3f, 0x21, 0xbc, 0x1b, 0xfd, 0x4a, 0x6d, 0x9c, 0xb5, 0xf2, 0xd8, 0xbb, 0x6e, - 0x74, 0xb6, 0xdd, 0x04, 0x7a, 0xe1, 0xaa, 0xb8, 0xc1, 0xa7, 0x23, 0xb4, 0x78, 0x7c, - 0x54, 0xe2, 0x53, 0x96, 0x7f, 0xa9, 0x44, 0x0b, 0x73, 0x61, 0x83, 0x50, 0x65, 0x74, - 0x35, 0x03, 0x55, 0x26, 0x9b, 0x2b, 0x66, 0xb7, 0x48, 0xe8, 0x8f, 0xe9, 0xb8, 0xd1, - 0x23, 0xe9, 0x4b, 0x5f, 0xa5, 0xd0, 0x72, 0xb8, 0xc3, 0x96, 0x52, 0xe9, 0x20, 0x2b, - 0x16, 0xf1, 0x65, 0x46, 0x0e, 0x4b, 0x97, 0x0f, 0x63, 0xee, 0x7d, 0x63, 0x8f, 0x48, - 0xe4, 0x90, 0x17, 0xea, 0x64, 0x1c, 0xd3, 0x70, 0x09, 0xd4, 0x4b, 0x77, 0x24, 0x18, - 0x25, 0x44, 0xdb, 0x92, 0xbd, 0x0c, 0x4a, 0x7e, 0x9d, 0x93, 0x93, 0xd4, 0x6f, 0xcb, - 0x7b, 0xdd, 0xf9, 0x6f, 0x02, 0xcb, 0xf4, 0x7f, 0xa0, 0xf5, 0x28, 0x04, 0x09, 0x8e, - 0xcb, 0xbb, 0x7a, 0x13, 0xf3, 0xa2, 0xa5, 0xf1, 0x63, 0x8e, 0x77, 0xf8, 0xa8, 0x2f, - 0x6c, 0x3d, 0xec, 0xb7, 0x60, 0x7f, 0x09, 0x51, 0xc5, 0x7c, 0x7f, 0x27, 0x76, 0x04, - 0x22, 0x14, 0xf9, 0x0a, 0x3b, 0x6e, 0x00, 0xed, 0x16, 0x05, 0x9d, 0xff, 0x45, 0x55, - 0xbd, 0x47, 0x1d, 0x78, 0xaf, 0xe7, 0xaa, 0x3d, 0xc7, 0x91, 0x41, 0xa0, 0x87, 0x2d, - 0x19, 0xc8, 0x1c, 0x35, 0x1c, 0xaf, 0x54, 0xa2, 0xfc, 0x6d, 0xe8, 0xfd, 0x76, 0x86, - 0xc4, 0xf2, 0xc5, 0x34, 0xef, 0xac, 0x77, 0x51, 0x5e, 0x30, 0xf2, 0x50, 0x7b, 0xa0, - 0xb2, 0x3b, 0x1e, 0xe3, 0x7c, 0xa9, 0x08, 0x94, 0x3d, 0xfe, 0xf3, 0x80, 0x9a, 0x7e, - 0x9b, 0xec, 0xf1, 0xb9, 0x69, 0x10, 0x49, 0xf7, 0x87, 0x6a, 0x59, 0x2e, 0xe7, 0xed, - 0x64, 0x74, 0x0f, 0x1b, 0xe7, 0xe3, 0x06, 0x6e, 0xf7, 0x6f, 0x81, 0x47, 0x0f, 0x43, - 0x54, 0x33, 0x1a, 0xa1, 0xbc, 0x49, 0x57, 0x96, 0x99, 0x69, 0x77, 0x82, 0xbb, 0x07, - 0x5c, 0xbf, 0x82, 0xd3, 0xa8, 0xc0, - ], - ock: [ - 0x6f, 0xce, 0x27, 0xbf, 0x1a, 0x62, 0xf0, 0x78, 0xe7, 0xe3, 0xcb, 0x5d, 0x8b, 0xf2, - 0x4c, 0xa7, 0xe4, 0xa5, 0x82, 0x1d, 0x45, 0x5f, 0x0f, 0xa8, 0x2c, 0xd5, 0x44, 0xec, - 0xb4, 0x20, 0x91, 0xfa, - ], - _op: [ - 0xa6, 0xb1, 0x3e, 0xa3, 0x36, 0xdd, 0xb7, 0xa6, 0x7b, 0xb0, 0x9a, 0x0e, 0x68, 0xe9, - 0xd3, 0xcf, 0xb3, 0x92, 0x10, 0x83, 0x1e, 0xa3, 0xa2, 0x96, 0xba, 0x09, 0xa9, 0x22, - 0x06, 0x0f, 0xd3, 0x8b, 0xad, 0x4a, 0xd6, 0x24, 0x77, 0xc2, 0xc8, 0x83, 0xc8, 0xba, - 0xbf, 0xed, 0x5d, 0x38, 0x5b, 0x51, 0xab, 0xdc, 0xc6, 0x98, 0xe9, 0x36, 0xe7, 0x8d, - 0xc2, 0x26, 0x71, 0x72, 0x91, 0x55, 0x62, 0x0b, - ], - c_out: [ - 0x88, 0x24, 0x58, 0x30, 0x2c, 0x0a, 0xba, 0x55, 0xed, 0x8d, 0x67, 0x18, 0xca, 0x26, - 0xd8, 0xc2, 0x8a, 0x12, 0x7a, 0x01, 0xe7, 0x7c, 0x2a, 0xe5, 0xbf, 0x15, 0xc6, 0x96, - 0x73, 0x91, 0x81, 0x77, 0xf9, 0x24, 0x77, 0xa2, 0x18, 0xa7, 0xf6, 0xcf, 0x12, 0x17, - 0x80, 0x22, 0xc9, 0xdd, 0xc7, 0x18, 0x5c, 0x18, 0xd0, 0x87, 0x6c, 0x3c, 0x29, 0x65, - 0x83, 0xe0, 0xbc, 0x54, 0x79, 0x3b, 0xf1, 0xe2, 0x6a, 0x85, 0x4a, 0x41, 0xab, 0x61, - 0x7f, 0x20, 0x52, 0x71, 0xba, 0x6c, 0x14, 0x29, 0xbd, 0xf4, - ], - }, - TestVector { - ovk: [ - 0x8b, 0xf4, 0x39, 0x0e, 0x28, 0xdd, 0xc9, 0x5b, 0x83, 0x02, 0xc3, 0x81, 0xd5, 0x81, - 0x0b, 0x84, 0xba, 0x8e, 0x60, 0x96, 0xe5, 0xa7, 0x68, 0x22, 0x77, 0x4f, 0xd4, 0x9f, - 0x49, 0x1e, 0x8f, 0x49, - ], - ivk: [ - 0x47, 0x1c, 0x24, 0xa3, 0xdc, 0x87, 0x30, 0xe7, 0x50, 0x36, 0xc0, 0xa9, 0x5f, 0x3e, - 0x2f, 0x7d, 0xd1, 0xbe, 0x6f, 0xb9, 0x3a, 0xd2, 0x95, 0x92, 0x20, 0x3d, 0xef, 0x30, - 0x41, 0x95, 0x45, 0x05, - ], - default_d: [ - 0x75, 0x99, 0xf0, 0xbf, 0x9b, 0x57, 0xcd, 0x2d, 0xc2, 0x99, 0xb6, - ], - default_pk_d: [ - 0x66, 0x14, 0x17, 0x39, 0x51, 0x4b, 0x28, 0xf0, 0x5d, 0xef, 0x8a, 0x18, 0xee, 0xee, - 0x5e, 0xed, 0x4d, 0x44, 0xc6, 0x22, 0x5c, 0x3c, 0x65, 0xd8, 0x8d, 0xd9, 0x90, 0x77, - 0x08, 0x01, 0x2f, 0x5a, - ], - v: 300000000, - rcm: [ - 0x14, 0x7c, 0xf2, 0xb5, 0x1b, 0x4c, 0x7c, 0x63, 0xcb, 0x77, 0xb9, 0x9e, 0x8b, 0x78, - 0x3e, 0x5b, 0x51, 0x11, 0xdb, 0x0a, 0x7c, 0xa0, 0x4d, 0x6c, 0x01, 0x4a, 0x1d, 0x7d, - 0xa8, 0x3b, 0xae, 0x0a, - ], - memo: [ - 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - cv: [ - 0x5c, 0xc9, 0xea, 0x16, 0x8e, 0x79, 0xff, 0x0d, 0x08, 0x3a, 0xf4, 0x21, 0xd3, 0x2d, - 0x27, 0xfb, 0xa1, 0xc8, 0xa6, 0x38, 0xc0, 0xc3, 0x52, 0xcf, 0x59, 0xdc, 0xb1, 0xca, - 0x84, 0xc3, 0xfb, 0x1b, - ], - cmu: [ - 0xb3, 0xb4, 0xe7, 0xab, 0x08, 0x0b, 0x9b, 0x0f, 0xe4, 0x73, 0xcf, 0xc5, 0xa3, 0x10, - 0x5e, 0x9a, 0x06, 0x2a, 0x4e, 0xe4, 0x9e, 0xdd, 0x70, 0x95, 0xa6, 0x71, 0x63, 0x7e, - 0x00, 0x57, 0x24, 0x2b, - ], - esk: [ - 0x99, 0xaa, 0x10, 0xc0, 0x57, 0x88, 0x08, 0x1c, 0x0d, 0xa7, 0xd8, 0x79, 0xcd, 0x95, - 0x43, 0xec, 0x18, 0x92, 0x15, 0x72, 0x92, 0x40, 0x2e, 0x96, 0x0b, 0x06, 0x99, 0x5a, - 0x08, 0x96, 0x4c, 0x03, - ], - epk: [ - 0x6a, 0x92, 0x02, 0x60, 0x43, 0xfa, 0x93, 0x0e, 0xeb, 0x2b, 0x28, 0xfd, 0x7b, 0xbd, - 0xc5, 0xa7, 0x05, 0x00, 0xbe, 0xb8, 0x4c, 0x67, 0x11, 0x36, 0x23, 0x8e, 0x5e, 0xfd, - 0xb0, 0x17, 0xd9, 0x9c, - ], - shared_secret: [ - 0x50, 0x78, 0x28, 0x7f, 0xf1, 0x7b, 0x1d, 0x92, 0x9b, 0x6a, 0x99, 0xb5, 0xe2, 0x82, - 0x68, 0xa1, 0x92, 0x93, 0x95, 0x73, 0xda, 0xc4, 0xe8, 0x4d, 0x51, 0x1b, 0x53, 0x93, - 0xd7, 0x2a, 0x6d, 0x68, - ], - k_enc: [ - 0xa4, 0x3c, 0xaa, 0xd6, 0x25, 0x30, 0xde, 0x86, 0xdf, 0x57, 0xe9, 0xde, 0x03, 0x47, - 0xa2, 0xd8, 0x06, 0x40, 0x53, 0x0a, 0x4c, 0xa9, 0x7b, 0x82, 0x92, 0xa5, 0xa5, 0x25, - 0x0f, 0x1b, 0xf2, 0x40, - ], - _p_enc: [ - 0x01, 0x75, 0x99, 0xf0, 0xbf, 0x9b, 0x57, 0xcd, 0x2d, 0xc2, 0x99, 0xb6, 0x00, 0xa3, - 0xe1, 0x11, 0x00, 0x00, 0x00, 0x00, 0x14, 0x7c, 0xf2, 0xb5, 0x1b, 0x4c, 0x7c, 0x63, - 0xcb, 0x77, 0xb9, 0x9e, 0x8b, 0x78, 0x3e, 0x5b, 0x51, 0x11, 0xdb, 0x0a, 0x7c, 0xa0, - 0x4d, 0x6c, 0x01, 0x4a, 0x1d, 0x7d, 0xa8, 0x3b, 0xae, 0x0a, 0xf6, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - c_enc: [ - 0x4c, 0xac, 0xe5, 0x2f, 0x2d, 0xa8, 0x2a, 0x34, 0xe3, 0x0d, 0xe8, 0xfb, 0x2e, 0x25, - 0x6b, 0xef, 0xd9, 0x2d, 0xd3, 0x0e, 0xf7, 0x86, 0x85, 0xa5, 0x08, 0xe4, 0x41, 0x0c, - 0x79, 0x33, 0x6f, 0x0a, 0xf1, 0xb2, 0x64, 0x84, 0x82, 0x33, 0x59, 0x24, 0x78, 0xd2, - 0x2d, 0xf7, 0x91, 0xab, 0x8d, 0x4c, 0x7d, 0x32, 0x3c, 0xd8, 0x4d, 0x6b, 0x2e, 0x4d, - 0xcf, 0x66, 0x49, 0x5b, 0x46, 0xc5, 0x31, 0xa3, 0x21, 0x67, 0x66, 0xfc, 0x8b, 0x6f, - 0x65, 0xfe, 0x57, 0x6c, 0x44, 0xef, 0x88, 0xc4, 0x44, 0xfa, 0x95, 0x7f, 0xbd, 0x87, - 0xaf, 0x7a, 0x30, 0xf5, 0x2b, 0xd3, 0xf2, 0x33, 0x8c, 0xbb, 0x0b, 0x7e, 0xe6, 0x68, - 0x5c, 0x51, 0xec, 0xef, 0xb5, 0xfd, 0x17, 0xd7, 0x53, 0x0b, 0xb6, 0x14, 0x52, 0x28, - 0xbb, 0x97, 0x6a, 0x56, 0xa1, 0xc9, 0xb2, 0xc8, 0xd2, 0x86, 0x4c, 0x43, 0xd3, 0xcd, - 0x64, 0x0b, 0xd7, 0xe0, 0x1f, 0x08, 0xaa, 0xc4, 0x16, 0xd2, 0x25, 0x0d, 0xf7, 0xf4, - 0xb1, 0xb9, 0xeb, 0xd9, 0xbd, 0x10, 0x3f, 0xd4, 0x17, 0xfd, 0xbe, 0x57, 0x13, 0x2e, - 0xab, 0xfc, 0x52, 0xc3, 0x79, 0x8e, 0x98, 0xc3, 0x7c, 0x1a, 0xf3, 0x4d, 0x28, 0x91, - 0x2c, 0x1d, 0x11, 0x64, 0xb5, 0x27, 0x71, 0x07, 0xc4, 0x7d, 0x6b, 0xd5, 0xf3, 0xc0, - 0xb3, 0x0f, 0x4e, 0xfa, 0xb7, 0xef, 0x04, 0x15, 0x8e, 0x11, 0x9d, 0x7c, 0x40, 0x79, - 0x4a, 0xb0, 0xd4, 0x23, 0x19, 0x49, 0xe7, 0xf8, 0x0f, 0x43, 0xd7, 0x63, 0x64, 0x56, - 0xfe, 0xe2, 0xe1, 0x27, 0x2e, 0xa1, 0xe2, 0xec, 0x3e, 0x8f, 0xf3, 0x06, 0x98, 0xb8, - 0x32, 0x64, 0x71, 0xeb, 0xa9, 0x40, 0x95, 0x0d, 0x55, 0x83, 0x62, 0x4d, 0xfd, 0xab, - 0xe8, 0x7d, 0x7c, 0x52, 0xa4, 0xd0, 0x0e, 0xf2, 0x00, 0x42, 0x38, 0x1c, 0x9e, 0x6f, - 0x03, 0xd3, 0x29, 0xbb, 0xf4, 0x20, 0x43, 0xf2, 0xf3, 0xb4, 0xfd, 0x77, 0x54, 0x16, - 0x32, 0x40, 0x2e, 0x06, 0x11, 0xb2, 0x44, 0xb0, 0xc2, 0x80, 0x3c, 0xd5, 0x12, 0x50, - 0x81, 0x4c, 0xff, 0xdd, 0x7e, 0xeb, 0x17, 0x35, 0xbe, 0xba, 0x8e, 0xa8, 0xa5, 0x8e, - 0xbc, 0xc3, 0x23, 0xf4, 0x24, 0xfc, 0xd5, 0xa7, 0x3d, 0xcc, 0xa2, 0xf5, 0x06, 0xfc, - 0xa4, 0x03, 0x19, 0x9f, 0x0c, 0xc7, 0xb1, 0xe9, 0x7b, 0x92, 0x0b, 0xa2, 0x72, 0x35, - 0xcd, 0x39, 0xe5, 0x27, 0x38, 0x2b, 0xad, 0x3a, 0x48, 0x3b, 0x9f, 0x1e, 0xbb, 0xf2, - 0x91, 0x77, 0xae, 0x94, 0xd8, 0xfa, 0x63, 0xbe, 0xeb, 0x45, 0x6d, 0x12, 0x78, 0xb9, - 0xd2, 0x28, 0x59, 0x44, 0x31, 0x99, 0x04, 0xdd, 0xe4, 0x2a, 0xdc, 0x70, 0x62, 0xb5, - 0x50, 0xb1, 0xff, 0x47, 0xb7, 0x0d, 0x3c, 0x78, 0xc2, 0x4c, 0x55, 0x06, 0x9f, 0x72, - 0x0f, 0xea, 0x60, 0x23, 0xf2, 0x19, 0x4a, 0x72, 0x91, 0xff, 0xb8, 0x11, 0xf6, 0x8a, - 0x16, 0xd6, 0xc1, 0x15, 0xf4, 0xd8, 0xc6, 0x85, 0xe0, 0x9a, 0x44, 0xda, 0x84, 0x11, - 0xe1, 0xb9, 0xb5, 0x3f, 0x39, 0xd5, 0x18, 0x46, 0x14, 0x7d, 0xdb, 0x62, 0x08, 0x98, - 0xe0, 0x80, 0xb7, 0xa6, 0x5f, 0xe8, 0xe2, 0xe1, 0x31, 0x2b, 0x0b, 0x81, 0x52, 0x13, - 0x8a, 0x8b, 0xa9, 0xe0, 0x86, 0x67, 0x90, 0x57, 0x17, 0x9f, 0xf0, 0x9f, 0x7b, 0x3c, - 0xbf, 0x58, 0xbf, 0x59, 0xe3, 0x3f, 0x83, 0xde, 0x2c, 0x70, 0x35, 0x0a, 0xb5, 0x7c, - 0x82, 0xbe, 0x9e, 0xc9, 0x5c, 0xcc, 0x95, 0xe2, 0xbe, 0x29, 0x4e, 0xc5, 0x38, 0x3f, - 0xa3, 0xbb, 0xd7, 0xa7, 0x59, 0x31, 0x5c, 0xc2, 0x5d, 0xea, 0x38, 0x53, 0xe7, 0xb5, - 0x36, 0x6b, 0xaa, 0xe0, 0x5a, 0xca, 0x8b, 0xc9, 0x56, 0xf1, 0xd5, 0xbd, 0xdc, 0xbd, - 0xa2, 0x95, 0xa5, 0xca, 0x7c, 0x2e, 0x26, 0xfb, 0x4e, 0x26, 0xf7, 0xeb, 0xdf, 0x62, - 0x44, 0xb7, 0x8a, 0x59, 0x1e, 0xfa, 0xa3, 0xa6, 0xf4, 0x8c, 0xc4, 0x10, 0x59, 0x78, - 0xc9, 0x68, 0xdd, 0x85, 0x88, 0x79, 0x5a, 0x9a, 0x65, 0x71, 0x17, 0x93, 0xf1, 0x98, - 0x04, 0xf8, 0x81, 0x4b, 0x4a, 0x9d, 0xb0, 0xbf, 0xa1, 0x57, 0x76, 0x9a, 0xaf, 0xda, - 0x2d, 0xb0, 0xee, 0xf0, 0x2b, 0x9a, 0x81, 0x16, 0x3b, 0x7c, 0x23, 0x56, 0x97, 0x62, - 0x0c, 0x72, 0xd8, 0x24, 0xe3, 0x2b, - ], - ock: [ - 0x24, 0x11, 0xa0, 0xf9, 0x31, 0xa8, 0xd3, 0x51, 0x6c, 0xdb, 0x71, 0x93, 0xc9, 0x41, - 0xcf, 0x0e, 0x49, 0xc3, 0x66, 0xae, 0x72, 0xc9, 0x79, 0xc4, 0x90, 0x49, 0xc9, 0x4b, - 0xd3, 0xc7, 0x5c, 0xf4, - ], - _op: [ - 0x66, 0x14, 0x17, 0x39, 0x51, 0x4b, 0x28, 0xf0, 0x5d, 0xef, 0x8a, 0x18, 0xee, 0xee, - 0x5e, 0xed, 0x4d, 0x44, 0xc6, 0x22, 0x5c, 0x3c, 0x65, 0xd8, 0x8d, 0xd9, 0x90, 0x77, - 0x08, 0x01, 0x2f, 0x5a, 0x99, 0xaa, 0x10, 0xc0, 0x57, 0x88, 0x08, 0x1c, 0x0d, 0xa7, - 0xd8, 0x79, 0xcd, 0x95, 0x43, 0xec, 0x18, 0x92, 0x15, 0x72, 0x92, 0x40, 0x2e, 0x96, - 0x0b, 0x06, 0x99, 0x5a, 0x08, 0x96, 0x4c, 0x03, - ], - c_out: [ - 0x9d, 0xcf, 0xab, 0x0d, 0x20, 0x54, 0xd2, 0xbd, 0xf4, 0x06, 0xc3, 0x1b, 0x41, 0x78, - 0x46, 0x5d, 0xe6, 0x50, 0x5d, 0xb3, 0xbe, 0x9b, 0x69, 0x36, 0xf7, 0x8d, 0x2e, 0x29, - 0x37, 0x57, 0x9b, 0x58, 0x2e, 0x83, 0x28, 0x61, 0x92, 0x9a, 0x75, 0x17, 0x88, 0x04, - 0xb6, 0x57, 0x12, 0x6a, 0xdd, 0x74, 0x2e, 0x06, 0xcb, 0x84, 0x36, 0x86, 0x42, 0xdb, - 0x9b, 0xf4, 0x7a, 0xc6, 0xe4, 0xdc, 0x1a, 0xf1, 0x78, 0x19, 0x8b, 0x22, 0xd6, 0x26, - 0x23, 0x45, 0x37, 0x3b, 0x0f, 0x56, 0x2e, 0xf2, 0x7b, 0xb0, - ], - }, - TestVector { - ovk: [ - 0x14, 0x76, 0x78, 0xe0, 0x55, 0x3b, 0x97, 0x82, 0x93, 0x47, 0x64, 0x7c, 0x5b, 0xc7, - 0xda, 0xb4, 0xcc, 0x22, 0x02, 0xb5, 0x4e, 0xc2, 0x9f, 0xd3, 0x1a, 0x3d, 0xe6, 0xbe, - 0x08, 0x25, 0xfc, 0x5e, - ], - ivk: [ - 0x63, 0x6a, 0xa9, 0x64, 0xbf, 0xc2, 0x3c, 0xe4, 0xb1, 0xfc, 0xf7, 0xdf, 0xc9, 0x91, - 0x79, 0xdd, 0xc4, 0x06, 0xff, 0x55, 0x40, 0x0c, 0x92, 0x95, 0xac, 0xfc, 0x14, 0xf0, - 0x31, 0xc7, 0x26, 0x00, - ], - default_d: [ - 0x1b, 0x81, 0x61, 0x4f, 0x1d, 0xad, 0xea, 0x0f, 0x8d, 0x0a, 0x58, - ], - default_pk_d: [ - 0x25, 0xeb, 0x55, 0xfc, 0xcf, 0x76, 0x1f, 0xc6, 0x4e, 0x85, 0xa5, 0x88, 0xef, 0xe6, - 0xea, 0xd7, 0x83, 0x2f, 0xb1, 0xf0, 0xf7, 0xa8, 0x31, 0x65, 0x89, 0x5b, 0xdf, 0xf9, - 0x42, 0x92, 0x5f, 0x5c, - ], - v: 400000000, - rcm: [ - 0x34, 0xa4, 0xb2, 0xa9, 0x14, 0x4f, 0xf5, 0xea, 0x54, 0xef, 0xee, 0x87, 0xcf, 0x90, - 0x1b, 0x5b, 0xed, 0x5e, 0x35, 0xd2, 0x1f, 0xbb, 0xd7, 0x88, 0xd5, 0xbd, 0x9d, 0x83, - 0x3e, 0x11, 0x28, 0x04, - ], - memo: [ - 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - cv: [ - 0x6d, 0x6e, 0xf8, 0xce, 0x97, 0x92, 0x74, 0x09, 0x4f, 0x19, 0x1a, 0xef, 0x64, 0x3f, - 0x3f, 0xcb, 0xd1, 0xac, 0x9d, 0x98, 0xd6, 0x07, 0xe2, 0xbc, 0xfe, 0xf6, 0xfd, 0x51, - 0xba, 0x4b, 0xb4, 0xb9, - ], - cmu: [ - 0x51, 0xfd, 0xdd, 0x70, 0x8c, 0xd1, 0x51, 0xd3, 0xca, 0x47, 0x17, 0xe3, 0xc9, 0x9e, - 0xeb, 0x8f, 0x64, 0xf1, 0x04, 0x49, 0x5f, 0x26, 0xde, 0x05, 0x7b, 0x68, 0x10, 0x63, - 0xb9, 0xc9, 0x78, 0x2d, - ], - esk: [ - 0xbd, 0xde, 0x13, 0x81, 0xec, 0x9f, 0xf4, 0x21, 0xca, 0xfd, 0x1e, 0x31, 0xcc, 0x5d, - 0xe2, 0x55, 0x59, 0x88, 0x1f, 0x6b, 0x21, 0xb2, 0x17, 0x5d, 0x0d, 0xce, 0x94, 0x08, - 0x59, 0x7e, 0xa1, 0x03, - ], - epk: [ - 0x04, 0xa1, 0x0a, 0x3e, 0xa0, 0xe4, 0xb1, 0xa1, 0xd1, 0x3a, 0x67, 0xbc, 0xb2, 0x7d, - 0xe6, 0x34, 0xe1, 0x94, 0xb2, 0x08, 0x01, 0x62, 0x61, 0x9f, 0xbc, 0xa7, 0x66, 0x2d, - 0x42, 0xb8, 0xa5, 0x5f, - ], - shared_secret: [ - 0xdd, 0x88, 0x05, 0x9f, 0xd9, 0x05, 0x90, 0x13, 0xf2, 0xb9, 0xfa, 0xa2, 0x3a, 0x6b, - 0xa1, 0x49, 0xb2, 0xff, 0x0e, 0x37, 0x79, 0x3a, 0x3e, 0x8d, 0x92, 0x70, 0xff, 0x71, - 0x67, 0xfd, 0x7a, 0x8d, - ], - k_enc: [ - 0xab, 0xa4, 0xd4, 0xa5, 0xb5, 0x1a, 0x8b, 0xf5, 0x2e, 0x29, 0xd6, 0x80, 0x3a, 0xb9, - 0x33, 0x0c, 0xf9, 0xc8, 0x2b, 0x1e, 0xb1, 0xfe, 0xe6, 0xa1, 0xa5, 0x54, 0x4a, 0x82, - 0xc7, 0xb3, 0x16, 0x82, - ], - _p_enc: [ - 0x01, 0x1b, 0x81, 0x61, 0x4f, 0x1d, 0xad, 0xea, 0x0f, 0x8d, 0x0a, 0x58, 0x00, 0x84, - 0xd7, 0x17, 0x00, 0x00, 0x00, 0x00, 0x34, 0xa4, 0xb2, 0xa9, 0x14, 0x4f, 0xf5, 0xea, - 0x54, 0xef, 0xee, 0x87, 0xcf, 0x90, 0x1b, 0x5b, 0xed, 0x5e, 0x35, 0xd2, 0x1f, 0xbb, - 0xd7, 0x88, 0xd5, 0xbd, 0x9d, 0x83, 0x3e, 0x11, 0x28, 0x04, 0xf6, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - c_enc: [ - 0x9d, 0xb8, 0xb2, 0x4a, 0x05, 0x6f, 0x99, 0x6d, 0x39, 0x2d, 0x4d, 0x96, 0x3e, 0xa3, - 0x89, 0x76, 0xd0, 0xf3, 0x5e, 0x85, 0xd8, 0xaa, 0x84, 0x7a, 0x08, 0x96, 0x16, 0x4e, - 0x39, 0xd8, 0x69, 0x7a, 0xe1, 0x80, 0xc4, 0xdc, 0xc1, 0x70, 0x61, 0xd5, 0xf3, 0x99, - 0xe0, 0xac, 0x4e, 0xcb, 0x5f, 0x02, 0xd4, 0xd9, 0xa3, 0xca, 0x5b, 0x33, 0x51, 0x8c, - 0x58, 0xb1, 0xa0, 0x73, 0xbc, 0xa7, 0xee, 0x67, 0x41, 0x01, 0x03, 0x05, 0xdb, 0xb8, - 0xc7, 0x38, 0x38, 0x35, 0xb9, 0xc7, 0x80, 0xa9, 0x42, 0x78, 0x5c, 0x57, 0xa3, 0x09, - 0x8a, 0x81, 0xae, 0xf5, 0xd7, 0x06, 0x1f, 0xda, 0xba, 0xcf, 0x52, 0x72, 0x15, 0x30, - 0xef, 0x32, 0xdf, 0xfc, 0x01, 0x10, 0x19, 0xeb, 0xd3, 0x60, 0x97, 0xe8, 0x4d, 0xf2, - 0x03, 0x63, 0xcf, 0x18, 0x22, 0xb1, 0x15, 0x0c, 0x24, 0x73, 0x58, 0x2b, 0x01, 0xf8, - 0xd8, 0x67, 0x99, 0xc1, 0x73, 0xf7, 0xfe, 0xf8, 0xca, 0x93, 0x8e, 0x4c, 0xde, 0x71, - 0x85, 0xa1, 0x9d, 0x70, 0xad, 0x38, 0x61, 0x47, 0x9e, 0x7d, 0x43, 0x81, 0x0d, 0xc5, - 0x64, 0x24, 0x71, 0x03, 0x33, 0x49, 0x28, 0x6b, 0xaf, 0x71, 0x4f, 0x7f, 0xdc, 0x22, - 0xb3, 0x81, 0xd9, 0xe3, 0xad, 0xf3, 0xbc, 0x10, 0x49, 0x87, 0x8e, 0x18, 0x6d, 0x53, - 0x2d, 0x8c, 0x98, 0x70, 0xf6, 0x01, 0x80, 0xd6, 0x54, 0x72, 0x45, 0x5d, 0x22, 0xd2, - 0x59, 0x24, 0xb9, 0x92, 0xc0, 0x2f, 0x94, 0xea, 0x6e, 0xaf, 0x75, 0xb9, 0xdc, 0x88, - 0x3d, 0xe7, 0x37, 0x6d, 0xa6, 0x01, 0x8e, 0x55, 0x45, 0x1e, 0x23, 0xf2, 0x38, 0xe1, - 0x09, 0xa6, 0x40, 0x07, 0x89, 0xf9, 0x30, 0x52, 0x57, 0x9b, 0xbb, 0x18, 0x40, 0x19, - 0xf3, 0x09, 0xb3, 0xd0, 0x6d, 0x07, 0x67, 0xa1, 0x07, 0xe4, 0xb7, 0x9a, 0x2b, 0xfc, - 0x84, 0x25, 0xd8, 0xb0, 0x70, 0x62, 0x7f, 0x2d, 0x55, 0xc9, 0xa2, 0x6b, 0x22, 0x82, - 0x3a, 0x21, 0xe1, 0xca, 0xf6, 0xfb, 0xc2, 0xa5, 0x7d, 0xce, 0x78, 0x4b, 0x25, 0x30, - 0x34, 0x5a, 0x5f, 0x8b, 0x0c, 0xea, 0x3f, 0xce, 0x3b, 0x7f, 0xf4, 0xf5, 0xbb, 0x88, - 0x4f, 0x68, 0xb7, 0xd1, 0x36, 0x06, 0x92, 0x33, 0xad, 0xe4, 0xd6, 0xbd, 0xda, 0xf3, - 0x40, 0xde, 0xe1, 0x43, 0x72, 0x33, 0x2e, 0xc3, 0x76, 0xf5, 0x93, 0x5d, 0x62, 0x79, - 0xc3, 0x74, 0x91, 0x1d, 0x95, 0x40, 0xfa, 0xcc, 0x75, 0x11, 0x5b, 0x20, 0xc5, 0x53, - 0x32, 0x9b, 0x43, 0xee, 0x57, 0xa8, 0xbb, 0x58, 0xa3, 0xf7, 0x46, 0x06, 0xa7, 0xf3, - 0xfa, 0x87, 0xe4, 0x6a, 0xaf, 0x72, 0xad, 0xae, 0x90, 0x48, 0xb9, 0x43, 0xe4, 0x64, - 0x89, 0x85, 0xad, 0xaa, 0x99, 0x0d, 0x78, 0x20, 0xfb, 0xb2, 0xb1, 0x24, 0x65, 0xa1, - 0x61, 0x7d, 0x01, 0xca, 0xf4, 0x14, 0x36, 0xa4, 0x94, 0x6e, 0xa0, 0x95, 0x96, 0x23, - 0x96, 0x40, 0xdc, 0x95, 0xe5, 0x86, 0x81, 0x9e, 0x6c, 0x00, 0x69, 0xee, 0xe0, 0x7a, - 0x72, 0x42, 0xb9, 0x4a, 0xfd, 0x69, 0xce, 0x35, 0x43, 0xb8, 0x87, 0x7b, 0x31, 0x94, - 0xcd, 0xb9, 0xe7, 0x07, 0xc0, 0x83, 0x8b, 0x15, 0x43, 0x46, 0x03, 0x57, 0x50, 0x46, - 0x35, 0x2c, 0x1b, 0xf4, 0xcf, 0xc2, 0x7f, 0x4e, 0xdf, 0x61, 0x91, 0xd8, 0xec, 0xf5, - 0x52, 0xb8, 0xf6, 0x98, 0x70, 0x2d, 0x3a, 0x8f, 0x6f, 0xda, 0x58, 0xb5, 0xcf, 0x16, - 0x1f, 0xed, 0x6e, 0x6f, 0xdb, 0x14, 0x9a, 0x79, 0xdb, 0x0a, 0x6b, 0x02, 0xc3, 0x27, - 0xe9, 0x62, 0x9c, 0x94, 0x8f, 0x66, 0x5d, 0x13, 0x28, 0x3f, 0x65, 0xe5, 0x4b, 0xe5, - 0x5a, 0xc1, 0xae, 0x82, 0x75, 0x35, 0xff, 0x7a, 0xc1, 0x43, 0xcc, 0x72, 0xd9, 0x2b, - 0xc4, 0xf4, 0x6e, 0xf4, 0xad, 0x88, 0xc7, 0x66, 0xab, 0x4b, 0xff, 0x1e, 0x1d, 0x11, - 0x5c, 0x85, 0x1e, 0x59, 0x85, 0x41, 0x10, 0x5d, 0x6e, 0xbb, 0x36, 0x7c, 0xe0, 0x54, - 0x93, 0x20, 0xa2, 0x30, 0x83, 0x53, 0x11, 0x47, 0x8b, 0xdd, 0x9f, 0x6c, 0x53, 0x85, - 0x03, 0xf3, 0x62, 0xe5, 0xf6, 0xc2, 0x7d, 0x15, 0xb5, 0x6c, 0x41, 0x43, 0xd4, 0x57, - 0x69, 0xc2, 0x54, 0x6e, 0x53, 0xfb, 0x45, 0x01, 0xf9, 0xba, 0x5e, 0xd4, 0x55, 0xd2, - 0x49, 0x86, 0xb4, 0xdf, 0xf7, 0xcd, - ], - ock: [ - 0xf6, 0xbd, 0x5d, 0x10, 0x80, 0xfc, 0xa6, 0x46, 0x00, 0xee, 0x92, 0x17, 0xb0, 0x9e, - 0xf1, 0x98, 0x4c, 0x9a, 0x8b, 0x98, 0xe0, 0x6e, 0xe5, 0xd8, 0x36, 0xce, 0x0e, 0x6c, - 0x89, 0xab, 0x56, 0xfd, - ], - _op: [ - 0x25, 0xeb, 0x55, 0xfc, 0xcf, 0x76, 0x1f, 0xc6, 0x4e, 0x85, 0xa5, 0x88, 0xef, 0xe6, - 0xea, 0xd7, 0x83, 0x2f, 0xb1, 0xf0, 0xf7, 0xa8, 0x31, 0x65, 0x89, 0x5b, 0xdf, 0xf9, - 0x42, 0x92, 0x5f, 0x5c, 0xbd, 0xde, 0x13, 0x81, 0xec, 0x9f, 0xf4, 0x21, 0xca, 0xfd, - 0x1e, 0x31, 0xcc, 0x5d, 0xe2, 0x55, 0x59, 0x88, 0x1f, 0x6b, 0x21, 0xb2, 0x17, 0x5d, - 0x0d, 0xce, 0x94, 0x08, 0x59, 0x7e, 0xa1, 0x03, - ], - c_out: [ - 0x25, 0x4f, 0x12, 0x2c, 0xfe, 0x94, 0x98, 0xad, 0xd7, 0x57, 0xcf, 0x0b, 0x61, 0x0d, - 0xa8, 0xcb, 0xae, 0xda, 0x05, 0x3e, 0x26, 0xcb, 0x72, 0x30, 0x6f, 0x36, 0x23, 0x08, - 0x55, 0x28, 0x53, 0xff, 0x02, 0x3c, 0x23, 0xc2, 0x6f, 0x3a, 0xb4, 0x41, 0xb8, 0x1e, - 0xa2, 0x5c, 0xe0, 0xae, 0x57, 0xd1, 0xa9, 0x49, 0x83, 0xbb, 0x45, 0xab, 0x8a, 0x86, - 0xda, 0x68, 0xef, 0x63, 0xf1, 0x58, 0x16, 0xc1, 0x43, 0x32, 0x7a, 0x1e, 0x46, 0x0c, - 0x51, 0x0c, 0x63, 0x1c, 0xc6, 0x9f, 0x39, 0x60, 0xfb, 0x5a, - ], - }, - TestVector { - ovk: [ - 0x1b, 0x6e, 0x75, 0xec, 0xe3, 0xac, 0xe8, 0xdb, 0xa6, 0xa5, 0x41, 0x0d, 0x9a, 0xd4, - 0x75, 0x56, 0x68, 0xe4, 0xb3, 0x95, 0x85, 0xd6, 0x35, 0xec, 0x1d, 0xa7, 0xc8, 0xdc, - 0xfd, 0x5f, 0xc4, 0xed, - ], - ivk: [ - 0x67, 0xfa, 0x2b, 0xf7, 0xc6, 0x7d, 0x46, 0x58, 0x24, 0x3c, 0x31, 0x7c, 0x0c, 0xb4, - 0x1f, 0xd3, 0x20, 0x64, 0xdf, 0xd3, 0x70, 0x9f, 0xe0, 0xdc, 0xb7, 0x24, 0xf1, 0x4b, - 0xb0, 0x1a, 0x1d, 0x04, - ], - default_d: [ - 0xfc, 0xfb, 0x68, 0xa4, 0x0d, 0x4b, 0xc6, 0xa0, 0x4b, 0x09, 0xc4, - ], - default_pk_d: [ - 0x8b, 0x2a, 0x33, 0x7f, 0x03, 0x62, 0x2c, 0x24, 0xff, 0x38, 0x1d, 0x4c, 0x54, 0x6f, - 0x69, 0x77, 0xf9, 0x05, 0x22, 0xe9, 0x2f, 0xde, 0x44, 0xc9, 0xd1, 0xbb, 0x09, 0x97, - 0x14, 0xb9, 0xdb, 0x2b, - ], - v: 500000000, - rcm: [ - 0xe5, 0x57, 0x85, 0x13, 0x55, 0x74, 0x7c, 0x09, 0xac, 0x59, 0x01, 0x3c, 0xbd, 0xe8, - 0x59, 0x80, 0x96, 0x4e, 0xc1, 0x84, 0x4d, 0x9c, 0x69, 0x67, 0xca, 0x0c, 0x02, 0x9c, - 0x84, 0x57, 0xbb, 0x04, - ], - memo: [ - 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - cv: [ - 0xce, 0x42, 0xf9, 0xd0, 0x89, 0xba, 0x9d, 0x9e, 0x62, 0xe3, 0xf6, 0x56, 0x33, 0x62, - 0xf0, 0xfd, 0xc7, 0xce, 0xde, 0x8a, 0xb3, 0x59, 0x43, 0x9e, 0x21, 0x4e, 0x26, 0x52, - 0xdb, 0xf0, 0x5a, 0x0c, - ], - cmu: [ - 0xc2, 0xb5, 0xf3, 0x57, 0x11, 0x7a, 0x40, 0x03, 0x62, 0x9e, 0x05, 0xca, 0x6f, 0x56, - 0xa6, 0x23, 0xa3, 0xc4, 0x8a, 0xa5, 0xeb, 0x79, 0x7c, 0xdd, 0x32, 0x2d, 0x48, 0x57, - 0xa0, 0xfb, 0xa4, 0x4e, - ], - esk: [ - 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, - ], - epk: [ - 0x5b, 0x54, 0xe5, 0xd4, 0x13, 0xa8, 0x07, 0xdf, 0x36, 0x42, 0x6d, 0x5c, 0x8c, 0x09, - 0x81, 0x0a, 0xc2, 0x45, 0x95, 0xb1, 0x52, 0xcd, 0x89, 0x41, 0xa2, 0x34, 0x3c, 0x96, - 0x30, 0x3d, 0x24, 0x6b, - ], - shared_secret: [ - 0x40, 0x64, 0xc2, 0xb7, 0xc1, 0x82, 0xd1, 0x80, 0x52, 0x50, 0xd3, 0x59, 0xfb, 0xa1, - 0xa5, 0x32, 0x54, 0x56, 0xb0, 0x12, 0x94, 0x4d, 0x7d, 0x92, 0x9f, 0x40, 0x9c, 0x6d, - 0xe5, 0x70, 0x5d, 0xc5, - ], - k_enc: [ - 0xc5, 0xfc, 0xf8, 0x13, 0xb1, 0xbb, 0xef, 0x20, 0xa6, 0x2a, 0xce, 0x7a, 0x47, 0xf3, - 0x7f, 0x26, 0x1f, 0xbb, 0x2d, 0xfa, 0xd8, 0x88, 0x66, 0xb4, 0x32, 0xff, 0x0d, 0xfa, - 0xee, 0xc5, 0xb2, 0xcf, - ], - _p_enc: [ - 0x01, 0xfc, 0xfb, 0x68, 0xa4, 0x0d, 0x4b, 0xc6, 0xa0, 0x4b, 0x09, 0xc4, 0x00, 0x65, - 0xcd, 0x1d, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x57, 0x85, 0x13, 0x55, 0x74, 0x7c, 0x09, - 0xac, 0x59, 0x01, 0x3c, 0xbd, 0xe8, 0x59, 0x80, 0x96, 0x4e, 0xc1, 0x84, 0x4d, 0x9c, - 0x69, 0x67, 0xca, 0x0c, 0x02, 0x9c, 0x84, 0x57, 0xbb, 0x04, 0xf6, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - c_enc: [ - 0xd7, 0xe7, 0x06, 0x31, 0x7c, 0x78, 0x95, 0x06, 0x2d, 0x89, 0xab, 0x5f, 0x10, 0x52, - 0x15, 0x5a, 0xc3, 0xd2, 0xa1, 0xe3, 0x43, 0x97, 0x3e, 0x5a, 0xab, 0x1c, 0xce, 0x53, - 0x59, 0xc6, 0xbc, 0x11, 0x1b, 0x9a, 0x7b, 0xb6, 0x68, 0xb6, 0xc7, 0xd0, 0x21, 0xb1, - 0x23, 0x35, 0x77, 0xe8, 0x2b, 0xaf, 0x33, 0x00, 0x5c, 0xd0, 0x34, 0xa9, 0x75, 0x4b, - 0x1e, 0x12, 0xdf, 0x03, 0x6b, 0x7b, 0xc7, 0x82, 0x98, 0x79, 0xca, 0x8c, 0x6b, 0x54, - 0x37, 0x8f, 0xcd, 0x5f, 0x18, 0x2f, 0x65, 0x16, 0x0e, 0xa7, 0x24, 0x3b, 0x7d, 0xfc, - 0xac, 0xfb, 0x6d, 0xac, 0xee, 0x02, 0x26, 0x34, 0x14, 0x9d, 0x8f, 0xb2, 0xf0, 0xca, - 0x51, 0xa8, 0x26, 0x72, 0xa5, 0x63, 0xd5, 0x36, 0xba, 0xf1, 0xaf, 0x88, 0x1a, 0x7a, - 0x8d, 0x25, 0xc5, 0xcf, 0x78, 0x61, 0x89, 0x53, 0x03, 0x2e, 0xf5, 0x65, 0xb0, 0xf3, - 0x98, 0xe3, 0x4b, 0xee, 0x2c, 0x30, 0x95, 0xa7, 0xbd, 0x0b, 0x7d, 0x09, 0x7a, 0x3d, - 0x26, 0x4d, 0x65, 0x46, 0xd0, 0x0c, 0x85, 0x83, 0x04, 0x43, 0x78, 0xd1, 0x48, 0x94, - 0x04, 0xa3, 0x1e, 0xec, 0xa8, 0x8f, 0x8f, 0x42, 0xeb, 0xfb, 0x82, 0x18, 0xd4, 0x9f, - 0xde, 0xd8, 0x2a, 0x9b, 0xa6, 0x23, 0x2c, 0xcc, 0x47, 0x94, 0x5d, 0x6f, 0x7d, 0x6e, - 0x39, 0xe0, 0xe8, 0x39, 0x29, 0x34, 0x1a, 0xcf, 0x88, 0xdb, 0x5a, 0x27, 0x73, 0xdc, - 0x55, 0x8a, 0x9d, 0xc1, 0x1d, 0xcd, 0xa1, 0xba, 0xb3, 0xcb, 0x21, 0xbf, 0x5c, 0x29, - 0x51, 0x83, 0xbf, 0x9a, 0x93, 0xee, 0x02, 0x5e, 0xb4, 0x60, 0xf7, 0xd7, 0x41, 0x20, - 0x42, 0xce, 0x5a, 0x84, 0x3a, 0x79, 0x0c, 0x3a, 0x94, 0xda, 0x2d, 0xb7, 0xf6, 0x12, - 0x03, 0x2f, 0xbf, 0x56, 0x4e, 0xfc, 0xf2, 0x04, 0xaf, 0xed, 0x0f, 0xf2, 0xab, 0x2b, - 0xc1, 0xb3, 0x77, 0xca, 0x41, 0x0f, 0x12, 0x7f, 0xaf, 0x98, 0x76, 0x62, 0x7f, 0xbd, - 0xb2, 0x26, 0x2a, 0xe6, 0x56, 0x23, 0x08, 0x84, 0x48, 0x00, 0xb5, 0xcd, 0x52, 0x74, - 0x3e, 0x7f, 0x7b, 0xca, 0xe3, 0xc7, 0xb2, 0x70, 0x34, 0xc5, 0xf2, 0x1d, 0x4f, 0xef, - 0xb5, 0x9b, 0xd2, 0x3b, 0xc6, 0xea, 0x0c, 0x39, 0x39, 0x87, 0x1a, 0xb4, 0x34, 0xb3, - 0xa5, 0xcb, 0x71, 0x03, 0x85, 0x1a, 0x24, 0x78, 0xc5, 0xf6, 0x13, 0x8f, 0x8f, 0xd9, - 0x91, 0x3f, 0xa7, 0xaf, 0x5a, 0x4a, 0xa2, 0x0e, 0xf9, 0x59, 0x40, 0x84, 0x0b, 0xcd, - 0x17, 0x4c, 0xa3, 0xe1, 0x06, 0x5a, 0xea, 0xee, 0x5f, 0x6c, 0x7d, 0x94, 0x34, 0x2c, - 0x68, 0x5f, 0x13, 0xa8, 0x1e, 0x7b, 0x53, 0xad, 0x42, 0x89, 0x0b, 0xa8, 0x10, 0x3a, - 0xc8, 0x34, 0xa4, 0xeb, 0x1f, 0x10, 0xb0, 0xa7, 0x0e, 0x76, 0x89, 0x1d, 0xbe, 0x18, - 0xf5, 0x80, 0x47, 0x2f, 0x5b, 0xdc, 0x3f, 0xc9, 0x55, 0x0f, 0x15, 0x6b, 0x31, 0x21, - 0xa8, 0x44, 0xd6, 0xc7, 0x7b, 0x22, 0x4b, 0x8d, 0x04, 0xf1, 0xfe, 0x8e, 0xa7, 0xb9, - 0x88, 0xd8, 0x78, 0xbf, 0xc0, 0x6d, 0xac, 0x33, 0x2a, 0x10, 0x6a, 0x6e, 0xad, 0x47, - 0xf8, 0x2b, 0xd8, 0xcb, 0x7c, 0x25, 0xae, 0x9e, 0x1d, 0x75, 0xbb, 0x76, 0x2a, 0xfe, - 0xe3, 0x49, 0x30, 0xf4, 0xa9, 0x98, 0xf2, 0x68, 0xd8, 0x76, 0x3c, 0xae, 0x7b, 0x32, - 0x15, 0x20, 0x5e, 0x58, 0x9c, 0x48, 0x11, 0x13, 0xb5, 0xa4, 0xcd, 0xb2, 0x09, 0xbe, - 0xce, 0x2f, 0x09, 0x4f, 0x33, 0x9f, 0x03, 0xfb, 0x39, 0xa1, 0x6e, 0xf1, 0x67, 0x2e, - 0x00, 0x89, 0x27, 0xfd, 0x97, 0x09, 0x8e, 0x00, 0x12, 0xbe, 0xca, 0xa0, 0x0f, 0x62, - 0xc6, 0xbf, 0xd9, 0x45, 0xa0, 0x16, 0xbe, 0x8b, 0x18, 0x66, 0xd9, 0x2b, 0x1d, 0x85, - 0x88, 0xae, 0x26, 0xc6, 0x35, 0x70, 0xd7, 0xe2, 0xa6, 0xb2, 0xee, 0x6e, 0xc2, 0xe6, - 0xb0, 0xbe, 0x22, 0x19, 0x38, 0x0e, 0x4e, 0xea, 0x6a, 0xf0, 0x9b, 0xf5, 0x85, 0xf2, - 0x85, 0x38, 0xd8, 0xb7, 0x89, 0x32, 0x6e, 0x6a, 0x3d, 0xe3, 0xbf, 0x45, 0x06, 0x80, - 0x28, 0xac, 0x80, 0xb1, 0x92, 0x25, 0x5f, 0x27, 0x33, 0x64, 0xda, 0x88, 0xdc, 0x1a, - 0x6f, 0x00, 0xe0, 0xcc, 0x32, 0xbb, 0x47, 0x5e, 0xcc, 0xbe, 0x09, 0x7a, 0x69, 0xf6, - 0x49, 0x2b, 0xdb, 0xa2, 0xad, 0xf0, - ], - ock: [ - 0xf9, 0x8d, 0x6e, 0x55, 0xff, 0x78, 0x3a, 0x13, 0x13, 0x14, 0x0f, 0xb8, 0x8b, 0x7f, - 0x3a, 0x4d, 0xb2, 0x81, 0x86, 0x37, 0x86, 0x88, 0xbe, 0xc6, 0x19, 0x56, 0x23, 0x2e, - 0x42, 0xb7, 0x0a, 0xba, - ], - _op: [ - 0x8b, 0x2a, 0x33, 0x7f, 0x03, 0x62, 0x2c, 0x24, 0xff, 0x38, 0x1d, 0x4c, 0x54, 0x6f, - 0x69, 0x77, 0xf9, 0x05, 0x22, 0xe9, 0x2f, 0xde, 0x44, 0xc9, 0xd1, 0xbb, 0x09, 0x97, - 0x14, 0xb9, 0xdb, 0x2b, 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, - ], - c_out: [ - 0x3b, 0xfc, 0x13, 0x67, 0x3c, 0x24, 0xac, 0x5e, 0xaf, 0x0b, 0xc2, 0x44, 0x6c, 0x38, - 0xa7, 0x92, 0xae, 0x42, 0xd9, 0x6b, 0xaf, 0x05, 0x53, 0xce, 0xe4, 0x36, 0xb6, 0x34, - 0xb5, 0x73, 0x89, 0xb3, 0x62, 0x1d, 0xdb, 0xba, 0x22, 0xe6, 0x84, 0x89, 0x0a, 0x7b, - 0x64, 0x5d, 0x63, 0xc4, 0xbc, 0x8c, 0x26, 0xdb, 0x54, 0x62, 0x8c, 0xef, 0x4d, 0xed, - 0x98, 0x0f, 0x60, 0x8f, 0x00, 0x20, 0xbb, 0xb5, 0xa2, 0xf6, 0x55, 0x22, 0xa6, 0x1f, - 0x89, 0xdf, 0x82, 0x18, 0x18, 0x67, 0x04, 0x01, 0x1e, 0x91, - ], - }, - TestVector { - ovk: [ - 0xc6, 0xbc, 0x1f, 0x39, 0xf0, 0xd7, 0x86, 0x31, 0x4c, 0xb2, 0x0b, 0xf9, 0xab, 0x22, - 0x85, 0x40, 0x91, 0x35, 0x55, 0xf9, 0x70, 0x69, 0x6b, 0x6d, 0x7c, 0x77, 0xbb, 0x33, - 0x23, 0x28, 0x37, 0x2a, - ], - ivk: [ - 0xea, 0x3f, 0x1d, 0x80, 0xe4, 0x30, 0x7c, 0xa7, 0x3b, 0x9f, 0x37, 0x80, 0x1f, 0x91, - 0xfb, 0xa8, 0x10, 0xcc, 0x41, 0xd2, 0x79, 0xfc, 0x29, 0xf5, 0x64, 0x23, 0x56, 0x54, - 0xa2, 0x17, 0x8e, 0x03, - ], - default_d: [ - 0xeb, 0x51, 0x98, 0x82, 0xad, 0x1e, 0x5c, 0xc6, 0x54, 0xcd, 0x59, - ], - default_pk_d: [ - 0x6b, 0x27, 0xda, 0xcc, 0xb5, 0xa8, 0x20, 0x7f, 0x53, 0x2d, 0x10, 0xca, 0x23, 0x8f, - 0x97, 0x86, 0x64, 0x8a, 0x11, 0xb5, 0x96, 0x6e, 0x51, 0xa2, 0xf7, 0xd8, 0x9e, 0x15, - 0xd2, 0x9b, 0x8f, 0xdf, - ], - v: 600000000, - rcm: [ - 0x68, 0xf0, 0x61, 0x04, 0x60, 0x6b, 0x0c, 0x54, 0x49, 0x84, 0x5f, 0xf4, 0xc6, 0x5f, - 0x73, 0xe9, 0x0f, 0x45, 0xef, 0x5a, 0x43, 0xc9, 0xd7, 0x4c, 0xb2, 0xc8, 0x5c, 0xf5, - 0x6c, 0x94, 0xc0, 0x02, - ], - memo: [ - 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - cv: [ - 0x30, 0x27, 0xd7, 0xb7, 0x47, 0x64, 0xca, 0xf7, 0x2b, 0x73, 0x87, 0x28, 0x9b, 0x12, - 0x8f, 0x43, 0x9f, 0xd0, 0x42, 0xc2, 0x1d, 0x81, 0x36, 0x4b, 0xc2, 0xae, 0x7b, 0xd2, - 0x9e, 0xab, 0x51, 0x23, - ], - cmu: [ - 0x38, 0x2c, 0x7d, 0x68, 0x8b, 0xdf, 0x34, 0xb9, 0x4d, 0x40, 0x1c, 0x41, 0x22, 0x79, - 0x52, 0xa2, 0xb9, 0x31, 0xc5, 0x7b, 0x00, 0x5c, 0x82, 0xf2, 0xc3, 0x63, 0x15, 0xf6, - 0x1c, 0x35, 0x02, 0x4e, - ], - esk: [ - 0x4e, 0x41, 0x8c, 0x3c, 0x54, 0x3d, 0x6b, 0xf0, 0x15, 0x31, 0x74, 0xa0, 0x4e, 0x85, - 0x44, 0xae, 0x7c, 0x58, 0x09, 0x2a, 0x2e, 0x4e, 0x5d, 0x7d, 0x9c, 0x67, 0x2a, 0x3a, - 0x79, 0x11, 0x09, 0x03, - ], - epk: [ - 0xe0, 0xc2, 0x9b, 0x43, 0x5d, 0xae, 0xdb, 0xc9, 0x8d, 0x46, 0x5f, 0x38, 0x9b, 0x1b, - 0x60, 0xd7, 0xdf, 0xac, 0x0e, 0x45, 0x9b, 0x1e, 0x62, 0x8f, 0xa0, 0x18, 0x4e, 0x92, - 0xf2, 0x64, 0x79, 0xca, - ], - shared_secret: [ - 0x34, 0xdd, 0x16, 0x13, 0xa8, 0x57, 0x75, 0x2a, 0xa9, 0x07, 0x26, 0xff, 0xf0, 0x7d, - 0x42, 0x9d, 0xcb, 0x52, 0xd2, 0xca, 0x27, 0x7d, 0x84, 0xeb, 0x7a, 0x12, 0xfa, 0x9a, - 0xfc, 0x99, 0xa7, 0x35, - ], - k_enc: [ - 0x03, 0x25, 0xb3, 0x12, 0x63, 0x58, 0x57, 0x3c, 0x09, 0x90, 0xa3, 0x62, 0xb8, 0xf2, - 0x7c, 0xd0, 0x0c, 0xe0, 0xdc, 0x4b, 0x4d, 0x00, 0xcc, 0x8d, 0x8d, 0x3b, 0xa2, 0xce, - 0x6e, 0xa9, 0xc2, 0x97, - ], - _p_enc: [ - 0x01, 0xeb, 0x51, 0x98, 0x82, 0xad, 0x1e, 0x5c, 0xc6, 0x54, 0xcd, 0x59, 0x00, 0x46, - 0xc3, 0x23, 0x00, 0x00, 0x00, 0x00, 0x68, 0xf0, 0x61, 0x04, 0x60, 0x6b, 0x0c, 0x54, - 0x49, 0x84, 0x5f, 0xf4, 0xc6, 0x5f, 0x73, 0xe9, 0x0f, 0x45, 0xef, 0x5a, 0x43, 0xc9, - 0xd7, 0x4c, 0xb2, 0xc8, 0x5c, 0xf5, 0x6c, 0x94, 0xc0, 0x02, 0xf6, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - c_enc: [ - 0x3f, 0x92, 0x6f, 0x4c, 0x93, 0xff, 0x12, 0x5b, 0xd1, 0xfa, 0x04, 0xc9, 0x1e, 0xf5, - 0x9e, 0x07, 0x14, 0x33, 0xf5, 0x7c, 0x60, 0x6e, 0xe1, 0xbc, 0x91, 0x2d, 0x54, 0x62, - 0x8d, 0x14, 0x07, 0x40, 0xa1, 0xab, 0x8a, 0x34, 0x51, 0x6a, 0xde, 0xfb, 0xe6, 0x48, - 0x00, 0x7f, 0x86, 0xf1, 0x31, 0xf4, 0x99, 0x3b, 0x99, 0xae, 0xbd, 0x18, 0x99, 0x63, - 0x48, 0xf4, 0xec, 0x85, 0x34, 0x1d, 0xf3, 0x35, 0x42, 0x2b, 0x12, 0x61, 0x8f, 0x63, - 0xaa, 0x80, 0x4b, 0x30, 0x6c, 0x6c, 0x6b, 0x23, 0x7a, 0x0c, 0x04, 0x4f, 0x79, 0x03, - 0x3d, 0x02, 0x8d, 0x13, 0xcf, 0x1f, 0x3d, 0x6e, 0x38, 0xac, 0xf3, 0x90, 0xf5, 0x54, - 0xa8, 0xd4, 0xe4, 0x64, 0x94, 0x8f, 0xb5, 0xa7, 0xf9, 0x8d, 0x16, 0x1e, 0x3a, 0x8a, - 0x15, 0x7a, 0xf4, 0xc8, 0x94, 0xca, 0x2d, 0xa4, 0x64, 0x7c, 0x53, 0x22, 0x35, 0x4f, - 0x26, 0x19, 0xfd, 0x6c, 0xcc, 0x3c, 0xab, 0xef, 0x03, 0x71, 0xba, 0x42, 0x2f, 0x3d, - 0x6d, 0x92, 0x16, 0x99, 0x6e, 0x49, 0xe6, 0x93, 0x87, 0x1c, 0x56, 0x3f, 0xfb, 0xf4, - 0xc6, 0xd1, 0xd1, 0xc4, 0x73, 0x9f, 0x73, 0x26, 0xda, 0x4c, 0x66, 0x97, 0x61, 0x84, - 0xf0, 0x13, 0x64, 0x96, 0x71, 0x2a, 0x7e, 0xed, 0x56, 0xea, 0x4c, 0xa1, 0xd0, 0x78, - 0x4c, 0x7f, 0xa2, 0xc5, 0x56, 0xd6, 0xa9, 0x64, 0x0b, 0x55, 0x45, 0xd2, 0x14, 0x0a, - 0xd7, 0x45, 0xf1, 0xfc, 0xda, 0xb6, 0xb1, 0xf9, 0xee, 0x59, 0x35, 0x6b, 0xed, 0x24, - 0x93, 0x38, 0xa5, 0xc6, 0xc1, 0xc6, 0x37, 0xea, 0x9b, 0x77, 0x9b, 0x83, 0x11, 0xa5, - 0x32, 0x3a, 0x15, 0xd6, 0x1f, 0x1a, 0x0f, 0xfc, 0x7b, 0x2f, 0xc9, 0xe0, 0xbe, 0x58, - 0xc5, 0xfc, 0xbd, 0xbe, 0x57, 0xa2, 0xe4, 0xd3, 0xbf, 0x21, 0x84, 0x5b, 0x90, 0x16, - 0x54, 0x1c, 0x8c, 0xb4, 0x4a, 0x59, 0xec, 0xa7, 0xf2, 0xb4, 0x18, 0x3b, 0xfb, 0xbc, - 0xda, 0x57, 0xeb, 0x54, 0x24, 0xe8, 0x9d, 0xc3, 0xb0, 0x67, 0x14, 0xe2, 0x0e, 0xdf, - 0x78, 0x46, 0xd6, 0x8a, 0x5f, 0x8a, 0x18, 0x4a, 0x7f, 0x7c, 0x5a, 0x08, 0xfc, 0xcc, - 0x79, 0x84, 0x12, 0x2e, 0x8c, 0x63, 0x63, 0x03, 0xd0, 0x3b, 0x52, 0xb5, 0x1e, 0xc8, - 0xcd, 0x97, 0x68, 0x88, 0x97, 0x6a, 0xc5, 0x9f, 0xe4, 0xeb, 0xda, 0x53, 0x95, 0x53, - 0x8d, 0xbe, 0xa3, 0xd0, 0x09, 0x7b, 0xe5, 0x54, 0x6e, 0x1e, 0x0a, 0xb1, 0xba, 0x4c, - 0xbb, 0x47, 0xf6, 0x20, 0x3d, 0xca, 0xb8, 0x4b, 0x12, 0x9c, 0x52, 0x99, 0xe3, 0xe9, - 0x9d, 0x65, 0xeb, 0xcb, 0xe4, 0x0f, 0xd0, 0x5b, 0x87, 0x36, 0x9c, 0x30, 0xdb, 0x29, - 0x38, 0x37, 0xdb, 0xd0, 0x4e, 0x7a, 0x71, 0x08, 0xab, 0x74, 0x4b, 0x4f, 0xb3, 0xda, - 0x1f, 0x8a, 0x7d, 0x2c, 0xba, 0x6a, 0x5f, 0x01, 0x4f, 0x0d, 0x70, 0x5e, 0xce, 0x11, - 0x9a, 0xe9, 0x80, 0xe9, 0x99, 0x3d, 0xa3, 0xdd, 0xaa, 0x3b, 0xf1, 0x89, 0x9a, 0x74, - 0x74, 0xd6, 0x0b, 0x72, 0xed, 0x1e, 0x39, 0x0d, 0xfe, 0x4a, 0x3a, 0x07, 0x1a, 0xce, - 0xfb, 0x02, 0xcc, 0xca, 0x0b, 0xa9, 0x39, 0x8c, 0x86, 0x1b, 0xed, 0x45, 0x21, 0x61, - 0x79, 0xee, 0x2a, 0x08, 0x53, 0x36, 0x1c, 0x7d, 0xea, 0x89, 0xac, 0x1c, 0xd7, 0xe2, - 0xb4, 0xef, 0xa6, 0xad, 0x82, 0x15, 0xf5, 0xf7, 0x6a, 0xc2, 0x8a, 0x73, 0x1d, 0x27, - 0x79, 0xc1, 0xff, 0xeb, 0xe9, 0xab, 0x6f, 0x51, 0x3d, 0x9b, 0x5e, 0xe0, 0x08, 0x13, - 0x5f, 0xf6, 0x0b, 0xb8, 0x6f, 0x8e, 0x13, 0x97, 0x87, 0xc6, 0xc3, 0x46, 0x8d, 0x31, - 0x29, 0x8f, 0x25, 0x91, 0x76, 0x48, 0xf0, 0x72, 0xa1, 0x1c, 0x0b, 0x8a, 0xf4, 0x0f, - 0x92, 0xa8, 0xb5, 0x04, 0x2c, 0xd4, 0xaf, 0x4f, 0x5a, 0x2a, 0x55, 0x27, 0x31, 0x54, - 0x61, 0x90, 0x44, 0x8d, 0xf1, 0x07, 0x86, 0x37, 0xf4, 0x2e, 0x97, 0x54, 0x5a, 0x86, - 0x64, 0x3a, 0xa4, 0x10, 0x37, 0xc5, 0x34, 0xbc, 0x3e, 0x2e, 0x44, 0xa8, 0x85, 0x34, - 0x10, 0xa0, 0x6e, 0x91, 0x25, 0x31, 0x8a, 0x96, 0x56, 0x55, 0xf3, 0x3f, 0xed, 0x8e, - 0xba, 0x35, 0x62, 0x93, 0xd7, 0xcc, 0xfb, 0x97, 0xa2, 0x33, 0x20, 0xbc, 0x35, 0x39, - 0x70, 0xaa, 0xa1, 0x18, 0xe7, 0x43, - ], - ock: [ - 0x95, 0x9a, 0x28, 0x02, 0x17, 0xb9, 0xef, 0x54, 0xab, 0x44, 0x3b, 0x8d, 0x0f, 0xea, - 0x5a, 0x11, 0x75, 0x86, 0xae, 0x8a, 0xdd, 0x64, 0x99, 0x7d, 0x02, 0xec, 0xb8, 0xb5, - 0xcb, 0xac, 0x14, 0x87, - ], - _op: [ - 0x6b, 0x27, 0xda, 0xcc, 0xb5, 0xa8, 0x20, 0x7f, 0x53, 0x2d, 0x10, 0xca, 0x23, 0x8f, - 0x97, 0x86, 0x64, 0x8a, 0x11, 0xb5, 0x96, 0x6e, 0x51, 0xa2, 0xf7, 0xd8, 0x9e, 0x15, - 0xd2, 0x9b, 0x8f, 0xdf, 0x4e, 0x41, 0x8c, 0x3c, 0x54, 0x3d, 0x6b, 0xf0, 0x15, 0x31, - 0x74, 0xa0, 0x4e, 0x85, 0x44, 0xae, 0x7c, 0x58, 0x09, 0x2a, 0x2e, 0x4e, 0x5d, 0x7d, - 0x9c, 0x67, 0x2a, 0x3a, 0x79, 0x11, 0x09, 0x03, - ], - c_out: [ - 0x65, 0x9d, 0xef, 0x25, 0x08, 0x34, 0x84, 0x6f, 0x85, 0xeb, 0x9e, 0x39, 0x5b, 0xef, - 0xe1, 0x5e, 0x1d, 0x4d, 0x2a, 0xb4, 0x36, 0x2d, 0x1a, 0xa7, 0xde, 0x84, 0x24, 0x3f, - 0x74, 0x45, 0xd5, 0xd2, 0x8f, 0x47, 0x92, 0x92, 0x4d, 0x60, 0xc7, 0x60, 0x53, 0x3c, - 0xef, 0x05, 0x10, 0x47, 0xe5, 0x4d, 0x52, 0x1e, 0x2b, 0x07, 0x2d, 0x13, 0x30, 0xb2, - 0x68, 0x5e, 0xb8, 0x70, 0x10, 0x6c, 0x66, 0x1f, 0x1f, 0x07, 0xb7, 0x6f, 0xdb, 0xb5, - 0x14, 0xaa, 0x9b, 0x94, 0xad, 0x41, 0x91, 0xbc, 0x0d, 0x2d, - ], - }, - TestVector { - ovk: [ - 0xf6, 0x2c, 0x05, 0xe8, 0x48, 0xa8, 0x73, 0xef, 0x88, 0x5e, 0x12, 0xb0, 0x8c, 0x5e, - 0x7c, 0xa2, 0xf3, 0x24, 0x24, 0xba, 0xcc, 0x75, 0x4c, 0xb6, 0x97, 0x50, 0x44, 0x4d, - 0x35, 0x5f, 0x51, 0x06, - ], - ivk: [ - 0xb5, 0xc5, 0x89, 0x49, 0x43, 0x95, 0x69, 0x33, 0xc0, 0xe5, 0xc1, 0x2d, 0x31, 0x1f, - 0xc1, 0x2c, 0xba, 0x58, 0x35, 0x4b, 0x5c, 0x38, 0x9e, 0xdc, 0x03, 0xda, 0x55, 0x08, - 0x4f, 0x74, 0xc2, 0x05, - ], - default_d: [ - 0xbe, 0xbb, 0x0f, 0xb4, 0x6b, 0x8a, 0xaf, 0xf8, 0x90, 0x40, 0xf6, - ], - default_pk_d: [ - 0xd1, 0x1d, 0xa0, 0x1f, 0x0b, 0x43, 0xbd, 0xd5, 0x28, 0x8d, 0x32, 0x38, 0x5b, 0x87, - 0x71, 0xd2, 0x23, 0x49, 0x3c, 0x69, 0x80, 0x25, 0x44, 0x04, 0x3f, 0x77, 0xcf, 0x1d, - 0x71, 0xc1, 0xcb, 0x8c, - ], - v: 700000000, - rcm: [ - 0x49, 0xf9, 0x0b, 0x47, 0xfd, 0x52, 0xfe, 0xe7, 0xc1, 0xc8, 0x1f, 0x0d, 0xcb, 0x5b, - 0x74, 0xc3, 0xfb, 0x9b, 0x3e, 0x03, 0x97, 0x6f, 0x8b, 0x75, 0x24, 0xea, 0xba, 0xd0, - 0x08, 0x89, 0x21, 0x07, - ], - memo: [ - 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - cv: [ - 0x77, 0x08, 0x94, 0xc7, 0xa5, 0x45, 0x8b, 0x16, 0x7d, 0x85, 0x18, 0xa5, 0x47, 0xbc, - 0x62, 0xb4, 0x6b, 0xa1, 0x89, 0x80, 0x7e, 0xb9, 0x7c, 0x08, 0x28, 0x4e, 0x1b, 0x92, - 0xb6, 0xda, 0x35, 0x2a, - ], - cmu: [ - 0x0d, 0xd4, 0x2d, 0x63, 0xff, 0x38, 0xee, 0x4c, 0x46, 0x65, 0x1e, 0x4d, 0x1d, 0xd5, - 0x22, 0x7d, 0xc5, 0x97, 0x33, 0x9f, 0x7d, 0x70, 0x4c, 0x51, 0x8e, 0xf4, 0x02, 0xf8, - 0xcd, 0x6f, 0x37, 0x44, - ], - esk: [ - 0x6d, 0xa9, 0x45, 0xd3, 0x03, 0x81, 0xc2, 0xee, 0xd2, 0xb8, 0x1d, 0x27, 0x08, 0x6d, - 0x22, 0x48, 0xe7, 0xc4, 0x49, 0xfe, 0x50, 0x9b, 0x38, 0xe2, 0x76, 0x79, 0x11, 0x89, - 0xea, 0xbc, 0x46, 0x02, - ], - epk: [ - 0xa5, 0x2f, 0x0b, 0x5a, 0xe4, 0xa9, 0x4f, 0xa8, 0x8a, 0xa7, 0xcb, 0x7e, 0x5f, 0x0f, - 0x34, 0x3c, 0xa2, 0xfa, 0x66, 0xb3, 0x94, 0x41, 0xba, 0x66, 0x28, 0x20, 0xe4, 0x6a, - 0x9b, 0xbb, 0xa3, 0xb5, - ], - shared_secret: [ - 0x81, 0xc7, 0xc5, 0xd5, 0xff, 0x63, 0xe9, 0xe6, 0x1f, 0xe3, 0x5a, 0x4b, 0x39, 0x6e, - 0xa7, 0xf1, 0x9e, 0x48, 0x07, 0x6f, 0x22, 0x09, 0x0a, 0xe7, 0x29, 0xa4, 0x11, 0x79, - 0x2f, 0x08, 0x58, 0x4a, - ], - k_enc: [ - 0xb4, 0xf9, 0xa7, 0xff, 0x9c, 0x60, 0x80, 0x6e, 0xc7, 0xf5, 0x5c, 0xee, 0xbe, 0xc2, - 0xba, 0x54, 0x76, 0x19, 0x8e, 0x29, 0x1d, 0xf7, 0x57, 0x8c, 0x2b, 0xef, 0x87, 0xe6, - 0x4a, 0x71, 0x6a, 0xe7, - ], - _p_enc: [ - 0x01, 0xbe, 0xbb, 0x0f, 0xb4, 0x6b, 0x8a, 0xaf, 0xf8, 0x90, 0x40, 0xf6, 0x00, 0x27, - 0xb9, 0x29, 0x00, 0x00, 0x00, 0x00, 0x49, 0xf9, 0x0b, 0x47, 0xfd, 0x52, 0xfe, 0xe7, - 0xc1, 0xc8, 0x1f, 0x0d, 0xcb, 0x5b, 0x74, 0xc3, 0xfb, 0x9b, 0x3e, 0x03, 0x97, 0x6f, - 0x8b, 0x75, 0x24, 0xea, 0xba, 0xd0, 0x08, 0x89, 0x21, 0x07, 0xf6, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - c_enc: [ - 0x20, 0x77, 0xdf, 0x43, 0x25, 0x24, 0x61, 0x4c, 0x07, 0x6e, 0x77, 0x93, 0x02, 0x41, - 0x91, 0xaa, 0xc9, 0xe4, 0x93, 0xf5, 0xc8, 0xa9, 0x87, 0x45, 0xae, 0x65, 0x31, 0x0c, - 0xfc, 0xb5, 0x75, 0x56, 0x4a, 0x93, 0xf1, 0x27, 0x2b, 0xce, 0x90, 0x07, 0x77, 0xb8, - 0x50, 0x49, 0x7e, 0x84, 0x54, 0x0c, 0xb1, 0x92, 0x03, 0x85, 0x65, 0x88, 0x2f, 0xa4, - 0xf3, 0x71, 0x21, 0x3e, 0xb5, 0x09, 0x00, 0x41, 0xff, 0xd9, 0x24, 0x7b, 0xee, 0x2b, - 0xb1, 0x53, 0x21, 0x22, 0x83, 0xb2, 0x7e, 0x36, 0xe2, 0x84, 0x60, 0x3c, 0x0b, 0xc4, - 0x0c, 0x46, 0x5f, 0xc6, 0xab, 0x8f, 0x88, 0x98, 0x5e, 0xf5, 0x0e, 0x2a, 0xb0, 0xeb, - 0x66, 0xa6, 0x34, 0x30, 0x9b, 0xb9, 0x02, 0xc6, 0xcd, 0xd6, 0xa5, 0x55, 0xb8, 0xc3, - 0x71, 0x48, 0x9f, 0x57, 0xc7, 0xea, 0x3b, 0x54, 0x37, 0xf2, 0x87, 0xc7, 0x4e, 0x35, - 0xe0, 0x34, 0xcc, 0x68, 0x08, 0xe2, 0xc9, 0xf2, 0xc9, 0x73, 0xfa, 0xc9, 0x6e, 0x84, - 0x9d, 0x31, 0xde, 0x76, 0xf8, 0x06, 0x63, 0xa5, 0x82, 0xb2, 0x3a, 0xfc, 0x36, 0x45, - 0x5e, 0xc4, 0x6e, 0x23, 0x8c, 0xb2, 0x84, 0xda, 0xf1, 0x11, 0x4a, 0x6e, 0x5b, 0xd0, - 0x28, 0x9a, 0xef, 0xb7, 0x46, 0x94, 0x31, 0xb8, 0xb8, 0x60, 0x89, 0xb9, 0xd3, 0x6f, - 0xfd, 0x67, 0x45, 0xbd, 0x86, 0x7b, 0xaa, 0x6b, 0x58, 0xfb, 0x30, 0xaf, 0xa0, 0x97, - 0xab, 0x9e, 0x57, 0x38, 0x8f, 0x4f, 0xdf, 0xc0, 0xfd, 0x48, 0x3d, 0xc6, 0x7f, 0x02, - 0xbc, 0x07, 0x99, 0x0e, 0x1a, 0x39, 0x7b, 0x11, 0x2d, 0x5d, 0xbc, 0xf2, 0x2f, 0x9b, - 0x64, 0xf5, 0xf5, 0x43, 0x10, 0x24, 0x63, 0xe3, 0x0f, 0x46, 0x81, 0x72, 0x85, 0x39, - 0xc0, 0xc5, 0xc5, 0xe0, 0x0a, 0x25, 0x35, 0xae, 0xf7, 0x68, 0xe3, 0xaf, 0x7d, 0x47, - 0xa0, 0x8d, 0xdb, 0x99, 0xea, 0x2e, 0xd0, 0x0c, 0x52, 0xbf, 0x4b, 0x5e, 0xb3, 0x14, - 0x05, 0x85, 0xb0, 0xf9, 0x0e, 0xcf, 0x7d, 0x21, 0x5b, 0x4c, 0xc1, 0x8a, 0xf9, 0xae, - 0xc8, 0x17, 0x0c, 0x6d, 0xb6, 0xc6, 0x69, 0x98, 0xb8, 0xda, 0x0f, 0x09, 0x17, 0xf1, - 0x38, 0x0c, 0x87, 0xa4, 0x18, 0x1b, 0x86, 0xc6, 0xcd, 0xfe, 0x6f, 0x2d, 0xb2, 0x21, - 0x41, 0xe7, 0x98, 0x4b, 0x1a, 0xac, 0xf7, 0xce, 0xc5, 0xe7, 0xd0, 0x76, 0xaa, 0xc5, - 0x47, 0x9e, 0xd7, 0x14, 0x40, 0xb2, 0xd4, 0x60, 0x18, 0x5b, 0xa3, 0xdb, 0xea, 0x03, - 0xc8, 0xfc, 0xca, 0xc0, 0x9a, 0xec, 0xd3, 0x3a, 0x3f, 0xdd, 0xa9, 0xa1, 0x34, 0xea, - 0x42, 0xa1, 0xa9, 0x78, 0xc4, 0x05, 0x17, 0x99, 0xe6, 0xcc, 0x69, 0x6f, 0x8a, 0x49, - 0x40, 0x0a, 0xea, 0xd6, 0x65, 0x2f, 0x93, 0xa2, 0x58, 0x22, 0x0c, 0x63, 0x38, 0xb9, - 0xe7, 0x3b, 0x10, 0xa0, 0x1c, 0xd2, 0xec, 0x39, 0x72, 0x86, 0x1c, 0x7b, 0x62, 0x69, - 0x5a, 0xda, 0xa5, 0x41, 0x4a, 0x78, 0x74, 0x50, 0xe7, 0xa5, 0xf8, 0x21, 0xe4, 0xf2, - 0x45, 0xdd, 0x97, 0x2c, 0x08, 0x92, 0xe8, 0x6f, 0xa1, 0x26, 0xba, 0x59, 0x5c, 0x12, - 0x25, 0x73, 0x8e, 0x2f, 0x8b, 0xe3, 0x6f, 0x11, 0xdc, 0xc5, 0x2c, 0xed, 0x4f, 0x78, - 0x75, 0xdf, 0x5b, 0xbb, 0xd8, 0x3a, 0xec, 0x8d, 0x43, 0x13, 0x07, 0x2d, 0x7e, 0xc9, - 0x47, 0xaf, 0x86, 0xb5, 0x6b, 0x65, 0xfc, 0xb1, 0xbd, 0x32, 0xf0, 0xdb, 0x0c, 0xb3, - 0x7d, 0xea, 0xa6, 0xcd, 0xe0, 0xdf, 0xe4, 0xbd, 0xb8, 0x09, 0x16, 0x1e, 0xda, 0x03, - 0x4a, 0x94, 0x9a, 0x3a, 0x03, 0x9a, 0xf9, 0xbb, 0xe0, 0x9e, 0xaf, 0xb3, 0x5b, 0x7c, - 0xd8, 0xb5, 0x32, 0x83, 0x42, 0xc3, 0x93, 0x22, 0x1a, 0x4f, 0x13, 0x4b, 0x15, 0xa4, - 0x16, 0x3c, 0x05, 0x3b, 0x32, 0xeb, 0xa8, 0x5e, 0x59, 0x36, 0x06, 0xda, 0x67, 0xa1, - 0x1c, 0xe1, 0x74, 0xb7, 0x7b, 0xbe, 0xfd, 0x50, 0xef, 0x10, 0x25, 0xe9, 0x4a, 0x06, - 0xc5, 0xe0, 0x98, 0x8d, 0xb7, 0xf9, 0xda, 0x54, 0x0a, 0xa3, 0xb1, 0xc0, 0x33, 0x09, - 0xb4, 0xb1, 0x40, 0x01, 0xe2, 0xc4, 0x5a, 0xa9, 0x99, 0x65, 0x0b, 0x01, 0xaa, 0x3b, - 0xef, 0x5f, 0xb2, 0xd3, 0x38, 0x0c, 0xbf, 0x33, 0xc5, 0x5d, 0x45, 0x70, 0x25, 0x9f, - 0x1e, 0x3e, 0xd7, 0xe0, 0x0c, 0xa9, - ], - ock: [ - 0x54, 0xce, 0xb1, 0x1b, 0xb0, 0xe8, 0xf8, 0x54, 0x86, 0x10, 0xd1, 0x1f, 0xf1, 0xab, - 0x14, 0x92, 0xd1, 0x8d, 0x5c, 0x85, 0x3c, 0x8f, 0x2f, 0x0c, 0xd5, 0xd1, 0x9d, 0x6d, - 0x34, 0xcf, 0x7c, 0x2d, - ], - _op: [ - 0xd1, 0x1d, 0xa0, 0x1f, 0x0b, 0x43, 0xbd, 0xd5, 0x28, 0x8d, 0x32, 0x38, 0x5b, 0x87, - 0x71, 0xd2, 0x23, 0x49, 0x3c, 0x69, 0x80, 0x25, 0x44, 0x04, 0x3f, 0x77, 0xcf, 0x1d, - 0x71, 0xc1, 0xcb, 0x8c, 0x6d, 0xa9, 0x45, 0xd3, 0x03, 0x81, 0xc2, 0xee, 0xd2, 0xb8, - 0x1d, 0x27, 0x08, 0x6d, 0x22, 0x48, 0xe7, 0xc4, 0x49, 0xfe, 0x50, 0x9b, 0x38, 0xe2, - 0x76, 0x79, 0x11, 0x89, 0xea, 0xbc, 0x46, 0x02, - ], - c_out: [ - 0xe7, 0x72, 0xe0, 0x1d, 0x61, 0x09, 0xb6, 0xf9, 0x85, 0xb1, 0x77, 0x2e, 0xd1, 0x55, - 0x0a, 0x94, 0x7b, 0x35, 0xa8, 0x4b, 0x3e, 0x71, 0x12, 0x33, 0x31, 0xa3, 0xd6, 0x1f, - 0x1b, 0xf5, 0x96, 0x4e, 0x97, 0x42, 0x54, 0x42, 0xe5, 0xc8, 0xef, 0x2b, 0x9d, 0x84, - 0xab, 0x3d, 0xcb, 0xab, 0x9c, 0x96, 0xfe, 0x6a, 0x89, 0xce, 0x1d, 0x5e, 0x8a, 0x9b, - 0x83, 0xb5, 0x09, 0x0b, 0xb0, 0x7c, 0x50, 0x45, 0x0b, 0xbb, 0xfc, 0x8a, 0x74, 0x64, - 0xa7, 0x7c, 0x33, 0x97, 0x16, 0x33, 0xb2, 0x13, 0x68, 0xf0, - ], - }, - TestVector { - ovk: [ - 0xe9, 0xe0, 0xdc, 0x1e, 0xd3, 0x11, 0xda, 0xed, 0x64, 0xbd, 0x74, 0xda, 0x5d, 0x94, - 0xfe, 0x88, 0xa6, 0xea, 0x41, 0x4b, 0x73, 0x12, 0xde, 0x3d, 0x2a, 0x78, 0xf6, 0x46, - 0x32, 0xbb, 0xe3, 0x73, - ], - ivk: [ - 0x87, 0x16, 0xc8, 0x28, 0x80, 0xe1, 0x36, 0x83, 0xe1, 0xbb, 0x05, 0x9d, 0xd0, 0x6c, - 0x80, 0xc9, 0x01, 0x34, 0xa9, 0x6d, 0x5a, 0xfc, 0xa8, 0xaa, 0xc2, 0xbb, 0xf6, 0x8b, - 0xb0, 0x5f, 0x84, 0x02, - ], - default_d: [ - 0xad, 0x6e, 0x2e, 0x18, 0x5a, 0x31, 0x00, 0xe3, 0xa6, 0xa8, 0xb3, - ], - default_pk_d: [ - 0x32, 0xcb, 0x28, 0x06, 0xb8, 0x82, 0xf1, 0x36, 0x8b, 0x0d, 0x4a, 0x89, 0x8f, 0x72, - 0xc4, 0xc8, 0xf7, 0x28, 0x13, 0x2c, 0xc1, 0x24, 0x56, 0x94, 0x6e, 0x7f, 0x4c, 0xb0, - 0xfb, 0x05, 0x8d, 0xa9, - ], - v: 800000000, - rcm: [ - 0x51, 0x65, 0xaf, 0xf2, 0x2d, 0xd4, 0xed, 0x56, 0xb4, 0xd8, 0x1d, 0x1f, 0x17, 0x1c, - 0xc3, 0xd6, 0x43, 0x2f, 0xed, 0x1b, 0xeb, 0xf2, 0x0a, 0x7b, 0xea, 0xb1, 0x2d, 0xb1, - 0x42, 0xf9, 0x4a, 0x0c, - ], - memo: [ - 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - cv: [ - 0x29, 0x54, 0xcc, 0x7f, 0x9f, 0x9d, 0xfe, 0xb1, 0x4f, 0x02, 0xee, 0xbf, 0xf3, 0xf8, - 0x48, 0xd5, 0xd0, 0xe3, 0xd2, 0xe0, 0x1f, 0xeb, 0xc9, 0x16, 0x41, 0xf4, 0x12, 0x6c, - 0x60, 0x34, 0x33, 0x0c, - ], - cmu: [ - 0x09, 0x90, 0xcd, 0xb9, 0xa5, 0x2e, 0x5c, 0xd1, 0xba, 0x54, 0xd9, 0x20, 0x4c, 0x26, - 0x69, 0x1c, 0xb0, 0x36, 0xb1, 0x30, 0x12, 0x21, 0x26, 0xeb, 0x14, 0x12, 0x9c, 0xdf, - 0x0f, 0xc5, 0x18, 0x3c, - ], - esk: [ - 0xab, 0x2a, 0xff, 0x03, 0x32, 0xd5, 0x43, 0xfd, 0x1d, 0x80, 0x23, 0x18, 0x5b, 0x8e, - 0xcb, 0x5f, 0x22, 0xa2, 0x9c, 0x32, 0xef, 0x74, 0x16, 0x33, 0x31, 0x6e, 0xee, 0x51, - 0x4f, 0xc2, 0x23, 0x09, - ], - epk: [ - 0xd0, 0x04, 0x99, 0x7c, 0x79, 0xd0, 0x07, 0xa5, 0x3b, 0xf2, 0xfd, 0x2f, 0x6a, 0x66, - 0xc0, 0xaf, 0xd9, 0xf8, 0x79, 0xb5, 0x5f, 0xec, 0xdc, 0x15, 0x8a, 0x90, 0x12, 0x32, - 0xb7, 0x88, 0x48, 0x09, - ], - shared_secret: [ - 0xa8, 0xde, 0xa9, 0xbe, 0x94, 0xdc, 0xca, 0xc8, 0x15, 0x75, 0xb4, 0x4f, 0x4b, 0xe8, - 0x53, 0xe8, 0xc0, 0xf7, 0xe6, 0xba, 0x7f, 0x0b, 0xf8, 0xf2, 0xb3, 0xa1, 0xb8, 0x9c, - 0x6a, 0xc8, 0x92, 0x39, - ], - k_enc: [ - 0x14, 0x1b, 0x55, 0x0a, 0xd3, 0xc2, 0xe7, 0xdf, 0xdc, 0xd4, 0x2d, 0x4a, 0xba, 0x31, - 0x39, 0x97, 0x42, 0xa9, 0x29, 0xbb, 0x23, 0x10, 0x0a, 0x7c, 0x51, 0xed, 0x32, 0xf9, - 0xcb, 0x45, 0x96, 0xc6, - ], - _p_enc: [ - 0x01, 0xad, 0x6e, 0x2e, 0x18, 0x5a, 0x31, 0x00, 0xe3, 0xa6, 0xa8, 0xb3, 0x00, 0x08, - 0xaf, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x51, 0x65, 0xaf, 0xf2, 0x2d, 0xd4, 0xed, 0x56, - 0xb4, 0xd8, 0x1d, 0x1f, 0x17, 0x1c, 0xc3, 0xd6, 0x43, 0x2f, 0xed, 0x1b, 0xeb, 0xf2, - 0x0a, 0x7b, 0xea, 0xb1, 0x2d, 0xb1, 0x42, 0xf9, 0x4a, 0x0c, 0xf6, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - c_enc: [ - 0x6d, 0x3e, 0xff, 0x72, 0x8a, 0x28, 0x8e, 0x35, 0x59, 0xd8, 0x96, 0x06, 0xa4, 0x50, - 0xce, 0x14, 0x86, 0x4d, 0xf9, 0x03, 0x23, 0xcb, 0x2f, 0x41, 0xfb, 0xa2, 0x68, 0x84, - 0x3c, 0xec, 0x77, 0x75, 0x48, 0xbc, 0xc4, 0x25, 0xf5, 0xed, 0x1e, 0x6e, 0x8c, 0x75, - 0xe2, 0xda, 0xe3, 0x56, 0x16, 0x84, 0x56, 0x39, 0x1b, 0x87, 0xb5, 0xc6, 0xcd, 0x55, - 0x50, 0x3f, 0x12, 0xc3, 0x4f, 0x94, 0xb0, 0xd8, 0x24, 0xa7, 0x7a, 0xe6, 0x21, 0x3f, - 0xf4, 0x3f, 0x12, 0xa3, 0x4f, 0x2c, 0x66, 0x8e, 0xa1, 0x6b, 0xd1, 0xf0, 0x4a, 0x91, - 0xd3, 0x9a, 0x7b, 0x60, 0x19, 0x7c, 0x7b, 0x58, 0x62, 0x90, 0x36, 0xa8, 0x8f, 0xa7, - 0x0a, 0x8d, 0x5b, 0xf8, 0x3e, 0xd4, 0xdb, 0x40, 0x63, 0xb1, 0xea, 0xce, 0x10, 0x95, - 0xf9, 0x06, 0x62, 0xce, 0x9f, 0x6a, 0xc0, 0x26, 0x73, 0xf7, 0xb9, 0xa3, 0x6e, 0xbc, - 0x52, 0xf4, 0x98, 0x4b, 0xd7, 0x11, 0x53, 0xb3, 0xe2, 0xed, 0xca, 0x80, 0x3d, 0x86, - 0x90, 0x26, 0xee, 0x2f, 0xf0, 0x22, 0x8a, 0xfa, 0x7b, 0x61, 0xd0, 0xd3, 0x8c, 0x9b, - 0xcc, 0xb3, 0x00, 0x8b, 0x32, 0xc6, 0xa0, 0x59, 0x84, 0x2e, 0xe8, 0xa0, 0x7b, 0xa1, - 0x2c, 0x63, 0x08, 0x43, 0x6b, 0x64, 0x89, 0x85, 0x35, 0x3d, 0x7d, 0xd5, 0x8b, 0x20, - 0x92, 0xb5, 0xac, 0x2e, 0xd7, 0xe7, 0x20, 0x65, 0xec, 0xad, 0xa6, 0x50, 0xae, 0xe6, - 0xcd, 0x00, 0xfd, 0x34, 0xd5, 0x8c, 0x2b, 0x58, 0xd4, 0x1a, 0x48, 0xaa, 0xc7, 0xbf, - 0x4b, 0x45, 0xc9, 0x6c, 0x53, 0xa1, 0x0b, 0x04, 0xdb, 0x73, 0xcc, 0x83, 0x27, 0x1b, - 0xa6, 0x71, 0x17, 0xd6, 0x42, 0xe4, 0xd8, 0x19, 0xc3, 0x02, 0xd7, 0x18, 0x5e, 0xcc, - 0xbf, 0xa5, 0x40, 0x5b, 0x80, 0xc5, 0xb3, 0xe4, 0xb2, 0xc5, 0x52, 0x43, 0x28, 0x60, - 0x80, 0x81, 0x78, 0xcb, 0x8f, 0xce, 0x40, 0x5b, 0x73, 0xfe, 0xf2, 0xb3, 0x46, 0xc4, - 0x1b, 0xb2, 0xb2, 0xfa, 0xd7, 0x1a, 0x80, 0x31, 0x3b, 0xe3, 0xcf, 0x01, 0xec, 0xfd, - 0x88, 0x8f, 0x25, 0x72, 0xed, 0xcf, 0x57, 0xe4, 0xd7, 0x1e, 0x47, 0xcf, 0x8d, 0x52, - 0xdb, 0xa4, 0xc6, 0x44, 0x0d, 0x0d, 0x4a, 0x9b, 0x19, 0x3f, 0x57, 0x74, 0x8d, 0x20, - 0xf8, 0x9a, 0xb5, 0xd6, 0xda, 0x16, 0x14, 0x36, 0x2a, 0x5f, 0xb8, 0x5f, 0x6a, 0xb2, - 0xbe, 0x35, 0xc7, 0x2f, 0xd6, 0x28, 0x7a, 0xe5, 0x5c, 0xd2, 0x77, 0x79, 0x19, 0x44, - 0xdf, 0x24, 0xa3, 0x76, 0x46, 0x71, 0xdd, 0xd4, 0x06, 0x0a, 0x9b, 0x9c, 0xab, 0x01, - 0x4a, 0xbe, 0x14, 0x35, 0x09, 0x31, 0x64, 0xa6, 0x9f, 0x61, 0xbf, 0x29, 0x24, 0x8c, - 0x35, 0x9c, 0xb6, 0x90, 0xab, 0x25, 0xe9, 0x93, 0xce, 0x39, 0x72, 0xd6, 0xee, 0x36, - 0x78, 0x5e, 0xf0, 0x61, 0x87, 0x20, 0x50, 0xf5, 0x26, 0xf7, 0xdb, 0x7f, 0xf1, 0x98, - 0xfb, 0xac, 0xff, 0x29, 0x85, 0x81, 0xb7, 0x33, 0x06, 0xef, 0xc0, 0x2b, 0xb9, 0xd4, - 0xab, 0x32, 0xdf, 0x26, 0x4f, 0x14, 0xa8, 0x0e, 0x7f, 0x0c, 0x76, 0xe5, 0xf1, 0x4d, - 0xa2, 0x9a, 0xb1, 0xea, 0x04, 0xa3, 0xe3, 0xf5, 0xba, 0x5e, 0x35, 0x05, 0x5d, 0xba, - 0xd2, 0x76, 0xe1, 0x20, 0x1c, 0xce, 0x0a, 0xec, 0x14, 0x82, 0xcb, 0xec, 0x1d, 0x3f, - 0xa4, 0xa1, 0x3d, 0x3e, 0x16, 0x51, 0x1b, 0x0d, 0xee, 0x35, 0x58, 0xc5, 0xae, 0xef, - 0x27, 0xe3, 0xe6, 0x1b, 0x91, 0x51, 0xe5, 0x5a, 0x5a, 0xe1, 0x57, 0x03, 0x0c, 0xe5, - 0x97, 0xf8, 0x21, 0x82, 0x89, 0x3e, 0xe4, 0xd6, 0xbd, 0x4f, 0xb0, 0x87, 0x29, 0xbb, - 0xc3, 0x01, 0x41, 0x9c, 0xe0, 0x66, 0x41, 0x45, 0xba, 0x7a, 0xb8, 0xcb, 0xc0, 0x65, - 0x48, 0xe1, 0xf7, 0xfd, 0xf5, 0x3d, 0x06, 0x05, 0xa7, 0x7b, 0xe6, 0xe4, 0x0c, 0x54, - 0x00, 0x90, 0xf9, 0x8c, 0x25, 0xb1, 0x25, 0xbe, 0x74, 0x99, 0xf1, 0x76, 0xbb, 0x85, - 0x01, 0x49, 0x33, 0x53, 0xcf, 0x90, 0x5f, 0x72, 0x25, 0x00, 0x62, 0xd6, 0xcf, 0x01, - 0x88, 0x14, 0x82, 0x46, 0xee, 0x94, 0xef, 0x9b, 0x21, 0xad, 0xb7, 0xae, 0x1a, 0xe7, - 0x3b, 0xb6, 0xe6, 0x8f, 0xa9, 0x1d, 0x7f, 0xb4, 0x98, 0x28, 0xd6, 0x57, 0xd8, 0x19, - 0x5f, 0x6e, 0x95, 0x08, 0x2f, 0xad, - ], - ock: [ - 0xda, 0xb4, 0x26, 0x26, 0x9e, 0x8d, 0x33, 0x09, 0x55, 0x23, 0x7a, 0x9f, 0xed, 0x86, - 0x83, 0xa9, 0x27, 0x7c, 0x61, 0x82, 0xa8, 0x08, 0xcc, 0x53, 0xa1, 0xbe, 0xdd, 0xd2, - 0x03, 0x68, 0xb1, 0x0a, - ], - _op: [ - 0x32, 0xcb, 0x28, 0x06, 0xb8, 0x82, 0xf1, 0x36, 0x8b, 0x0d, 0x4a, 0x89, 0x8f, 0x72, - 0xc4, 0xc8, 0xf7, 0x28, 0x13, 0x2c, 0xc1, 0x24, 0x56, 0x94, 0x6e, 0x7f, 0x4c, 0xb0, - 0xfb, 0x05, 0x8d, 0xa9, 0xab, 0x2a, 0xff, 0x03, 0x32, 0xd5, 0x43, 0xfd, 0x1d, 0x80, - 0x23, 0x18, 0x5b, 0x8e, 0xcb, 0x5f, 0x22, 0xa2, 0x9c, 0x32, 0xef, 0x74, 0x16, 0x33, - 0x31, 0x6e, 0xee, 0x51, 0x4f, 0xc2, 0x23, 0x09, - ], - c_out: [ - 0xaf, 0x4d, 0x97, 0xfb, 0x72, 0x28, 0xf0, 0x1f, 0x6d, 0x9e, 0x2f, 0x79, 0xa1, 0xa1, - 0xba, 0x45, 0xa2, 0x3d, 0x60, 0x90, 0x59, 0x78, 0x4e, 0xa9, 0x35, 0x0f, 0x1e, 0xb0, - 0x92, 0xb0, 0x54, 0xa3, 0x26, 0x8c, 0xc0, 0x26, 0xd3, 0xd7, 0x37, 0xef, 0x35, 0xad, - 0xc2, 0x86, 0xd1, 0x95, 0xea, 0xa4, 0x14, 0x49, 0x3e, 0xd2, 0xa5, 0x1f, 0x2f, 0x61, - 0x09, 0x9a, 0x34, 0x51, 0xf9, 0x55, 0x5b, 0xab, 0x1a, 0x5e, 0xf3, 0xe3, 0xfb, 0xbe, - 0x8e, 0xc6, 0x41, 0x6b, 0xd3, 0x3d, 0x50, 0xdf, 0xf9, 0x8f, - ], - }, - TestVector { - ovk: [ - 0x14, 0x7d, 0xd1, 0x1d, 0x77, 0xeb, 0xa1, 0xb1, 0x63, 0x6f, 0xd6, 0x19, 0x0c, 0x62, - 0xb9, 0xa5, 0xd0, 0x48, 0x1b, 0xee, 0x7e, 0x91, 0x7f, 0xab, 0x02, 0xe2, 0x18, 0x58, - 0x06, 0x3a, 0xb5, 0x04, - ], - ivk: [ - 0x99, 0xc9, 0xb4, 0xb8, 0x4f, 0x4b, 0x4e, 0x35, 0x0f, 0x78, 0x7d, 0x1c, 0xf7, 0x05, - 0x1d, 0x50, 0xec, 0xc3, 0x4b, 0x1a, 0x5b, 0x20, 0xd2, 0xd2, 0x13, 0x9b, 0x4a, 0xf1, - 0xf1, 0x60, 0xe0, 0x01, - ], - default_d: [ - 0x21, 0xc9, 0x0e, 0x1c, 0x65, 0x8b, 0x3e, 0xfe, 0x86, 0xaf, 0x58, - ], - default_pk_d: [ - 0x9e, 0x64, 0x17, 0x4b, 0x4a, 0xb9, 0x81, 0x40, 0x5c, 0x32, 0x3b, 0x5e, 0x12, 0x47, - 0x59, 0x45, 0xa4, 0x6d, 0x4f, 0xed, 0xf8, 0x06, 0x08, 0x28, 0x04, 0x1c, 0xd2, 0x0e, - 0x62, 0xfd, 0x2c, 0xef, - ], - v: 900000000, - rcm: [ - 0x8c, 0x3e, 0x56, 0x44, 0x9d, 0xc8, 0x63, 0x54, 0xd3, 0x3b, 0x02, 0x5e, 0xf2, 0x79, - 0x34, 0x60, 0xbc, 0xb1, 0x69, 0xf3, 0x32, 0x4e, 0x4a, 0x6b, 0x64, 0xba, 0xa6, 0x08, - 0x32, 0x31, 0x57, 0x04, - ], - memo: [ - 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - cv: [ - 0x4a, 0x85, 0xeb, 0x3f, 0x25, 0x3f, 0x3b, 0xaa, 0xf6, 0xb5, 0x5a, 0x99, 0x49, 0x51, - 0xb2, 0xca, 0x82, 0x48, 0xcb, 0xd6, 0x79, 0xf7, 0xa5, 0x77, 0xe3, 0x3b, 0xcd, 0x66, - 0x46, 0xb2, 0x13, 0x51, - ], - cmu: [ - 0x56, 0x90, 0xcd, 0x51, 0xa4, 0x5c, 0xe8, 0x9a, 0x51, 0xac, 0xbe, 0x01, 0x60, 0x60, - 0xf0, 0xdf, 0xee, 0x0d, 0x2f, 0xc9, 0xb8, 0x97, 0x58, 0x5f, 0x97, 0x4a, 0x40, 0x2e, - 0x53, 0x7f, 0xe2, 0x18, - ], - esk: [ - 0xa5, 0x3d, 0x19, 0xf5, 0x69, 0x45, 0x95, 0xd5, 0xae, 0x63, 0x02, 0x27, 0x67, 0x3c, - 0x80, 0x24, 0x9c, 0xe1, 0x24, 0x41, 0x9f, 0x46, 0xdf, 0x4e, 0x7b, 0x3f, 0xc1, 0x04, - 0x61, 0x28, 0xcd, 0x0b, - ], - epk: [ - 0x4d, 0xfc, 0x8a, 0x70, 0xb2, 0x10, 0xdf, 0xd4, 0x48, 0x37, 0xaa, 0x52, 0xd6, 0x3b, - 0xd5, 0xd8, 0x1a, 0x5e, 0x40, 0xd8, 0xb4, 0xc1, 0x7a, 0x2d, 0xca, 0x25, 0xa5, 0xf7, - 0x5f, 0xe5, 0x20, 0x2e, - ], - shared_secret: [ - 0x1f, 0xf7, 0x5f, 0x5e, 0x7a, 0x51, 0x4b, 0x3c, 0xf5, 0xb3, 0x3c, 0xa3, 0x1a, 0x67, - 0x1f, 0xc5, 0x0c, 0x26, 0x8c, 0xf1, 0xa3, 0x16, 0xb2, 0x1b, 0x98, 0x67, 0x4b, 0xaa, - 0x45, 0x00, 0x85, 0xcf, - ], - k_enc: [ - 0x3c, 0x52, 0xd9, 0xc8, 0x32, 0x07, 0xee, 0x14, 0xf5, 0x62, 0x0d, 0x16, 0x21, 0x82, - 0xa6, 0xb9, 0xca, 0xbe, 0xfd, 0xba, 0x9e, 0x7a, 0x74, 0xf5, 0xba, 0x2f, 0x81, 0xb8, - 0x71, 0x40, 0x1f, 0x08, - ], - _p_enc: [ - 0x01, 0x21, 0xc9, 0x0e, 0x1c, 0x65, 0x8b, 0x3e, 0xfe, 0x86, 0xaf, 0x58, 0x00, 0xe9, - 0xa4, 0x35, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x3e, 0x56, 0x44, 0x9d, 0xc8, 0x63, 0x54, - 0xd3, 0x3b, 0x02, 0x5e, 0xf2, 0x79, 0x34, 0x60, 0xbc, 0xb1, 0x69, 0xf3, 0x32, 0x4e, - 0x4a, 0x6b, 0x64, 0xba, 0xa6, 0x08, 0x32, 0x31, 0x57, 0x04, 0xf6, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - c_enc: [ - 0x84, 0xd3, 0x61, 0x09, 0xbd, 0xd2, 0x1c, 0x67, 0x8e, 0x84, 0x47, 0xf8, 0x89, 0xe5, - 0x60, 0xef, 0x6d, 0x07, 0xa8, 0x27, 0xaa, 0xab, 0x78, 0x9b, 0x46, 0xc3, 0xf9, 0xeb, - 0x32, 0x2e, 0xea, 0x21, 0x4c, 0x20, 0xf7, 0xe9, 0xfa, 0x7f, 0x7a, 0xa5, 0xe0, 0x44, - 0xa4, 0xed, 0x4c, 0xb1, 0x5d, 0xa9, 0xc5, 0x6c, 0x32, 0xf3, 0x7e, 0x4c, 0xbe, 0x7d, - 0x1e, 0xd1, 0xf6, 0x85, 0xa8, 0x74, 0x8d, 0xbf, 0x78, 0x12, 0x90, 0xf9, 0x7a, 0xc1, - 0x41, 0x40, 0xaa, 0x8b, 0x50, 0x93, 0x2a, 0x3f, 0x66, 0xc2, 0x08, 0x22, 0x6f, 0x8d, - 0x8e, 0xc0, 0xde, 0xb7, 0xbb, 0x58, 0x35, 0x72, 0xc9, 0xe9, 0x70, 0xbc, 0xd0, 0xc6, - 0x44, 0x67, 0x26, 0xaa, 0x5b, 0x6a, 0x5f, 0x81, 0xcf, 0x18, 0xc6, 0x7a, 0x99, 0x2d, - 0x6c, 0x86, 0x03, 0x86, 0xab, 0xbb, 0x5b, 0x90, 0xbe, 0x58, 0x64, 0x34, 0x4f, 0xc8, - 0xbf, 0x3e, 0xbb, 0x75, 0x41, 0xaa, 0x9b, 0x9e, 0x1e, 0x3f, 0x96, 0x25, 0xac, 0xce, - 0x7f, 0x4b, 0xf1, 0x58, 0x39, 0xa0, 0x81, 0x70, 0x68, 0xe9, 0x15, 0x1b, 0x63, 0x7f, - 0xa2, 0xa2, 0xca, 0x09, 0xb9, 0xbe, 0x28, 0x5f, 0xea, 0x7e, 0x0a, 0x03, 0x31, 0x7c, - 0x29, 0x8a, 0xd7, 0xff, 0xfe, 0x40, 0xc5, 0xf0, 0xf6, 0xe9, 0xfb, 0x44, 0xe8, 0xf0, - 0x6e, 0x19, 0x2f, 0x1a, 0xc2, 0x10, 0x8f, 0x3f, 0x11, 0xf7, 0x76, 0x3c, 0xf2, 0x1e, - 0x96, 0x62, 0x4d, 0x52, 0xf3, 0xe7, 0x2a, 0xaf, 0x15, 0x7f, 0x3b, 0xc7, 0xc5, 0xd1, - 0x8f, 0x1e, 0xba, 0x3d, 0x82, 0x7f, 0x71, 0x9c, 0x27, 0x9f, 0xd9, 0x66, 0xc2, 0x7d, - 0x94, 0xd7, 0x47, 0x23, 0xc5, 0x31, 0x1b, 0x86, 0x65, 0xbd, 0x29, 0xb3, 0xa1, 0x00, - 0xbb, 0x21, 0x11, 0xaa, 0x42, 0x16, 0xf0, 0x66, 0x5b, 0x16, 0x9e, 0xc0, 0x94, 0x17, - 0x68, 0xa9, 0x57, 0x4a, 0xe5, 0x0c, 0x2b, 0xc7, 0x90, 0x05, 0x53, 0xf5, 0xc4, 0x50, - 0xee, 0x98, 0x82, 0xaf, 0x44, 0x55, 0xd1, 0xd8, 0xce, 0x35, 0x18, 0x49, 0xd7, 0x8d, - 0xbb, 0xe6, 0x1e, 0xd1, 0xdb, 0x7a, 0x2f, 0xd6, 0x57, 0x75, 0xd5, 0x50, 0x6d, 0xfd, - 0x02, 0xa9, 0x4d, 0x9d, 0x42, 0x85, 0xa2, 0x3a, 0x3c, 0xab, 0x8a, 0xa3, 0x32, 0x14, - 0x22, 0xa4, 0xaa, 0xa5, 0x49, 0x27, 0x4a, 0x25, 0xf7, 0xf1, 0x2f, 0xf7, 0xa5, 0x19, - 0x5e, 0x51, 0x55, 0x73, 0x9f, 0x31, 0x8c, 0x30, 0xc0, 0x24, 0x8c, 0x3a, 0x21, 0x9a, - 0x7a, 0xde, 0x72, 0x98, 0x38, 0x0a, 0x59, 0x5c, 0x5c, 0x88, 0x5b, 0x42, 0x06, 0x69, - 0xcd, 0x6d, 0xeb, 0x2e, 0x5c, 0x80, 0x49, 0x78, 0xcb, 0x42, 0xd2, 0x06, 0x02, 0x74, - 0x57, 0x33, 0x60, 0x7c, 0xef, 0x4e, 0x26, 0xa5, 0xc9, 0x7c, 0xca, 0x1c, 0xc5, 0x2b, - 0x7f, 0xdc, 0x10, 0x69, 0x01, 0x70, 0x18, 0x07, 0x6c, 0xac, 0x62, 0xe5, 0xc4, 0xdb, - 0xf9, 0x07, 0x48, 0x72, 0x05, 0x0a, 0x42, 0x22, 0x19, 0x51, 0x3b, 0xca, 0x27, 0xa8, - 0x35, 0xf4, 0x82, 0x4f, 0x47, 0xba, 0x33, 0x7d, 0xeb, 0x74, 0x40, 0xf3, 0xf2, 0xca, - 0xce, 0x9e, 0x33, 0x16, 0x70, 0xdd, 0x98, 0xe3, 0x28, 0xab, 0x0a, 0x16, 0xac, 0x4a, - 0xb6, 0x62, 0x76, 0xd1, 0xe1, 0x01, 0x8b, 0x2c, 0xf1, 0x79, 0x43, 0x62, 0x66, 0xa4, - 0x08, 0xda, 0x8d, 0xda, 0xfc, 0x44, 0xb2, 0x27, 0x6b, 0x11, 0x68, 0x52, 0xd4, 0xcc, - 0xb3, 0x52, 0x89, 0xb4, 0x21, 0x30, 0x09, 0x12, 0x5d, 0x2d, 0x87, 0x84, 0x5d, 0x6e, - 0xb7, 0x8e, 0x55, 0x03, 0x15, 0x3d, 0x92, 0xfb, 0xd4, 0x93, 0xd1, 0x9e, 0xf0, 0x1f, - 0x37, 0x00, 0x26, 0xba, 0xf1, 0x72, 0x30, 0x7b, 0x3f, 0xe2, 0xc4, 0x56, 0x96, 0xfb, - 0xce, 0xda, 0x3b, 0x6e, 0xab, 0x05, 0xe2, 0xb0, 0x68, 0x5c, 0x72, 0x79, 0x04, 0x98, - 0x23, 0x3a, 0xbb, 0xbd, 0x6e, 0x05, 0xb0, 0xf4, 0x4a, 0x72, 0x98, 0xae, 0x0a, 0x25, - 0xaf, 0x08, 0xd7, 0x95, 0x74, 0x61, 0x4c, 0xf2, 0xd8, 0x3e, 0xa7, 0x9c, 0x2b, 0x79, - 0x53, 0xf8, 0x6c, 0xf5, 0xd0, 0x49, 0x27, 0xf0, 0x9c, 0x0d, 0x7d, 0xf8, 0x12, 0xf1, - 0xcf, 0x18, 0xa4, 0x53, 0xa0, 0x49, 0x70, 0xaf, 0x0d, 0x72, 0x9c, 0xe7, 0xd9, 0xc8, - 0xd6, 0xa2, 0x4d, 0x7e, 0xed, 0x3d, - ], - ock: [ - 0xc9, 0x72, 0x1e, 0x9e, 0x65, 0xa2, 0x61, 0x85, 0x10, 0x07, 0xcd, 0x81, 0x46, 0x7b, - 0xa5, 0xf3, 0x58, 0x05, 0xba, 0x78, 0x5a, 0x2c, 0x92, 0xa9, 0xaa, 0x62, 0x32, 0xb0, - 0x55, 0x1c, 0xf3, 0xf4, - ], - _op: [ - 0x9e, 0x64, 0x17, 0x4b, 0x4a, 0xb9, 0x81, 0x40, 0x5c, 0x32, 0x3b, 0x5e, 0x12, 0x47, - 0x59, 0x45, 0xa4, 0x6d, 0x4f, 0xed, 0xf8, 0x06, 0x08, 0x28, 0x04, 0x1c, 0xd2, 0x0e, - 0x62, 0xfd, 0x2c, 0xef, 0xa5, 0x3d, 0x19, 0xf5, 0x69, 0x45, 0x95, 0xd5, 0xae, 0x63, - 0x02, 0x27, 0x67, 0x3c, 0x80, 0x24, 0x9c, 0xe1, 0x24, 0x41, 0x9f, 0x46, 0xdf, 0x4e, - 0x7b, 0x3f, 0xc1, 0x04, 0x61, 0x28, 0xcd, 0x0b, - ], - c_out: [ - 0xbc, 0x16, 0xaf, 0xa8, 0xaa, 0xb2, 0x38, 0x06, 0x26, 0x01, 0x8c, 0xe2, 0x75, 0x58, - 0x67, 0x55, 0x8f, 0x9d, 0x59, 0x85, 0x73, 0x93, 0xa1, 0xf3, 0x48, 0xb2, 0x1c, 0xb5, - 0x0f, 0x53, 0xea, 0xba, 0xe7, 0xf6, 0xe4, 0x7b, 0x45, 0x24, 0x1f, 0x6b, 0x7b, 0x3d, - 0x68, 0x94, 0x5d, 0xd4, 0x0c, 0xad, 0xc5, 0x7a, 0x9a, 0xde, 0x6a, 0xf9, 0x69, 0xae, - 0x07, 0x4f, 0xf2, 0x89, 0xbc, 0xb6, 0x61, 0x0a, 0xe3, 0x8c, 0x82, 0x10, 0xa5, 0xcb, - 0xd7, 0x47, 0xb8, 0x31, 0x15, 0x1c, 0x56, 0xef, 0x02, 0xc9, - ], - }, - TestVector { - ovk: [ - 0x57, 0x34, 0x67, 0xa7, 0xb3, 0x0e, 0xad, 0x6c, 0xcc, 0x50, 0x47, 0x44, 0xca, 0x9e, - 0x1a, 0x28, 0x1a, 0x0d, 0x1a, 0x08, 0x73, 0x8b, 0x06, 0xa0, 0x68, 0x4f, 0xea, 0xcd, - 0x1e, 0x9d, 0x12, 0x6d, - ], - ivk: [ - 0xdb, 0x95, 0xea, 0x8b, 0xd9, 0xf9, 0x3d, 0x41, 0xb5, 0xab, 0x2b, 0xeb, 0xc9, 0x1a, - 0x38, 0xed, 0xd5, 0x27, 0x08, 0x3e, 0x2a, 0x6e, 0xf9, 0xf3, 0xc2, 0x97, 0x02, 0xd5, - 0xff, 0x89, 0xed, 0x00, - ], - default_d: [ - 0x23, 0x3c, 0x4a, 0xb8, 0x86, 0xa5, 0x5e, 0x3b, 0xa3, 0x74, 0xc0, - ], - default_pk_d: [ - 0xb6, 0x8e, 0x9e, 0xe0, 0xc0, 0x67, 0x8d, 0x7b, 0x30, 0x36, 0x93, 0x1c, 0x83, 0x1a, - 0x25, 0x25, 0x5f, 0x7e, 0xe4, 0x87, 0x38, 0x5a, 0x30, 0x31, 0x6e, 0x15, 0xf6, 0x48, - 0x2b, 0x87, 0x4f, 0xda, - ], - v: 1000000000, - rcm: [ - 0x6e, 0xbb, 0xed, 0x74, 0x36, 0x19, 0xa2, 0x56, 0xf9, 0xad, 0x2e, 0x85, 0x88, 0x0c, - 0xfa, 0xa9, 0x09, 0x8a, 0x5f, 0xdb, 0x16, 0x29, 0x99, 0x0d, 0x9a, 0x7d, 0x3b, 0xb9, - 0x3f, 0xc9, 0x00, 0x03, - ], - memo: [ - 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - cv: [ - 0x2a, 0x54, 0x7d, 0x97, 0x8c, 0x7c, 0x90, 0xa8, 0xd0, 0xa5, 0x47, 0x4e, 0x29, 0xdb, - 0xff, 0xf3, 0x4b, 0xae, 0x81, 0xe6, 0x40, 0x8e, 0xc1, 0xfe, 0x2d, 0x56, 0xa2, 0x52, - 0x41, 0xa8, 0xe3, 0x29, - ], - cmu: [ - 0xf4, 0xba, 0x4e, 0xf0, 0x40, 0xf8, 0x0d, 0x00, 0x08, 0x0d, 0x29, 0xa6, 0xb3, 0x99, - 0xdc, 0x40, 0x32, 0x40, 0x33, 0x61, 0xe0, 0x59, 0x1e, 0xd6, 0x14, 0x99, 0xbc, 0x06, - 0x8e, 0x41, 0xed, 0x38, - ], - esk: [ - 0x29, 0x95, 0x89, 0x80, 0x69, 0x4f, 0x7f, 0x67, 0x08, 0x09, 0x97, 0xc2, 0x66, 0x47, - 0x02, 0x89, 0x0c, 0xd1, 0xb5, 0x03, 0xdd, 0xa4, 0x2d, 0x33, 0xa8, 0x99, 0xce, 0x99, - 0x1f, 0xe0, 0xf8, 0x00, - ], - epk: [ - 0xea, 0x6b, 0x3c, 0x98, 0x5f, 0x33, 0xb2, 0xa2, 0x2d, 0x0d, 0xbf, 0x7c, 0xd9, 0x30, - 0x19, 0xfd, 0x9e, 0x57, 0x31, 0x6c, 0x85, 0xb7, 0x67, 0x49, 0x54, 0x62, 0x9c, 0x77, - 0xdf, 0xae, 0xc0, 0x66, - ], - shared_secret: [ - 0xc0, 0x64, 0x58, 0x25, 0xdf, 0xc4, 0x4d, 0x54, 0x82, 0x83, 0xf6, 0xe8, 0x88, 0x25, - 0x3b, 0xf5, 0xc3, 0x2a, 0x90, 0xde, 0xbb, 0x92, 0x8e, 0x89, 0x67, 0x86, 0xac, 0x0b, - 0x16, 0xd5, 0xf6, 0x56, - ], - k_enc: [ - 0x33, 0xd2, 0xda, 0x8d, 0x80, 0xe0, 0xce, 0xd8, 0xb4, 0xbe, 0xec, 0x94, 0x3a, 0x0f, - 0xc9, 0xc9, 0x60, 0xad, 0x7c, 0xcc, 0x59, 0x77, 0x43, 0x74, 0x4c, 0x18, 0xc9, 0xc2, - 0xa5, 0x62, 0xf6, 0x3a, - ], - _p_enc: [ - 0x01, 0x23, 0x3c, 0x4a, 0xb8, 0x86, 0xa5, 0x5e, 0x3b, 0xa3, 0x74, 0xc0, 0x00, 0xca, - 0x9a, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x6e, 0xbb, 0xed, 0x74, 0x36, 0x19, 0xa2, 0x56, - 0xf9, 0xad, 0x2e, 0x85, 0x88, 0x0c, 0xfa, 0xa9, 0x09, 0x8a, 0x5f, 0xdb, 0x16, 0x29, - 0x99, 0x0d, 0x9a, 0x7d, 0x3b, 0xb9, 0x3f, 0xc9, 0x00, 0x03, 0xf6, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - ], - c_enc: [ - 0x14, 0x9a, 0x52, 0xf8, 0xf5, 0x34, 0x2b, 0x44, 0x84, 0x88, 0x91, 0xf8, 0x85, 0xd3, - 0xcd, 0x09, 0x9a, 0xbe, 0x80, 0x5a, 0xa5, 0x09, 0x1f, 0xe1, 0x71, 0x0e, 0xb7, 0x35, - 0x02, 0xde, 0x38, 0x7d, 0xf3, 0xf9, 0x64, 0x67, 0x22, 0xe8, 0xb8, 0x5c, 0x37, 0x7c, - 0x82, 0x2a, 0x71, 0x03, 0x34, 0x7c, 0x81, 0x01, 0xe9, 0xae, 0x8c, 0x31, 0x82, 0xca, - 0x36, 0xda, 0xfd, 0x75, 0x8d, 0x96, 0xce, 0xba, 0x48, 0x32, 0x7a, 0x09, 0x82, 0x86, - 0xa4, 0xe8, 0x32, 0x1d, 0x1e, 0x74, 0xfe, 0x3d, 0x61, 0x59, 0xc0, 0x29, 0x48, 0x3d, - 0xe9, 0xee, 0xf3, 0xb2, 0x4d, 0x85, 0xe4, 0xd5, 0x16, 0xb8, 0x70, 0x4f, 0x8e, 0x7d, - 0x93, 0xe7, 0x44, 0x42, 0xed, 0x00, 0x7a, 0xd7, 0x9a, 0x61, 0x52, 0xf2, 0xb6, 0x64, - 0x2f, 0xbe, 0xe6, 0x04, 0x35, 0xe1, 0x92, 0x09, 0xd8, 0x11, 0xc6, 0x6c, 0x17, 0xb7, - 0xdf, 0x3d, 0xfd, 0x76, 0x9f, 0xb5, 0xc7, 0xd0, 0x06, 0xb3, 0x67, 0x42, 0xbb, 0xe7, - 0x26, 0x92, 0x9e, 0x87, 0x9b, 0x11, 0x6d, 0x36, 0x13, 0x57, 0x1a, 0xa6, 0x3a, 0xc2, - 0xcc, 0xca, 0x43, 0xf8, 0x90, 0x0b, 0x89, 0x3e, 0x64, 0xdd, 0x0b, 0x8f, 0xf9, 0x1e, - 0xc5, 0x11, 0x40, 0x82, 0xe6, 0xd0, 0x0c, 0xf9, 0x3a, 0x7c, 0xfa, 0x75, 0x18, 0xbb, - 0x7f, 0xb6, 0x4a, 0x7f, 0x34, 0x64, 0x20, 0xb6, 0x44, 0x78, 0xd7, 0x18, 0x69, 0xe9, - 0x1d, 0x47, 0x97, 0x90, 0x1f, 0xa8, 0x6e, 0x70, 0xb2, 0x20, 0x1a, 0xfe, 0x4b, 0xd3, - 0xea, 0x55, 0x03, 0x81, 0x6f, 0xac, 0x68, 0x7d, 0x81, 0x25, 0x2f, 0x65, 0x61, 0x6e, - 0x7f, 0xb2, 0x68, 0x46, 0x52, 0x1e, 0x39, 0xff, 0x94, 0xbe, 0x73, 0xb8, 0xac, 0xa8, - 0x04, 0xc6, 0x5c, 0xf9, 0x4e, 0x32, 0x56, 0xbd, 0x3c, 0x69, 0xad, 0x31, 0x8e, 0x6b, - 0x28, 0x55, 0x19, 0x48, 0x77, 0x93, 0xee, 0x29, 0x88, 0x51, 0x40, 0xf0, 0xbc, 0x00, - 0x84, 0x5f, 0x67, 0x41, 0x5f, 0x67, 0x0f, 0x04, 0xca, 0x81, 0x8c, 0x5f, 0x32, 0x49, - 0xd3, 0xfb, 0x70, 0xbf, 0xea, 0x10, 0xc6, 0x25, 0xeb, 0x8c, 0xf2, 0xca, 0xb3, 0xf5, - 0x83, 0x62, 0x2a, 0x21, 0xa3, 0x8b, 0x8f, 0xe5, 0x1a, 0x5f, 0xf2, 0x91, 0x9e, 0xf4, - 0xc1, 0xbd, 0x98, 0x30, 0xa9, 0xf2, 0x48, 0x6a, 0xbd, 0x88, 0x5d, 0xd9, 0x43, 0xb9, - 0x4e, 0xdc, 0x8f, 0x88, 0xc8, 0xb7, 0x8a, 0x5e, 0xb0, 0x31, 0xf3, 0x4b, 0x7d, 0x93, - 0x1c, 0x87, 0x53, 0xaf, 0xd9, 0x76, 0x8d, 0x0f, 0xa8, 0xd2, 0x6e, 0x88, 0xc9, 0x56, - 0x7a, 0xd5, 0x89, 0x23, 0xe7, 0xb0, 0xaf, 0xbd, 0xaa, 0xdf, 0x47, 0x7b, 0xd1, 0xd2, - 0x3f, 0xc4, 0x0a, 0x42, 0xc2, 0x9b, 0x4d, 0x5f, 0xe1, 0x08, 0x76, 0x45, 0xdd, 0xfd, - 0xeb, 0xa0, 0xc7, 0xd5, 0x67, 0x15, 0xcd, 0x57, 0xf0, 0xd1, 0x74, 0x1a, 0x3d, 0x9c, - 0xb3, 0x8d, 0x88, 0xd6, 0x47, 0xb1, 0xc5, 0xb2, 0x4a, 0xdd, 0xba, 0xd1, 0xac, 0xfa, - 0x3a, 0x8d, 0xa3, 0x7a, 0x74, 0x26, 0x05, 0x55, 0xec, 0x0d, 0xea, 0x88, 0xed, 0x2c, - 0x7f, 0x46, 0xdd, 0x87, 0xb3, 0xf2, 0x79, 0xa9, 0x6a, 0x0e, 0x78, 0x54, 0xec, 0x4a, - 0x79, 0xce, 0xad, 0xc7, 0x4a, 0x68, 0x0f, 0xc8, 0x2d, 0x75, 0xae, 0xc7, 0xf2, 0xd1, - 0x3d, 0xfb, 0x62, 0x23, 0x50, 0x57, 0xe4, 0xf7, 0xdc, 0x5b, 0x07, 0xc6, 0xba, 0xba, - 0x82, 0xb3, 0x2f, 0xe9, 0x0b, 0x5c, 0x6e, 0x9d, 0xc6, 0xb2, 0xfb, 0x33, 0xbe, 0xac, - 0x88, 0x0d, 0x3a, 0x60, 0xba, 0x08, 0x48, 0xfa, 0xc6, 0x61, 0x9d, 0xa8, 0xca, 0x33, - 0xa6, 0x32, 0x94, 0xeb, 0x63, 0xd0, 0xf2, 0x4c, 0xbb, 0x1e, 0x03, 0x17, 0x82, 0x88, - 0x0f, 0xfa, 0x18, 0x35, 0x6c, 0x98, 0x76, 0x2c, 0xcd, 0xd3, 0xaf, 0xab, 0x81, 0xf1, - 0x9a, 0xbf, 0x3b, 0xdd, 0x2b, 0xc4, 0x3c, 0xb1, 0xf2, 0x15, 0x5c, 0xaf, 0x64, 0x98, - 0x89, 0x4e, 0x06, 0x8b, 0xa7, 0x49, 0xc9, 0x76, 0xec, 0x23, 0xf2, 0x11, 0x62, 0x26, - 0x14, 0x60, 0x78, 0x56, 0xd8, 0x7b, 0x74, 0x16, 0x24, 0xf7, 0xf8, 0x34, 0x95, 0xd7, - 0xde, 0x4d, 0x6d, 0xe2, 0x08, 0xe1, 0x35, 0x74, 0xc8, 0x2a, 0x1b, 0x8b, 0x1c, 0xfe, - 0x87, 0xe9, 0x18, 0xe7, 0xb3, 0x96, - ], - ock: [ - 0xdb, 0x5b, 0xa6, 0xb9, 0xdb, 0xb1, 0x1f, 0x7c, 0xe8, 0x12, 0xeb, 0x1b, 0xf3, 0x29, - 0x8c, 0xca, 0x55, 0x71, 0xee, 0xcc, 0x69, 0xb7, 0x22, 0xa0, 0xa3, 0xb8, 0x67, 0x50, - 0x72, 0x92, 0x99, 0xa0, - ], - _op: [ - 0xb6, 0x8e, 0x9e, 0xe0, 0xc0, 0x67, 0x8d, 0x7b, 0x30, 0x36, 0x93, 0x1c, 0x83, 0x1a, - 0x25, 0x25, 0x5f, 0x7e, 0xe4, 0x87, 0x38, 0x5a, 0x30, 0x31, 0x6e, 0x15, 0xf6, 0x48, - 0x2b, 0x87, 0x4f, 0xda, 0x29, 0x95, 0x89, 0x80, 0x69, 0x4f, 0x7f, 0x67, 0x08, 0x09, - 0x97, 0xc2, 0x66, 0x47, 0x02, 0x89, 0x0c, 0xd1, 0xb5, 0x03, 0xdd, 0xa4, 0x2d, 0x33, - 0xa8, 0x99, 0xce, 0x99, 0x1f, 0xe0, 0xf8, 0x00, - ], - c_out: [ - 0xe2, 0x7a, 0x46, 0x4d, 0x6f, 0x44, 0xcc, 0x44, 0xf6, 0x17, 0xe2, 0x3c, 0x9f, 0xb1, - 0xb7, 0x1f, 0xff, 0xd4, 0x6a, 0xeb, 0xf0, 0x36, 0x77, 0xcf, 0x7d, 0xd2, 0x4d, 0x71, - 0x1b, 0xa0, 0xc6, 0xca, 0x38, 0x53, 0x09, 0x7b, 0x24, 0x7a, 0xb7, 0x4c, 0x15, 0xbb, - 0x93, 0x8e, 0xd6, 0x02, 0xfb, 0xcd, 0x30, 0xf4, 0xa6, 0x59, 0x56, 0x43, 0x0f, 0x47, - 0xa0, 0xfb, 0xcb, 0xe8, 0xe0, 0x8a, 0xad, 0xa3, 0x86, 0x30, 0x78, 0x5a, 0x80, 0x57, - 0x53, 0xba, 0x33, 0xb3, 0x34, 0xcd, 0x2a, 0x4b, 0xfc, 0x3d, - ], - }, - ] -} diff --git a/zcash_primitives/src/transaction/components/sapling.rs b/zcash_primitives/src/transaction/components/sapling.rs index 0d37250d5..d77512122 100644 --- a/zcash_primitives/src/transaction/components/sapling.rs +++ b/zcash_primitives/src/transaction/components/sapling.rs @@ -47,10 +47,10 @@ fn read_cmu(mut reader: R) -> io::Result { /// Consensus rules (§7.3) & (§7.4): /// - Canonical encoding is enforced here -pub fn read_base(mut reader: R, field: &str) -> io::Result { +pub fn read_base(mut reader: R, field: &str) -> io::Result { let mut f = [0u8; 32]; reader.read_exact(&mut f)?; - Option::from(bls12_381::Scalar::from_repr(f)).ok_or_else(|| { + Option::from(jubjub::Base::from_repr(f)).ok_or_else(|| { io::Error::new( io::ErrorKind::InvalidInput, format!("{} not in field", field), @@ -379,7 +379,7 @@ pub(crate) fn read_v5_bundle( .map(|(od_5, zkproof)| od_5.into_output_description(zkproof)) .collect(); - Ok(binding_sig.map(|binding_sig| { + Ok(binding_sig.and_then(|binding_sig| { Bundle::from_parts( shielded_spends, shielded_outputs, diff --git a/zcash_primitives/src/transaction/mod.rs b/zcash_primitives/src/transaction/mod.rs index d25ca56fa..431f421a5 100644 --- a/zcash_primitives/src/transaction/mod.rs +++ b/zcash_primitives/src/transaction/mod.rs @@ -646,7 +646,7 @@ impl Transaction { expiry_height, transparent_bundle, sprout_bundle, - sapling_bundle: binding_sig.map(|binding_sig| { + sapling_bundle: binding_sig.and_then(|binding_sig| { sapling::Bundle::from_parts( shielded_spends, shielded_outputs,