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`.
This commit is contained in:
Kris Nuttycombe 2024-03-10 10:25:52 -06:00
parent a6b3407e2a
commit 1a8ded0038
8 changed files with 174 additions and 52 deletions

View File

@ -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`

View File

@ -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<T> Action<T> {
&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

View File

@ -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();

View File

@ -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<NonIdentityPallasPoint>,
pub(crate) pk_d_old: Value<DiversifiedTransmissionKey>,
pub(crate) v_old: Value<NoteValue>,
pub(crate) rho_old: Value<Nullifier>,
pub(crate) rho_old: Value<Rho>,
pub(crate) psi_old: Value<pallas::Base>,
pub(crate) rcm_old: Value<NoteCommitTrapdoor>,
pub(crate) cm_old: Value<NoteCommitment>,
@ -143,7 +143,7 @@ impl Circuit {
alpha: pallas::Scalar,
rcv: ValueCommitTrapdoor,
) -> Option<Circuit> {
(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<pallas::Base> 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();

View File

@ -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),

View File

@ -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<Self> {
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<Self> {
/// 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<Self> {
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<NonZeroPallasScalar> {
fn esk_inner(&self, rho: &Rho) -> CtOption<NonZeroPallasScalar> {
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<Self> {
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<Nullifier>,
rho: Option<Rho>,
) -> (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 {

View File

@ -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<T>(act: &Action<T>) -> 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<R: RngCore>(
rng: &mut R,
nf_old: Nullifier,
recipient: Address,
value: NoteValue,
ovk: Option<OutgoingViewingKey>,
) -> (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,

View File

@ -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<TestVector> {
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<TestVector> {
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<TestVector> {
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<TestVector> {
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<TestVector> {
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<TestVector> {
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<TestVector> {
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<TestVector> {
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<TestVector> {
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<TestVector> {
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,