From 1a8ded00389facc38756bf8ce8d43548a252c13c Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Sun, 10 Mar 2024 10:25:52 -0600 Subject: [PATCH] Add a `Rho` type, to distinguish from revealed note nullifiers. This change removes the ability to construct a `Rho` value directly from the public API, except via deserialization from bytes (which is necessary in order to be able to serialize a `Note`). Ordinarily, `Rho` should be obtained either from an already-constructed `Note` or from an `Action` or `CompactAction`. --- CHANGELOG.md | 17 ++++++ src/action.rs | 7 ++- src/builder.rs | 5 +- src/circuit.rs | 13 ++--- src/keys.rs | 4 +- src/note.rs | 76 +++++++++++++++++++------- src/note_encryption.rs | 82 ++++++++++++++++++++++++----- src/test_vectors/note_encryption.rs | 22 ++++---- 8 files changed, 174 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb92d1993..995654890 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,23 @@ and this project adheres to Rust's notion of ## [Unreleased] +### Added +- `orchard::note::Rho` +- `orchard::action::Action::rho` +- `orchard::note_encryption::CompactAction::rho` +- `orchard::note_encryption::OrchardDomain::for_compact_action` + +### Changed +- The following methods have their `Nullifier`-typed argument or return value + now take or return `note::Rho` instead: + - `orchard::note::RandomSeed::from_bytes` + - `orchard::note::Note::from_parts` + - `orchard::note::Note::rho` + +### Removed +- `orchard::note_encryption::OrchardDomain::for_nullifier` (use `for_action` + or `for_compact_action` instead). + ## [0.7.1] - 2024-02-29 ### Added - `impl subtle::ConstantTimeEq for orchard::note::Nullifier` diff --git a/src/action.rs b/src/action.rs index 76ec740d2..04bcc2089 100644 --- a/src/action.rs +++ b/src/action.rs @@ -1,7 +1,7 @@ use memuse::DynamicUsage; use crate::{ - note::{ExtractedNoteCommitment, Nullifier, TransmittedNoteCiphertext}, + note::{ExtractedNoteCommitment, Nullifier, Rho, TransmittedNoteCiphertext}, primitives::redpallas::{self, SpendAuth}, value::ValueCommitment, }; @@ -66,6 +66,11 @@ impl Action { &self.encrypted_note } + /// Obtains the [`Rho`] value that was used to construct the new note being created. + pub fn rho(&self) -> Rho { + Rho::from_nf_old(self.nf) + } + /// Returns the commitment to the net value created or consumed by this action. pub fn cv_net(&self) -> &ValueCommitment { &self.cv_net diff --git a/src/builder.rs b/src/builder.rs index 69ae5b597..37bdc3883 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -18,7 +18,7 @@ use crate::{ FullViewingKey, OutgoingViewingKey, Scope, SpendAuthorizingKey, SpendValidatingKey, SpendingKey, }, - note::{Note, TransmittedNoteCiphertext}, + note::{Note, Rho, TransmittedNoteCiphertext}, note_encryption::OrchardNoteEncryption, primitives::redpallas::{self, Binding, SpendAuth}, tree::{Anchor, MerklePath}, @@ -335,11 +335,12 @@ impl ActionInfo { let cv_net = ValueCommitment::derive(v_net, self.rcv.clone()); let nf_old = self.spend.note.nullifier(&self.spend.fvk); + let rho = Rho::from_nf_old(nf_old); let ak: SpendValidatingKey = self.spend.fvk.clone().into(); let alpha = pallas::Scalar::random(&mut rng); let rk = ak.randomize(&alpha); - let note = Note::new(self.output.recipient, self.output.value, nf_old, &mut rng); + let note = Note::new(self.output.recipient, self.output.value, rho, &mut rng); let cm_new = note.commitment(); let cmx = cm_new.into(); diff --git a/src/circuit.rs b/src/circuit.rs index 36c0bf3da..567b60658 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -36,7 +36,7 @@ use crate::{ note::{ commitment::{NoteCommitTrapdoor, NoteCommitment}, nullifier::Nullifier, - ExtractedNoteCommitment, Note, + ExtractedNoteCommitment, Note, Rho, }, primitives::redpallas::{SpendAuth, VerificationKey}, spec::NonIdentityPallasPoint, @@ -105,7 +105,7 @@ pub struct Circuit { pub(crate) g_d_old: Value, pub(crate) pk_d_old: Value, pub(crate) v_old: Value, - pub(crate) rho_old: Value, + pub(crate) rho_old: Value, pub(crate) psi_old: Value, pub(crate) rcm_old: Value, pub(crate) cm_old: Value, @@ -143,7 +143,7 @@ impl Circuit { alpha: pallas::Scalar, rcv: ValueCommitTrapdoor, ) -> Option { - (spend.note.nullifier(&spend.fvk) == output_note.rho()) + (Rho::from_nf_old(spend.note.nullifier(&spend.fvk)) == output_note.rho()) .then(|| Self::from_action_context_unchecked(spend, output_note, alpha, rcv)) } @@ -406,7 +406,7 @@ impl plonk::Circuit for Circuit { let rho_old = assign_free_advice( layouter.namespace(|| "witness rho_old"), config.advices[0], - self.rho_old.map(|rho| rho.0), + self.rho_old.map(|rho| rho.into_inner()), )?; // Witness cm_old @@ -970,7 +970,7 @@ mod tests { use super::{Circuit, Instance, Proof, ProvingKey, VerifyingKey, K}; use crate::{ keys::SpendValidatingKey, - note::Note, + note::{Note, Rho}, tree::MerklePath, value::{ValueCommitTrapdoor, ValueCommitment}, }; @@ -982,11 +982,12 @@ mod tests { let nk = *fvk.nk(); let rivk = fvk.rivk(fvk.scope_for_address(&spent_note.recipient()).unwrap()); let nf_old = spent_note.nullifier(&fvk); + let rho = Rho::from_nf_old(nf_old); let ak: SpendValidatingKey = fvk.into(); let alpha = pallas::Scalar::random(&mut rng); let rk = ak.randomize(&alpha); - let (_, _, output_note) = Note::dummy(&mut rng, Some(nf_old)); + let (_, _, output_note) = Note::dummy(&mut rng, Some(rho)); let cmx = output_note.commitment().into(); let value = spent_note.value() - output_note.value(); diff --git a/src/keys.rs b/src/keys.rs index 3189e4e2e..8b85bdcec 100644 --- a/src/keys.rs +++ b/src/keys.rs @@ -961,7 +961,7 @@ mod tests { *, }; use crate::{ - note::{ExtractedNoteCommitment, Nullifier, RandomSeed}, + note::{ExtractedNoteCommitment, RandomSeed, Rho}, value::NoteValue, Note, }; @@ -1041,7 +1041,7 @@ mod tests { let addr = fvk.address(diversifier, Scope::External); assert_eq!(&addr.pk_d().to_bytes(), &tv.default_pk_d); - let rho = Nullifier::from_bytes(&tv.note_rho).unwrap(); + let rho = Rho::from_bytes(&tv.note_rho).unwrap(); let note = Note::from_parts( addr, NoteValue::from_raw(tv.note_v), diff --git a/src/note.rs b/src/note.rs index e55397884..6a9c70b5a 100644 --- a/src/note.rs +++ b/src/note.rs @@ -1,6 +1,8 @@ //! Data structures used for note construction. use core::fmt; +use memuse::DynamicUsage; +use ff::PrimeField; use group::GroupEncoding; use pasta_curves::pallas; use rand::RngCore; @@ -19,12 +21,50 @@ pub use self::commitment::{ExtractedNoteCommitment, NoteCommitment}; pub(crate) mod nullifier; pub use self::nullifier::Nullifier; +/// The randomness used to construct a note. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Rho(pallas::Base); + +// We know that `pallas::Base` doesn't allocate internally. +memuse::impl_no_dynamic_usage!(Rho); + +impl Rho { + /// Deserialize the rho value from a byte array. + /// + /// This should only be used in cases where the components of a `Note` are being serialized and + /// stored individually. Use [`Action::rho`] or [`CompactAction::rho`] to obtain the [`Rho`] + /// value otherwise. + /// + /// [`Action::rho`]: crate::action::Action::rho + /// [`CompactAction::rho`]: crate::note_encryption::CompactAction::rho + pub fn from_bytes(bytes: &[u8; 32]) -> CtOption { + pallas::Base::from_repr(*bytes).map(Rho) + } + + /// Serialize the rho value to its canonical byte representation. + pub fn to_bytes(self) -> [u8; 32] { + self.0.to_repr() + } + + /// Constructs the [`Rho`] value to be used to construct a new note from the revealed nullifier + /// of the note being spent in the [`Action`] under construction. + /// + /// [`Action`]: crate::action::Action + pub(crate) fn from_nf_old(nf: Nullifier) -> Self { + Rho(nf.0) + } + + pub(crate) fn into_inner(self) -> pallas::Base { + self.0 + } +} + /// The ZIP 212 seed randomness for a note. #[derive(Copy, Clone, Debug)] pub struct RandomSeed([u8; 32]); impl RandomSeed { - pub(crate) fn random(rng: &mut impl RngCore, rho: &Nullifier) -> Self { + pub(crate) fn random(rng: &mut impl RngCore, rho: &Rho) -> Self { loop { let mut bytes = [0; 32]; rng.fill_bytes(&mut bytes); @@ -35,10 +75,10 @@ impl RandomSeed { } } - /// Reads a note's random seed from bytes, given the note's nullifier. + /// Reads a note's random seed from bytes, given the note's rho value. /// - /// Returns `None` if the nullifier is not for the same note as the seed. - pub fn from_bytes(rseed: [u8; 32], rho: &Nullifier) -> CtOption { + /// Returns `None` if the rho value is not for the same note as the seed. + pub fn from_bytes(rseed: [u8; 32], rho: &Rho) -> CtOption { let rseed = RandomSeed(rseed); let esk = rseed.esk_inner(rho); CtOption::new(rseed, esk.is_some()) @@ -52,14 +92,14 @@ impl RandomSeed { /// Defined in [Zcash Protocol Spec § 4.7.3: Sending Notes (Orchard)][orchardsend]. /// /// [orchardsend]: https://zips.z.cash/protocol/nu5.pdf#orchardsend - pub(crate) fn psi(&self, rho: &Nullifier) -> pallas::Base { + pub(crate) fn psi(&self, rho: &Rho) -> pallas::Base { to_base(PrfExpand::PSI.with(&self.0, &rho.to_bytes())) } /// Defined in [Zcash Protocol Spec § 4.7.3: Sending Notes (Orchard)][orchardsend]. /// /// [orchardsend]: https://zips.z.cash/protocol/nu5.pdf#orchardsend - fn esk_inner(&self, rho: &Nullifier) -> CtOption { + fn esk_inner(&self, rho: &Rho) -> CtOption { NonZeroPallasScalar::from_scalar(to_scalar( PrfExpand::ORCHARD_ESK.with(&self.0, &rho.to_bytes()), )) @@ -68,7 +108,7 @@ impl RandomSeed { /// Defined in [Zcash Protocol Spec § 4.7.3: Sending Notes (Orchard)][orchardsend]. /// /// [orchardsend]: https://zips.z.cash/protocol/nu5.pdf#orchardsend - fn esk(&self, rho: &Nullifier) -> NonZeroPallasScalar { + fn esk(&self, rho: &Rho) -> NonZeroPallasScalar { // We can't construct a RandomSeed for which this unwrap fails. self.esk_inner(rho).unwrap() } @@ -76,7 +116,7 @@ impl RandomSeed { /// Defined in [Zcash Protocol Spec § 4.7.3: Sending Notes (Orchard)][orchardsend]. /// /// [orchardsend]: https://zips.z.cash/protocol/nu5.pdf#orchardsend - pub(crate) fn rcm(&self, rho: &Nullifier) -> commitment::NoteCommitTrapdoor { + pub(crate) fn rcm(&self, rho: &Rho) -> commitment::NoteCommitTrapdoor { commitment::NoteCommitTrapdoor(to_scalar( PrfExpand::ORCHARD_RCM.with(&self.0, &rho.to_bytes()), )) @@ -92,11 +132,11 @@ pub struct Note { value: NoteValue, /// A unique creation ID for this note. /// - /// This is set to the nullifier of the note that was spent in the [`Action`] that - /// created this note. + /// This is produced from the nullifier of the note that will be spent in the [`Action`] that + /// creates this note. /// /// [`Action`]: crate::action::Action - rho: Nullifier, + rho: Rho, /// The seed randomness for various note components. rseed: RandomSeed, } @@ -129,7 +169,7 @@ impl Note { pub fn from_parts( recipient: Address, value: NoteValue, - rho: Nullifier, + rho: Rho, rseed: RandomSeed, ) -> CtOption { let note = Note { @@ -149,7 +189,7 @@ impl Note { pub(crate) fn new( recipient: Address, value: NoteValue, - rho: Nullifier, + rho: Rho, mut rng: impl RngCore, ) -> Self { loop { @@ -167,7 +207,7 @@ impl Note { /// [orcharddummynotes]: https://zips.z.cash/protocol/nu5.pdf#orcharddummynotes pub(crate) fn dummy( rng: &mut impl RngCore, - rho: Option, + rho: Option, ) -> (SpendingKey, FullViewingKey, Self) { let sk = SpendingKey::random(rng); let fvk: FullViewingKey = (&sk).into(); @@ -176,7 +216,7 @@ impl Note { let note = Note::new( recipient, NoteValue::zero(), - rho.unwrap_or_else(|| Nullifier::dummy(rng)), + rho.unwrap_or_else(|| Rho::from_nf_old(Nullifier::dummy(rng))), rng, ); @@ -204,7 +244,7 @@ impl Note { } /// Returns rho of this note. - pub fn rho(&self) -> Nullifier { + pub fn rho(&self) -> Rho { self.rho } @@ -283,7 +323,7 @@ pub mod testing { address::testing::arb_address, note::nullifier::testing::arb_nullifier, value::NoteValue, }; - use super::{Note, RandomSeed}; + use super::{Note, RandomSeed, Rho}; prop_compose! { /// Generate an arbitrary random seed @@ -296,7 +336,7 @@ pub mod testing { /// Generate an action without authorization data. pub fn arb_note(value: NoteValue)( recipient in arb_address(), - rho in arb_nullifier(), + rho in arb_nullifier().prop_map(Rho::from_nf_old), rseed in arb_rseed(), ) -> Note { Note { diff --git a/src/note_encryption.rs b/src/note_encryption.rs index 27da4724a..56d5599cf 100644 --- a/src/note_encryption.rs +++ b/src/note_encryption.rs @@ -16,7 +16,7 @@ use crate::{ DiversifiedTransmissionKey, Diversifier, EphemeralPublicKey, EphemeralSecretKey, OutgoingViewingKey, PreparedEphemeralPublicKey, PreparedIncomingViewingKey, SharedSecret, }, - note::{ExtractedNoteCommitment, Nullifier, RandomSeed}, + note::{ExtractedNoteCommitment, Nullifier, RandomSeed, Rho}, value::{NoteValue, ValueCommitment}, Address, Note, }; @@ -81,7 +81,7 @@ where /// Orchard-specific note encryption logic. #[derive(Debug)] pub struct OrchardDomain { - rho: Nullifier, + rho: Rho, } impl memuse::DynamicUsage for OrchardDomain { @@ -97,14 +97,12 @@ impl memuse::DynamicUsage for OrchardDomain { impl OrchardDomain { /// Constructs a domain that can be used to trial-decrypt this action's output note. pub fn for_action(act: &Action) -> Self { - OrchardDomain { - rho: *act.nullifier(), - } + Self { rho: act.rho() } } - /// Constructs a domain from a nullifier. - pub fn for_nullifier(nullifier: Nullifier) -> Self { - OrchardDomain { rho: nullifier } + /// Constructs a domain that can be used to trial-decrypt this action's output note. + pub fn for_compact_action(act: &CompactAction) -> Self { + Self { rho: act.rho() } } } @@ -335,6 +333,65 @@ impl CompactAction { pub fn cmx(&self) -> ExtractedNoteCommitment { self.cmx } + + /// Obtains the [`Rho`] value that was used to construct the new note being created. + pub fn rho(&self) -> Rho { + Rho::from_nf_old(self.nullifier) + } +} + +/// Utilities for constructing test data. +#[cfg(feature = "test-dependencies")] +pub mod testing { + use rand::RngCore; + use zcash_note_encryption::Domain; + + use crate::{ + keys::OutgoingViewingKey, + note::{ExtractedNoteCommitment, Nullifier, RandomSeed, Rho}, + value::NoteValue, + Address, Note, + }; + + use super::{CompactAction, OrchardDomain, OrchardNoteEncryption}; + + /// Creates a fake `CompactAction` paying the given recipient the specified value. + /// + /// Returns the `CompactAction` and the new note. + pub fn fake_compact_action( + rng: &mut R, + nf_old: Nullifier, + recipient: Address, + value: NoteValue, + ovk: Option, + ) -> (CompactAction, Note) { + let rho = Rho::from_nf_old(nf_old); + let rseed = { + loop { + let mut bytes = [0; 32]; + rng.fill_bytes(&mut bytes); + let rseed = RandomSeed::from_bytes(bytes, &rho); + if rseed.is_some().into() { + break rseed.unwrap(); + } + } + }; + let note = Note::from_parts(recipient, value, rho, rseed).unwrap(); + let encryptor = OrchardNoteEncryption::new(ovk, note, [0u8; 512]); + let cmx = ExtractedNoteCommitment::from(note.commitment()); + let ephemeral_key = OrchardDomain::epk_bytes(encryptor.epk()); + let enc_ciphertext = encryptor.encrypt_note_plaintext(); + + ( + CompactAction { + nullifier: nf_old, + cmx, + ephemeral_key, + enc_ciphertext: enc_ciphertext.as_ref()[..52].try_into().unwrap(), + }, + note, + ) + } } #[cfg(test)] @@ -352,7 +409,7 @@ mod tests { DiversifiedTransmissionKey, Diversifier, EphemeralSecretKey, IncomingViewingKey, OutgoingViewingKey, PreparedIncomingViewingKey, }, - note::{ExtractedNoteCommitment, Nullifier, RandomSeed, TransmittedNoteCiphertext}, + note::{ExtractedNoteCommitment, Nullifier, RandomSeed, Rho, TransmittedNoteCiphertext}, primitives::redpallas, value::{NoteValue, ValueCommitment}, Address, Note, @@ -377,7 +434,8 @@ mod tests { // Received Action let cv_net = ValueCommitment::from_bytes(&tv.cv_net).unwrap(); - let rho = Nullifier::from_bytes(&tv.rho).unwrap(); + let nf_old = Nullifier::from_bytes(&tv.nf_old).unwrap(); + let rho = Rho::from_nf_old(nf_old); let cmx = ExtractedNoteCommitment::from_bytes(&tv.cmx).unwrap(); let esk = EphemeralSecretKey::from_bytes(&tv.esk).unwrap(); @@ -405,8 +463,8 @@ mod tests { assert_eq!(ExtractedNoteCommitment::from(note.commitment()), cmx); let action = Action::from_parts( - // rho is the nullifier in the receiving Action. - rho, + // nf_old is the nullifier revealed by the receiving Action. + nf_old, // We don't need a valid rk for this test. redpallas::VerificationKey::dummy(), cmx, diff --git a/src/test_vectors/note_encryption.rs b/src/test_vectors/note_encryption.rs index 10ac4f5e0..e27ec24d8 100644 --- a/src/test_vectors/note_encryption.rs +++ b/src/test_vectors/note_encryption.rs @@ -9,7 +9,7 @@ pub(crate) struct TestVector { pub(crate) rseed: [u8; 32], pub(crate) memo: [u8; 512], pub(crate) cv_net: [u8; 32], - pub(crate) rho: [u8; 32], + pub(crate) nf_old: [u8; 32], pub(crate) cmx: [u8; 32], pub(crate) esk: [u8; 32], pub(crate) ephemeral_key: [u8; 32], @@ -96,7 +96,7 @@ pub(crate) fn test_vectors() -> Vec { 0x42, 0xc2, 0x38, 0x51, 0x38, 0x15, 0x30, 0x2d, 0xf0, 0xf4, 0x83, 0x04, 0x21, 0xa6, 0xc1, 0x3e, 0x71, 0x01, ], - rho: [ + nf_old: [ 0xc5, 0x96, 0xfb, 0xd3, 0x2e, 0xbb, 0xcb, 0xad, 0xae, 0x60, 0xd2, 0x85, 0xc7, 0xd7, 0x5f, 0xa8, 0x36, 0xf9, 0xd2, 0xfa, 0x86, 0x10, 0x0a, 0xb8, 0x58, 0xea, 0x2d, 0xe1, 0xf1, 0x1c, 0x83, 0x06, @@ -305,7 +305,7 @@ pub(crate) fn test_vectors() -> Vec { 0xa2, 0x17, 0x64, 0x10, 0x4a, 0x23, 0xea, 0xf6, 0xba, 0x49, 0x6c, 0xb9, 0xb8, 0xe8, 0x25, 0x7a, 0xd8, 0xb3, ], - rho: [ + nf_old: [ 0x33, 0x88, 0xda, 0x05, 0x06, 0xda, 0x9e, 0xa2, 0xd5, 0x16, 0x73, 0x9b, 0x95, 0x1c, 0x7c, 0xc0, 0x58, 0x53, 0x36, 0xb4, 0x4d, 0xf9, 0xb3, 0xb5, 0x0e, 0x48, 0x93, 0xe4, 0xb1, 0x84, 0x92, 0x11, @@ -514,7 +514,7 @@ pub(crate) fn test_vectors() -> Vec { 0x9d, 0x5e, 0x64, 0x07, 0x19, 0xbc, 0xa5, 0xc8, 0xed, 0x49, 0x99, 0x97, 0x34, 0xe6, 0xc5, 0xb3, 0x73, 0x3e, ], - rho: [ + nf_old: [ 0xbe, 0xf8, 0xcf, 0x16, 0x98, 0xe4, 0x78, 0x47, 0xd3, 0x8e, 0x1a, 0xaa, 0x88, 0x86, 0x10, 0x77, 0xcd, 0xb5, 0xad, 0x4c, 0xf6, 0x6f, 0xe4, 0x2f, 0xd6, 0x52, 0x57, 0x81, 0xb6, 0xd3, 0x4f, 0x1e, @@ -723,7 +723,7 @@ pub(crate) fn test_vectors() -> Vec { 0xfa, 0xde, 0x94, 0xfa, 0x0b, 0x46, 0xe3, 0xb1, 0xa5, 0x73, 0x34, 0x99, 0x34, 0xe2, 0x32, 0xb5, 0x0e, 0x96, ], - rho: [ + nf_old: [ 0x18, 0x89, 0x8e, 0x75, 0x21, 0x7b, 0x32, 0x9b, 0x3a, 0x56, 0x7b, 0x09, 0x37, 0x89, 0xa4, 0xd8, 0x19, 0xcd, 0xb0, 0x34, 0x88, 0xb8, 0x10, 0xda, 0x22, 0x0c, 0x3f, 0x59, 0xba, 0x03, 0x39, 0x26, @@ -932,7 +932,7 @@ pub(crate) fn test_vectors() -> Vec { 0x72, 0x95, 0x89, 0xbe, 0x69, 0xd8, 0x28, 0xbe, 0x54, 0x30, 0x69, 0x16, 0x41, 0x3c, 0xd2, 0x50, 0x21, 0x17, ], - rho: [ + nf_old: [ 0x23, 0x39, 0xa8, 0x95, 0x29, 0xcf, 0x35, 0x7b, 0x06, 0x7d, 0xd2, 0x8b, 0xe4, 0x06, 0x6e, 0x16, 0x23, 0x6d, 0xc5, 0xd7, 0x87, 0x06, 0x14, 0x9a, 0x72, 0x8c, 0x3e, 0x3d, 0x9d, 0xc1, 0x08, 0x1c, @@ -1141,7 +1141,7 @@ pub(crate) fn test_vectors() -> Vec { 0x6e, 0x62, 0xe4, 0xed, 0xc7, 0x86, 0xd9, 0xe0, 0xb2, 0x7d, 0x26, 0x62, 0x8b, 0x79, 0xda, 0x6b, 0x15, 0x14, ], - rho: [ + nf_old: [ 0xe5, 0xd0, 0x8c, 0x40, 0x26, 0x3e, 0x4a, 0x2a, 0x56, 0x96, 0xda, 0x21, 0x0d, 0x8e, 0x9a, 0x77, 0xf0, 0xaf, 0xc4, 0xc6, 0x8a, 0x6d, 0xda, 0x38, 0xe2, 0x85, 0xf4, 0xe3, 0xef, 0x13, 0xb8, 0x17, @@ -1350,7 +1350,7 @@ pub(crate) fn test_vectors() -> Vec { 0x0a, 0x12, 0x01, 0x2d, 0x63, 0xc0, 0x09, 0xc6, 0x77, 0x44, 0xba, 0xe0, 0xd5, 0x83, 0x88, 0xff, 0xee, 0x2f, ], - rho: [ + nf_old: [ 0xe9, 0x16, 0x93, 0xc3, 0x7d, 0x04, 0x37, 0x5e, 0x67, 0xc5, 0x71, 0x5a, 0x39, 0xc9, 0x79, 0x4a, 0x4e, 0xcd, 0x08, 0x38, 0xe2, 0x35, 0x1f, 0xd7, 0xcd, 0x93, 0xa1, 0x55, 0x7f, 0x01, 0x02, 0x3e, @@ -1559,7 +1559,7 @@ pub(crate) fn test_vectors() -> Vec { 0xcd, 0x51, 0x00, 0x89, 0x08, 0xa6, 0xcd, 0xd0, 0xaa, 0x02, 0x1b, 0x88, 0x8b, 0x98, 0xe2, 0x3c, 0x39, 0x11, ], - rho: [ + nf_old: [ 0x35, 0x6f, 0xc7, 0x2e, 0x1b, 0xf1, 0xe3, 0xa2, 0xa5, 0x9a, 0xa9, 0xe4, 0x75, 0x15, 0x5c, 0xf7, 0x43, 0xf8, 0xfd, 0xf0, 0xd1, 0x5b, 0x4c, 0xc4, 0x02, 0x60, 0xd0, 0xd0, 0x9a, 0xda, 0x04, 0x08, @@ -1768,7 +1768,7 @@ pub(crate) fn test_vectors() -> Vec { 0x7e, 0xed, 0xd2, 0xa7, 0x06, 0x44, 0x07, 0x34, 0x78, 0x41, 0x01, 0xae, 0x2d, 0x8e, 0x87, 0xe5, 0x05, 0xad, ], - rho: [ + nf_old: [ 0x32, 0x91, 0x87, 0x35, 0x66, 0x3f, 0x34, 0xad, 0xa0, 0x22, 0x8a, 0xea, 0x4a, 0xcc, 0x19, 0x2a, 0x12, 0x3f, 0xcf, 0xa0, 0x60, 0x46, 0x89, 0xf9, 0x1a, 0xcb, 0xe9, 0x38, 0x31, 0xe4, 0x8c, 0x0c, @@ -1977,7 +1977,7 @@ pub(crate) fn test_vectors() -> Vec { 0xbd, 0xb9, 0x6f, 0x1c, 0xe0, 0x57, 0xc3, 0x30, 0xd1, 0xcc, 0xba, 0x2f, 0x7d, 0xa8, 0x71, 0x55, 0x00, 0xb5, ], - rho: [ + nf_old: [ 0x3b, 0x37, 0x96, 0x78, 0x0c, 0x0a, 0xec, 0x14, 0xed, 0x28, 0x74, 0xb5, 0x23, 0x06, 0xe1, 0xc3, 0xd5, 0xde, 0x45, 0x93, 0xc6, 0x69, 0xaf, 0x1c, 0xaf, 0x11, 0xbc, 0xb4, 0xd3, 0x5c, 0x60, 0x12,